通话话单

更新时间: 2024/12/19 16:19:04

呼叫组件提供通话话单功能,在一通通话结束后,您会收到对应的通话话单。通话话单是一条事件通知消息,标记此次呼叫的状态。话单以 IM 会话类型消息抄送的形式发送,收到话单后,您可以解析消息体,获得通话时间等通话详情。

下图为常见话单示例,从上至下分别为主叫取消话单、被叫拒绝话单、超时未接听话单、被叫占线话单、正常通话带有时长的话单。

image-netease

多人通话默认未封装话单功能。若您需要使用话单,请通过其他方式自行实现。

方式一:使用封装话单

第一步:开通话单功能

具体请参考 开通服务

第二步:发送话单

开通话单功能后,默认发送话单消息。

话单消息共有 5 类,其中 4 类为未接通时的话单,如拒接话单、占线话单、超时未接听话单、主叫取消话单,此类话单均由主叫方客户端发送。另外一类为带有通话时长的正常话单,此类话单为服务端直接发送。话单结构见话单解析部分。

呼叫组件不包含话单接收及解析功能,用户需要参考示例项目源码自行实现。详细说明请参考 消息收发

第三步:接收并解析话单

话单消息同普通消息一样通过 IM SDK 进行消息接收,示例代码如下:

Java/**
  * 话单消息接收注册,同正常消息接收一样
  */
private void registerObserver() {
    /**
      * 注册消息接收观察者。
      * 通知的消息列表中的消息不一定全是接收的消息,也有可能是自己发出去,例如其他端发的消息漫游过来。
      */
    NIMClient.getService(MsgServiceObserve.class).observeReceiveMessage(new Observer<List<IMMessage>>() {
        @Override
        public void onEvent(List<IMMessage> imMessages) {
            for (IMMessage item : imMessages) {
                parseForNetCall(item);
            }
        }
    }, true);
    /**
      * 用于发送消息后本地列表解析对应消息
      */
    NIMClient.getService(MsgServiceObserve.class).observeMsgStatus(new Observer<IMMessage>() {
        @Override
        public void onEvent(IMMessage imMessage) {
            parseForNetCall(imMessage);
        }
    }, true);
}

话单消息结构

话单类型:

类型(V1)
类型(V2)
话单类型
说明
NERecordCallStatus.NrtcCallStatusComplete NERecordCallStatus.COMPLETE 1 正常通话话单,通话双方都进入音视频通话后进行挂断。由组件服务器发送。
NrtcCallStatus.NrtcCallStatusCanceled NERecordCallStatus.CANCELED 2 主叫取消话单,主叫呼叫后主动取消的话单。由客户端主叫方发送。
NrtcCallStatus.NrtcCallStatusRejected NERecordCallStatus.REJECTED 3 被叫拒接话单,被叫拒接接听后的话单。客户端主叫方收到被叫拒接消息后进行发送。
NrtcCallStatus.NrtcCallStatusTimeout NERecordCallStatus.TIMEOUT 4 超时话单,被叫收到通话邀请后不操作等待超时产生的话单。客户端主叫方发送。
NrtcCallStatus.NrtcCallStatusBusy NERecordCallStatus.BUSY 5 占线话单(用户忙),当主叫呼叫被叫时,被叫仍处于通话以及呼叫/被叫中,此时被叫会拒绝主叫的通话邀请。客户端主叫收到消息后会发送占线话单。

话单以 IM 消息抄送的形式发送,抄送类型为会话类型,即 eventType 为 1。会话类型的消息体中一般包含 eventType、convType、to、fromAccount、msgTimestamp、msgType、msgidClient、msgidServer、attach 等字段,其中:

  • 话单消息的 msgType 字段的值 为 NRTC_NETCALL,表示音视频话单消息抄送。
  • 话单消息中 attach 字段中包含通话类型、呼叫状态等通话详情。
  • 其他字段说明请参考 会话类型消息抄送

attach 字段说明:

字段 类型 示例 说明

type

Number

1

通话类型。

  • 1:音频通话。
  • 2:视频通话。
channelId Number 123 房间 ID。

status

Number

1

呼叫状态。

  • 1:通话正常结束。
  • 2:主叫取消呼叫。
  • 3:被叫拒绝通话。
  • 4:被叫未接听呼叫,呼叫因超时被取消。
  • 5:被叫忙线,通话未接通。

durations

JsonArray

通话过程详情,JSON 数组格式,其中包括:

  • accid:通话成员的 accid。
  • duration:对应成员的通话时长。

收到的话单的 JSON 结构:

JSON{
   "type": 1,                       //1 表示音频,2 表示视频
   "channelId": 123,                //音视频通话 2.0 的 channelId
   "status": 1,                     //1 表示正常结束通话话单,对应上表的话单类型
   "durations": [
           {
               "accid":"acc01",
               "duration":10
           },
           {
               "accid":"acc02",
               "duration":12
           }
   ]
}

