Ozeki SIP C#语音通话问题:接通后立即挂断求助
问题分析与解决方案
核心问题定位
你的代码中存在几个关键问题导致接听后立即挂断:
全局与局部
call变量冲突
点击面板发起呼叫时,AyarlarTelefonPanel_Click里声明了局部IPhoneCall call,但全局静态call变量并未被赋值。而SetupDevices方法中使用的是全局call,此时该变量为null,调用mediaSender.AttachToCall(call)会引发异常,直接导致通话中断。媒体资源未正确管理
每次通话接通时重复创建MediaConnector、PhoneCallAudioSender和PhoneCallAudioReceiver,但未在通话结束时释放这些资源,容易引发资源占用冲突;同时没有检查麦克风/扬声器设备是否成功初始化,若设备获取失败会直接导致媒体链路异常。SIP账号信息未完善
RegisterAccount方法中的账号参数全为空,虽然你提到已在Yate客户端配置,但代码中未正确填写会影响注册稳定性,可能间接导致通话异常。
修改后的完整代码
using Ozeki.Media; using Ozeki.VoIP; using Ozeki.VoIP.Media; using System; using System.Windows.Forms; namespace OperationRoomControlPanelV1._1._0 { public partial class FormMain : Form { static ISoftPhone softphone; static IPhoneLine phoneLine; static IPhoneCall _activeCall; // 重命名避免冲突 static Microphone microphone; static Speaker speaker; static MediaConnector connector; static PhoneCallAudioSender mediaSender; static PhoneCallAudioReceiver mediaReceiver; public FormMain() { CheckForIllegalCrossThreadCalls = false; InitializeComponent(); try { softphone = SoftPhoneFactory.CreateSoftPhone(5000, 10000); // 检查设备是否获取成功 microphone = Microphone.GetDefaultDevice(); if (microphone == null) { MessageBox.Show("未找到默认麦克风设备"); return; } speaker = Speaker.GetDefaultDevice(); if (speaker == null) { MessageBox.Show("未找到默认扬声器设备"); return; } RegisterAccount(); softphone.IncomingCall += SoftPhone_IncomingCall; ayarlarTelefonPanel.Click += AyarlarTelefonPanel_Click; } catch (Exception ex) { MessageBox.Show($"初始化失败: {ex.Message}"); } } private void RegisterAccount() { try { // 替换为你的实际SIP账号信息 var registrationRequired = true; var userName = "你的SIP用户名"; var displayName = "显示名称"; var authenticationId = "认证ID(通常和用户名一致)"; var registerPassword = "SIP密码"; var domainHost = "SIP服务器地址"; var domainPort = 5060; var account = new SIPAccount(registrationRequired, displayName, userName, authenticationId, registerPassword, domainHost, domainPort); phoneLine = softphone.CreatePhoneLine(account); phoneLine.RegistrationStateChanged += PhoneLine_RegistrationStateChanged; // 监听注册状态 softphone.RegisterPhoneLine(phoneLine); } catch (Exception ex) { MessageBox.Show($"账号注册失败: {ex.Message}"); } } private void PhoneLine_RegistrationStateChanged(object sender, RegistrationStateChangedArgs e) { Console.WriteLine($"注册状态: {e.State}"); if (e.State == RegState.Registered) { MessageBox.Show("SIP账号注册成功"); } } private void SoftPhone_IncomingCall(object sender, VoIPEventArgs<IPhoneCall> e) { _activeCall = e.Item; _activeCall.CallStateChanged += PhoneCall_CallStateChanged; _activeCall.Answer(); } private void PhoneCall_CallStateChanged(object sender, CallStateChangedArgs e) { Console.WriteLine($"通话状态变更: {e.State}"); if (e.State == CallState.Answered) { SetupMediaDevices(); } else if (e.State == CallState.Completed || e.State == CallState.Cancelled) { CleanupMediaDevices(); } } private void SetupMediaDevices() { try { // 仅在无活跃媒体资源时初始化 if (connector == null) { connector = new MediaConnector(); mediaSender = new PhoneCallAudioSender(); mediaReceiver = new PhoneCallAudioReceiver(); } connector.Connect(microphone, mediaSender); connector.Connect(mediaReceiver, speaker); mediaSender.AttachToCall(_activeCall); mediaReceiver.AttachToCall(_activeCall); microphone.Start(); speaker.Start(); } catch (Exception ex) { Console.WriteLine($"媒体设备初始化错误: {ex.Message}"); _activeCall?.HangUp(); // 异常时主动挂断避免僵死 } } private void CleanupMediaDevices() { try { microphone?.Stop(); speaker?.Stop(); mediaSender?.Detach(); mediaReceiver?.Detach(); // 断开连接并释放资源 connector?.DisconnectAll(); connector = null; mediaSender = null; mediaReceiver = null; _activeCall = null; } catch (Exception ex) { Console.WriteLine($"媒体设备清理错误: {ex.Message}"); } } private void AyarlarTelefonPanel_Click(object sender, EventArgs e) { if (phoneLine == null || phoneLine.RegistrationState != RegState.Registered) { MessageBox.Show("SIP账号未注册,无法发起呼叫"); return; } string sipAddress = "sip:nnurcihangunsur@sip.linphone.org"; _activeCall = softphone.CreateCallObject(phoneLine, sipAddress); _activeCall.CallStateChanged += PhoneCall_CallStateChanged; _activeCall.Start(); } } }
关键修改说明
- 变量重命名:将全局
call改为_activeCall,避免与局部变量冲突,确保媒体操作使用的是当前活跃通话实例。 - 设备有效性检查:初始化时检查麦克风和扬声器是否存在,提前发现硬件问题。
- 媒体资源管理:通话结束时彻底断开连接、释放媒体资源,避免资源泄漏;初始化时判断资源是否已存在,避免重复创建。
- 注册状态监听:添加
PhoneLine_RegistrationStateChanged事件,确认账号注册状态,避免未注册时发起呼叫。 - 异常处理增强:媒体初始化失败时主动挂断通话,避免通话僵死;全局初始化添加异常捕获,提前反馈错误。
额外注意事项
- 务必将
RegisterAccount中的参数替换为你的实际SIP账号信息,确保注册成功。 - 检查系统麦克风和扬声器的权限,确保应用有权限访问音频设备。
- 测试时关闭其他占用音频设备的程序,避免设备冲突。
内容的提问来源于stack exchange,提问作者Nurcihan Günsür
相关产品推荐
相关产品推荐

