Cable Messenger 多人实时音视频聊天:信令系统

本文详细介绍了Cable Messenger的信令系统,包括管理房间和用户状态、信令的发送和接收、上层处理逻辑以及多人聊天的信令扩散算法。信令系统采用HTTP发送指令,确保在不同网络环境下稳定工作,支持心跳检测和实时通话时长更新,实现实时音视频聊天的可靠连接。

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


信令系统,作为音视频聊天中最必不可少的系统,承担着房间管理,用户管理,状态管理,聊天前用户间信息交互等重要功能。没有信令系统,音视频聊天将难以开展。

一般流程

在这里插入图片描述

信令系统的作用:

  1. 管理房间及用户:包括申请及记录当前房间,房间当前状态,用户当前状态(忙时,闲时,不在线等)等信息。
  2. 对房间内从发起聊天到聊天结束整个过程的指令进行各个用户的转发和通知。
  3. 保存用户的媒体属性,连接信息等相关SDP数据。

在Webrtc中,网络穿透在调用生成本地媒体约束SDP的时候,或者是接收到邀请方的SDP数据后,对远程SDP数据进行设置,并调用本地本地媒体约束SDP的时候,触发网络穿透的操作。网络穿透成功后,会多次回调不同类型的网络信息,包括若干个内网及外网信息。在正常情况下,应该经过多次的信令系统的调用,及时传递到对方聊天用户进行设置。

同时,当手机网络不稳定,或经过网络切换的情况下,网络穿透也会自动进行处理和回调。保证了在短暂的断开连接状态下,不用再次重新建立新的启动流程。只要相互交互一次Candidate数据后就可以正常继续使用。这个是经过实践验证的可行流程。

信令的发送和接收

在这里插入图片描述
在APP音视频系统架构中, 信令系统的逻辑处理主要由SIPLogicManager来完成,主要负责包括心跳处理,指令发送及信令回调后的逻辑处理的任务。

Cable Messenger中抽象出了信息系统所有情况下的回调规范:

public protocol CUSIPEventListener{
   
    ///审请加入房间回复
    func onJoinded(chatId:String, roomId:String, users:[CUSipUserInfo], myId:String)
    ///审请者主动结束
    func onCancel(roomId:String)
    ///收到邀请聊天
    func onInvite(roomId:String, users:[CUSipUserInfo], fUid:String, audioOnly:Bool)
    ///对方忙线
    func onBusy(roomId:String, fUid:String)
    ///对方拒绝
    func onReject(roomId:String, fUid:String)
    ///有新人加入聊天(你的当前状态已经进入聊天室)
    func onNewJoin(roomId:String, user:CUSipUserInfo)
    ///有新人加入聊天(你的当前状态还没进入聊天室)
    func onNewMember(roomId:String, user:CUSipUserInfo)
    ///接收到对方的sdp信息
    func onOffer(roomId:String, sdp:String, fUid:String)
    ///接收到对方回复的sdp信息
    func onReceiveCandidate(roomId:String, sdpMid:String, sdpMLineIndex:Int32, candidate:String, fUid:String)
    ///接收answer
    func onAnswer(roomId:String, sdp:String, fUid:String)
    ///视频状态发生改变
    func onVideoStateChange(roomId:String, fUid:String, enable:Bool)
    ///聊天室成员离开
    func onLeave(roomId:String, fUid:String)
    ///聊天结束
    func onFinish(roomId:String)
    ///同一帐号的其它设置已经进行会话
    func onPickup(roomId:String)
}

对于指令的发送,我还是比较推荐以HTTP的方式进行发送。对于指令系统来说,技术稳定可控,实现相对简单对于系统来说是致关重要的。以下为部分指令发送代码,仅供参考:

    //MARK: - 用户ID登录
    public func idLogin(uid:String, password:String, handler:@escaping (PHResponse<CUSipUserInfo>) ->Void){
   
        var params:[String:Any] = [:]
        params["uid"]      = uid
        params["password"] = password
        self.requestPost(requestUrl: Constant.BASE_URL + ID_LOGIN, params: params) {
    (result:PHResponse<Any>) in
            if result.isSuccess == true, let dictData = result.data as? [String:Any]{
   
                do{
   
                    let data:[String:Any] = try JSONTranslater.toDictionary(any: dictData["data"])
                    if let info:CUSipUserInfo = CUSipUserInfo.parseToObject(data){
   
                        handler(PHResponse<CUSipUserInfo>(data:info))
                    }else{
   
                        handler(PHResponse<CUSipUserInfo>(data:nil, result:false, msg:self.launchTranslateError()))
                    }
                }catch{
   
                    handler(PHResponse<CUSipUserInfo>(data:nil, result:false, msg:self.launchTranslateError()))
                }
            }else {
   
                handler(PHResponse<CUSipUserInfo>(msg:result.msg))
            }
        }
    }
    
    //MARK: - 退出登录
    public func logout(handler:@escaping (PHResponse<Bool>) ->Void){
   
        let params:[String:Any] = [:]
        self.requestPost(requestUrl: Constant.BASE_URL + LOGOUT, params:params) {
    (result:PHResponse<Any>) in
            if result.isSuccess == true{
   
                handler(PHResponse<Bool>(data:true))
            }else {
   
                handler(PHResponse<Bool>(msg:result.msg))
            }
        }
    }
    
    //MARK: - 基础方法
    public func getRoomInfo(roomId:String, handler:@escaping (PHResponse<CURoomInfo>) ->Void){
   
        var params:[String:Any] = [:]
        params["room_id"] = roomId
        self.requestPost(requestUrl: Constant.BASE_URL + GET_ROOM_INFO, params: params) {
    (result:PHResponse<Any>) in
            if result.isSuccess == true, let dictData = result.data as? [String:Any]{
   
                do{
   
                    let data:[String:Any] = try JSONTranslater.toDictionary(any: dictData["data"])
                    let roomInfo:CURoomInfo = CURoomInfo.parseToObject(data)
                    handler(PHResponse<CURoomInfo>(data:roomInfo))
                }catch{
   
                    handler(PHResponse<CURoomInfo>(data:nil, result:false, msg:self.launchTranslateError()))
                }
            }else {
   
                handler(PHResponse<CURoomInfo>(msg:result.msg))
            }
        }
    }
    
    //MARK: - 发起者创建并进入房间
    public func start(chatId:String, deviceId:String, handler:@escaping (PHResponse<[String:Any]>) ->Void){
   
        var params:[String:Any] = [:]
        if chatId.count > 0{
   
            params["chat_id"] = chatId
        }
        params["device_id"] = deviceId
        self.postRtcCommon(eventName:"__start", params:params) {
    (response:PHResponse<[String : Any]>) in
            handler(response)
        }
    }

    //MARK: - 被邀请者进入房间
    public func join(roomId:String, deviceId:String, handler:@escaping (PHResponse<[String:Any]>) ->Void){
   
        var params:[String:Any] = [:]
        params["room_id"]   = roomId
        params["device_id"] = deviceId
        self.postRtcCommon(eventName:"__join", params:params) {
    (response:PHResponse<[String : Any]>) in
            handler(response)
        }
    }
    
    //MARK: - 发起进入房间
    public func invite(roomId:String, ids:[String], audioOnly:Int, handler:@escaping (PHResponse<[String
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值