浏览代码

Merge branch 'feature/0529-live' into master_saas

# Conflicts:
#	mec-biz/src/main/java/com/ym/mec/biz/service/impl/CourseScheduleServiceImpl.java
shangke 2 年之前
父节点
当前提交
c82581ba96

+ 11 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dto/CourseScheduleDto.java

@@ -99,6 +99,9 @@ public class CourseScheduleDto extends CourseSchedule {
 
     private int enableAssignHomework;
 
+    @ApiModelProperty("直播间信息")
+    private ImLiveBroadcastRoomDto liveBroadcastRoom;
+
     public int getEnableAssignHomework() {
         return enableAssignHomework;
     }
@@ -348,4 +351,12 @@ public class CourseScheduleDto extends CourseSchedule {
     public void setStudentId(Integer studentId) {
         this.studentId = studentId;
     }
+
+    public ImLiveBroadcastRoomDto getLiveBroadcastRoom() {
+        return liveBroadcastRoom;
+    }
+
+    public void setLiveBroadcastRoom(ImLiveBroadcastRoomDto liveBroadcastRoom) {
+        this.liveBroadcastRoom = liveBroadcastRoom;
+    }
 }

+ 44 - 1
mec-biz/src/main/java/com/ym/mec/biz/service/impl/CourseScheduleServiceImpl.java

@@ -3,6 +3,7 @@ package com.ym.mec.biz.service.impl;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.google.common.collect.Maps;
 import com.ym.mec.auth.api.client.SysUserFeignService;
 import com.ym.mec.auth.api.entity.SysUser;
 import com.ym.mec.biz.dal.dao.*;
@@ -41,6 +42,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections.ListUtils;
 import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
@@ -1078,6 +1080,9 @@ public class CourseScheduleServiceImpl extends BaseServiceImpl<Long, CourseSched
 						|| cs.getType().equals(CourseScheduleType.COMM))
                 .map(CourseScheduleDto::getId).collect(Collectors.toList());
 
+		// 直播课设置直播间信息
+		Map<String, ImLiveBroadcastRoomDto> liveRoomMap = getLiveRoomMap(studentCourseSchedulesWithDate);
+
 		Map<Integer, String> subjectNameCourseMap = new HashMap<>();
         Map<Integer, String> subjectIdCourseMap = new HashMap<>();
         Map<Integer, Integer> reviewIdMap = new HashMap<>();
@@ -1117,12 +1122,44 @@ public class CourseScheduleServiceImpl extends BaseServiceImpl<Long, CourseSched
 			if(CourseScheduleType.PRACTICE.equals(courseScheduleDto.getType())&&Objects.nonNull(courseScheduleDto.getMusicGroupId())){
 				courseScheduleDto.setPracticeType(practiceGroupTypeMap.get(Long.valueOf(courseScheduleDto.getMusicGroupId())));
 			}
+
+			// 设置直播间配置
+			courseScheduleDto.setLiveBroadcastRoom(liveRoomMap.get(courseScheduleDto.getMusicGroupId()));
         }
         result.put("list", studentCourseSchedulesWithDate);
         return result;
     }
 
-    @Override
+	/**
+	 * 直播课设置直播间信息
+	 * @param studentCourseSchedulesWithDate List<CourseScheduleDto>
+	 * @return Map<String, ImLiveBroadcastRoomDto>
+	 */
+	private Map<String, ImLiveBroadcastRoomDto> getLiveRoomMap(List<CourseScheduleDto> studentCourseSchedulesWithDate) {
+
+		Map<String, ImLiveBroadcastRoomDto> liveRoomMap = Maps.newHashMap();
+		{
+			Map<Long, String> collect = studentCourseSchedulesWithDate.stream()
+					.filter(x -> StringUtils.isNotEmpty(x.getMusicGroupId()))
+					.filter(x -> x.getType().equals(CourseScheduleType.LIVE))
+					.collect(Collectors.toMap(CourseSchedule::getId, CourseSchedule::getMusicGroupId, (o, n) -> n));
+
+			if (MapUtils.isNotEmpty(collect)) {
+
+				List<Long> liveGroupIds = collect.values().stream().map(Long::parseLong).distinct().collect(Collectors.toList());
+
+				liveRoomMap = vipGroupDao.getVipGroupByIds(liveGroupIds).stream()
+						.filter(x -> Objects.nonNull(x.getLiveConfigJson()))
+						.collect(Collectors.toMap(x -> String.valueOf(x.getId()),
+								x -> JSON.parseObject(x.getLiveConfigJson(), ImLiveBroadcastRoomDto.class), (o, n) -> n));
+
+			}
+
+		}
+		return liveRoomMap;
+	}
+
+	@Override
     public PageInfo getCourseSchedulesWithDateByEdu(CourseScheduleQueryInfo queryInfo) {
 //        queryInfo.setOrganId(Long.parseLong(user.getOrganId()));
         PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
@@ -1210,6 +1247,9 @@ public class CourseScheduleServiceImpl extends BaseServiceImpl<Long, CourseSched
 						cs.getType().equals(CourseScheduleType.COMM))
                 .map(CourseScheduleDto::getId).collect(Collectors.toList());
 
