实现语聊房
更新时间: 2024/08/14 14:11:32
本文档为您展示通过 NERoom房间组件实现语聊房场景的相关步骤,帮助您在业务中实现麦位管理、低延时语音互动、文字聊天等能力。
开发环境要求
不同的目标平台,开发环境要求也不同,具体如下:
-
Flutter 3.10.0 及以上版本
-
Dart 3.0.0 及以上版本
-
如果您的目标平台是 iOS:
- Xcode 11.0 及以上版本
- 请确保您的项目已设置有效的开发者签名
- macOS 操作系统
- 11.0 及以上的 iPhone 或者 iPad 真机
- 使用 Objective-C 作为开发语言
-
如果您的目标平台是 Android:
- Android Studio 4.1 及以上版本
- macOS 或 Windows 操作系统
- Android 系统 5.0 及以上版本的真机
- 使用 Java 作为开发语言
前提条件
方案架构
方案架构说明如下:
- 主播、连麦者和观众加入同一个音视频房间。
- 主播和连麦者在音视频房间内进行音频流的实时发布和订阅。
- 观众在音视频房间内仅订阅音频流,不发布音频流。
API调用时序图
sequenceDiagram
participant hostClientA as 主播A client
participant NERoomA as NERoom
participant app_server as VoiceRoom_Server
participant NERoomB as NERoom
participant audienceB as 观众B client
note over hostClientA, audienceB: 主播开播
hostClientA ->> NERoomA: createRoom
NERoomA ->> app_server: createRoom
app_server -->> hostClientA: 房间信息
hostClientA ->> NERoomA: joinRoom
NERoomA ->> app_server: joinRoom
app_server -->> hostClientA: 加入成功
hostClientA ->> NERoomA: unmuteMyAudio
NERoomA ->> app_server: unmuteMyAudio
note over hostClientA, audienceB: 观众进入房间
audienceB ->> NERoomB: joinRoom
NERoomB ->> app_server: joinRoom
app_server -->> audienceB: 房间信息
audienceB ->> NERoomB: unmuteMyAudio
NERoomB ->> app_server: unmuteMyAudio
sequenceDiagram
participant hostClientA as 主播A client
participant NERoomA as NERoom
participant app_server as VoiceRoom_Server
participant NERoomB as NERoom
participant audienceB as 观众B client
note over hostClientA, audienceB: 抱观众上麦
hostClientA ->> NERoomA: sendSeatInvitation <br>(邀请上麦)
NERoomA ->> app_server: sendSeatInvitation <br>(邀请上麦)
app_server -->> NERoomB: onSeatInvitationAccepted <br>(自动同意上麦的回调)
NERoomB -->> audienceB: onSeatInvitationAccepted <br>(自动同意上麦的回调)
app_server -->> NERoomB: onSeatListChanged <br>(麦位变更的回调)
NERoomB -->> audienceB: onSeatListChanged <br>(麦位变更的回调)
app_server -->> NERoomA: onSeatInvitationAccepted <br>(自动同意上麦的回调)
NERoomA -->> hostClientA: onSeatInvitationAccepted <br>(自动同意上麦的回调)
app_server -->> NERoomA: onSeatListChanged <br> (麦位变更的回调)
NERoomA -->> hostClientA: onSeatListChanged <br>(麦位变更的回调)
audienceB ->> audienceB: 刷新UI
hostClientA ->> hostClientA: 刷新UI
note over hostClientA, audienceB: 将观众移出麦位
hostClientA ->> NERoomA: kickSeat <br>(主播踢观众B下麦)
NERoomA ->> app_server: kickSeat <br>(主播踢观众B下麦)
app_server -->> NERoomB: onSeatKicked <br>(主播踢观众B下麦的回调)
NERoomB -->> audienceB: onSeatKicked <br>(主播踢观众B下麦的回调)
app_server -->> NERoomB: onSeatListChanged <br>(麦位变更的回调)
NERoomB -->> audienceB: onSeatListChanged <br>(麦位变更的回调)
app_server -->> NERoomA: onSeatKicked <br>(主播踢观众B下麦的回调)
NERoomA -->> hostClientA: onSeatKicked <br>(主播踢观众B下麦的回调)
app_server -->> NERoomA: onSeatListChanged <br>(麦位变更的回调)
NERoomA -->> hostClientA: onSeatListChanged <br>(麦位变更的回调)
audienceB ->> audienceB: 刷新UI
hostClientA ->> hostClientA: 刷新UI
sequenceDiagram
participant hostClientA as 主播A client
participant NERoomA as NERoom
participant app_server as VoiceRoom_Server
participant NERoomB as NERoom
participant audienceB as 观众B client
note over hostClientA, audienceB: 观众申请上麦
audienceB ->> NERoomB: submitSeatRequest <br>(申请上麦)
NERoomB ->> app_server: submitSeatRequest <br>(申请上麦)
app_server ->> NERoomB: onSeatListChanged <br>(麦位变更的回调)
NERoomB ->> audienceB: onSeatListChanged <br>(麦位变更的回调)
app_server ->> NERoomA: onSeatRequestSubmitted <br>(观众B申请上麦的回调)
NERoomA ->> hostClientA: onSeatRequestSubmitted <br>(观众B申请上麦的回调)
app_server ->> NERoomA: onSeatListChanged <br>(麦位变更的回调)
NERoomA ->> hostClientA: onSeatListChanged <br>(麦位变更的回调)
audienceB ->> audienceB: 刷新UI
hostClientA ->> hostClientA: 刷新UI
alt 主播同意上麦申请
hostClientA ->> NERoomA: approveSeatRequest <br>(主播同意上麦申请)
NERoomA ->> app_server: approveSeatRequest <br>(主播同意上麦申请)
app_server ->> NERoomA: onSeatRequestApproved <br>(主播同意上麦申请的回调)
NERoomA ->> hostClientA: onSeatRequestApproved <br>(主播同意上麦申请的回调)
app_server ->> NERoomA: onSeatListChanged <br>(麦位变更的回调)
NERoomA ->> hostClientA: onSeatListChanged <br>(麦位变更的回调)
app_server ->> NERoomB: onSeatRequestApproved <br>(主播同意上麦申请的回调)
NERoomB ->> audienceB: onSeatRequestApproved <br> (主播同意上麦申请的回调)
app_server ->> NERoomB: onSeatListChanged <br>(麦位变更的回调)
NERoomB ->> audienceB: onSeatListChanged <br> (麦位变更的回调)
audienceB ->> audienceB: 刷新UI
hostClientA ->> hostClientA: 刷新UI
else 主播拒绝上麦申请
hostClientA ->> NERoomA: rejectRequestSeat <br>(主播不同意上麦申请)
NERoomA ->> app_server: rejectRequestSeat <br>(主播不同意上麦申请)
app_server -->> NERoomA: onSeatRequestRejected <br>(主播拒绝观众B上麦的回调)
NERoomA -->> hostClientA: onSeatRequestRejected <br>(主播拒绝观众B上麦的回调)
app_server -->> NERoomA: onSeatListChanged <br>(麦位变更的回调)
NERoomA -->> hostClientA: onSeatListChanged <br>(麦位变更的回调)
app_server -->> NERoomB: onSeatRequestRejected <br>(主播拒绝观众B上麦的回调)
NERoomB -->> audienceB: onSeatRequestRejected <br>(主播拒绝观众B上麦的回调)
app_server -->> NERoomB: onSeatListChanged <br>(麦位变更的回调)
NERoomB -->> audienceB: onSeatListChanged <br>(麦位变更的回调)
audienceB ->> audienceB: 刷新UI
hostClientA ->> hostClientA: 刷新UI
end
sequenceDiagram
participant hostClientA as 主播A client
participant NERoomA as NERoom
participant app_server as VoiceRoom_Server
participant NERoomB as NERoom
participant audienceB as 观众B client
note over hostClientA, audienceB: 观众取消申请上麦
audienceB ->> NERoomB: cancelSeatRequest<br> (取消申请上麦)
NERoomB ->> app_server: cancelSeatRequest <br> (取消申请上麦)
app_server -->> NERoomA: onSeatRequestCancelled <br>(观众B取消上麦的回调)
NERoomA -->> hostClientA: onSeatRequestCancelled <br>(观众B取消上麦的回调)
app_server -->> NERoomA: onSeatListChanged <br>(麦位变更的回调)
NERoomA -->> hostClientA: onSeatListChanged <br>(麦位变更的回调)
app_server -->> NERoomB: onSeatRequestCancelled <br>(观众B取消上麦的回调)
NERoomB -->> audienceB: onSeatRequestCancelled <br> (观众B取消上麦的回调)
app_server -->> NERoomB: onSeatListChanged <br>(麦位变更的回调)
NERoomB -->> audienceB: onSeatListChanged <br>(麦位变更的回调)
audienceB ->> audienceB: 刷新UI
hostClientA ->> hostClientA: 刷新UI
note over hostClientA, audienceB: 观众下麦
audienceB ->> NERoomB: leaveSeat (下麦)
NERoomB ->> app_server: leaveSeat (下麦)
app_server -->> NERoomA: onSeatLeave <br>(观众B成功下麦的回调)
NERoomA -->> hostClientA: onSeatLeave <br>(观众B成功下麦的回调)
app_server -->> NERoomA: onSeatListChanged <br>(麦位变更的回调)
NERoomA -->> hostClientA: onSeatListChanged <br>(麦位变更的回调)
app_server -->> NERoomB: onSeatLeave <br>(观众B成功下麦的回调)
NERoomB -->> audienceB: onSeatLeave <br>(观众B成功下麦的回调)
app_server -->> NERoomB: onSeatListChanged <br>(麦位变更的回调)
NERoomB -->> audienceB: onSeatListChanged <br>(麦位变更的回调)
audienceB ->> audienceB: 刷新UI
hostClientA ->> hostClientA: 刷新UI
登录鉴权
调用 login
接口进行账号登录。
登录鉴权的详细说明请参见账号集成与登录。
NERoomKit.instance.authService.login(account, token).then((value){
if(value.isSuccess()){
print("login success");
}else{
print("login failed,code:${value.code},msg:${value.msg}");
}
});
主播开播
-
主播调用
createRoom
接口创建房间。创建房间麦位
NESeatInitParams
参数说明:参数 类型 描述 seatCount int 麦位数量 seatRequestApprovalMode int 从 NESeatRequestApprovalMode
内获取麦位申请审批模式。OFF
:关闭审批模式,即成员提交申请后不需要管理员同意,可直接上麦。ON
:开启审批模式,即成员提交申请后需要管理员同意才能上麦。
seatInvitationConfirmMode int 麦位邀请确认模式。 OFF
: 关闭确认模式,即管理员邀请其他成员上麦,不需要被邀请的成员确认,可直接上麦。ON
:开启确认模式,即管理员邀请其他成员上麦,需要被邀请的成员确认,接受后方可上麦。
示例代码如下:
NERoomService roomService = NERoomKit.instance.roomService; String roomUuid="123"; String roomName="roomName"; int templateId= 21; String password = "12345"; Map<String,String> initialProperties = new HashMap<String,String>(); initialProperties.put("custom-property-key0", "custom-property-value0"); initialProperties.put("custom-property-key1", "custom-property-value1"); /// 设置麦位数量8个,麦位申请需要审批。房主邀请上麦不需要观众同意 NESeatInitParams seatInitParams = NESeatInitParams(8,NESeatRequestApprovalMode.ON,NESeatInvitationConfirmMode.OFF); NECreateRoomParams params= NECreateRoomParams(roomUuid,roomName,templateId, password,seatInitParams, initialProperties); NECreateRoomOptions options = NECreateRoomOptions(); roomService.createRoom(params, options).then((value){ if(value.isSuccess()){ print("create room success"); }else{ print("create room failed"); } });
-
主播调用
joinRoom
接口加入房间。示例代码如下:
NERoomService roomService = NERoomKit.instance.roomService; String roomUuid="123"; String userName="userName"; String role="host";//从模板获取角色名称,比如PK直播的场景中的角色名为:host,invited_host,audience String password = "password"; //设置为null,表示没有密码 Map<String,String> initialProperties = new HashMap<String,String>(); initialProperties["custom-property-key0"]="custom-property-value0"; initialProperties["custom-property-key1"]="custom-property-value1"; roomService.joinRoom( NEJoinRoomParams(userName: userName, role: role, roomUuid: roomUuid,password: password, initialMyProperties: initialProperties), NEJoinRoomOptions()).then((value){ if(value.isSuccess()){ print("join room success"); }else{ print("join room failed"); } });
-
调用
joinRtcChannel
接口加入音视频房间。示例代码如下:
NERoomService roomService = NERoomKit.instance.roomService; NERoomContext? roomContext = roomService.getRoomContext(roomUuid); if (roomContext!=null){ roomContext.rtcController.joinRtcChannel(); }
-
调用
addEventCallback
接口监听房间里的事件。示例代码如下:
NERoomService roomService = NERoomKit.instance.roomService; NERoomContext? roomContext = roomService.getRoomContext(roomUuid); if (roomContext!=null){ roomContext.addEventCallback(NERoomEventCallback( roomEnd:(NERoomEndReason reason){ }, roomPropertiesChanged:(Map<String, String> properties){ }, roomPropertiesDeleted:(Map<String, String> properties){}, memberPropertiesChanged:(NERoomMember member, Map<String, String> properties){ }, memberPropertiesDeleted:(NERoomMember member, Map<String, String> properties){ }, memberRoleChanged:(NERoomMember member, NERoomRole oldRole, NERoomRole newRole){ }, memberNameChanged:(NERoomMember member, String name){ }, memberJoinRoom:(List<NERoomMember> members){ }, memberLeaveRoom:(List<NERoomMember> members){ }, memberJoinRtcChannel:(List<NERoomMember> members){ }, memberLeaveRtcChannel:(List<NERoomMember> members){ }, rtcChannelError:(int code){ }, memberJoinChatroom:(List<NERoomMember> members){ }, memberLeaveChatroom:(List<NERoomMember> members){ }, memberAudioMuteChanged:(NERoomMember member, bool mute, NERoomMember? operateBy){ }, memberVideoMuteChanged:(NERoomMember member, bool mute, NERoomMember? operateBy){ }, memberScreenShareStateChanged:(NERoomMember member, bool isSharing, NERoomMember? operateBy){ }, chatroomMessagesReceived:(List<NERoomChatMessage> messages){ }, liveStateChanged:(NERoomLiveState state){ }, rtcAudioVolumeIndication:(List<NEMemberVolumeInfo> volumes, int totalVolume){ }, rtcAudioOutputDeviceChanged:(NEAudioOutputDevice device){ }, rtcAudioMixingStateChanged:(int reason){ }, )); }
-
收到加入成功的
memberJoinRoom
回调后,调用unmuteMyAudio
方法开启本地音频采集。示例代码如下:
NERoomService roomService = NERoomKit.instance.roomService; NERoomContext? roomContext = roomService.getRoomContext(roomUuid); if (roomContext != null) { roomContext.rtcController.unmuteMyAudio(); }
6.调用 submitSeatRequest
方法上麦。
示例代码如下:
var _currentRoomContext= NERoomKit.instance.roomService.getRoomContext(roomUuid);
if (_currentRoomContext != null) {
var ret = await _currentRoomContext!.seatController
.submitSeatRequest(seatIndex, exclusive);
commonLogger.i('submitSeatRequest,ret:$ret');
return ret;
} else {
commonLogger.e("_currentRoomContext == null");
return Future.value(const NEResult(
code: NEVoiceRoomErrorCode.failure, msg: ERROR_MSG_NOT_IN_ROOM));
}
观众进入房间
- 观众调用
joinRoom
接口加入房间。
NERoomService roomService = NERoomKit.instance.roomService;
String roomUuid="123";
String userName="userName";
String role="host";//从模板获取角色名称,比如PK直播的场景中的角色名为:host,invited_host,audience
String password = "password"; //设置为null,表示没有密码
Map<String,String> initialProperties = new HashMap<String,String>();
initialProperties["custom-property-key0"]="custom-property-value0";
initialProperties["custom-property-key1"]="custom-property-value1";
roomService.joinRoom( NEJoinRoomParams(userName: userName, role: role, roomUuid: roomUuid,password: password,
initialMyProperties: initialProperties), NEJoinRoomOptions()).then((value){
if(value.isSuccess()){
print("join room success");
}else{
print("join room failed");
}
});
- 观众调用
addEventCallback
接口监听房间里的事件。
NERoomService roomService = NERoomKit.instance.roomService;
NERoomContext? roomContext = roomService.getRoomContext(roomUuid);
if (roomContext!=null){
roomContext.addEventCallback(NERoomEventCallback(
roomEnd:(NERoomEndReason reason){
},
roomPropertiesChanged:(Map<String, String> properties){
},
roomPropertiesDeleted:(Map<String, String> properties){},
memberPropertiesChanged:(NERoomMember member, Map<String, String> properties){
},
memberPropertiesDeleted:(NERoomMember member, Map<String, String> properties){
},
memberRoleChanged:(NERoomMember member, NERoomRole oldRole, NERoomRole newRole){
},
memberNameChanged:(NERoomMember member, String name){
},
memberJoinRoom:(List<NERoomMember> members){
},
memberLeaveRoom:(List<NERoomMember> members){
},
memberJoinRtcChannel:(List<NERoomMember> members){
},
memberLeaveRtcChannel:(List<NERoomMember> members){
},
rtcChannelError:(int code){
},
memberJoinChatroom:(List<NERoomMember> members){
},
memberLeaveChatroom:(List<NERoomMember> members){
},
memberAudioMuteChanged:(NERoomMember member, bool mute, NERoomMember? operateBy){
},
memberVideoMuteChanged:(NERoomMember member, bool mute, NERoomMember? operateBy){
},
memberScreenShareStateChanged:(NERoomMember member, bool isSharing, NERoomMember? operateBy){
},
chatroomMessagesReceived:(List<NERoomChatMessage> messages){
},
liveStateChanged:(NERoomLiveState state){
},
rtcAudioVolumeIndication:(List<NEMemberVolumeInfo> volumes, int totalVolume){
},
rtcAudioOutputDeviceChanged:(NEAudioOutputDevice device){
},
rtcAudioMixingStateChanged:(int reason){
},
));
}
-
观众调用
muteMyAudio
方法关闭本地音频采集。等到上麦后,再开启本地音频采集。
NERoomService roomService = NERoomKit.instance.roomService;
NERoomContext? roomContext = roomService.getRoomContext(roomUuid);
if (roomContext != null) {
roomContext.rtcController.muteMyAudio();
}
麦位管理
添加麦位事件监听
调用 addEventCallback
接口,监听麦位相关的事件。
示例代码如下:
NEVoiceRoomEventCallback eventCallback = NEVoiceRoomEventCallback(
memberAudioMuteChangedCallback: (member, mute, operateBy) {
_notifyMemberAudioMuteChanged(member, mute, operateBy);
}, memberAudioBannedCallback: (member, banned) {
_notifyMemberAudioBanned(member, banned);
}, seatRequestSubmittedCallback: (seatIndex, account) {
_notifySeatRequestSubmitted(seatIndex, account);
}, seatRequestCancelledCallback: (seatIndex, account) {
_notifySeatRequestCancelled(seatIndex, account);
}, seatRequestApprovedCallback:
(seatIndex, account, operateBy, isAutoAgree) {
_notifySeatRequestApproved(seatIndex, account, operateBy, isAutoAgree);
}, seatRequestRejectedCallback: (seatIndex, account, operateBy) {
_notifySeatRequestRejected(seatIndex, account, operateBy);
}, seatLeaveCallback: (seatIndex, account) {
_notifySeatLeave(seatIndex, account);
}, seatKickedCallback: (seatIndex, account, operateBy) {
_notifySeatKicked(seatIndex, account, operateBy);
}, seatInvitationAcceptedCallback: (seatIndex, account, isAutoAgree) {
_notifySeatInvitationAccepted(seatIndex, account, isAutoAgree);
}, seatListChangedCallback: (seatItems) {
_notifySeatListChanged(seatItems);
});
NEVoiceRoomKit.instance.addVoiceRoomListener(eventCallback);
主播邀请观众上麦
- 主播调用
sendSeatInvitation
接口邀请观众上麦。String userId = "56789"; int index=2; NERoomService roomService = NERoomKit.instance.roomService; NERoomContext? roomContext = roomService.getRoomContext(roomUuid); if (roomContext != null) { roomContext.seatController.sendSeatInvitation(index,userId); }
主播同意观众上麦
主播调用 approveSeatRequest
接口同意观众上麦。
String userId = "56789";
NERoomService roomService = NERoomKit.instance.roomService;
NERoomContext? roomContext = roomService.getRoomContext(roomUuid);
if (roomContext != null) {
roomContext.seatController.approveSeatRequest(userId);
}
主播拒绝观众上麦
主播调用 rejectSeatRequest
接口拒绝观众上麦。
String userId = "56789";
NERoomService roomService = NERoomKit.instance.roomService;
NERoomContext? roomContext = roomService.getRoomContext(roomUuid);
if (roomContext != null) {
roomContext.seatController.rejectSeatRequest(userId);
}
主播将观众移出麦位
主播调用 kickSeat
接口将观众移出麦位。
String userId = "56789";
NERoomService roomService = NERoomKit.instance.roomService;
NERoomContext? roomContext = roomService.getRoomContext(roomUuid);
if (roomContext != null) {
roomContext.seatController.kickSeat(userId);
}
观众申请上麦
观众调用 submitSeatRequest
接口申请上麦。
int index=1;
NERoomService roomService = NERoomKit.instance.roomService;
NERoomContext? roomContext = roomService.getRoomContext(roomUuid);
if (roomContext != null) {
roomContext.seatController.submitSeatRequest(index,exclusive);
}
观众取消申请上麦
观众调用 cancelSeatRequest
接口取消申请上麦。
NERoomService roomService = NERoomKit.instance.roomService;
NERoomContext? roomContext = roomService.getRoomContext(roomUuid);
if (roomContext != null) {
roomContext.seatController.cancelSeatRequest();
}
观众主动下麦
观众调用 leaveSeat
接口下麦。
NERoomService roomService = NERoomKit.instance.roomService;
NERoomContext? roomContext = roomService.getRoomContext(roomUuid);
if (roomContext != null) {
roomContext.seatController.leaveSeat();
}
离开房间
-
调用
leaveRoom
接口离开房间。示例代码如下:
NERoomService roomService = NERoomKit.instance.roomService; NERoomContext? roomContext = roomService.getRoomContext(roomUuid); if (roomContext != null) { roomContext.leaveRoom(); }
-
离开房间成功后,会触发
NERoomEventCallback.memberLeaveRoom
回调,通知房间内所有成员。 -
主播调用
endRoom
接口删除房间。示例代码如下:
NERoomService roomService = NERoomKit.instance.roomService; NERoomContext? roomContext = roomService.getRoomContext(roomUuid); if (roomContext != null) { roomContext.endRoom(); }
-
删除房间成功后,会触发
NERoomEventCallback
协议中的roomEnd
回调方法。
进阶功能
伴音
- 调用
RtcController
的 <a href =https://doc.yunxin.163.com/neroom/api-docs/neroom_Flutter_zh/NERoom_Flutter_API_Reference/netease_roomkit/NERoomRtcController/startAudioMixing" target="_blank">startAudioMixing
方法播放伴音。
NECreateAudioMixingOption
参数说明如下表所示。
参数 | 类型 | 描述 |
---|---|---|
path | String | 待播放的音乐文件的绝对路径或 URL 地址,支持本地 SD 卡中的绝对路径或 URL 地址 |
loopCount | int | 伴音循环播放的次数。1:(默认)播放一次。≤ 0:无限循环播放 |
sendEnabled | boolean | 是否将伴音发送远端,默认为 true,即远端用户可以听到该伴音。 |
sendVolume | int | 音乐文件的发送音量,取值范围为 0~200。默认为 100,表示使用文件的原始音量。 |
playbackEnabled | boolean | 是否本地播放伴音。默认为 true,即本地用户可以听到该伴音。 |
playbackVolume | int | 音乐文件的播放音量,取值范围为 0~200。默认为 100,表示使用文件的原始音量。 |
startTimeStamp | long | 音乐文件开始播放的时间,UTC 时间戳,即从1970 年 1 月 1 日 0 点 0 分 0 秒开始到事件发生时的毫秒数。默认值为 0,表示立即播放。 |
sendWithAudioType | NERoomRtcAudioStreamType | 伴音跟随音频主流还是辅流,默认跟随主流。
|
-
设置伴音的音量。
- 通过
setAudioMixingSendVolume
设置伴音的发送音量 - 通过
setAudioMixingPlaybackVolume
设置伴音的播放音量。
- 通过
-
在离开房间前调用
stopAudioMixing
结束伴音。
示例代码如下:
NERoomService roomService = NERoomKit.instance.roomService;
NERoomContext? roomContext = roomService.getRoomContext(roomUuid);
String path = "music path";
int loopCount = 1;
bool sendEnabled = true;
int sendVolume = 100;
bool playbackEnabled = true;
int playbackVolume = 100;
int startTimeStamp = 0;
NERoomRtcAudioStreamType sendWithAudioType = NERoomRtcAudioStreamType.NERtcAudioStreamTypeMain
NECreateAudioMixingOption options = NECreateAudioMixingOption(path:path,loopCount,sendEnabled,playbackEnabled,sendVolume,
playbackVolume,startTimeStamp,sendWithAudioType);
if (roomContext != null) {
roomContext.rtcController.startAudioMixing(options);
}
if (roomContext != null) {
roomContext.rtcController.setAudioMixingSendVolume(80);
}
if (roomContext != null) {
roomContext.rtcController.setAudioMixingPlaybackVolume(80);
}
if (roomContext != null) {
roomContext.rtcController.stopAudioMixing();
}
音效
-
调用
RtcController
的playEffect
方法播放音效。NECreateAudioEffectOption
参数说明如下表所示。参数 类型 描述 path String 待播放的音乐文件的绝对路径或 URL 地址,支持本地 SD 卡中的绝对路径或 URL 地址 loopCount int 音效循环播放的次数。1:(默认)播放一次。≤ 0:无限循环播放 sendEnabled boolean 是否将音效发送远端,默认为 true,即远端用户可以听到该音效。 sendVolume int 音效文件的发送音量,取值范围为 0~200。默认为 100,表示使用文件的原始音量。 playbackEnabled boolean 是否本地播放音效。默认为 true,即本地用户可以听到该音效。 playbackVolume int 音乐文件的播放音量,取值范围为 0~200。默认为 100,表示使用文件的原始音量。 startTimeStamp long 音乐文件开始播放的时间,UTC 时间戳,即从1970 年 1 月 1 日 0 点 0 分 0 秒开始到事件发生时的毫秒数。默认值为 0,表示立即播放。 sendWithAudioType NERoomRtcAudioStreamType 伴音跟随音频主流还是辅流,默认跟随主流。 - kNERtcAudioStreamTypeMain:伴音跟随主流
- kNERtcAudioStreamTypeSub:伴音跟随辅流
-
设置音效的音量。
-
调用
setEffectSendVolume
方法设置音效文件发送音量。 -
调用
setEffectPlaybackVolume
方法设置音效文件播放音量。
-
-
在离开房间前,调用
stopAllEffects
方法停止播放所有音效文件。
示例代码如下:
NERoomService roomService = NERoomKit.instance.roomService;
NERoomContext? roomContext = roomService.getRoomContext(roomUuid);
String path = "effect file path";
int loopCount = 1;
bool sendEnabled = true;
int sendVolume = 100;
bool playbackEnabled = true;
int playbackVolume = 100;
int startTimeStamp = 0;
NERoomRtcAudioStreamType sendWithAudioType = NERoomRtcAudioStreamType.NERtcAudioStreamTypeMain
NECreateAudioEffectOption options = NECreateAudioEffectOption(path:path,loopCount,sendEnabled,sendVolume,
playbackEnabled,playbackVolume,startTimeStamp,sendWithAudioType);
if (roomContext != null) {
roomContext.rtcController.playEffect(options);
}
if (roomContext != null) {
roomContext.rtcController.setEffectSendVolume(0, 80);
}
if (roomContext != null) {
roomContext.rtcController.setEffectPlaybackVolume(0, 80);
}
if (roomContext != null) {
roomContext.rtcController.stopAllEffects();
}
耳返
-
通过
rtcAudioOutputDeviceChanged
监听播放设备的变化,当监听到播放设备切换为耳机时才开启耳返。_roomEventCallback = NERoomEventCallback( rtcAudioOutputDeviceChanged: _notifyAudioOutputDeviceChanged, ); void _notifyAudioOutputDeviceChanged(NEAudioOutputDevice device) { switch(device){ case NEAudioOutputDevice.kWiredHeadset: print("有线耳机"); break; case NEAudioOutputDevice.kSpeakerPhone: print("扬声器"); break; case NEAudioOutputDevice.kEarpiece: print("听筒"); break; case NEAudioOutputDevice.kBluetoothHeadset: print("蓝牙耳机"); break; } }
-
调用
enableEarBack
方法开启耳返。NERoomService roomService = NERoomKit.instance.roomService; int volumn = 100; // 耳返音量 默认100 NERoomContext? roomContext = roomService.getRoomContext(roomUuid); if (roomContext != null) { roomContext.rtcController.enableEarBack(volumn); }
-
调用
disableEarBack
方法关闭耳返。NERoomService roomService = NERoomKit.instance.roomService; NERoomContext? roomContext = roomService.getRoomContext(roomUuid); if (roomContext != null) { roomContext.rtcController.disableEarBack(); }