通话话单
更新时间: 2025/12/16 10:01:31
呼叫组件提供通话话单功能,在一通通话结束后,您会收到对应的通话话单。通话话单是一条事件通知消息,标记此次呼叫的状态。话单以 IM 会话类型消息抄送的形式发送,收到话单后,您可以解析消息体,获得通话时间等通话详情。
云信呼叫组件的话单消息共有 5 类,其中 4 类为 未接通时的话单(主叫方客户端发送),1 类为 带有通话时长的正常话单(服务端直接发送)。
由主叫方客户端发送的未接通话单包括 拒接话单、占线话单、超时未接听话单、主叫取消话单。
下图为常见话单示例,从上至下分别为主叫取消话单、被叫拒绝话单、超时未接听话单、被叫占线话单、正常通话带有时长的话单。
多人通话默认未封装话单功能。若您需要使用话单,请通过其他方式自行实现。
使用话单功能
方式一:使用组件封装的话单
第一步:开通话单抄送
-
登录网易云信控制台。开通 IM 即时通讯、音视频通话以及信令(信令是 IM 即时通讯的子功能,需要单独开通)。具体请参考 开通或关闭功能。
-
在抄送消息中开通呼叫组件的话单抄送。

第二步:发送话单
开通话单功能后,默认发送话单消息。
呼叫组件不包含话单接收及解析功能,用户需要参考示例项目源码自行实现。详细说明请参考 消息收发。
第三步:接收并解析话单
话单消息同普通消息一样通过 NIM SDK 进行消息接收,示例代码如下:
Java/**
* 话单消息接收注册,同正常消息接收一样
*/
private void registerObserver() {
V2NIMMessageListener messageListener = new V2NIMMessageListener() {
@Override
public void onReceiveMessages(List<V2NIMMessage> messages) {
if (messages != null) {
for (V2NIMMessage msg : messages) {
V2NIMMessageAttachment attachment = msg.getAttachment();
if (attachment instanceof V2NIMMessageCallAttachment) {
parseForNetCall(msg, (V2NIMMessageCallAttachment) attachment);
}
}
}
}
@Override
public void onSendMessage(V2NIMMessage message) {
if (message.getSendingState() == V2NIMMessageSendingState.V2NIM_MESSAGE_SENDING_STATE_SUCCEEDED) {
V2NIMMessageAttachment attachment = message.getAttachment();
if (attachment instanceof V2NIMMessageCallAttachment) {
parseForNetCall(message, (V2NIMMessageCallAttachment) attachment);
}
}
}
};
NIMClient.getService(V2NIMMessageService.class).addMessageListener(messageListener);
}
话单消息结构
| 话单类型 | 值 | 说明 |
|---|---|---|
NERecordCallStatus.COMPLETE |
1 | 正常通话话单,通话双方都进入音视频通话后进行挂断。由服务器发送。 |
NERecordCallStatus.CANCELED |
2 | 主叫取消话单,主叫呼叫后主动取消的话单。由客户端主叫方发送。 |
NERecordCallStatus.REJECTED |
3 | 被叫拒接话单,被叫拒接接听后的话单。客户端主叫方收到被叫拒接消息后进行发送。 |
NERecordCallStatus.TIMEOUT |
4 | 超时话单,被叫收到通话邀请后不操作等待超时产生的话单。客户端主叫方发送。 |
NERecordCallStatus.BUSY |
5 | 占线话单(用户忙),当主叫呼叫被叫时,被叫仍处于通话以及呼叫/被叫中,此时被叫会拒绝主叫的通话邀请。客户端主叫收到消息后会发送占线话单。 |
话单以 IM 消息抄送的形式发送,抄送类型为会话类型,即 eventType 为 1。会话类型的消息体中一般包含 eventType、convType、to、fromAccount、msgTimestamp、msgType、msgidClient、msgidServer、attach 等字段,全量字段请参考 返回数据的 JSON 字段说明。其中:
-
话单消息的
msgType字段的值为NRTC_NETCALL,表示音视频话单消息抄送。 -
话单消息中
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 消息
* @param attachment 话单附件
*/
private void parseForNetCall(V2NIMMessage message, V2NIMMessageCallAttachment attachment) {
if (message == null || attachment == null) {
return;
}
// 获取通话对端用户 ID
String targetId = V2NIMConversationIdUtil.conversationTargetId(message.getConversationId());
// 音频/视频 类型通话
int type = attachment.getType();
// 房间 ID
long channelId = attachment.getChannelId();
// 话单类型
int status = attachment.getStatus();
// 时长列表
List<V2NIMMessageCallDuration> durations = attachment.getDurations();
// 按照话单类型解析
switch (status) {
case NERecordCallStatus.COMPLETE:
// 成功接听
if (durations != null) {
// 通话时长渲染
for (V2NIMMessageCallDuration duration : durations) {
if (duration != null) {
// 参与通话用户
String accId = duration.getAccountId();
// 通话时长 单位为 秒
int seconds = duration.getDuration();
}
}
}
break;
case NERecordCallStatus.CANCELED:
// 主叫用户取消
break;
case NERecordCallStatus.REJECTED:
// 被叫用户拒接
break;
case NERecordCallStatus.TIMEOUT:
// 被叫接听超时
break;
case NERecordCallStatus.BUSY:
// 被叫用户在通话中,占线
break;
}
}
方式二:自行实现话单
若组件自带的话单功能无法满足您的业务需求,可以参考以下步骤自行实现话单。
-
关闭 服务端 话单抄送。具体步骤请参考 开通话单功能。
-
确定话单协议,通常用 JSON 表示。
JSON{ "type": 1 // 话单类型 "data": ... // 话单消息内容,如通话时长等信息 } -
设置
setCallRecordProvider,实现开发者自己的话单逻辑(设置setCallRecordProvider后客户端本地不再发送组件内部话单),参考 自定义消息发送,将步骤 3 中确定的话单协议作为自定义内容进行发送。您可以通过设置
NERecordProvider来发送话单。此处仅回调未接通话单,接通话单需要您在通话结束后独立处理。
JavaNECallEngine.sharedInstance().setCallRecordProvider(new NERecordProvider() { @Override public void onRecordSend(NERecord record) { // 发送未成功通话话单 } });NERecord 通话话单字段说明:
字段 类型 示例 accId String 通话对端的用户 ID。 callType int 通话类型,包括: NECallType.AUDIO:音频通话NECallType.VIDEO:视频通话
callState int 通话话单类型( NERecordCallStatus),具体请参考 话单消息结构
关闭话单功能
若您不需要使用话单功能,可以参考以下步骤自行关闭话单功能。
-
关闭 服务端 话单抄送。具体步骤请参考 开通话单功能。
-
关闭 客户端 话单发送。设置
setCallRecordProvider,然后空实现onRecordSend回调。javaNECallEngine.sharedInstance().setCallRecordProvider(new NERecordProvider() { @Override public void onRecordSend(NERecord record) { //空实现即可 } });