+		// 直播课设置直播间信息
+		Map<String, ImLiveBroadcastRoomDto> liveRoomMap = getLiveRoomMap(teacherCourseSchedulesWithDate);
+
         Map<Integer, String> subjectNameCourseMap = new HashMap<>();
         Map<Integer, String> subjectIdCourseMap = new HashMap<>();
         if (!CollectionUtils.isEmpty(courseScheduleIds)) {
@@ -1294,6 +1334,9 @@ public class CourseScheduleServiceImpl extends BaseServiceImpl<Long, CourseSched
             if(homeworkCourseIds.contains(courseScheduleDto.getId())){
 				courseScheduleDto.setEnableAssignHomework(1);
 			}
+
+			// 直播课直播间配置
+			courseScheduleDto.setLiveBroadcastRoom(liveRoomMap.get(courseScheduleDto.getMusicGroupId()));
 		}
         return teacherCourseSchedulesWithDate;
     }

+ 2 - 1
mec-biz/src/main/resources/config/mybatis/CourseScheduleMapper.xml

@@ -730,7 +730,8 @@
         IF(ta.sign_in_status_ IS NULL,0,1) sign_in_status_,
         IF(ta.sign_out_status_ IS NULL,0,1) sign_out_status_,
         cs.teach_mode_,
-        cs.live_room_id_
+        cs.live_room_id_,
+        cs.group_type_
         FROM
         course_schedule_teacher_salary csts
         LEFT JOIN course_schedule cs ON csts.course_schedule_id_=cs.id_

+ 9 - 0
mec-im/src/main/java/com/ym/pojo/RoomResult.java

@@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.microsvc.toolkit.middleware.rtc.message.RTCRoomConfig;
 import com.ym.mec.biz.dal.entity.CourseScheduleStudentMusicScore;
+import com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomVo;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.Getter;
@@ -19,6 +20,8 @@ import java.util.stream.Collectors;
 /**
  * Created by weiqinxiao on 2019/2/28.
  */
