实时互动频道
更新时间: 2024/11/21 17:47:19
实时互动频道模块,是基于圈组,在文字基础上新增的,用于提供产品能力、丰富社区运营、提升用户活跃的,适用于百万用户量级、多场景、多能力的在线实时互动的多媒体插件。
网易云信 NIM SDK 通过插件的方式引入实时互动频道模块,通过接口的融合,帮助用户在圈组中实现在线实时互动,用户无需独立对接。
实时互动频道相关能力为增值服务,需单独开通,您可通过云信官网提供的联系方式咨询商务经理开通。
实时互动频道模块(QChatMedia
)中主要包含以下三类接口,分别实现不同的功能。
QChatMediaKit
接口提供实时互动频道模块的初始化、登录、连接等能力。QChatRTCChannelController
接口提供实时互动频道内多样的音视频通话能力。QChatRTCChannelListener
接口提供实时互动频道相关事件的监听能力。
本文介绍如何在圈组中引入实时互动频道模块,并在实时互动频道中实现实时音视频通话功能。
技术原理
图中的圈组服务器并非传统意义上的服务器,它是社群本身。所有的内容、兴趣、话题、关系都是以此为基础进行发展的。在圈组的场景下,任何行为的开始前都应该先创建一个圈组服务器。圈组详细信息,请参见圈组介绍。
实时互动频道与频道的关联逻辑
实时互动频道是频道的一种类型,通过参数 QChatChannelType
来区分。
频道的管理需要在 QChatChannel
中进行,包括创建、删除实时互动频道等,具体请参见频道管理。
实时互动频道内的音视频相关功能需要在实时互动频道模块(QChatMedia
)中实现。
使用实时互动频道模块相关接口,需要拥有实时互动相关权限(具体权限类型请参见 QChatRoleResource
),可通过更新身份组来实现。
实时互动频道可见机制
实时互动频道的可见机制与频道相同,分以下两种情况:
- 如果实时互动频道为公开频道,那么只要用户未被加入频道黑名单,实时互动频道就对其可见。
- 如果实时互动频道为私密频道,那么用户需被加入频道白名单,实时互动频道才对其可见。
频道黑白名单相关操作,请参见频道管理。
实现方法
本节以实时互动频道创建者与实时互动频道成员之间的交互为例,介绍在圈组中实现音视频通话功能的流程。
前提条件
- 已开通实时互动频道功能。实时互动频道需要在开通圈组功能的基础上额外开通后才能使用。
- 已初始化登录圈组,并创建或加入圈组服务器和身份组,具体请参见圈组服务器管理和身份组管理。
实现流程
sequenceDiagram
par 创建创建实时互动频道
用户A ->> 圈组: 初始化并登录圈组
用户B ->> 圈组: 初始化并登录圈组
用户A ->> 圈组: 创建圈组服务器(自动生成@everyone身份组)
用户B ->> 圈组: 加入圈组服务器和身份组
用户A ->> 圈组: 修改服务器身份组并设置实时互动相关权限
用户A ->> 圈组: 创建实时互动频道
end
par 实现音视频通话功能(以共享屏幕为例)
用户A ->> 圈组: 引入QChatMedia模块
用户B ->> 圈组: 引入QChatMedia模块
用户A ->> 圈组: 初始化QChatMedia模块
用户A ->> 圈组: 连接已创建的实时互动频道
用户B ->> 圈组: 初始化QChatMedia模块
用户B ->> 圈组: 连接实时互动频道
用户A ->> 圈组: 监听成员屏幕共享状态
用户B ->> 圈组: 开启本端屏幕共享
圈组 ->> 用户A: 返回成员屏幕共享状态
end
这里主要介绍部分步骤,其余步骤请参考具体文档。
1.用户 A 通过调用 updateServerRole
方法修改服务器身份组并设置实时互动相关权限。示例代码如下:
QChatServerRole serverRole = getServerRole();
QChatUpdateServerRoleParam param = new QChatUpdateServerRoleParam(serverRole.getServerId(), serverRole.getRoleId());
param.setName("修改身份组名称");
param.setIcon("http://xxxxxx/xxx/");
param.setExt("修改自定义扩展");
Map<QChatRoleResource, QChatRoleOption> map = new HashMap<>();
map.put(QChatRoleResource.MANAGE_CHANNEL,QChatRoleOption.ALLOW);//管理频道的权限
map.put(QChatRoleResource.MANAGE_ROLE,QChatRoleOption.ALLOW);//管理身份组的权限
map.put(QChatRoleResource.RTC_CHANNEL_CONNECT,QChatRoleOption.ALLOW);// 实时互动频道:连接的权限
map.put(QChatRoleResource.RTC_CHANNEL_DISCONNECT_OTHER,QChatRoleOption.ALLOW);// 实时互动频道:断开他人连接的权限
map.put(QChatRoleResource.RTC_CHANNEL_OPEN_MICROPHONE,QChatRoleOption.ALLOW);// 实时互动频道:开启麦克风的权限
map.put(QChatRoleResource.RTC_CHANNEL_OPEN_CAMERA,QChatRoleOption.ALLOW);// 实时互动频道:开启摄像头的权限
map.put(QChatRoleResource.RTC_CHANNEL_OPEN_CLOSE_OTHER_MICROPHONE,QChatRoleOption.ALLOW);// 实时互动频道:开启/关闭他人麦克风的权限
map.put(QChatRoleResource.RTC_CHANNEL_OPEN_CLOSE_OTHER_CAMERA,QChatRoleOption.ALLOW);// 实时互动频道:开启/关闭他人摄像头的权限
map.put(QChatRoleResource.RTC_CHANNEL_OPEN_CLOSE_EVERYONE_MICROPHONE,QChatRoleOption.ALLOW);// 实时互动频道:开启/关闭全员麦克风的权限
map.put(QChatRoleResource.RTC_CHANNEL_OPEN_CLOSE_EVERYONE_CAMERA,QChatRoleOption.ALLOW);// 实时互动频道:开启/关闭全员摄像头的权限
map.put(QChatRoleResource.RTC_CHANNEL_OPEN_SCREEN_SHARE,QChatRoleOption.ALLOW);// 实时互动频道:打开自己屏幕共享的权限
map.put(QChatRoleResource.RTC_CHANNEL_CLOSE_OTHER_SCREEN_SHARE,QChatRoleOption.ALLOW);// 实时互动频道:关闭他人屏幕共享的权限
param.setResourceAuths(map);
QChatAntiSpamConfig antiSpamConfig = new QChatAntiSpamConfig("用户配置的对某些资料内容另外的反垃圾的业务ID");
antiSpamConfig.setAntiSpamBusinessId(antiSpamConfig);
NIMClient.getService(QChatRoleService.class).updateServerRole(param).setCallback(new RequestCallback<QChatUpdateServerRoleResult>() {
@Override
public void onSuccess(QChatUpdateServerRoleResult result) {
//更新成功,返回更新后的Server身份组
QChatServerRole role = result.getRole();
}
@Override
public void onFailed(int code) {
//更新失败,返回错误code
}
@Override
public void onException(Throwable exception) {
//更新异常
}
});
- 用户 A 通过调用
createChannel
方法创建实时互动频道。示例代码如下:
QChatCreateChannelParam param = new QChatCreateChannelParam(943445L, "测试频道", QChatChannelType.RTCChannel);
param.setCustom("自定义扩展");
param.setTopic("主题");
//设置频道为公开频道
param.setViewMode(QChatChannelMode.PUBLIC);
QChatAntiSpamConfig antiSpamConfig = new QChatAntiSpamConfig("用户配置的对某些资料内容另外的反垃圾的业务ID");
param.setAntiSpamBusinessId(antiSpamConfig);
NIMClient.getService(QChatChannelService.class).createChannel(param).setCallback(
new RequestCallback<QChatCreateChannelResult>() {
@Override
public void onSuccess(QChatCreateChannelResult result) {
//创建Channel成功,返回创建成功的Channel信息
QChatChannel channel = result.getChannel();
}
@Override
public void onFailed(int code) {
//创建Channel失败,返回错误code
}
@Override
public void onException(Throwable exception) {
//创建Channel异常
}
});
- 创建实时互动频道需要拥有管理身份组的权限(
MANAGE_ROLE
)。具体请参见身份组管理。 - 创建的实时互动频道需要对用户 B 可见,后续用户 B 才能进行连接。具体请参见实时互动频道可见机制。
- 引入实时互动频道功能插件(
QChatMedia
)。示例代码如下:
implementation 'com.netease.nimlib:qchatmedia:x.x.x'
x.x.x 为接入的 NIM SDK 版本号。
- 调用
initialize
方法初始化QChatMedia
模块。您也可以调用isInitialized
方法查询初始化状态。示例代如下:
//如果没有初始化,则进行初始化操作
if(!QChatMediaKit.getInstance().isInitialized()){
QChatMediaKit.getInstance().initialize(getContext(), new QCMCallback2<Void>() {
@Override
public void onSuccess(Void data) {
super.onSuccess(data);
//初始化成功
}
@Override
public void onError(QChatMediaErrorType errorType, int code, String message) {
super.onError(errorType, code, message);
//初始化失败
}
});
}
- 调用
connect
方法连接已创建的实时互动频道。您也可以调用isConnected
方法查询当前连接状态。示例代码如下:
//如果没有连接实时互动频道,则进行连接操作
if(!QChatMediaKit.getInstance().isConnected()){
QChatMediaKit.getInstance().connect(311254, 211234, QChatMediaType.RTC, new QCMCallback2<Void>() {
@Override
public void onSuccess(Void data) {
super.onSuccess(data);
//连接成功
}
@Override
public void onError(QChatMediaErrorType errorType, int code, String message) {
super.onError(errorType, code, message);
//连接失败
}
});
}
-
在实时互动频道中实现具体的音视频功能(以共享屏幕为例)。
a. 用户 A 调用
addRTCChannelListener
方法添加成员共享屏幕状态(onMemberScreenShareStateChanged
)监听事件。b. 用户 B 调用
startScreenShare
方法开启屏幕共享。c. 触发回调,用户 A 收发服务器返回的成员共享屏幕状态。
//添加实时互动频道监听事件
QChatRTCChannelController rtcChannelRoomController = QChatMediaKit.getInstance().getRTCChannelRoomController();
if(rtcChannelRoomController != null){
rtcChannelRoomController.addRTCChannelListener(new QChatRTCChannelListener() {
/**
* 成员屏幕共享状态回调
*
* @param memberAccid 成员accid
* @param isSharing 是否正在进行屏幕共享。true 表示房间内有人正在屏幕共享,false 表示房间内没有有人正在屏幕共享
* @param operateAccid 操作者
*/
@Override
public void onMemberScreenShareStateChanged(String memberAccid, boolean isSharing, String operateAccid) {
}
});
//绑定屏幕共享服务
private void bindScreenService() {
Intent intent = new Intent();
intent.setClass(this, ScreenShareService.class);
mServiceConnection = new ScreenShareServiceConnection();
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
private class ScreenShareServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
if (service instanceof ScreenShareService.ScreenShareBinder) {
mScreenService = ((ScreenShareService.ScreenShareBinder) service).getService();
NimLog.i(TAG, "onServiceConnect");
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mScreenService = null;
}
}
private ActivityResultLauncher<Intent> launcher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
NimLog.d(TAG, "onActivityResult,result:" + result.getResultCode());
if (result.getResultCode() == Activity.RESULT_OK) {
mScreenService.startScreenCapture(QChatMediaKit.getInstance().getRTCChannelRoomController(), result.getData(),
new MediaProjection.Callback() {
@Override
public void onStop() {
super.onStop();
showToast("屏幕共享结束");
}
}, new QCMCallback2<Void>() {
@Override
public void onSuccess(@Nullable Void unit) {
super.onSuccess(unit);
showToast("开始屏幕共享");
}
@Override
public void onError(QChatMediaErrorType errorType,int code, @Nullable String message) {
super.onError(errorType,code, message);
showToast("startScreenCapture error,code:" + code + ",message:" + message);
}
});
}
}
});
private void initListener(){
findViewById(R.id.startScreenShare).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//开启屏幕共享
MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(
Context.MEDIA_PROJECTION_SERVICE);
launcher.launch(mediaProjectionManager.createScreenCaptureIntent());
}
});
findViewById(R.id.unmuteMyAudio).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
unMuteAudio(currentAccid);
}
});
}
- 调用
disConnect
方法与实时互动频道断开连接。示例代码如下:
QChatMediaKit.getInstance().disConnect(new QCMCallback<Void>() {
@Override
public void onResult(QChatMediaErrorType errorType, int code, @Nullable String message, @Nullable Void data) {
finish();
}
});
实时互动频道功能列表
功能 |
描述 |
---|---|
切换摄像头 | switchCamera |
打开音频 | unMuteAllAudio (所有成员);unMuteAudio (指定成员) |
打开视频 | unMuteAllVideo (所有成员); unMuteVideo (指定成员) |
共享屏幕 | startScreenShare |
查询屏幕共享者 | getScreenSharingUserUuid |
订阅远端视频流/辅流视频 | subscribeRemoteVideoStream ;subscribeRemoteVideoSubStream |
设置用户视图 | setupVideoCanvas ; |
设置远端辅流视频画布 | setupRemoteVideoSubStreamCanvas |
调节信号音量 | adjustUserPlaybackSignalVolume |
打开/查询扬声器 | setSpeakerphoneOn ;isSpeakerphoneOn |
获取实时互动频道成员 | getLocalQChatMediaMember (本端成员);getQChatMediaMembers (远端成员) |
启动说话者音量提示 | enableAudioVolumeIndication |
移除成员 | kickMemberOut |
API 参考
以下为本文涉及的实时互动频道相关 API。
API |
说明 |
---|---|
updateServerRole |
修改服务器身份组 |
createChannel |
创建实时互动频道 |
initialize |
初始化实时互动频道模块 |
isInitialized |
查询初始化状态 |
connect |
连接实时互动频道 |
disConnect |
取消连接实时互动频道 |
isConnected |
查询当前连接状态 |
addRTCChannelListener |
添加实时互动频道事件监听 |
removeRTCChannelListener |
移除实时互动频道监听 |
startScreenShare |
开启本端屏幕共享 |
stopScreenShare |
关闭本端屏幕共享 |
onMemberScreenShareStateChanged |
成员屏幕共享状态回调 |
更多实时互动频道相关接口如下:
QChatMediaKit
接口提供实时互动频道模块的初始化、登录、连接等能力。QChatRTCChannelController
接口提供实时互动频道内多样的音视频通话能力。QChatRTCChannelListener
接口提供实时互动频道相关事件的监听能力。