|
@@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
|
@@ -45,6 +46,7 @@ import java.io.Serializable;
|
|
|
import java.util.*;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
import java.util.function.BiConsumer;
|
|
|
+import java.util.function.BiFunction;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
@@ -125,7 +127,6 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
return room;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/**
|
|
|
* 查询直播间信息
|
|
|
*
|
|
@@ -239,6 +240,55 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * 推广直播间-每个机构只能有一个直播间在首页推广
|
|
|
+ *
|
|
|
+ * @param id 直播间id
|
|
|
+ * @param popularize 是否在首页推广 0否 1是
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public void opsPopularize(Integer id, Integer popularize) {
|
|
|
+ if (!WrapperUtil.checkInObj(popularize, 0, 1)) {
|
|
|
+ throw new BizException("参数错误");
|
|
|
+ }
|
|
|
+ Optional<ImLiveBroadcastRoom> roomOptional = Optional.ofNullable(id)
|
|
|
+ .map(this::getById);
|
|
|
+ roomOptional.orElseThrow(() -> new BizException("直播间不存在"));
|
|
|
+ roomOptional.filter(room -> room.getRoomState() == 0)
|
|
|
+ .orElseThrow(() -> new BizException("直播间已经删除,无法设置推广"));
|
|
|
+ roomOptional.filter(room -> room.getLiveState() != 2)
|
|
|
+ .orElseThrow(() -> new BizException("直播已结束,无法设置推广"));
|
|
|
+ ImLiveBroadcastRoom obj = roomOptional.get();
|
|
|
+ if (Objects.equals(obj.getPopularize(), popularize)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //推广该直播间,先清除其该机构他直播间的推广状态
|
|
|
+ if (popularize == 1) {
|
|
|
+ this.update(Wrappers.<ImLiveBroadcastRoom>lambdaUpdate()
|
|
|
+ .set(ImLiveBroadcastRoom::getPopularize, 0)
|
|
|
+ .eq(ImLiveBroadcastRoom::getTenantId, obj.getTenantId()));
|
|
|
+ }
|
|
|
+ //更新直播间推广状态
|
|
|
+ obj.setPopularize(popularize);
|
|
|
+ this.updateById(obj);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询该机构目前推广的直播间
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public ImLiveBroadcastRoomVo queryPopularizeRoom() {
|
|
|
+ Map<String, Object> param = new HashMap<>();
|
|
|
+ param.put("tenantId", TenantContextHolder.getTenantId());
|
|
|
+ param.put("popularize", 1);
|
|
|
+ List<ImLiveBroadcastRoomVo> list = baseMapper.queryPage(param);
|
|
|
+ if (CollectionUtils.isNotEmpty(list)) {
|
|
|
+ return list.get(0);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* 定时任务,每分钟执行
|
|
|
* 销毁主讲人退出超过30分钟的直播间
|
|
|
*/
|
|
@@ -281,7 +331,7 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
|
|
|
//1.主播没有进入房间,则直接销毁房间
|
|
|
if (Objects.isNull(speakerInfo.getJoinRoomTime())) {
|
|
|
- log.info("roomDestroy not joinRoom >>>> cache : {}", JSONObject.toJSONString(test(room.getRoomUid(), room.getSpeakerId())));
|
|
|
+ log.info("roomDestroy not joinRoom >>>> cache : {}", JSONObject.toJSONString(test(room.getRoomUid())));
|
|
|
roomDestroy(room);
|
|
|
return;
|
|
|
}
|
|
@@ -293,7 +343,7 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
//如果退出时间大于进入时间,就将退出时间+expiredMinute分钟
|
|
|
Date exitExpiredTime = DateUtil.addMinutes(speakerInfo.getExitRoomTime(), expiredMinute);
|
|
|
if (now.getTime() >= exitExpiredTime.getTime()) {
|
|
|
- log.info("roomDestroy exitExpiredTime >>>> cache : {}", JSONObject.toJSONString(test(room.getRoomUid(), room.getSpeakerId())));
|
|
|
+ log.info("roomDestroy exitExpiredTime >>>> cache : {}", JSONObject.toJSONString(test(room.getRoomUid())));
|
|
|
roomDestroy(room);
|
|
|
}
|
|
|
}
|
|
@@ -360,19 +410,19 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
room.setUpdatedBy(userId);
|
|
|
room.setUpdatedTime(date);
|
|
|
room.setLiveEndTime(date);
|
|
|
+ room.setPopularize(0);//销毁直播间后要关闭推广
|
|
|
this.updateById(room);
|
|
|
}
|
|
|
|
|
|
//获取该直播间所有数据写入数据库-并清理缓存
|
|
|
private void insertAndCleanLiveData(String roomUid, Integer speakerId) {
|
|
|
//总观看人数
|
|
|
- int totalLookNum = 0;
|
|
|
+ List<ImLiveBroadcastRoomMember> memberList = new ArrayList<>();
|
|
|
//获取直播间所有人数据写入 im_live_broadcast_room_member
|
|
|
RMap<Integer, RoomUserInfoVo> roomTotalUserCache = redissonClient.getMap(LIVE_ROOM_TOTAL_USER_LIST.replace(ROOM_UID, roomUid));
|
|
|
if (roomTotalUserCache.isExists()) {
|
|
|
List<RoomUserInfoVo> roomTotalUser = new ArrayList<>(roomTotalUserCache.values());
|
|
|
- List<ImLiveBroadcastRoomMember> memberList = new ArrayList<>();
|
|
|
- roomTotalUser.forEach(v -> {
|
|
|
+ for (RoomUserInfoVo v : roomTotalUser) {
|
|
|
ImLiveBroadcastRoomMember member = new ImLiveBroadcastRoomMember();
|
|
|
member.setTenantId(v.getTenantId());
|
|
|
member.setRoomUid(roomUid);
|
|
@@ -380,10 +430,6 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
member.setJoinTime(v.getFirstJoinTime());
|
|
|
member.setTotalTime(v.getTotalViewTime());
|
|
|
memberList.add(member);
|
|
|
- });
|
|
|
- if (CollectionUtils.isNotEmpty(memberList)) {
|
|
|
- liveBroadcastRoomMemberService.getDao().insertBatch(memberList);
|
|
|
- totalLookNum = roomTotalUser.size();
|
|
|
}
|
|
|
//删除用户对应的直播间关系缓存
|
|
|
roomTotalUser.stream()
|
|
@@ -402,7 +448,7 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
//删除房间点赞数据
|
|
|
likeCache.delete();
|
|
|
}
|
|
|
-
|
|
|
+ int speakerLiveTime = 0;
|
|
|
//获取直播间主讲人信息 写入im_live_broadcast_room_data
|
|
|
RBucket<RoomSpeakerInfo> speakerCache = redissonClient.getBucket(LIVE_SPEAKER_INFO.replace(USER_ID, speakerId.toString()));
|
|
|
if (speakerCache.isExists()) {
|
|
@@ -411,14 +457,25 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
liveData.setTenantId(speakerInfo.getTenantId());
|
|
|
liveData.setRoomUid(roomUid);
|
|
|
liveData.setLikeNum(like);
|
|
|
- liveData.setTotalUserNum(totalLookNum);
|
|
|
+ liveData.setTotalUserNum(CollectionUtils.isNotEmpty(memberList) ? memberList.size() : 0);
|
|
|
liveData.setUpdatedTime(new Date());
|
|
|
liveData.setLiveTime(speakerInfo.getTotalLiveTime());
|
|
|
liveBroadcastRoomDataService.save(liveData);
|
|
|
//删除房间主讲人数据
|
|
|
speakerCache.delete();
|
|
|
+ //获取主讲人直播时长
|
|
|
+ speakerLiveTime = speakerInfo.getTotalLiveTime();
|
|
|
}
|
|
|
|
|
|
+ //写入im_live_broadcast_room_member表,校验用户观看时长,不能大于主讲人直播时长
|
|
|
+ if (CollectionUtils.isNotEmpty(memberList)) {
|
|
|
+ for (ImLiveBroadcastRoomMember member : memberList) {
|
|
|
+ if (member.getTotalTime() > speakerLiveTime) {
|
|
|
+ member.setTotalTime(speakerLiveTime);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ liveBroadcastRoomMemberService.getDao().insertBatch(memberList);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -461,7 +518,7 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
}
|
|
|
}
|
|
|
//将最新的时间写入缓存
|
|
|
- userStateTimeCache.set(userStateTime,5L, TimeUnit.MINUTES);
|
|
|
+ userStateTimeCache.set(userStateTime, 5L, TimeUnit.MINUTES);
|
|
|
//查询主讲人userId,若是主讲人
|
|
|
RBucket<RoomSpeakerInfo> speakerCache = redissonClient.getBucket(LIVE_SPEAKER_INFO.replace(USER_ID, userid));
|
|
|
if (speakerCache.isExists()) {
|
|
@@ -514,16 +571,16 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
}
|
|
|
log.info("opsRoom>>>> looker LOOKER_LOGIN_OUT : {}", JSONObject.toJSONString(userInfo));
|
|
|
}
|
|
|
- //每次退出房间计算当前用户观看时长
|
|
|
- int minutesBetween = getMinutesBetween(userInfo.getDynamicJoinTime(), now);
|
|
|
- userInfo.setTotalViewTime(userInfo.getTotalViewTime() + minutesBetween);
|
|
|
+ //只有在主播开播后用户才有观看时间,才需要计算当前用户观看时长
|
|
|
+ if (Objects.nonNull(userInfo.getDynamicLookTime())) {
|
|
|
+ int minutesBetween = getMinutesBetween(userInfo.getDynamicLookTime(), now);
|
|
|
+ userInfo.setTotalViewTime(userInfo.getTotalViewTime() + minutesBetween);
|
|
|
+ }
|
|
|
//记录退出时间 并写入缓存
|
|
|
- userInfo.setLastOutTime(now);
|
|
|
userInfo.setState(1);
|
|
|
roomTotalUser.fastPut(userId, userInfo);
|
|
|
log.info("opsRoom>>>> looker userInfo: {}", JSONObject.toJSONString(userInfo));
|
|
|
});
|
|
|
-
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -576,7 +633,6 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
userInfo.setTotalViewTime(0);
|
|
|
}
|
|
|
userInfo.setState(0);//0 进入/在房间
|
|
|
- userInfo.setDynamicJoinTime(now);
|
|
|
roomTotalUser.fastPut(userId, userInfo);
|
|
|
log.info("joinRoom>>>> userInfo: {}", JSONObject.toJSONString(userInfo));
|
|
|
}
|
|
@@ -587,9 +643,17 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
* @param roomUid 房间uid
|
|
|
*/
|
|
|
public void startLive(String roomUid, Integer userId) {
|
|
|
- //查询房间信息是否允许录像
|
|
|
+ //查询房间信息
|
|
|
RBucket<RoomSpeakerInfo> speakerCache = redissonClient.getBucket(LIVE_SPEAKER_INFO.replace(USER_ID, userId.toString()));
|
|
|
+ if (!speakerCache.isExists()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
RoomSpeakerInfo roomSpeakerInfo = speakerCache.get();
|
|
|
+ //已是直播状态则直接返回
|
|
|
+ if (Objects.nonNull(roomSpeakerInfo.getState()) && roomSpeakerInfo.getState() == 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //是否允许录像
|
|
|
if (Objects.nonNull(roomSpeakerInfo.getWhetherVideo()) && roomSpeakerInfo.getWhetherVideo() == 0) {
|
|
|
//开始录制视频
|
|
|
try {
|
|
@@ -598,11 +662,26 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
log.error("startRecord error: {}", e.getMessage());
|
|
|
}
|
|
|
}
|
|
|
+ Date now = new Date();
|
|
|
//开始直播
|
|
|
roomSpeakerInfo.setState(0);
|
|
|
- roomSpeakerInfo.setStartLiveTime(new Date());
|
|
|
+ roomSpeakerInfo.setStartLiveTime(now);
|
|
|
speakerCache.set(roomSpeakerInfo);
|
|
|
log.info("startLive>>>> roomSpeakerInfo: {}", JSONObject.toJSONString(roomSpeakerInfo));
|
|
|
+
|
|
|
+ //主播开启直播,查询所有在直播间的用户并写入观看时间
|
|
|
+ RMap<Integer, RoomUserInfoVo> roomTotalUser = redissonClient.getMap(LIVE_ROOM_TOTAL_USER_LIST.replace(ROOM_UID, roomSpeakerInfo.getRoomUid()));
|
|
|
+ if (!roomTotalUser.isExists()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ roomTotalUser.forEach((id, userInfo) -> {
|
|
|
+ //对在房间的用户
|
|
|
+ if (Objects.nonNull(userInfo.getState()) && userInfo.getState() == 0) {
|
|
|
+ userInfo.setDynamicLookTime(now);
|
|
|
+ roomTotalUser.fastPut(id, userInfo);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -613,6 +692,9 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
public void closeLive(String roomUid, Integer userId) {
|
|
|
//查询房间主播信息
|
|
|
RBucket<RoomSpeakerInfo> speakerCache = redissonClient.getBucket(LIVE_SPEAKER_INFO.replace(USER_ID, userId.toString()));
|
|
|
+ if (!speakerCache.isExists()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
RoomSpeakerInfo roomSpeakerInfo = speakerCache.get();
|
|
|
//关闭直播
|
|
|
closeLive(roomSpeakerInfo);
|
|
@@ -620,24 +702,46 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
}
|
|
|
|
|
|
private void closeLive(RoomSpeakerInfo roomSpeakerInfo) {
|
|
|
+ //直播状态 true 直播中 false关闭直播
|
|
|
boolean stateFlag = Objects.nonNull(roomSpeakerInfo.getState()) && roomSpeakerInfo.getState() == 0;
|
|
|
- if (Objects.nonNull(roomSpeakerInfo.getWhetherVideo()) && roomSpeakerInfo.getWhetherVideo() == 0
|
|
|
- && stateFlag) {
|
|
|
- //停止录制视频
|
|
|
+ //是否录像 true允许 false不允许
|
|
|
+ boolean whetherVideoFlag = Objects.nonNull(roomSpeakerInfo.getWhetherVideo()) && roomSpeakerInfo.getWhetherVideo() == 0;
|
|
|
+ //允许录像并在直播中
|
|
|
+ if (whetherVideoFlag && stateFlag) {
|
|
|
try {
|
|
|
+ //停止录制视频
|
|
|
imFeignService.stopRecord(roomSpeakerInfo.getRoomUid());
|
|
|
} catch (Exception e) {
|
|
|
log.error("stopRecord error: {}", e.getMessage());
|
|
|
}
|
|
|
}
|
|
|
+ //直播状态 true 直播中
|
|
|
if (stateFlag) {
|
|
|
Date now = new Date();
|
|
|
roomSpeakerInfo.setEndLiveTime(now);
|
|
|
roomSpeakerInfo.setState(1);
|
|
|
- //计算时长
|
|
|
- int minutesBetween = getMinutesBetween(roomSpeakerInfo.getStartLiveTime(), now);
|
|
|
- int i = Objects.isNull(roomSpeakerInfo.getTotalLiveTime()) ? 0 : roomSpeakerInfo.getTotalLiveTime();
|
|
|
- roomSpeakerInfo.setTotalLiveTime(i + minutesBetween);
|
|
|
+ //计算时长方法
|
|
|
+ BiFunction<Date, Integer, Integer> getLookMinutes = (startDate, nowMinutes) -> {
|
|
|
+ int minutesBetween = getMinutesBetween(startDate, new Date());
|
|
|
+ minutesBetween += Objects.isNull(nowMinutes) ? 0 : nowMinutes;
|
|
|
+ return Math.max(minutesBetween, 0);
|
|
|
+ };
|
|
|
+ //写入本次直播时长
|
|
|
+ int lookMinutes = getLookMinutes.apply(roomSpeakerInfo.getStartLiveTime(), roomSpeakerInfo.getTotalLiveTime());
|
|
|
+ roomSpeakerInfo.setTotalLiveTime(lookMinutes);
|
|
|
+ //主播关闭直播,查询所有在直播间的用户并计算观看时长
|
|
|
+ RMap<Integer, RoomUserInfoVo> roomTotalUser = redissonClient.getMap(LIVE_ROOM_TOTAL_USER_LIST.replace(ROOM_UID, roomSpeakerInfo.getRoomUid()));
|
|
|
+ if (!roomTotalUser.isExists()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ roomTotalUser.forEach((id, userInfo) -> {
|
|
|
+ //对在房间的用户计算观看时长
|
|
|
+ if (Objects.nonNull(userInfo.getState()) && userInfo.getState() == 0) {
|
|
|
+ Integer userLookMinutes = getLookMinutes.apply(userInfo.getDynamicLookTime(), userInfo.getTotalViewTime());
|
|
|
+ userInfo.setTotalViewTime(userLookMinutes);
|
|
|
+ roomTotalUser.fastPut(id, userInfo);
|
|
|
+ }
|
|
|
+ });
|
|
|
}
|
|
|
log.info("closeLive>>>> roomSpeakerInfo: {}", JSONObject.toJSONString(roomSpeakerInfo));
|
|
|
}
|
|
@@ -754,7 +858,7 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
/**
|
|
|
* 测试
|
|
|
*/
|
|
|
- public Map<String, Object> test(String roomUid, Integer userId) {
|
|
|
+ public Map<String, Object> test(String roomUid) {
|
|
|
//test
|
|
|
Map<String, Object> result = new HashMap<>();
|
|
|
//点赞数
|
|
@@ -784,9 +888,15 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
} else {
|
|
|
result.put("总人员数据", "没有人员数据");
|
|
|
}
|
|
|
+ String userId = "";
|
|
|
+ try {
|
|
|
+ String[] split = roomUid.split("-");
|
|
|
+ userId = split[1];
|
|
|
+ } catch (Exception ignored) {
|
|
|
+ }
|
|
|
|
|
|
//获取主讲人信息
|
|
|
- RBucket<RoomSpeakerInfo> speakerCache = redissonClient.getBucket(LIVE_SPEAKER_INFO.replace(USER_ID, userId.toString()));
|
|
|
+ RBucket<RoomSpeakerInfo> speakerCache = redissonClient.getBucket(LIVE_SPEAKER_INFO.replace(USER_ID, userId));
|
|
|
if (speakerCache.isExists()) {
|
|
|
result.put("主讲人信息", speakerCache.get());
|
|
|
} else {
|
|
@@ -805,11 +915,10 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
}
|
|
|
SysUser sysUser = sysUserFeignService.queryUserInfo();
|
|
|
String baseApiUrl = sysConfigDao.findConfigValue(SysConfigService.BASE_API_URL);
|
|
|
- StringBuffer pushUrl = new StringBuffer(baseApiUrl).append("/#/liveClassTransfer?roomUid=").append(roomUid);
|
|
|
sysMessageService.batchSendImGroupMessage(MessageTypeEnum.IM_SHARE_LIVE_URL, sysUser.getId().toString(), null, groupIds.split(","), null,
|
|
|
imLiveBroadcastRoomVo.getTenantName(), imLiveBroadcastRoomVo.getRoomTitle(), imLiveBroadcastRoomVo.getSpeakerName(),
|
|
|
DateUtil.format(imLiveBroadcastRoomVo.getLiveStartTime(), DateUtil.CHINESE_DATA_FORMAT_1),
|
|
|
- imLiveBroadcastRoomVo.getLiveRemark(), HttpUtil.getSortUrl(pushUrl.toString()));
|
|
|
+ imLiveBroadcastRoomVo.getLiveRemark(), HttpUtil.getSortUrl(baseApiUrl + "/#/liveClassTransfer?roomUid=" + roomUid));
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -861,6 +970,9 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
if (Objects.isNull(startDT) || Objects.isNull(endDT)) {
|
|
|
return 0;
|
|
|
}
|
|
|
+ if (startDT.getTime() > endDT.getTime()) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
//课程结束时间-课程开始时间
|
|
|
long durationTime = endDT.getTime() - startDT.getTime();
|
|
|
//相差多少分钟
|