+@Getter
+@Setter
 public class RoomResult {
     private @Getter @Setter String roomId;
     //课程结束后是否自动关闭课程
@@ -48,6 +51,12 @@ public class RoomResult {
     @ApiModelProperty("课程人数")
     private @Getter @Setter Integer studentNums;
 
+    @ApiModelProperty("直播间编号")
+    public String liveRoomId;
+
+    @ApiModelProperty("直播间信息")
+    public ImLiveBroadcastRoomVo liveRoom;
+
     public RoomResult rtcRoomConfig(RTCRoomConfig rtcRoomConfig) {
         this.rtcRoomConfig = rtcRoomConfig;
         return this;

+ 209 - 60
mec-im/src/main/java/com/ym/service/Impl/RoomServiceImpl.java

@@ -34,9 +34,11 @@ import com.ym.mec.biz.dal.dto.RongyunBasicUserDto;
 import com.ym.mec.biz.dal.entity.*;
 import com.ym.mec.biz.dal.enums.GroupType;
 import com.ym.mec.biz.dal.enums.TeachModeEnum;
+import com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomVo;
 import com.ym.mec.biz.service.*;
 import com.ym.mec.common.exception.BizException;
 import com.ym.mec.common.page.WrapperUtil;
+import com.ym.mec.common.tenant.TenantContextHolder;
 import com.ym.mec.im.IMHelper;
 import com.ym.mec.im.message.*;
 import com.ym.mec.util.collection.MapUtil;
@@ -124,6 +126,8 @@ public class RoomServiceImpl implements RoomService {
     private RTCRoomPluginContext rtcRoomPluginContext;
     @Autowired
     private VipGroupDao vipGroupDao;
+    @Autowired
+    private ImLiveBroadcastRoomService imLiveBroadcastRoomService;
 
     @Override
     public Integer getCurrentCourseId(String roomId) {
@@ -208,6 +212,8 @@ public class RoomServiceImpl implements RoomService {
         }
 
         RoomResult roomResult = new RoomResult();
+        // 直播间编号
+        roomResult.setLiveRoomId(courseSchedule.getLiveRoomId());
         roomResult.setAutoCloseNetworkRoomTime(this.getCloseNetworkRoomTime(courseSchedule, continueCourseTime));
         CourseSchedule schedule = courseSchedule;
         //如果当前课程是连堂课,那么获取第一节课的课程编号
@@ -231,7 +237,6 @@ public class RoomServiceImpl implements RoomService {
         }
         redisTemplate.opsForValue().setIfAbsent(roomId + userId, courseSchedule.getId().toString());
         log.info("joinRoom current: roomId={}, userId={}", roomId, userId);
-        RoleEnum roleEnum;
 
         // 获取RTC服务提供方
         if (StringUtils.isBlank(courseSchedule.getServiceProvider())) {
@@ -252,19 +257,178 @@ public class RoomServiceImpl implements RoomService {
             }
 
             courseSchedule.setServiceProvider(rtcServiceProvider);
+
+            // 更新网络课服务提供方
+            courseScheduleDao.updateServiceProvider(courseSchedule.getId(), courseSchedule.getServiceProvider());
+        }
+
+        // 主讲老师信息
+        SysUser teacherInfo = sysUserFeignService.queryUserById(courseSchedule.getActualTeacherId());
+        if (Objects.isNull(teacherInfo)) {
+            throw new BizException("主讲老师不存在");
         }
 
+        // RTC服务提供方
+        roomResult.setServiceProvider(Optional.ofNullable(courseSchedule.getServiceProvider()).orElse("rongCloud"));
+        //获取当前课程剩余时长
+        roomResult.setSurplusTime(DateUtil.secondsBetween(new Date(), courseSchedule.getEndClassTime()));
+        roomResult.setRoomId(roomId);
+
+        // 网络课形式:RTC房间,直播间
+        if (GroupType.LIVE == courseSchedule.getGroupType()) {
+
+            if (Optional.ofNullable(joinRoom).orElse(true)) {
+
+                String joinImGroupKey = "joinImGroup:" + roomId;
+                // VIP课或网络课,IM群聊已创建标识
+                redisTemplate.opsForValue().setIfAbsent(joinImGroupKey, roomId, 1L, TimeUnit.DAYS);
+            }
+
+            // 直播形式网络课
+            ImLiveBroadcastRoom liveRoom;
+            if (StringUtils.isNotBlank(courseSchedule.getLiveRoomId())) {
+
+                // 直播间状态判断
+                liveRoom = imLiveBroadcastRoomService.lambdaQuery()
+                        .eq(ImLiveBroadcastRoom::getRoomUid, courseSchedule.getLiveRoomId())
+                        .last("LIMIT 1")
+                        .one();
+
+                if (Objects.isNull(liveRoom)) {
+                    // 创建网络课直播教室
+                    liveRoom = createVipGroupLiveRoom(roomId, courseSchedule);
+                }
+
+                // 直播间状态不在进行中
+                if (liveRoom.getLiveState() != 1) {
+
+                    ImLiveBroadcastRoom updateInfo = new ImLiveBroadcastRoom();
+                    updateInfo.setId(liveRoom.getId());
+                    updateInfo.setLiveStartTime(DateTime.now().toDate());
+
+                    // 更新直播间状态
+                    imLiveBroadcastRoomService.updateById(updateInfo);
+
+                    // 开启直播间
+                    imLiveBroadcastRoomService.createLiveRoom(liveRoom);
+                }
+
+            } else {
+
+                // 创建网络课直播教室
+                liveRoom = createVipGroupLiveRoom(roomId, courseSchedule);
+            }
+
+            // 返回直播间配置参数
+            roomResult.setLiveRoom(imLiveBroadcastRoomService.visitorRoomInfo(liveRoom.getRoomUid(), sysUser.getId()));
+
+            // 主动触发用户加入直播间
+            imLiveBroadcastRoomService.joinRoom(liveRoom.getRoomUid(), sysUser.getId());
+
+        } else {
+
+            // 创建聊天群组
+            if (Optional.ofNullable(joinRoom).orElse(true)) {
+                // 创建IM群聊
+                this.joinImGroup(roomId, courseSchedule.getActualTeacherId(), courseSchedule);
+            }
+
+            // RTC房间网络课
+            genRtcRoomMemberInfoConfig(roomId, joinRoom, sysUser, userId, teacher, courseSchedule, curTime, roomResult, courseId);
+        }
+
+        log.info("join room: roomId = {}, userId = {}, userName={}, role = {}", roomId, userId);
+        return new BaseResponse(roomResult);
+    }
+
+    /**
+     * 创建网络课直播间
+     * @param roomId 课程房间编号
+     * @param courseSchedule 课程信息
+     * @return ImLiveBroadcastRoom
+     */
+    private ImLiveBroadcastRoom createVipGroupLiveRoom(String roomId, CourseSchedule courseSchedule) {
+
+        // 主动创建直播间
+        VipGroup vipGroup = vipGroupDao.get(Long.parseLong(courseSchedule.getMusicGroupId()));
+        if (Objects.isNull(vipGroup)) {
+            throw new BizException("直播课程组不存在");
+        }
+
+        if (StringUtils.isBlank(vipGroup.getLiveConfigJson())) {
+            throw new BizException("直播课程组未配置直播间");
+        }
+
+        ImLiveBroadcastRoom liveRoom = JSON.parseObject(vipGroup.getLiveConfigJson(), ImLiveBroadcastRoom.class);
+
+        if (StringUtils.isBlank(liveRoom.getServiceProvider())) {
+            //查询房间过期时间
+            String liveClient = sysConfigDao.findConfigValue("live_client");
+            liveRoom.setServiceProvider(liveClient);
+        }
+
+        String roomUid = "LIVE-" + roomId + "-" + DateTime.now().toDate().getTime();
+        liveRoom.setTenantId(TenantContextHolder.getTenantId());
+        liveRoom.setRoomUid(roomUid);
+        liveRoom.setRoomConfig(JSONObject.toJSONString(liveRoom.getRoomConfig()));
+        liveRoom.setLiveState(1);
+        liveRoom.setRoomState(0);
+        liveRoom.setGroupType("LIVE");
+        liveRoom.setCreatedBy(liveRoom.getSpeakerId());
+        liveRoom.setCreatedTime(DateTime.now().toDate());
+        liveRoom.setLiveStartTime(DateTime.now().toDate());
+        liveRoom.setTenantId(courseSchedule.getTenantId());
+
+        // 创建直播间
+        imLiveBroadcastRoomService.save(liveRoom);
+
+        // 开启直播间
+        imLiveBroadcastRoomService.createLiveRoom(liveRoom);
+
+        // 返回直播间信息
+        return imLiveBroadcastRoomService.lambdaQuery()
+                .eq(ImLiveBroadcastRoom::getRoomUid, courseSchedule.getLiveRoomId())
+                .last("LIMIT 1")
+                .one();
+    }
+
+    /**
+     * RTC房间成员信息配置
+     * @param roomId 房间编号
+     * @param joinRoom 是否加入房间
+     * @param sysUser 用户信息
+     * @param userId 用户编号
+     * @param teacher 主讲老师信息
+     * @param courseSchedule 课程信息
+     * @param curTime 当前时间
+     * @param roomResult 房间信息
+     * @param courseId 课程编号
+     * @throws Exception 异常信息
+     */
+    private void genRtcRoomMemberInfoConfig(String roomId,
+                                            Boolean joinRoom,
+                                            SysUser sysUser,
+                                            String userId,
+                                            Teacher teacher,
+                                            CourseSchedule courseSchedule,
+                                            Date curTime,
+                                            RoomResult roomResult,
+                                            Long courseId) throws Exception {
+
         // 全员静音状态
         Boolean muteAll = Optional.ofNullable(courseSchedule.getMuteAll()).orElse(false);
 
         RoomResult.MemberResult userResult = new RoomResult.MemberResult();
         RoomMember member = roomMemberDao.findByRidAndUid(roomId, userId);
+
+        RoleEnum roleEnum;
         String userName;
         if (member == null) {
             int count = roomMemberDao.countByRidAndExcludeRole(roomId, RoleEnum.RoleAudience.getValue());
             if (count == roomProperties.getMaxCount()) {
                 log.info("join error Over max count: roomId = {}, userId = {}", roomId, userId);
-                return new BaseResponse(ErrorEnum.ERR_OVER_MAX_COUNT, ErrorEnum.ERR_OVER_MAX_COUNT.getErrMsg(), null);
+                throw new BizException(ErrorEnum.ERR_OVER_MAX_COUNT.getErrCode(), ErrorEnum.ERR_OVER_MAX_COUNT.getErrMsg());
+                //return new BaseResponse(ErrorEnum.ERR_OVER_MAX_COUNT, ErrorEnum.ERR_OVER_MAX_COUNT.getErrMsg(), null);
             }
 
             boolean microphone = true;
@@ -302,12 +466,6 @@ public class RoomServiceImpl implements RoomService {
         }
 //        imHelper.joinGroup(new String[]{userId}, roomId, roomId);
 
-        // 主讲老师信息
-        SysUser teacherInfo = sysUserFeignService.queryUserById(courseSchedule.getActualTeacherId());
-        if (Objects.isNull(teacherInfo)) {
-            throw new BizException("主讲老师不存在");
-        }
-
         RTCRoomPluginService pluginService = rtcRoomPluginContext.getPluginService(courseSchedule.getServiceProvider());
         if (TencentCloudRTCPlugin.PLUGIN_NAME.equals(pluginService.pluginName())) {
             // 腾讯云RTC
@@ -325,13 +483,6 @@ public class RoomServiceImpl implements RoomService {
                     .setGroupId(roomId);
         }
 
-        if (Optional.ofNullable(joinRoom).orElse(true)) {
-            // 创建IM群聊
-            this.joinImGroup(roomId, courseSchedule.getActualTeacherId(), courseSchedule);
-            // RTC服务提供方
-            roomResult.setServiceProvider(Optional.ofNullable(courseSchedule.getServiceProvider()).orElse("rongCloud"));
-        }
-
         List<CourseScheduleStudentMusicScore> scheduleStudentMusicScores = courseScheduleStudentMusicScoreDao.queryByScoreIdAndCourseId(null, courseId, null, null, null);
         Room room = roomDao.findByRid(roomId);
         String display = "";
@@ -375,12 +526,8 @@ public class RoomServiceImpl implements RoomService {
         String midi = courseScheduleStudentPaymentDao.getMidiByCourseIdAndUserId(courseId.toString(), userId);
         userResult.setPlayMidiJson(JSONObject.parseObject(midi, CustomMessage.class));
 
-        //获取当前课程剩余时长
-        roomResult.setSurplusTime(DateUtil.secondsBetween(new Date(), courseSchedule.getEndClassTime()));
-
         roomResult.setUserInfo(userResult);
         roomResult.setDisplay(display);
-        roomResult.setRoomId(roomId);
 
         // 课程人数
         {
@@ -436,7 +583,6 @@ public class RoomServiceImpl implements RoomService {
             roomResult.setRandomNumeric("1");
         }
         log.info("join room: roomId = {}, userId = {}, userName={}, role = {}", roomId, userId, userName, roleEnum);
-        return new BaseResponse(roomResult);
     }
 
     private void joinImGroup(String roomId, Integer actualTeacherId, CourseSchedule courseSchedule) throws Exception {
@@ -504,10 +650,7 @@ public class RoomServiceImpl implements RoomService {
                 throw e;
             }
 
-            // 更新网络课服务提供方
-            courseScheduleDao.updateServiceProvider(courseSchedule.getId(), courseSchedule.getServiceProvider());
         }
-
     }
     private void dismissImGroup(String userId,String roomId, String serviceProvider) throws Exception {
         log.info("dismissImGroup: roomId = {}, userId = {}", roomId, userId);
@@ -818,49 +961,55 @@ public class RoomServiceImpl implements RoomService {
 
             // 删除群组信息
             roomDao.deleteByRid(roomId);
-            // 删除白板信息
-            deleteWhiteboardByUser(roomId, userId);
-            // 删除群组
-            this.dismissImGroup(userId, roomId, courseSchedule.getServiceProvider());
-            //关闭所有曲目播放
-            courseScheduleStudentMusicScoreDao.closePlayStatus(courseSchedule.getId(), null, null);
+
+            if (GroupType.LIVE != courseSchedule.getGroupType()) {
+                // 删除白板信息
+                deleteWhiteboardByUser(roomId, userId);
+                // 删除群组
+                this.dismissImGroup(userId, roomId, courseSchedule.getServiceProvider());
+                //关闭所有曲目播放
+                courseScheduleStudentMusicScoreDao.closePlayStatus(courseSchedule.getId(), null, null);
+            }
             log.info("leaveRoomSuccess dismiss the room: {}, userId: {}, role={}", roomId, userId, roleEnum.name());
 
         } else {
             roomMemberDao.deleteUserByRidAndUid(roomId, userId);
 
-            // 获取RTC服务提供方
-            String rtcServiceProvider = Optional.ofNullable(courseSchedule.getServiceProvider()).orElse("rongCloud");
-
-            RTCRoomPluginService pluginService = rtcRoomPluginContext.getPluginService(rtcServiceProvider);
-            if (rtcServiceProvider.equals(TencentCloudRTCPlugin.PLUGIN_NAME)) {
-                // 腾讯云RTC服务
-                RTCRoomMessage.MessageContent messageContent = RTCRoomMessage.MessageContent
-                        .builder()
-                        .action(EMemberAction.LEAVE.getValue())
-                        .role(roleEnum.getValue())
-                        .handUpOn(false)
-                        .timestamp(System.currentTimeMillis())
-                        .microphone(false)
-                        .camera(false)
-                        .sendUserInfo(getSendUser(userId, roleEnum))
-                        .build();
-
-                RTCRoomMessage roomMessage = RTCRoomMessage.builder()
-                        .objectName(RTCRoomMessage.MEMBER_CHANGE_MESSAGE)
-                        .toChatRoomId(roomId)
-                        .content(messageContent)
-                        .fromUserId(userId)
-                        .isPersisted(1)
-                        .isIncludeSender(1)
-                        .build();
-
-                pluginService.sendChatRoomMessage(roomMessage);
-            } else {
-                MemberChangedMessage msg = new MemberChangedMessage(MemberChangedMessage.Action_Leave, userId, roleEnum.getValue());
-                msg.setUserName(username);
-                imHelper.publishMessage(userId, roomId, msg);
+            if (GroupType.LIVE != courseSchedule.getGroupType()) {
+
+                // 获取RTC服务提供方
+                String rtcServiceProvider = Optional.ofNullable(courseSchedule.getServiceProvider()).orElse("rongCloud");
+
+                RTCRoomPluginService pluginService = rtcRoomPluginContext.getPluginService(rtcServiceProvider);
+                if (rtcServiceProvider.equals(TencentCloudRTCPlugin.PLUGIN_NAME)) {
+                    // 腾讯云RTC服务
+                    RTCRoomMessage.MessageContent messageContent = RTCRoomMessage.MessageContent
+                            .builder()
+                            .action(EMemberAction.LEAVE.getValue())
+                            .role(roleEnum.getValue())
+                            .handUpOn(false)
+                            .timestamp(System.currentTimeMillis())
+                            .microphone(false)
+                            .camera(false)
+                            .sendUserInfo(getSendUser(userId, roleEnum))
+                            .build();
+
+                    RTCRoomMessage roomMessage = RTCRoomMessage.builder()
+                            .objectName(RTCRoomMessage.MEMBER_CHANGE_MESSAGE)
+                            .toChatRoomId(roomId)
+                            .content(messageContent)
+                            .fromUserId(userId)
+                            .isPersisted(1)
+                            .isIncludeSender(1)
+                            .build();
+
+                    pluginService.sendChatRoomMessage(roomMessage);
+                } else {
+                    MemberChangedMessage msg = new MemberChangedMessage(MemberChangedMessage.Action_Leave, userId, roleEnum.getValue());
+                    msg.setUserName(username);
+                    imHelper.publishMessage(userId, roomId, msg);
 //            imHelper.quit(new String[]{userId}, roomId);
+                }
             }
 
             log.info("leaveRoomSuccess quit group: roomId={}, userId: {}, roomMembers={}", roomId, userId, roomMembers);