概念

房间

房间是一个音视频空间,同一房间内的用户可以互相接收对方的实时音视频

  • 实时音视频使用房间这个虚拟的概念,用于用户之间的相互隔离。
  • 只有在同一个房间里的用户才可以相互接收音视频。
  • 一个用户同一时间只能在一个房间内。如果要进入另一个房间,必须从前一个房间内退出。

注意:

  • 第一个创建房间的用户即这个房间的所有者,但该用户无法主动解散房间。
  • 所有用户都主动退出房间时,服务端会马上解散房间。
  • 如果单个用户异常掉线,30 秒后服务端会将该用户清理出房间;如果所有的用户都异常掉线,30 秒后服务端会自动解散这个房间。
  • 当用户要加入的房间不存在时,实时音视频后台会先创建一个房间,然后再把用户加入。

旁路直播

旁路直播是一种直播方式,通常用于不同协议的音视频系统之间进行数据转发。实时音视频服务端通过旁路直播的方式,将通话房间中的音视频数据以 RTMP 推流的形式,推送至云直播服务,从而实现旁路直播、旁路转推、云端混流以及云端录制等功能。

RoomID

实时音视频服务里使用 RoomID(房间号)来唯一标识一个房间。RoomID 是由开发者自行维护和分配的一个 uint32 范围内的数字

UserID

UserID(用户标识)用于在一个实时音视频应用中唯一标识一个用户。

  • 用户标识是用户登录开发者业务系统的帐号在腾讯云上的映射。通常情况下,开发者可直接使用用户名作为 UserID。
  • 长度建议不超过 32 字节。请使用英文字符、数字或下划线,不能全为数字,大小写不敏感。

UserSig

UserSig(用户签名)用于对一个用户进行登录鉴权认证,确认用户是否真实。用户签名生成方法可参考 生成签名 文档。

入门

https://console.cloud.tencent.com/trtc/app/detail/quickstart/

使用案例

调用

1
2
3
//loginname 发起方 
// peer_username 被发起方
window.open("https://ip:8443/TRTC/index.html?user=" + loginname + "&peer=" + encodeURIComponent(peer_username), "new");

Web

IM 登录,向指定用户发送自定义消息「加入指定房间,进行音视频通信」

  1. GenerateTestUserSig.js

    1
    配置 SDKAPPID、SECRETKEY
  2. common.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//原有代码-音视频客户端初始化-加入指定房间
rtc = new RtcClient(options);
join();

//新增代码-IM 登录后向对方发送自定义消息:「加入指定房间,进行音视频通信」
var tim_options = {
SDKAppID: options.sdkAppId // 接入时需要将0替换为您的即时通信 IM 应用的 SDKAppID
};
// 创建 SDK 实例,`TIM.create()`方法对于同一个 `SDKAppID` 只会返回同一份实例
var tim = TIM.create(tim_options);
// 设置 SDK 日志输出级别,详细分级请参见 setLogLevel 接口的说明
tim.setLogLevel(0); // 普通级别,日志量较多,接入时建议使用
// tim.setLogLevel(1); // release 级别,SDK 输出关键信息,生产环境时建议使用

// 注册 COS SDK 插件,发送图片、文件等消息需要的 COS SDK
// tim.registerPlugin({'cos-js-sdk': COS});

// 接下来可以通过 tim 进行事件绑定和构建 IM 应用
// 监听事件,例如:
tim.on(TIM.EVENT.SDK_READY, function (event) {
// 收到离线消息和会话列表同步完毕通知,接入侧可以调用 sendMessage 等需要鉴权的接口
// event.name - TIM.EVENT.SDK_READY

var roomId = $("#roomId").val();
var peerUser = $("#peerUser").val();
if(peerUser == '') {
return;
}
// 1. 创建消息实例-向手机端发送视频通话消息
let message = tim.createCustomMessage({
to: peerUser,
conversationType: TIM.TYPES.CONV_C2C,
// 消息优先级,用于群聊(v2.4.2起支持)。如果某个群的消息超过了频率限制,后台会优先下发高优先级的消息,详细请参考 消息优先级与频率控制
// 支持的枚举值:TIM.TYPES.MSG_PRIORITY_HIGH, TIM.TYPES.MSG_PRIORITY_NORMAL(默认), TIM.TYPES.MSG_PRIORITY_LOW, TIM.TYPES.MSG_PRIORITY_LOWEST
// priority: TIM.TYPES.MSG_PRIORITY_HIGH,
payload: {
data: JSON.stringify({'call_type': 2, 'room_id': parseInt(roomId), 'version': 1}), // 用于标识该消息是骰子类型消息
description: 'description',
extension: ''
}
});
// 3. 发送消息
let promise = tim.sendMessage(message);
promise.then(function (imResponse) {
// 发送成功
console.log(imResponse);
}).catch(function (imError) {
// 发送失败
console.warn('sendMessage error:', imError);
});
});

tim.on(TIM.EVENT.MESSAGE_RECEIVED, function (event) {
// 收到推送的单聊、群聊、群提示、群系统通知的新消息,可通过遍历 event.data 获取消息列表数据并渲染到页面
// event.name - TIM.EVENT.MESSAGE_RECEIVED
// event.data - 存储 Message 对象的数组 - [Message]
console.log(event.data);
event.data.forEach(msg=>{
if(msg.payload.data) {
var data = JSON.parse(msg.payload.data);
if(data.line_busy == 3) {
//对方忙
layer.msg("对方已挂断,请稍后再拨");
}
}
});
});

// 开始登录
tim.login({userID: options.userId, userSig: options.userSig});

Android

解析来自 Web 发送的自定义消息,解析房间 Id,进入房间,音视频通话

  1. 配置 GenerateTestUserSig.java

    1
    SDKAPPID、SECRETKEY
  2. 核心 TRTCCallingImpl.java -> login()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//监听普通消息-web 发起的音视频等消息。默认只有音视频消息信令监听器
V2TIMManager.getInstance().addSimpleMsgListener(new V2TIMSimpleMsgListener() {
@Override
public void onRecvC2CCustomMessage(String msgID, V2TIMUserInfo s, byte[] customData) {
String data = new String(customData).toString();
final String sender = s.getUserID();
TRTCLogger.d(TAG, "sender:" + sender + " data:" + data);
Map<String, Object> extraMap = new Gson().fromJson(data, Map.class);
if (extraMap.containsKey(CallModel.SIGNALING_EXTRA_KEY_CALL_TYPE)) {
int callType = ((Double) extraMap.get(CallModel.SIGNALING_EXTRA_KEY_CALL_TYPE)).intValue();
switch (callType) {
case TRTCCalling.TYPE_VIDEO_CALL:
//视频通话请求
if (!isCallingData(data)) {
return;
}

mCurCallID = msgID;
processInvite(msgID, sender, null, Arrays.asList(sender), data);
break;
case CallModel.VIDEO_CALL_ACTION_ACCEPT:
//对方接通
// TRTCLogger.d(TAG, "对方接通: msgID:" + msgID + ", sender:" + sender + " data:" + data);

if (!isCallingData(data)) {
return;
}
mCurInvitedList.remove(sender);
break;
case CallModel.VIDEO_CALL_ACTION_HANGUP:
//对方挂断

break;
}
}
}
});