接收到消息后进行消息解析。示例代码如下:

Java/**
 * 解析话单消息数据,一般用于 recyclerView adapter 中渲染
 *
 * @param message 当前 IM 消息
 */
private void parseForNetCall(IMMessage message) {
    if (message == null) {
        return;
    }
    // 此处只处理话单消息
    if (message.getAttachment() instanceof NetCallAttachment) {
        NetCallAttachment attachment = (NetCallAttachment) message.getAttachment();
        /**
          * 消息来源方向请参考 {@link MsgDirectionEnum}
          */
        MsgDirectionEnum direction = message.getDirect();
        // 音频/视频 类型通话
        int type = attachment.getType();
        // 话单类型
        int status = attachment.getStatus();
        // 时长列表
        List<NetCallAttachment.Duration> durations = attachment.getDurations();

        // 按照话单类型解析
        switch (attachment.getStatus()) {
            case NrtcCallStatus.NrtcCallStatusComplete:
                // 成功接听
                if (attachment.getDurations() == null) {
                    break;
                }
                // 通话时长渲染
                for (NetCallAttachment.Duration duration : durations) {
                    // 参与通话用户
                    String accId = duration.getAccid();
                    // 通话时长 单位为 秒
                    int seconds = duration.getDuration();
                }
                break;
            case NrtcCallStatus.NrtcCallStatusCanceled:
                // 主叫用户取消
                break;
            case NrtcCallStatus.NrtcCallStatusRejected:
                // 被叫用户拒接
                break;
            case NrtcCallStatus.NrtcCallStatusTimeout:
                // 被叫接听超时
                break;
            case NrtcCallStatus.NrtcCallStatusBusy:
                // 被叫用户在通话中,占线
                break;
        }
    }
}

方式二:自行实现话单

若组件自带的话单功能无法满足您的业务需求,可以参考以下步骤自行实现话单。

  1. 关闭组件自带话单功能。

    1. 登录 网易云信控制台,关闭话单功能,具体步骤请参考 开通话单功能

    2. 关闭客户端本地发送未接通话单功能。

      Java CallKitUIOptions options = new CallKitUIOptions.Builder()
         ......
             .enableOrder(false)
         ......
         .build();
      CallKitUI.init(context,options);
      

    至此,通话结束后话单消息将不再下发。

  2. 网易云信控制台 开通房间时长消息抄送(eventType=8)。详细步骤请参考 开通消息抄送

  3. 确定话单协议,通常用 JSON 表示。

    JSON{
      "type": 1   // 话单类型
      "data": ... // 话单消息内容,如通话时长等信息
    }
    
  4. 参考 自定义消息发送与解析,将步骤 3 中确定的话单协议作为自定义内容进行发送与解析。

    • V2.0 及之后版本

      您可以通过设置 NERecordProvider 来发送话单,也可以根据 V1.0 的时机自己处理发送。

      此处仅回调未接通话单,接通话单需要您在通话结束后独立处理。

      JavaNECallEngine.sharedInstance().setCallRecordProvider(new NERecordProvider() {
      @Override
      public void onRecordSend(NERecord record) {
          // 发送未成功通话话单
      }
      });
      

      NERecord 通话话单字段说明:

      字段 类型 示例
      accId String 通话对端的 accId
      callType int 通话类型,包括:
      • NECallType.AUDIO:音频通话
      • NECallType.VIDEO:视频通话
      callState int 通话话单类型(NERecordCallStatus),具体请参考 话单消息结构
    • V1.8.2 及之前版本

      至此,您已经完成自定义话单消息的发送以及解析,各个消息发送实际建议请参考下文。

      组件支持的话单种类共有 5 类,分别为:

      • 主叫取消话单:主叫方统一发送。主叫取消话单可在主叫调用取消呼叫方法成功后发送。
      • 被叫拒绝话单:主叫方统一发送。在收到 NERTCCallingDelegate#onRejectByUserId 回调发送被叫拒绝话单。
      • 超时未接听话单:主叫方统一发送。在收到 NERTCCallingDelegate#timeOut 回调发送超时未接听话单。
      • 被叫占线话单:主叫方统一发送。在收到 NERTCCallingDelegate#onUserBusy 回调发送被叫占线话单。
      • 正常通话带有时长的话单:建议由服务端发送,用户服务器收到网易云信服务器的 8 房间时长消息抄送时,根据抄送发送时长话单。
此文档是否对你有帮助?
有帮助
去反馈
  • 方式一:使用封装话单
  • 第一步:开通话单功能
  • 第二步:发送话单
  • 第三步:接收并解析话单
  • 方式二:自行实现话单