Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
541 changes: 541 additions & 0 deletions main/manager-api/README copy.md

Large diffs are not rendered by default.

75 changes: 37 additions & 38 deletions main/manager-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>21</java.version>
<junit.version>5.10.1</junit.version>
<junit.version>5.10.2</junit.version>
<druid.version>1.2.20</druid.version>
<mybatisplus.version>3.5.5</mybatisplus.version>
<hutool.version>5.8.24</hutool.version>
Expand All @@ -41,7 +41,42 @@
<classifier>jakarta</classifier>
<version>${shiro.version}</version>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.10.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-commons</artifactId>
<version>1.10.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-engine</artifactId>
<version>1.10.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
Expand Down Expand Up @@ -87,42 +122,6 @@
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.10.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-commons</artifactId>
<version>1.10.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-engine</artifactId>
<version>1.10.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;

import jakarta.annotation.Resource;

Expand All @@ -30,4 +31,11 @@ public RedisTemplate<String, Object> redisTemplate() {

return redisTemplate;
}

@Bean
public RedisMessageListenerContainer redisMessageListenerContainer() {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(factory);
return container;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package xiaozhi.modules.device.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import xiaozhi.common.utils.Result;
import xiaozhi.modules.device.dto.CameraStreamStartDTO;
import xiaozhi.modules.device.service.CameraStreamService;

import java.io.IOException;

@Tag(name = "设备摄像头")
@RestController
@RequiredArgsConstructor
@RequestMapping("/device/camera")
public class DeviceCameraController {

private final CameraStreamService cameraStreamService;

@Operation(summary = "启动设备摄像头推流")
@PostMapping("/{deviceId}/start")
public Result<Boolean> start(@PathVariable String deviceId,
@RequestBody(required = false) CameraStreamStartDTO body,
HttpServletRequest request) {
Integer fps = body != null ? body.getFps() : null;
Integer quality = body != null ? body.getQuality() : null;
cameraStreamService.startStream(deviceId, fps, quality);
return new Result<Boolean>().ok(true);
}

@Operation(summary = "停止设备摄像头推流")
@PostMapping("/{deviceId}/stop")
public Result<Boolean> stop(@PathVariable String deviceId,
HttpServletRequest request) {
cameraStreamService.stopStream(deviceId);
return new Result<Boolean>().ok(true);
}

@Operation(summary = "获取设备摄像头MJPEG流")
@GetMapping(value = "/{deviceId}/stream", produces = MediaType.MULTIPART_MIXED_VALUE)
public void stream(@PathVariable String deviceId,
HttpServletRequest request,
HttpServletResponse resp) throws IOException {
// 调试日志
System.out.println("=== DeviceCamera stream method called ===");
System.out.println("Device ID: " + deviceId);
System.out.println("Request URL: " + request.getRequestURL());
System.out.println("Request URI: " + request.getRequestURI());
System.out.println("Authorization header: " + request.getHeader("Authorization"));

resp.setStatus(200);
resp.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
resp.setHeader("Pragma", "no-cache");
resp.setHeader("Connection", "close");
resp.setContentType("multipart/x-mixed-replace; boundary=frame");
cameraStreamService.openMjpegStream(deviceId, resp.getOutputStream());
// 注意:保持连接直到客户端关闭,由下层写入帧
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package xiaozhi.modules.device.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

@Data
public class CameraStreamStartDTO {
@Schema(description = "帧率(1-15)")
private Integer fps;

@Schema(description = "JPEG质量(5-30)")
private Integer quality;
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package xiaozhi.modules.device.service;

import java.io.IOException;
import java.io.OutputStream;

public interface CameraStreamService {
void startStream(String deviceId, Integer fps, Integer quality);
void stopStream(String deviceId);
void openMjpegStream(String deviceId, OutputStream os) throws IOException;
}


Loading