parent
92ce67245d
commit
12cfe0a184
9
pom.xml
9
pom.xml
|
@ -229,13 +229,6 @@
|
||||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- SRS Java SDK -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.ossrs</groupId>
|
|
||||||
<artifactId>srs-sdk</artifactId>
|
|
||||||
<version>1.0.0</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Netty -->
|
<!-- Netty -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
|
@ -245,7 +238,7 @@
|
||||||
|
|
||||||
<!-- Easy-Es -->
|
<!-- Easy-Es -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.easyes</groupId>
|
<groupId>cn.easy-es</groupId>
|
||||||
<artifactId>easy-es-boot-starter</artifactId>
|
<artifactId>easy-es-boot-starter</artifactId>
|
||||||
<version>1.1.1</version>
|
<version>1.1.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
|
@ -1,83 +1,83 @@
|
||||||
package com.guwan.backend.client;
|
//package com.guwan.backend.client;
|
||||||
|
//
|
||||||
import lombok.Data;
|
//import lombok.Data;
|
||||||
import lombok.RequiredArgsConstructor;
|
//import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
//import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
//import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.http.ResponseEntity;
|
//import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.stereotype.Component;
|
//import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.client.RestTemplate;
|
//import org.springframework.web.client.RestTemplate;
|
||||||
|
//
|
||||||
@Slf4j
|
//@Slf4j
|
||||||
@Component
|
//@Component
|
||||||
@RequiredArgsConstructor
|
//@RequiredArgsConstructor
|
||||||
public class SrsClient {
|
//public class SrsClient {
|
||||||
|
//
|
||||||
private final RestTemplate restTemplate;
|
// private final RestTemplate restTemplate;
|
||||||
|
//
|
||||||
@Value("${srs.server.url}")
|
// @Value("${srs.server.url}")
|
||||||
private String srsServerUrl;
|
// private String srsServerUrl;
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 开始录制
|
// * 开始录制
|
||||||
*/
|
// */
|
||||||
public void startRecord(String streamKey, RecordConfig config) {
|
// public void startRecord(String streamKey, RecordConfig config) {
|
||||||
String url = String.format("%s/api/v1/streams/%s/recording/start", srsServerUrl, streamKey);
|
// String url = String.format("%s/api/v1/streams/%s/recording/start", srsServerUrl, streamKey);
|
||||||
try {
|
// try {
|
||||||
ResponseEntity<String> response = restTemplate.postForEntity(url, config, String.class);
|
// ResponseEntity<String> response = restTemplate.postForEntity(url, config, String.class);
|
||||||
if (!response.getStatusCode().is2xxSuccessful()) {
|
// if (!response.getStatusCode().is2xxSuccessful()) {
|
||||||
throw new RuntimeException("开始录制失败: " + response.getBody());
|
// throw new RuntimeException("开始录制失败: " + response.getBody());
|
||||||
}
|
// }
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
log.error("开始录制失败", e);
|
// log.error("开始录制失败", e);
|
||||||
throw new RuntimeException("开始录制失败", e);
|
// throw new RuntimeException("开始录制失败", e);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 停止录制
|
// * 停止录制
|
||||||
*/
|
// */
|
||||||
public void stopRecord(String streamKey) {
|
// public void stopRecord(String streamKey) {
|
||||||
String url = String.format("%s/api/v1/streams/%s/recording/stop", srsServerUrl, streamKey);
|
// String url = String.format("%s/api/v1/streams/%s/recording/stop", srsServerUrl, streamKey);
|
||||||
try {
|
// try {
|
||||||
ResponseEntity<String> response = restTemplate.postForEntity(url, null, String.class);
|
// ResponseEntity<String> response = restTemplate.postForEntity(url, null, String.class);
|
||||||
if (!response.getStatusCode().is2xxSuccessful()) {
|
// if (!response.getStatusCode().is2xxSuccessful()) {
|
||||||
throw new RuntimeException("停止录制失败: " + response.getBody());
|
// throw new RuntimeException("停止录制失败: " + response.getBody());
|
||||||
}
|
// }
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
log.error("停止录制失败", e);
|
// log.error("停止录制失败", e);
|
||||||
throw new RuntimeException("停止录制失败", e);
|
// throw new RuntimeException("停止录制失败", e);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 获取流信息
|
// * 获取流信息
|
||||||
*/
|
// */
|
||||||
public StreamInfo getStreamInfo(String streamKey) {
|
// public StreamInfo getStreamInfo(String streamKey) {
|
||||||
String url = String.format("%s/api/v1/streams/%s", srsServerUrl, streamKey);
|
// String url = String.format("%s/api/v1/streams/%s", srsServerUrl, streamKey);
|
||||||
try {
|
// try {
|
||||||
ResponseEntity<StreamInfo> response = restTemplate.getForEntity(url, StreamInfo.class);
|
// ResponseEntity<StreamInfo> response = restTemplate.getForEntity(url, StreamInfo.class);
|
||||||
return response.getBody();
|
// return response.getBody();
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
log.error("获取流信息失败", e);
|
// log.error("获取流信息失败", e);
|
||||||
throw new RuntimeException("获取流信息失败", e);
|
// throw new RuntimeException("获取流信息失败", e);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Data
|
// @Data
|
||||||
public static class RecordConfig {
|
// public static class RecordConfig {
|
||||||
private String format = "flv"; // 录制格式
|
// private String format = "flv"; // 录制格式
|
||||||
private String filePath; // 文件路径
|
// private String filePath; // 文件路径
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Data
|
// @Data
|
||||||
public static class StreamInfo {
|
// public static class StreamInfo {
|
||||||
private String streamId; // 流ID
|
// private String streamId; // 流ID
|
||||||
private String clientId; // 客户端ID
|
// private String clientId; // 客户端ID
|
||||||
private String ip; // 客户端IP
|
// private String ip; // 客户端IP
|
||||||
private Long startTime; // 开始时间
|
// private Long startTime; // 开始时间
|
||||||
private String status; // 状态
|
// private String status; // 状态
|
||||||
private Long bytesIn; // 输入字节数
|
// private Long bytesIn; // 输入字节数
|
||||||
private Long bytesOut; // 输出字节数
|
// private Long bytesOut; // 输出字节数
|
||||||
}
|
// }
|
||||||
}
|
//}
|
|
@ -1,82 +1,82 @@
|
||||||
package com.guwan.backend.controller;
|
//package com.guwan.backend.controller;
|
||||||
|
//
|
||||||
import com.guwan.backend.entity.LiveRoom;
|
//import com.guwan.backend.entity.LiveRoom;
|
||||||
import com.guwan.backend.entity.LiveRoomDTO;
|
//import com.guwan.backend.entity.LiveRoomDTO;
|
||||||
import com.guwan.backend.service.LiveService;
|
//import com.guwan.backend.service.LiveService;
|
||||||
import com.guwan.backend.util.Result;
|
//import com.guwan.backend.util.Result;
|
||||||
import com.guwan.backend.util.SecurityUtil;
|
//import com.guwan.backend.util.SecurityUtil;
|
||||||
import lombok.RequiredArgsConstructor;
|
//import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
//import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.*;
|
//import org.springframework.web.bind.annotation.*;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
//import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
//import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
//import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
//import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
//
|
||||||
@Slf4j
|
//@Slf4j
|
||||||
@Tag(name = "直播管理", description = "直播相关接口")
|
//@Tag(name = "直播管理", description = "直播相关接口")
|
||||||
@RestController
|
//@RestController
|
||||||
@RequestMapping("/api/live")
|
//@RequestMapping("/api/live")
|
||||||
@RequiredArgsConstructor
|
//@RequiredArgsConstructor
|
||||||
public class LiveController {
|
//public class LiveController {
|
||||||
|
//
|
||||||
private final LiveService liveService;
|
// private final LiveService liveService;
|
||||||
private final SecurityUtil securityUtil;
|
// private final SecurityUtil securityUtil;
|
||||||
|
//
|
||||||
@Operation(summary = "创建直播间")
|
// @Operation(summary = "创建直播间")
|
||||||
@SecurityRequirement(name = "bearer-jwt")
|
// @SecurityRequirement(name = "bearer-jwt")
|
||||||
@PostMapping("/room")
|
// @PostMapping("/room")
|
||||||
public Result<LiveRoom> createLiveRoom(@RequestBody LiveRoomDTO dto) {
|
// public Result<LiveRoom> createLiveRoom(@RequestBody LiveRoomDTO dto) {
|
||||||
try {
|
// try {
|
||||||
return Result.success(liveService.createLiveRoom(dto));
|
// return Result.success(liveService.createLiveRoom(dto));
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
log.error("创建直播间失败", e);
|
// log.error("创建直播间失败", e);
|
||||||
return Result.error(e.getMessage());
|
// return Result.error(e.getMessage());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Operation(summary = "开始直播")
|
// @Operation(summary = "开始直播")
|
||||||
@SecurityRequirement(name = "bearer-jwt")
|
// @SecurityRequirement(name = "bearer-jwt")
|
||||||
@PostMapping("/room/{id}/start")
|
// @PostMapping("/room/{id}/start")
|
||||||
public Result<Void> startLive(@PathVariable Long id) {
|
// public Result<Void> startLive(@PathVariable Long id) {
|
||||||
try {
|
// try {
|
||||||
// 检查权限
|
// // 检查权限
|
||||||
checkPermission(id);
|
// checkPermission(id);
|
||||||
liveService.startLive(id);
|
// liveService.startLive(id);
|
||||||
return Result.success();
|
// return Result.success();
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
log.error("开始直播失败", e);
|
// log.error("开始直播失败", e);
|
||||||
return Result.error(e.getMessage());
|
// return Result.error(e.getMessage());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Operation(summary = "结束直播")
|
// @Operation(summary = "结束直播")
|
||||||
@SecurityRequirement(name = "bearer-jwt")
|
// @SecurityRequirement(name = "bearer-jwt")
|
||||||
@PostMapping("/room/{id}/end")
|
// @PostMapping("/room/{id}/end")
|
||||||
public Result<Void> endLive(@PathVariable Long id) {
|
// public Result<Void> endLive(@PathVariable Long id) {
|
||||||
try {
|
// try {
|
||||||
// 检查权限
|
// // 检查权限
|
||||||
checkPermission(id);
|
// checkPermission(id);
|
||||||
liveService.endLive(id);
|
// liveService.endLive(id);
|
||||||
return Result.success();
|
// return Result.success();
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
log.error("结束直播失败", e);
|
// log.error("结束直播失败", e);
|
||||||
return Result.error(e.getMessage());
|
// return Result.error(e.getMessage());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 检查权限
|
// * 检查权限
|
||||||
*/
|
// */
|
||||||
private void checkPermission(Long roomId) {
|
// private void checkPermission(Long roomId) {
|
||||||
LiveRoom room = liveService.getLiveRoom(roomId);
|
// LiveRoom room = liveService.getLiveRoom(roomId);
|
||||||
if (room == null) {
|
// if (room == null) {
|
||||||
throw new IllegalArgumentException("直播间不存在");
|
// throw new IllegalArgumentException("直播间不存在");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Long currentUserId = securityUtil.getCurrentUserId();
|
// Long currentUserId = securityUtil.getCurrentUserId();
|
||||||
if (!room.getUserId().equals(currentUserId)) {
|
// if (!room.getUserId().equals(currentUserId)) {
|
||||||
throw new IllegalStateException("无权操作此直播间");
|
// throw new IllegalStateException("无权操作此直播间");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
|
@ -27,12 +27,12 @@ public class VideoController {
|
||||||
// @SecurityRequirement(name = "bearer-jwt")
|
// @SecurityRequirement(name = "bearer-jwt")
|
||||||
@PostMapping("/upload")
|
@PostMapping("/upload")
|
||||||
public Result<VideoDTO> uploadVideo(
|
public Result<VideoDTO> uploadVideo(
|
||||||
@Parameter(description = "视频文件") @RequestParam("file") MultipartFile file,
|
@Parameter(description = "视频文件") @RequestParam("fileUrl") String fileUrl,
|
||||||
@Parameter(description = "视频标题") @RequestParam("title") String title,
|
@Parameter(description = "视频标题") @RequestParam("title") String title,
|
||||||
@Parameter(description = "视频描述") @RequestParam("description") String description,
|
@Parameter(description = "视频描述") @RequestParam("description") String description,
|
||||||
@Parameter(description = "视频标签,多个用逗号分隔") @RequestParam(value = "tags", required = false) String tags) {
|
@Parameter(description = "视频标签,多个用逗号分隔") @RequestParam(value = "tags", required = false) String tags) {
|
||||||
try {
|
try {
|
||||||
VideoDTO video = videoService.uploadVideo(file, title, description, tags);
|
VideoDTO video = videoService.uploadVideo(fileUrl, title, description, tags);
|
||||||
return Result.success(video);
|
return Result.success(video);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("上传视频失败", e);
|
log.error("上传视频失败", e);
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
package com.guwan.backend.entity;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class LiveMessage {
|
public class LiveMessage {
|
||||||
private String type; // 消息类型:CHAT-聊天,GIFT-礼物,LIKE-点赞,ENTER-进入,LEAVE-离开
|
private String type; // 消息类型:CHAT-聊天,GIFT-礼物,LIKE-点赞,ENTER-进入,LEAVE-离开
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
package com.guwan.backend.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@TableName("live_room")
|
@TableName("live_room")
|
||||||
public class LiveRoom {
|
public class LiveRoom {
|
||||||
|
|
|
@ -1,120 +1,132 @@
|
||||||
@Slf4j
|
//package com.guwan.backend.service;
|
||||||
@Service
|
//
|
||||||
@RequiredArgsConstructor
|
//import com.guwan.backend.client.SrsClient;
|
||||||
public class LiveService {
|
//import com.guwan.backend.dto.live.LiveRoomDTO;
|
||||||
|
//import com.guwan.backend.entity.LiveRoom;
|
||||||
private final LiveRoomMapper liveRoomMapper;
|
//import com.guwan.backend.mapper.LiveRoomMapper;
|
||||||
private final SrsClient srsClient;
|
//import com.guwan.backend.util.SecurityUtil;
|
||||||
private final SecurityUtil securityUtil;
|
//import lombok.RequiredArgsConstructor;
|
||||||
|
//import lombok.extern.slf4j.Slf4j;
|
||||||
/**
|
//import org.springframework.beans.BeanUtils;
|
||||||
* 创建直播间
|
//import org.springframework.stereotype.Service;
|
||||||
*/
|
//
|
||||||
public LiveRoom createLiveRoom(LiveRoomDTO dto) {
|
//@Slf4j
|
||||||
// 获取当前用户
|
//@Service
|
||||||
Long userId = securityUtil.getCurrentUserId();
|
//@RequiredArgsConstructor
|
||||||
String username = securityUtil.getCurrentUsername();
|
//public class LiveService {
|
||||||
if (userId == null) {
|
//
|
||||||
throw new IllegalStateException("用户未登录");
|
// private final LiveRoomMapper liveRoomMapper;
|
||||||
}
|
// private final SrsClient srsClient;
|
||||||
|
// private final SecurityUtil securityUtil;
|
||||||
LiveRoom room = new LiveRoom();
|
//
|
||||||
BeanUtils.copyProperties(dto, room);
|
// /**
|
||||||
|
// * 创建直播间
|
||||||
// 设置用户信息
|
// */
|
||||||
room.setUserId(userId);
|
// public LiveRoom createLiveRoom(LiveRoomDTO dto) {
|
||||||
room.setUsername(username);
|
// // 获取当前用户
|
||||||
|
// Long userId = securityUtil.getCurrentUserId();
|
||||||
// 生成推流密钥
|
// String username = securityUtil.getCurrentUsername();
|
||||||
String streamKey = generateStreamKey();
|
// if (userId == null) {
|
||||||
room.setStreamKey(streamKey);
|
// throw new IllegalStateException("用户未登录");
|
||||||
|
// }
|
||||||
// 生成推流地址
|
//
|
||||||
String rtmpUrl = generateRtmpUrl(streamKey);
|
// LiveRoom room = new LiveRoom();
|
||||||
room.setRtmpUrl(rtmpUrl);
|
// BeanUtils.copyProperties(dto, room);
|
||||||
|
//
|
||||||
// 生成播放地址
|
// // 设置用户信息
|
||||||
String hlsUrl = generateHlsUrl(streamKey);
|
// room.setUserId(userId);
|
||||||
room.setHlsUrl(hlsUrl);
|
// room.setUsername(username);
|
||||||
|
//
|
||||||
room.setStatus("PREPARING");
|
// // 生成推流密钥
|
||||||
room.setOnlineCount(0);
|
// String streamKey = generateStreamKey();
|
||||||
room.setLikeCount(0);
|
// room.setStreamKey(streamKey);
|
||||||
|
//
|
||||||
liveRoomMapper.insert(room);
|
// // 生成推流地址
|
||||||
return room;
|
// String rtmpUrl = generateRtmpUrl(streamKey);
|
||||||
}
|
// room.setRtmpUrl(rtmpUrl);
|
||||||
|
//
|
||||||
/**
|
// // 生成播放地址
|
||||||
* 开始直播
|
// String hlsUrl = generateHlsUrl(streamKey);
|
||||||
*/
|
// room.setHlsUrl(hlsUrl);
|
||||||
public void startLive(Long roomId) {
|
//
|
||||||
LiveRoom room = liveRoomMapper.selectById(roomId);
|
// room.setStatus("PREPARING");
|
||||||
room.setStatus("LIVING");
|
// room.setOnlineCount(0);
|
||||||
liveRoomMapper.updateById(room);
|
// room.setLikeCount(0);
|
||||||
|
//
|
||||||
// 开始录制
|
// liveRoomMapper.insert(room);
|
||||||
startRecording(room.getStreamKey());
|
// return room;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 结束直播
|
// * 开始直播
|
||||||
*/
|
// */
|
||||||
public void endLive(Long roomId) {
|
// public void startLive(Long roomId) {
|
||||||
LiveRoom room = liveRoomMapper.selectById(roomId);
|
// LiveRoom room = liveRoomMapper.selectById(roomId);
|
||||||
room.setStatus("ENDED");
|
// room.setStatus("LIVING");
|
||||||
liveRoomMapper.updateById(room);
|
// liveRoomMapper.updateById(room);
|
||||||
|
//
|
||||||
// 停止录制
|
// // 开始录制
|
||||||
stopRecording(room.getStreamKey());
|
// startRecording(room.getStreamKey());
|
||||||
|
// }
|
||||||
// 生成回放地址
|
//
|
||||||
String replayUrl = generateReplayUrl(room.getStreamKey());
|
// /**
|
||||||
room.setReplayUrl(replayUrl);
|
// * 结束直播
|
||||||
liveRoomMapper.updateById(room);
|
// */
|
||||||
}
|
// public void endLive(Long roomId) {
|
||||||
|
// LiveRoom room = liveRoomMapper.selectById(roomId);
|
||||||
/**
|
// room.setStatus("ENDED");
|
||||||
* 开始录制
|
// liveRoomMapper.updateById(room);
|
||||||
*/
|
//
|
||||||
private void startRecording(String streamKey) {
|
// // 停止录制
|
||||||
SrsClient.RecordConfig config = new SrsClient.RecordConfig();
|
// stopRecording(room.getStreamKey());
|
||||||
config.setFilePath("/recordings/" + streamKey + ".flv");
|
//
|
||||||
srsClient.startRecord(streamKey, config);
|
// // 生成回放地址
|
||||||
}
|
// String replayUrl = generateReplayUrl(room.getStreamKey());
|
||||||
|
// room.setReplayUrl(replayUrl);
|
||||||
/**
|
// liveRoomMapper.updateById(room);
|
||||||
* 停止录制
|
// }
|
||||||
*/
|
//
|
||||||
private void stopRecording(String streamKey) {
|
// /**
|
||||||
srsClient.stopRecord(streamKey);
|
// * 开始录制
|
||||||
}
|
// */
|
||||||
|
// private void startRecording(String streamKey) {
|
||||||
/**
|
// SrsClient.RecordConfig config = new SrsClient.RecordConfig();
|
||||||
* 生成推流密钥
|
// config.setFilePath("/recordings/" + streamKey + ".flv");
|
||||||
*/
|
// srsClient.startRecord(streamKey, config);
|
||||||
private String generateStreamKey() {
|
// }
|
||||||
return UUID.randomUUID().toString();
|
//
|
||||||
}
|
// /**
|
||||||
|
// * 停止录制
|
||||||
/**
|
// */
|
||||||
* 生成推流地址
|
// private void stopRecording(String streamKey) {
|
||||||
*/
|
// srsClient.stopRecord(streamKey);
|
||||||
private String generateRtmpUrl(String streamKey) {
|
// }
|
||||||
return "rtmp://localhost:1935/live/" + streamKey;
|
//
|
||||||
}
|
// /**
|
||||||
|
// * 生成推流密钥
|
||||||
/**
|
// */
|
||||||
* 生成播放地址
|
// private String generateStreamKey() {
|
||||||
*/
|
// return UUID.randomUUID().toString();
|
||||||
private String generateHlsUrl(String streamKey) {
|
// }
|
||||||
return "http://localhost:8088/live/" + streamKey + ".m3u8";
|
//
|
||||||
}
|
// /**
|
||||||
|
// * 生成推流地址
|
||||||
/**
|
// */
|
||||||
* 生成回放地址
|
// private String generateRtmpUrl(String streamKey) {
|
||||||
*/
|
// return "rtmp://localhost:1935/live/" + streamKey;
|
||||||
private String generateReplayUrl(String streamKey) {
|
// }
|
||||||
return "http://localhost:8080/recordings/" + streamKey + ".flv";
|
//
|
||||||
}
|
// /**
|
||||||
}
|
// * 生成播放地址
|
||||||
|
// */
|
||||||
|
// private String generateHlsUrl(String streamKey) {
|
||||||
|
// return "http://localhost:8088/live/" + streamKey + ".m3u8";
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 生成回放地址
|
||||||
|
// */
|
||||||
|
// private String generateReplayUrl(String streamKey) {
|
||||||
|
// return "http://localhost:8080/recordings/" + streamKey + ".flv";
|
||||||
|
// }
|
||||||
|
//}
|
|
@ -2,11 +2,10 @@ package com.guwan.backend.service;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.guwan.backend.dto.video.VideoDTO;
|
import com.guwan.backend.dto.video.VideoDTO;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
public interface VideoService {
|
public interface VideoService {
|
||||||
// 上传视频
|
// 上传视频
|
||||||
VideoDTO uploadVideo(MultipartFile file, String title, String description, String tags);
|
VideoDTO uploadVideo(String fileUrl, String title, String description, String tags);
|
||||||
|
|
||||||
// 更新视频信息
|
// 更新视频信息
|
||||||
VideoDTO updateVideo(VideoDTO videoDTO);
|
VideoDTO updateVideo(VideoDTO videoDTO);
|
||||||
|
|
|
@ -18,7 +18,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -36,7 +35,7 @@ public class VideoServiceImpl implements VideoService {
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
@OperationLog(description = "上传视频", operationType = "上传")
|
@OperationLog(description = "上传视频", operationType = "上传")
|
||||||
public VideoDTO uploadVideo(MultipartFile file, String title, String description, String tags) {
|
public VideoDTO uploadVideo(String fileUrl, String title, String description, String tags) {
|
||||||
// 获取当前用户
|
// 获取当前用户
|
||||||
Long userId = securityUtil.getCurrentUserId();
|
Long userId = securityUtil.getCurrentUserId();
|
||||||
if (userId == null) {
|
if (userId == null) {
|
||||||
|
@ -45,15 +44,15 @@ public class VideoServiceImpl implements VideoService {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 上传视频文件到MinIO
|
// 上传视频文件到MinIO
|
||||||
String fileName = minioUtil.uploadFile("videos", file);
|
|
||||||
String url = minioUtil.getUrl(minioUtil.getFileUrl("videos", fileName));
|
String url = fileUrl;
|
||||||
|
|
||||||
// 创建视频记录
|
// 创建视频记录
|
||||||
Video video = new Video();
|
Video video = new Video();
|
||||||
video.setTitle(title);
|
video.setTitle(title);
|
||||||
video.setDescription(description);
|
video.setDescription(description);
|
||||||
video.setUrl(url);
|
video.setUrl(url);
|
||||||
video.setSize(file.getSize());
|
// video.setSize(file.getSize());
|
||||||
video.setUserId(userId);
|
video.setUserId(userId);
|
||||||
video.setStatus("PUBLISHED");
|
video.setStatus("PUBLISHED");
|
||||||
video.setTags(tags);
|
video.setTags(tags);
|
||||||
|
|
|
@ -172,6 +172,22 @@ public class MinioUtil {
|
||||||
return UUID.randomUUID() + "." + extension;
|
return UUID.randomUUID() + "." + extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getFileSize(String bucketName, String objectName) {
|
||||||
|
try {
|
||||||
|
StatObjectResponse objectInfo = minioClient.statObject(
|
||||||
|
StatObjectArgs.builder()
|
||||||
|
.bucket(bucketName)
|
||||||
|
.object(objectName)
|
||||||
|
.build());
|
||||||
|
return objectInfo.size();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 初始化时创建视频桶
|
// 初始化时创建视频桶
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void init() {
|
public void init() {
|
||||||
|
|
|
@ -1,82 +1,82 @@
|
||||||
package com.guwan.backend.websocket;
|
//package com.guwan.backend.websocket;
|
||||||
|
//
|
||||||
import com.alibaba.fastjson.JSON;
|
//import com.alibaba.fastjson.JSON;
|
||||||
import com.guwan.backend.entity.LiveMessage;
|
//import com.guwan.backend.entity.LiveMessage;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
//import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
//import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.socket.CloseStatus;
|
//import org.springframework.web.socket.CloseStatus;
|
||||||
import org.springframework.web.socket.TextMessage;
|
//import org.springframework.web.socket.TextMessage;
|
||||||
import org.springframework.web.socket.WebSocketSession;
|
//import org.springframework.web.socket.WebSocketSession;
|
||||||
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
//import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||||
|
//
|
||||||
import java.io.IOException;
|
//import java.io.IOException;
|
||||||
import java.util.Map;
|
//import java.util.Map;
|
||||||
import java.util.Set;
|
//import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
//import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentHashSet;
|
//import java.util.concurrent.ConcurrentHashSet;
|
||||||
|
//
|
||||||
@Slf4j
|
//@Slf4j
|
||||||
@Component
|
//@Component
|
||||||
public class LiveWebSocketHandler extends TextWebSocketHandler {
|
//public class LiveWebSocketHandler extends TextWebSocketHandler {
|
||||||
|
//
|
||||||
private static final Map<String, Set<WebSocketSession>> roomSessions = new ConcurrentHashMap<>();
|
// private static final Map<String, Set<WebSocketSession>> roomSessions = new ConcurrentHashMap<>();
|
||||||
private static final Map<String, WebSocketSession> userSessions = new ConcurrentHashMap<>();
|
// private static final Map<String, WebSocketSession> userSessions = new ConcurrentHashMap<>();
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public void afterConnectionEstablished(WebSocketSession session) {
|
// public void afterConnectionEstablished(WebSocketSession session) {
|
||||||
String roomId = getRoomId(session);
|
// String roomId = getRoomId(session);
|
||||||
String userId = getUserId(session);
|
// String userId = getUserId(session);
|
||||||
|
//
|
||||||
// 加入房间
|
// // 加入房间
|
||||||
roomSessions.computeIfAbsent(roomId, k -> new ConcurrentHashSet<>()).add(session);
|
// roomSessions.computeIfAbsent(roomId, k -> new ConcurrentHashSet<>()).add(session);
|
||||||
userSessions.put(userId, session);
|
// userSessions.put(userId, session);
|
||||||
|
//
|
||||||
// 广播进入消息
|
// // 广播进入消息
|
||||||
broadcastMessage(roomId, createEnterMessage(userId));
|
// broadcastMessage(roomId, createEnterMessage(userId));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public void handleTextMessage(WebSocketSession session, TextMessage message) {
|
// public void handleTextMessage(WebSocketSession session, TextMessage message) {
|
||||||
String roomId = getRoomId(session);
|
// String roomId = getRoomId(session);
|
||||||
LiveMessage liveMessage = JSON.parseObject(message.getPayload(), LiveMessage.class);
|
// LiveMessage liveMessage = JSON.parseObject(message.getPayload(), LiveMessage.class);
|
||||||
|
//
|
||||||
// 处理不同类型的消息
|
// // 处理不同类型的消息
|
||||||
switch (liveMessage.getType()) {
|
// switch (liveMessage.getType()) {
|
||||||
case "CHAT":
|
// case "CHAT":
|
||||||
broadcastMessage(roomId, message);
|
// broadcastMessage(roomId, message);
|
||||||
break;
|
// break;
|
||||||
case "GIFT":
|
// case "GIFT":
|
||||||
handleGiftMessage(roomId, liveMessage);
|
// handleGiftMessage(roomId, liveMessage);
|
||||||
break;
|
// break;
|
||||||
case "LIKE":
|
// case "LIKE":
|
||||||
handleLikeMessage(roomId, liveMessage);
|
// handleLikeMessage(roomId, liveMessage);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
|
// public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
|
||||||
String roomId = getRoomId(session);
|
// String roomId = getRoomId(session);
|
||||||
String userId = getUserId(session);
|
// String userId = getUserId(session);
|
||||||
|
//
|
||||||
// 离开房间
|
// // 离开房间
|
||||||
roomSessions.get(roomId).remove(session);
|
// roomSessions.get(roomId).remove(session);
|
||||||
userSessions.remove(userId);
|
// userSessions.remove(userId);
|
||||||
|
//
|
||||||
// 广播离开消息
|
// // 广播离开消息
|
||||||
broadcastMessage(roomId, createLeaveMessage(userId));
|
// broadcastMessage(roomId, createLeaveMessage(userId));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private void broadcastMessage(String roomId, TextMessage message) {
|
// private void broadcastMessage(String roomId, TextMessage message) {
|
||||||
Set<WebSocketSession> sessions = roomSessions.get(roomId);
|
// Set<WebSocketSession> sessions = roomSessions.get(roomId);
|
||||||
if (sessions != null) {
|
// if (sessions != null) {
|
||||||
sessions.forEach(session -> {
|
// sessions.forEach(session -> {
|
||||||
try {
|
// try {
|
||||||
session.sendMessage(message);
|
// session.sendMessage(message);
|
||||||
} catch (IOException e) {
|
// } catch (IOException e) {
|
||||||
log.error("发送消息失败", e);
|
// log.error("发送消息失败", e);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
|
@ -71,4 +71,11 @@ class MinioUtilTest {
|
||||||
// 删除图片
|
// 删除图片
|
||||||
// minioUtil.deleteFile(minioConfig.getBucket().getImages(), fileName);
|
// minioUtil.deleteFile(minioConfig.getBucket().getImages(), fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSize() {
|
||||||
|
System.out.println(minioUtil.getFileSize("images", "7c9360ba-0cf7-41db-9e11-6c02379e1170.jpg"));
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue