实现语聊房

更新时间: 2023/09/15 03:05:18

本文档为您展示通过 NERoom房间组件实现语聊房场景的相关步骤,帮助您在业务中实现麦位管理、低延时语音互动、文字聊天等能力。

开发环境要求

不同的目标平台,开发环境要求也不同,具体如下:

  • Flutter 3.10.0 及以上版本

  • Dart 3.0.0 及以上版本

  • 安装 Flutter 和 Dart 插件

  • 如果您的目标平台是 iOS:

    • Xcode 11.0 及以上版本
    • 请确保您的项目已设置有效的开发者签名
    • macOS 操作系统
    • 11.0 及以上的 iPhone 或者 iPad 真机
    • 使用 Objective-C 作为开发语言
  • 如果您的目标平台是 Android:

    • Android Studio 4.1 及以上版本
    • macOS 或 Windows 操作系统
    • Android 系统 5.0 及以上版本的真机
    • 使用 Java 作为开发语言

前提条件

方案架构

基于NERoom的方案架构.png

方案架构说明如下:

  • 主播、连麦者和观众加入同一个音视频房间。
  • 主播和连麦者在音视频房间内进行音频流的实时发布和订阅。
  • 观众在音视频房间内仅订阅音频流,不发布音频流。

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}");
       }
    });

主播开播

  1. 主播调用 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");
       }
     });
    
  2. 主播调用 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");
       }
     });
    
  3. 调用 joinRtcChannel 接口加入音视频房间。

    示例代码如下:

        NERoomService roomService = NERoomKit.instance.roomService;
     NERoomContext? roomContext = roomService.getRoomContext(roomUuid);
     if (roomContext!=null){
       roomContext.rtcController.joinRtcChannel();
     }
    
  4. 调用 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){
    
         },
       ));
     }
    
  5. 收到加入成功的 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));
}

观众进入房间

  1. 观众调用 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");
       }
     });
  1. 观众调用 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){

         },
       ));
     }
  1. 观众调用 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();
    }

离开房间

  1. 调用 leaveRoom 接口离开房间。

    示例代码如下:

    NERoomService roomService = NERoomKit.instance.roomService;
    NERoomContext? roomContext = roomService.getRoomContext(roomUuid);
    if (roomContext != null) {
      roomContext.leaveRoom();
    }
    
  2. 离开房间成功后,会触发 NERoomEventCallback.memberLeaveRoom 回调,通知房间内所有成员。

  3. 主播调用 endRoom 接口删除房间。

    示例代码如下:

     NERoomService roomService = NERoomKit.instance.roomService;
    NERoomContext? roomContext = roomService.getRoomContext(roomUuid);
    if (roomContext != null) {
      roomContext.endRoom();
    }
    
  4. 删除房间成功后,会触发 NERoomEventCallback 协议中的 roomEnd 回调方法。

进阶功能

伴音

  1. 调用 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 伴音跟随音频主流还是辅流,默认跟随主流。
  • NERtcAudioStreamTypeMain:伴音跟随主流
  • NERtcAudioStreamTypeSub:伴音跟随辅流
  1. 设置伴音的音量。

    • 通过 setAudioMixingSendVolume 设置伴音的发送音量
    • 通过 setAudioMixingPlaybackVolume 设置伴音的播放音量。
  2. 在离开房间前调用 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();
    }

音效

  1. 调用 RtcControllerplayEffect 方法播放音效。

    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:伴音跟随辅流
  2. 设置音效的音量。

    • 调用 setEffectSendVolume 方法设置音效文件发送音量。

    • 调用 setEffectPlaybackVolume 方法设置音效文件播放音量。

  3. 在离开房间前,调用 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();
    }

耳返

  1. 通过 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;
        }
      }
    
  2. 调用 enableEarBack 方法开启耳返。

      NERoomService roomService = NERoomKit.instance.roomService;
            int volumn = 100; // 耳返音量 默认100
                NERoomContext? roomContext = roomService.getRoomContext(roomUuid);
                if (roomContext != null) {
                    roomContext.rtcController.enableEarBack(volumn);
                }
    
  3. 调用 disableEarBack 方法关闭耳返。

    NERoomService roomService = NERoomKit.instance.roomService;
    NERoomContext? roomContext = roomService.getRoomContext(roomUuid);
    if (roomContext != null) {
        roomContext.rtcController.disableEarBack();
    }
    
此文档是否对你有帮助?
有帮助
去反馈
  • 开发环境要求
  • 前提条件
  • 方案架构
  • API调用时序图
  • 登录鉴权
  • 主播开播
  • 观众进入房间
  • 麦位管理
  • 添加麦位事件监听
  • 主播邀请观众上麦
  • 主播同意观众上麦
  • 主播拒绝观众上麦
  • 主播将观众移出麦位
  • 观众申请上麦
  • 观众取消申请上麦
  • 观众主动下麦
  • 离开房间
  • 进阶功能
  • 伴音
  • 音效
  • 耳返