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

Ozeki SIP C#语音通话问题:接通后立即挂断求助

问题分析与解决方案

核心问题定位

你的代码中存在几个关键问题导致接听后立即挂断:

  1. 全局与局部call变量冲突
    点击面板发起呼叫时,AyarlarTelefonPanel_Click里声明了局部IPhoneCall call,但全局静态call变量并未被赋值。而SetupDevices方法中使用的是全局call,此时该变量为null,调用mediaSender.AttachToCall(call)会引发异常,直接导致通话中断。

  2. 媒体资源未正确管理
    每次通话接通时重复创建MediaConnector、PhoneCallAudioSender和PhoneCallAudioReceiver,但未在通话结束时释放这些资源,容易引发资源占用冲突;同时没有检查麦克风/扬声器设备是否成功初始化,若设备获取失败会直接导致媒体链路异常。

  3. 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事件,确认账号注册状态,避免未注册时发起呼叫。
  • 异常处理增强:媒体初始化失败时主动挂断通话,避免通话僵死;全局初始化添加异常捕获,提前反馈错误。

额外注意事项

  1. 务必将RegisterAccount中的参数替换为你的实际SIP账号信息,确保注册成功。
  2. 检查系统麦克风和扬声器的权限,确保应用有权限访问音频设备。
  3. 测试时关闭其他占用音频设备的程序,避免设备冲突。

内容的提问来源于stack exchange,提问作者Nurcihan Günsür

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 18:46:01