[*] 日常优化

This commit is contained in:
acgist
2023-07-18 08:24:44 +08:00
parent 9f6fdd564d
commit 6f9b66cb6f
17 changed files with 720 additions and 699 deletions

View File

@@ -1,282 +1,282 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
<relativePath />
</parent>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
<relativePath />
</parent>
<groupId>com.acgist</groupId>
<artifactId>taoyao</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<groupId>com.acgist</groupId>
<artifactId>taoyao</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<url>https://gitee.com/acgist/taoyao</url>
<name>taoyao</name>
<description>桃夭:桃夭是套基于`Mediasoup`开发的`WebRTC`音视频信令服务,可以非常方便的扩展信令接入更多智能终端。</description>
<inceptionYear>2022</inceptionYear>
<url>https://gitee.com/acgist/taoyao</url>
<name>taoyao</name>
<description>桃夭:桃夭是套基于`Mediasoup`开发的`WebRTC`音视频信令服务,可以非常方便的扩展信令接入更多智能终端。</description>
<inceptionYear>2022</inceptionYear>
<properties>
<!-- 版本 -->
<java.version>17</java.version>
<lombok.version>1.18.28</lombok.version>
<springdoc.version>2.1.0</springdoc.version>
<mapstruct.version>1.5.5.Final</mapstruct.version>
<!-- 配置 -->
<taoyao.maven.basedir>${project.basedir}</taoyao.maven.basedir>
<taoyao.maven.encoding>UTF-8</taoyao.maven.encoding>
<taoyao.maven.skip.assembly>true</taoyao.maven.skip.assembly>
</properties>
<properties>
<!-- 版本 -->
<java.version>17</java.version>
<lombok.version>1.18.28</lombok.version>
<springdoc.version>2.1.0</springdoc.version>
<mapstruct.version>1.5.5.Final</mapstruct.version>
<!-- 配置 -->
<taoyao.maven.basedir>${project.basedir}</taoyao.maven.basedir>
<taoyao.maven.encoding>UTF-8</taoyao.maven.encoding>
<taoyao.maven.skip.assembly>true</taoyao.maven.skip.assembly>
</properties>
<modules>
<module>taoyao-boot</module>
<module>taoyao-signal</module>
<module>taoyao-server</module>
</modules>
<modules>
<module>taoyao-boot</module>
<module>taoyao-signal</module>
<module>taoyao-server</module>
</modules>
<dependencies>
<!-- 快速开发 -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 开发工具 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- Jackson -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<!-- 接口文档 -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
<!-- AOP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 日志框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependencies>
<!-- 快速开发 -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 开发工具 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- Jackson -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<!-- 接口文档 -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
<!-- AOP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 日志框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- 单元测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.acgist</groupId>
<artifactId>taoyao-boot</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.acgist</groupId>
<artifactId>taoyao-signal</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.acgist</groupId>
<artifactId>taoyao-server</artifactId>
<version>${project.version}</version>
</dependency>
<!-- mapstruct -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
<scope>provided</scope>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.acgist</groupId>
<artifactId>taoyao-boot</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.acgist</groupId>
<artifactId>taoyao-signal</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.acgist</groupId>
<artifactId>taoyao-server</artifactId>
<version>${project.version}</version>
</dependency>
<!-- mapstruct -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
<scope>provided</scope>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.yml</include>
<include>**/*.properties</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<!-- 匹配所有文件:**/* -->
<!-- 匹配所有带有后缀文件:**/*.* -->
<include>**/*.*</include>
</includes>
<excludes>
<exclude>**/*.yml</exclude>
<exclude>**/*.properties</exclude>
</excludes>
<filtering>false</filtering>
</resource>
</resources>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.yml</include>
<include>**/*.properties</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<!-- 匹配所有文件:**/* -->
<!-- 匹配所有带有后缀文件:**/*.* -->
<include>**/*.*</include>
</includes>
<excludes>
<exclude>**/*.yml</exclude>
<exclude>**/*.properties</exclude>
</excludes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${taoyao.maven.encoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<!-- Jar配置独立config目录 -->
<excludes>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${taoyao.maven.encoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<!-- Jar配置独立config目录 -->
<excludes>
<include>*.cer</include>
<include>*.jks</include>
<include>*.p12</include>
<include>*.pfx</include>
<exclude>*.yml</exclude>
<exclude>*.properties</exclude>
</excludes>
<archive>
<manifestEntries>
<!-- 配置文件 -->
<Class-Path>../config/</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<attach>false</attach>
<skipAssembly>${taoyao.maven.skip.assembly}</skipAssembly>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
<exclude>*.yml</exclude>
<exclude>*.properties</exclude>
</excludes>
<archive>
<manifestEntries>
<!-- 配置文件 -->
<Class-Path>../config/</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<attach>false</attach>
<skipAssembly>${taoyao.maven.skip.assembly}</skipAssembly>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<profile>dev</profile>
<taoyao.maven.jvm.arg></taoyao.maven.jvm.arg>
<taoyao.maven.jvm.mem>-Xms512M -Xmx1024M -XX:NewRatio=1 -XX:SurvivorRatio=2</taoyao.maven.jvm.mem>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>${taoyao.maven.basedir}/docs/assembly/dev.xml</descriptor>
</descriptors>
</configuration>
</plugin>
</plugins>
</build>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</profile>
<profile>
<id>prd</id>
<properties>
<profile>prd</profile>
<taoyao.maven.jvm.arg></taoyao.maven.jvm.arg>
<taoyao.maven.jvm.mem>-Xms2048M -Xmx4096M -XX:NewRatio=1 -XX:SurvivorRatio=2</taoyao.maven.jvm.mem>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>${taoyao.maven.basedir}/docs/assembly/prd.xml</descriptor>
</descriptors>
</configuration>
</plugin>
</plugins>
</build>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</dependencyManagement>
</profile>
</profiles>
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<profile>dev</profile>
<taoyao.maven.jvm.arg></taoyao.maven.jvm.arg>
<taoyao.maven.jvm.mem>-Xms512M -Xmx1024M -XX:NewRatio=1 -XX:SurvivorRatio=2</taoyao.maven.jvm.mem>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>${taoyao.maven.basedir}/docs/assembly/dev.xml</descriptor>
</descriptors>
</configuration>
</plugin>
</plugins>
</build>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</profile>
<profile>
<id>prd</id>
<properties>
<profile>prd</profile>
<taoyao.maven.jvm.arg></taoyao.maven.jvm.arg>
<taoyao.maven.jvm.mem>-Xms2048M -Xmx4096M -XX:NewRatio=1 -XX:SurvivorRatio=2</taoyao.maven.jvm.mem>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>${taoyao.maven.basedir}/docs/assembly/prd.xml</descriptor>
</descriptors>
</configuration>
</plugin>
</plugins>
</build>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</dependencyManagement>
</profile>
</profiles>
</project>

View File

@@ -118,8 +118,11 @@ public final class NetUtils {
final InetAddress clientAddress = NetUtils.realAddress(clientIP);
final boolean sourceLocal = NetUtils.localAddress(sourceAddress);
final boolean clientLocal = NetUtils.localAddress(clientAddress);
// 内网服务 && 内网设备
// 内网服务 && 内网设备 => 重写服务地址
if(sourceLocal && clientLocal) {
if(NetUtils.subnetIP(sourceIP, clientIP)) {
return sourceIP;
}
final RewriteRuleProperties rule = NetUtils.rewriteProperties.getRule().stream()
.filter(v -> NetUtils.subnetIP(v.getNetwork(), clientIP))
.findFirst()
@@ -127,11 +130,10 @@ public final class NetUtils {
if(rule == null) {
return sourceIP;
}
log.debug("地址重写:{} - {} - {}", sourceIP, clientIP, rule.getNetwork());
// 明确配置
if(StringUtils.isNotEmpty(rule.getInnerHost())) {
return rule.getInnerHost();
}
log.debug("地址重写:{} - {} - {}", sourceIP, clientIP, rule.getNetwork());
// 地址 = 网络号 + 主机号
final byte[] sourceBytes = sourceAddress.getAddress();
final byte[] clientBytes = clientAddress.getAddress();
@@ -151,7 +153,7 @@ public final class NetUtils {
return InetAddress.getByAddress(bytes).getHostAddress();
}
}
// 内网服务 && 公网设备
// 内网服务 && 公网设备 => 公网服务地址
if(sourceLocal && !clientLocal) {
final RewriteRuleProperties rule = NetUtils.rewriteProperties.getRule().stream()
.filter(v -> NetUtils.subnetIP(v.getNetwork(), sourceIP))
@@ -164,7 +166,7 @@ public final class NetUtils {
return rule.getOuterHost();
}
}
// 公网服务 && 内网设备
// 公网服务 && 内网设备 => 内网服务地址
if(!sourceLocal && clientLocal) {
final RewriteRuleProperties rule = NetUtils.rewriteProperties.getRule().stream()
.filter(v -> NetUtils.subnetIP(v.getNetwork(), clientIP))

View File

@@ -2,52 +2,52 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.acgist</groupId>
<artifactId>taoyao</artifactId>
<version>1.0.0</version>
</parent>
<parent>
<groupId>com.acgist</groupId>
<artifactId>taoyao</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>taoyao-server</artifactId>
<packaging>jar</packaging>
<artifactId>taoyao-server</artifactId>
<packaging>jar</packaging>
<name>taoyao-server</name>
<description>启动服务</description>
<name>taoyao-server</name>
<description>启动服务</description>
<properties>
<taoyao.maven.basedir>${project.parent.basedir}</taoyao.maven.basedir>
<taoyao.maven.skip.assembly>false</taoyao.maven.skip.assembly>
</properties>
<properties>
<taoyao.maven.basedir>${project.parent.basedir}</taoyao.maven.basedir>
<taoyao.maven.skip.assembly>false</taoyao.maven.skip.assembly>
</properties>
<dependencies>
<dependency>
<groupId>com.acgist</groupId>
<artifactId>taoyao-signal</artifactId>
</dependency>
<dependencies>
<dependency>
<groupId>com.acgist</groupId>
<artifactId>taoyao-signal</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
</dependencies>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.acgist.taoyao.main.TaoyaoApplication</mainClass>
<addClasspath>true</addClasspath>
<classpathPrefix>./</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.acgist.taoyao.main.TaoyaoApplication</mainClass>
<addClasspath>true</addClasspath>
<classpathPrefix>./</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -22,29 +22,29 @@ import com.acgist.taoyao.signal.service.impl.SecurityServiceImpl;
@AutoConfiguration
public class TaoyaoAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public SlowInterceptor slowInterceptor(TaoyaoProperties taoyaoProperties) {
return new SlowInterceptor(taoyaoProperties);
}
@Bean
@ConditionalOnMissingBean
public SlowInterceptor slowInterceptor(TaoyaoProperties taoyaoProperties) {
return new SlowInterceptor(taoyaoProperties);
}
@Bean
@ConditionalOnMissingBean
public SecurityService securityService(
SecurityProperties securityProperties,
@Autowired(required = true) SecurityProperties securityProperties,
@Autowired(required = false) UsernamePasswordService usernamePasswordService
) {
return new SecurityServiceImpl(securityProperties, usernamePasswordService);
}
@Bean
@ConditionalOnProperty(prefix = "taoyao.security", name = "enabled", havingValue = "true", matchIfMissing = true)
@ConditionalOnMissingBean
public SecurityInterceptor securityInterceptor(
SecurityService securityService,
SecurityProperties securityProperties
) {
return new SecurityInterceptor(securityService, securityProperties);
}
@Bean
@ConditionalOnProperty(prefix = "taoyao.security", name = "enabled", havingValue = "true", matchIfMissing = true)
@ConditionalOnMissingBean
public SecurityInterceptor securityInterceptor(
SecurityService securityService,
SecurityProperties securityProperties
) {
return new SecurityInterceptor(securityService, securityProperties);
}
}

View File

@@ -5,8 +5,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.acgist.taoyao.boot.config.FfmpegProperties;
import com.acgist.taoyao.boot.config.RewriteProperties;
import com.acgist.taoyao.boot.config.MediaProperties;
import com.acgist.taoyao.boot.config.RewriteProperties;
import com.acgist.taoyao.boot.config.SocketProperties;
import com.acgist.taoyao.boot.config.WebrtcProperties;
import com.acgist.taoyao.boot.model.Message;
@@ -29,18 +29,18 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class ConfigController {
private final MediaProperties mediaProperties;
private final FfmpegProperties ffmpegProperties;
private final SocketProperties socketProperties;
private final WebrtcProperties webrtcProperties;
private final RewriteProperties rewriteProperties;
private final MediaProperties mediaProperties;
private final FfmpegProperties ffmpegProperties;
private final SocketProperties socketProperties;
private final WebrtcProperties webrtcProperties;
private final RewriteProperties rewriteProperties;
@Operation(summary = "媒体配置", description = "媒体配置")
@GetMapping("/media")
@ApiResponse(content = @Content(schema = @Schema(implementation = MediaProperties.class)))
public Message media() {
return Message.success(this.mediaProperties);
}
@GetMapping("/media")
@ApiResponse(content = @Content(schema = @Schema(implementation = MediaProperties.class)))
public Message media() {
return Message.success(this.mediaProperties);
}
@Operation(summary = "FFmpeg配置", description = "FFmpeg配置")
@GetMapping("/ffmpeg")
@@ -56,18 +56,18 @@ public class ConfigController {
return Message.success(this.socketProperties);
}
@Operation(summary = "WebRTC配置", description = "WebRTC配置")
@GetMapping("/webrtc")
@ApiResponse(content = @Content(schema = @Schema(implementation = WebrtcProperties.class)))
public Message webrtc() {
return Message.success(this.webrtcProperties);
}
@Operation(summary = "WebRTC配置", description = "WebRTC配置")
@GetMapping("/webrtc")
@ApiResponse(content = @Content(schema = @Schema(implementation = WebrtcProperties.class)))
public Message webrtc() {
return Message.success(this.webrtcProperties);
}
@Operation(summary = "地址重写配置", description = "地址重写配置")
@GetMapping("/rewrite")
@ApiResponse(content = @Content(schema = @Schema(implementation = WebrtcProperties.class)))
public Message rewrite() {
return Message.success(this.rewriteProperties);
}
@Operation(summary = "地址重写配置", description = "地址重写配置")
@GetMapping("/rewrite")
@ApiResponse(content = @Content(schema = @Schema(implementation = WebrtcProperties.class)))
public Message rewrite() {
return Message.success(this.rewriteProperties);
}
}

View File

@@ -17,6 +17,7 @@ import com.acgist.taoyao.signal.protocol.control.IControlPhotographProtocol;
import com.acgist.taoyao.signal.protocol.control.IControlServerRecordProtocol;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
@@ -34,31 +35,22 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class ControlController {
private final IControlBellProtocol controlBellProtocol;
private final IControlPhotographProtocol controlPhotographProtocol;
private final IControlConfigAudioProtocol controlConfigAudioProtocol;
private final IControlConfigVideoProtocol controlConfigVideoProtocol;
private final IControlBellProtocol controlBellProtocol;
private final IControlPhotographProtocol controlPhotographProtocol;
private final IControlConfigAudioProtocol controlConfigAudioProtocol;
private final IControlConfigVideoProtocol controlConfigVideoProtocol;
private final IControlClientRecordProtocol controlClientRecordProtocol;
private final IControlServerRecordProtocol controlServerRecordProtocol;
@Operation(summary = "响铃", description = "响铃控制")
@GetMapping("/bell/{clientId}")
public Message bell(@PathVariable String clientId, @NotNull(message = "没有指定操作状态") Boolean enabled) {
public Message bell(
@PathVariable String clientId,
@NotNull(message = "没有指定操作状态") Boolean enabled
) {
return this.controlBellProtocol.execute(clientId, enabled);
}
@Operation(summary = "录像", description = "终端录像控制")
@GetMapping("/client/record/{clientId}")
public Message record(@PathVariable String clientId, @NotNull(message = "没有指定操作状态") Boolean enabled) {
return this.controlClientRecordProtocol.execute(clientId, enabled);
}
@Operation(summary = "录像", description = "服务端录像控制")
@GetMapping("/server/record/{roomId}/{clientId}")
public Message record(@PathVariable String roomId, @PathVariable String clientId, @NotNull(message = "没有指定操作状态") Boolean enabled) {
return this.controlServerRecordProtocol.execute(roomId, clientId, enabled);
}
@Operation(summary = "拍照", description = "拍照控制")
@GetMapping("/photograph/{clientId}")
public Message photograph(@PathVariable String clientId) {
@@ -67,14 +59,39 @@ public class ControlController {
@Operation(summary = "配置音频", description = "配置音频")
@GetMapping("/config/audio/{clientId}")
public Message configAudio(@PathVariable String clientId, @Valid MediaAudioProperties mediaAudioProperties) {
public Message configAudio(
@PathVariable String clientId,
@Valid @RequestBody MediaAudioProperties mediaAudioProperties
) {
return this.controlConfigAudioProtocol.execute(clientId, mediaAudioProperties);
}
@Operation(summary = "配置视频", description = "配置视频")
@GetMapping("/config/video/{clientId}")
public Message configVideo(@PathVariable String clientId, @Valid MediaVideoProperties mediaVideoProperties) {
public Message configVideo(
@PathVariable String clientId,
@Valid @RequestBody MediaVideoProperties mediaVideoProperties
) {
return this.controlConfigVideoProtocol.execute(clientId, mediaVideoProperties);
}
@Operation(summary = "录像", description = "终端录像控制")
@GetMapping("/client/record/{clientId}")
public Message record(
@PathVariable String clientId,
@NotNull(message = "没有指定操作状态") Boolean enabled
) {
return this.controlClientRecordProtocol.execute(clientId, enabled);
}
@Operation(summary = "录像", description = "服务端录像控制")
@GetMapping("/server/record/{roomId}/{clientId}")
public Message record(
@PathVariable String roomId,
@PathVariable String clientId,
@NotNull(message = "没有指定操作状态") Boolean enabled
) {
return this.controlServerRecordProtocol.execute(roomId, clientId, enabled);
}
}

View File

@@ -25,14 +25,14 @@ import io.swagger.v3.oas.annotations.tags.Tag;
@RequestMapping("/platform")
public class PlatformController {
private final PlatformRebootProtocol platformRebootProtocol;
private final PlatformRebootProtocol platformRebootProtocol;
private final PlatformShutdownProtocol platformShutdownProtocol;
public PlatformController(
@Autowired(required = false) PlatformRebootProtocol platformRebootProtocol,
@Autowired(required = false) PlatformRebootProtocol platformRebootProtocol,
@Autowired(required = false) PlatformShutdownProtocol platformShutdownProtocol
) {
this.platformRebootProtocol = platformRebootProtocol;
this.platformRebootProtocol = platformRebootProtocol;
this.platformShutdownProtocol = platformShutdownProtocol;
}

View File

@@ -25,14 +25,14 @@ import io.swagger.v3.oas.annotations.tags.Tag;
@RequestMapping("/system")
public class SystemController {
private final SystemRebootProtocol systemRebootProtocol;
private final SystemRebootProtocol systemRebootProtocol;
private final SystemShutdownProtocol systemShutdownProtocol;
public SystemController(
@Autowired(required = false) SystemRebootProtocol systemRebootProtocol,
@Autowired(required = false) SystemRebootProtocol systemRebootProtocol,
@Autowired(required = false) SystemShutdownProtocol systemShutdownProtocol
) {
this.systemRebootProtocol = systemRebootProtocol;
this.systemRebootProtocol = systemRebootProtocol;
this.systemShutdownProtocol = systemShutdownProtocol;
}

View File

@@ -24,19 +24,22 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public class SecurityInterceptor extends InterceptorAdapter {
private final SecurityService securityService;
private final SecurityProperties securityProperties;
private final SecurityService securityService;
private final SecurityProperties securityProperties;
/**
* 鉴权信息
*/
private final String authenticate;
/**
* 地址匹配
*/
private final AntPathMatcher matcher;
/**
* 鉴权信息
*/
private final String authenticate;
/**
* 地址匹配
*/
private final AntPathMatcher matcher;
public SecurityInterceptor(SecurityService securityService, SecurityProperties securityProperties) {
public SecurityInterceptor(
SecurityService securityService,
SecurityProperties securityProperties
) {
this.securityService = securityService;
this.securityProperties = securityProperties;
this.authenticate = "Basic Realm=\"" + this.securityProperties.getRealm() + "\"";
@@ -44,76 +47,76 @@ public class SecurityInterceptor extends InterceptorAdapter {
log.info("安全拦截密码:{}", securityProperties.getPassword());
}
@Override
public String name() {
return "安全拦截器";
}
@Override
public String name() {
return "安全拦截器";
}
@Override
public String[] pathPattern() {
return new String[] { "/**" };
}
@Override
public String[] pathPattern() {
return new String[] { "/**" };
}
@Override
public int getOrder() {
return Integer.MIN_VALUE + 1;
}
@Override
public int getOrder() {
return Integer.MIN_VALUE + 1;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(this.permit(request) || this.authorization(request)) {
return true;
}
if(log.isDebugEnabled()) {
log.debug("授权失败:{}", request.getRequestURL());
}
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setHeader(HttpHeaders.WWW_AUTHENTICATE, this.authenticate);
return false;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(this.permit(request) || this.authorization(request)) {
return true;
}
if(log.isDebugEnabled()) {
log.debug("授权失败:{}", request.getRequestURL());
}
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setHeader(HttpHeaders.WWW_AUTHENTICATE, this.authenticate);
return false;
}
/**
* @param request 请求
*
* @return 是否许可请求
*/
private boolean permit(HttpServletRequest request) {
final String uri = request.getRequestURI();
final String[] permit = this.securityProperties.getPermit();
if(ArrayUtils.isEmpty(permit)) {
return false;
}
for (String pattern : permit) {
if(this.matcher.match(pattern, uri)) {
return true;
}
}
return false;
}
/**
* @param request 请求
*
* @return 是否许可请求
*/
private boolean permit(HttpServletRequest request) {
final String uri = request.getRequestURI();
final String[] permit = this.securityProperties.getPermit();
if(ArrayUtils.isEmpty(permit)) {
return false;
}
for (String pattern : permit) {
if(this.matcher.match(pattern, uri)) {
return true;
}
}
return false;
}
/**
* @param request 请求
*
* @return 是否授权成功
*/
private boolean authorization(HttpServletRequest request) {
String authorization = request.getHeader(HttpHeaders.AUTHORIZATION);
if(StringUtils.isEmpty(authorization)) {
return false;
}
int index = authorization.indexOf(' ');
if(index < 0) {
return false;
}
authorization = authorization.substring(index + 1).strip();
authorization = new String(Base64.getMimeDecoder().decode(authorization));
index = authorization.indexOf(':');
if(index < 0) {
return false;
}
final String username = authorization.substring(0, index);
final String password = authorization.substring(index + 1);
return this.securityService.authenticate(username, password);
}
/**
* @param request 请求
*
* @return 是否授权成功
*/
private boolean authorization(HttpServletRequest request) {
String authorization = request.getHeader(HttpHeaders.AUTHORIZATION);
if(StringUtils.isEmpty(authorization)) {
return false;
}
int index = authorization.indexOf(' ');
if(index < 0) {
return false;
}
authorization = authorization.substring(index + 1).strip();
authorization = new String(Base64.getMimeDecoder().decode(authorization));
index = authorization.indexOf(':');
if(index < 0) {
return false;
}
final String username = authorization.substring(0, index);
final String password = authorization.substring(index + 1);
return this.securityService.authenticate(username, password);
}
}

View File

@@ -15,47 +15,46 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public class SlowInterceptor extends InterceptorAdapter {
private final TaoyaoProperties taoyaoProperties;
private final TaoyaoProperties taoyaoProperties;
/**
* 请求开始时间
*/
private final ThreadLocal<Long> local;
/**
* 请求开始时间
*/
private final ThreadLocal<Long> local;
public SlowInterceptor(TaoyaoProperties taoyaoProperties) {
public SlowInterceptor(TaoyaoProperties taoyaoProperties) {
this.taoyaoProperties = taoyaoProperties;
this.local = new ThreadLocal<>();
}
@Override
public String name() {
return "过慢请求拦截器";
}
@Override
public String name() {
return "过慢请求拦截器";
}
@Override
public String[] pathPattern() {
return new String[] { "/**" };
}
@Override
public String[] pathPattern() {
return new String[] { "/**" };
}
@Override
public int getOrder() {
return Integer.MIN_VALUE;
}
@Override
public int getOrder() {
return Integer.MIN_VALUE;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
this.local.set(System.currentTimeMillis());
return true;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
this.local.set(System.currentTimeMillis());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) throws Exception {
final long duration;
final Long last = this.local.get();
if(last != null && (duration = System.currentTimeMillis() - last) > this.taoyaoProperties.getTimeout()) {
log.info("请求执行时间过慢:{} - {}", request.getRequestURI(), duration);
}
this.local.remove();
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) throws Exception {
final long duration = System.currentTimeMillis() - this.local.get();
if(duration > this.taoyaoProperties.getTimeout()) {
log.info("请求执行时间过慢:{} - {}", request.getRequestURI(), duration);
}
this.local.remove();
}
}

View File

@@ -8,8 +8,8 @@ import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
public class TaoyaoApplication {
public static void main(String[] args) {
SpringApplication.run(TaoyaoApplication.class, args);
}
public static void main(String[] args) {
SpringApplication.run(TaoyaoApplication.class, args);
}
}

View File

@@ -1,15 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>桃夭信令服务</title>
<style type="text/css">
p{text-align:center;}
a{text-decoration:none;}
</style>
<meta charset="UTF-8">
<title>桃夭信令服务</title>
<style type="text/css">
p{text-align:center;}
a{text-decoration:none;}
</style>
</head>
<body>
<p><a href="https://gitee.com/acgist/taoyao">taoyao-signal-server</a></p>
<p><a href="https://www.acgist.com">acgist</a></p>
<p><a href="https://gitee.com/acgist/taoyao">taoyao-signal-server</a></p>
<p><a href="https://www.acgist.com">acgist</a></p>
</body>
</html>

View File

@@ -19,29 +19,29 @@ import java.util.concurrent.TimeUnit;
@Documented
public @interface CostedTest {
/**
* @return 执行次数
*/
int count() default 1;
/**
* @return 执行次数
*/
int count() default 1;
/**
* @return 线程数量
*/
int thread() default 1;
/**
* @return 线程数量
*/
int thread() default 1;
/**
* @return 超时时间
*/
long timeout() default 1000L;
/**
* @return 超时时间
*/
long timeout() default 1000L;
/**
* @return 等待资源释放时间
*/
long waitRelease() default 0L;
/**
* @return 等待资源释放时间
*/
long waitRelease() default 0L;
/**
* @return 超时时间单位
*/
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
/**
* @return 超时时间单位
*/
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
}

View File

@@ -19,45 +19,45 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public class CostedTestTestExecutionListener implements TestExecutionListener {
@Override
public void afterTestMethod(TestContext testContext) throws Exception {
final CostedTest costedTest = testContext.getTestMethod().getDeclaredAnnotation(CostedTest.class);
if(costedTest == null) {
return;
}
final int count = costedTest.count();
final int thread = costedTest.thread();
final long timeout = costedTest.timeout();
final TimeUnit timeUnit = costedTest.timeUnit();
final long aTime = System.currentTimeMillis();
if(thread == 1) {
for (int index = 0; index < count; index++) {
testContext.getTestMethod().invoke(testContext.getTestInstance());
}
} else {
final CountDownLatch countDownLatch = new CountDownLatch(count);
final ExecutorService executor = Executors.newFixedThreadPool(thread);
for (int index = 0; index < count; index++) {
executor.execute(() -> {
try {
testContext.getTestMethod().invoke(testContext.getTestInstance());
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
log.error("多线程测试异常", e);
} finally {
countDownLatch.countDown();
}
});
}
countDownLatch.await(timeout, timeUnit);
executor.shutdown();
}
final long zTime = System.currentTimeMillis();
final long costed = zTime - aTime;
log.info("多线程测试消耗时间:{}", costed);
final long waitRelease = costedTest.waitRelease();
if(waitRelease > 0) {
Thread.sleep(waitRelease);
}
}
@Override
public void afterTestMethod(TestContext testContext) throws Exception {
final CostedTest costedTest = testContext.getTestMethod().getDeclaredAnnotation(CostedTest.class);
if(costedTest == null) {
return;
}
final int count = costedTest.count();
final int thread = costedTest.thread();
final long timeout = costedTest.timeout();
final TimeUnit timeUnit = costedTest.timeUnit();
final long aTime = System.currentTimeMillis();
if(thread == 1) {
for (int index = 0; index < count; index++) {
testContext.getTestMethod().invoke(testContext.getTestInstance());
}
} else {
final CountDownLatch countDownLatch = new CountDownLatch(count);
final ExecutorService executor = Executors.newFixedThreadPool(thread);
for (int index = 0; index < count; index++) {
executor.execute(() -> {
try {
testContext.getTestMethod().invoke(testContext.getTestInstance());
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
log.error("多线程测试异常", e);
} finally {
countDownLatch.countDown();
}
});
}
countDownLatch.await(timeout, timeUnit);
executor.shutdown();
}
final long zTime = System.currentTimeMillis();
final long costed = zTime - aTime;
log.info("多线程测试消耗时间:{}", costed);
final long waitRelease = costedTest.waitRelease();
if(waitRelease > 0) {
Thread.sleep(waitRelease);
}
}
}

View File

@@ -25,7 +25,7 @@ import org.springframework.test.context.TestExecutionListeners.MergeMode;
@TestExecutionListeners(listeners = CostedTestTestExecutionListener.class, mergeMode = MergeMode.MERGE_WITH_DEFAULTS)
public @interface TaoyaoTest {
@AliasFor(annotation = SpringBootTest.class)
Class<?>[] classes() default {};
@AliasFor(annotation = SpringBootTest.class)
Class<?>[] classes() default {};
}

View File

@@ -21,99 +21,99 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public class RtpTest {
@Test
void testSocket() throws Exception {
final Socket socket = new Socket();
socket.connect(new InetSocketAddress("127.0.0.1", 9999));
final InputStream inputStream = socket.getInputStream();
final OutputStream outputStream = socket.getOutputStream();
// 随机密码https://localhost:8888/config/socket
final String secret = "TSFXzB7hcfE=".strip();
final Cipher encrypt = CipherUtils.buildCipher(Cipher.ENCRYPT_MODE, Encrypt.DES, secret);
final Cipher decrypt = CipherUtils.buildCipher(Cipher.DECRYPT_MODE, Encrypt.DES, secret);
// 接收
new Thread(() -> {
int length = 0;
short messageLength = 0;
final byte[] bytes = new byte[1024];
final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
try {
while((length = inputStream.read(bytes)) >= 0) {
buffer.put(bytes, 0, length);
while(buffer.position() > 0) {
if(messageLength <= 0) {
if(buffer.position() < Short.BYTES) {
// 不够消息长度
break;
} else {
buffer.flip();
messageLength = buffer.getShort();
buffer.compact();
if(messageLength > 16 * 1024) {
throw MessageCodeException.of("超过最大数据大小:" + messageLength);
}
}
} else {
if(buffer.position() < messageLength) {
// 不够消息长度
break;
} else {
final byte[] message = new byte[messageLength];
messageLength = 0;
buffer.flip();
buffer.get(message);
buffer.compact();
log.debug("收到消息:{}", new String(decrypt.doFinal(message)));
}
}
}
}
} catch (Exception e) {
log.error("读取异常", e);
}
}).start();
// 发送
String line = """
{
"header":{"v":"1.0.0","id":1215293599999001,"signal":"client::register"},
"body":{"clientId":"ffmpeg","name":"ffmpeg","clientType":"WEB","battery":100,"charging":true,"username":"taoyao","password":"taoyao"}
}
""";
// {"header":{"v":"1.0.0","id":1215310510002009,"signal":"room::enter"},"body":{"roomId":"8260e615-3081-4bfc-96a8-574f4dd780d9"}}
// {"header":{"v":"1.0.0","id":1215310510002010,"signal":"media::transport::plain"},"body":{"roomId":"8260e615-3081-4bfc-96a8-574f4dd780d9","rtcpMux":false,"comedia":true}}
// {"header":{"v":"1.0.0","id":1215375110006012,"signal":"media::produce"},"body":{"kind":"video","roomId":"8260e615-3081-4bfc-96a8-574f4dd780d9","transportId":"14dc9307-bf9c-4442-a9ad-ce6a97623ef4","appData":{},"rtpParameters":{"codecs":[{"mimeType":"video/vp8","clockRate":90000,"payloadType":102,"rtcpFeedback":[]}],"encodings":[{"ssrc":123123}]}}}
// 音频转为PCM
// ffmpeg.exe -i .\a.m4a -f s16le a.pcm
// ffmpeg.exe -i .\a.m4a -f s16le -ac 2 -ar 8000 a.pcm
// ffplay.exe -ar 48000 -ac 2 -f s16le -i a.pcm
// ffmpeg不支持rtcpMux
// ffmpeg -re -i video.mp4 -c:v vp8 -map 0:0 -f tee "[select=v:f=rtp:ssrc=123123:payload_type=102]rtp://192.168.1.110:40793?rtcpport=47218"
// ffmpeg -re -i video.mp4 -c:v libvpx -map 0:0 -f tee "[select=v:f=rtp:ssrc=123123:payload_type=102]rtp://192.168.1.110:40793?rtcpport=47218"
// 音频视频同时传输
// ffmpeg -re -i video.mp4 -c:a libopus -vn -f rtp rtp://192.168.1.110:8888 -c:v libx264 -an -f rtp rtp://192.168.1.110:9999 -sdp_file taoyao.sdp
// ffplay -protocol_whitelist "file,rtp,udp" -i taoyao.sdp
// ffmpeg -protocol_whitelist "file,rtp,udp" -i taoyao.sdp taoyao.mp4
final Scanner scanner = new Scanner(System.in);
do {
if(StringUtils.isEmpty(line)) {
break;
}
try {
final byte[] bytes = line.getBytes();
final byte[] encryptBytes = encrypt.doFinal(bytes);
final ByteBuffer buffer = ByteBuffer.allocateDirect(Short.BYTES + encryptBytes.length);
buffer.putShort((short) encryptBytes.length);
buffer.put(encryptBytes);
buffer.flip();
final byte[] message = new byte[buffer.capacity()];
buffer.get(message);
outputStream.write(message);
} catch (Exception e) {
log.error("发送异常", e);
}
} while((line = scanner.next()) != null);
socket.close();
scanner.close();
}
@Test
void testSocket() throws Exception {
final Socket socket = new Socket();
socket.connect(new InetSocketAddress("127.0.0.1", 9999));
final InputStream inputStream = socket.getInputStream();
final OutputStream outputStream = socket.getOutputStream();
// 随机密码https://localhost:8888/config/socket
final String secret = "TSFXzB7hcfE=".strip();
final Cipher encrypt = CipherUtils.buildCipher(Cipher.ENCRYPT_MODE, Encrypt.DES, secret);
final Cipher decrypt = CipherUtils.buildCipher(Cipher.DECRYPT_MODE, Encrypt.DES, secret);
// 接收
new Thread(() -> {
int length = 0;
short messageLength = 0;
final byte[] bytes = new byte[1024];
final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
try {
while((length = inputStream.read(bytes)) >= 0) {
buffer.put(bytes, 0, length);
while(buffer.position() > 0) {
if(messageLength <= 0) {
if(buffer.position() < Short.BYTES) {
// 不够消息长度
break;
} else {
buffer.flip();
messageLength = buffer.getShort();
buffer.compact();
if(messageLength > 16 * 1024) {
throw MessageCodeException.of("超过最大数据大小:" + messageLength);
}
}
} else {
if(buffer.position() < messageLength) {
// 不够消息长度
break;
} else {
final byte[] message = new byte[messageLength];
messageLength = 0;
buffer.flip();
buffer.get(message);
buffer.compact();
log.debug("收到消息:{}", new String(decrypt.doFinal(message)));
}
}
}
}
} catch (Exception e) {
log.error("读取异常", e);
}
}).start();
// 发送
String line = """
{
"header":{"v":"1.0.0","id":1215293599999001,"signal":"client::register"},
"body":{"clientId":"ffmpeg","name":"ffmpeg","clientType":"WEB","battery":100,"charging":true,"username":"taoyao","password":"taoyao"}
}
""";
// {"header":{"v":"1.0.0","id":1215310510002009,"signal":"room::enter"},"body":{"roomId":"8260e615-3081-4bfc-96a8-574f4dd780d9"}}
// {"header":{"v":"1.0.0","id":1215310510002010,"signal":"media::transport::plain"},"body":{"roomId":"8260e615-3081-4bfc-96a8-574f4dd780d9","rtcpMux":false,"comedia":true}}
// {"header":{"v":"1.0.0","id":1215375110006012,"signal":"media::produce"},"body":{"kind":"video","roomId":"8260e615-3081-4bfc-96a8-574f4dd780d9","transportId":"14dc9307-bf9c-4442-a9ad-ce6a97623ef4","appData":{},"rtpParameters":{"codecs":[{"mimeType":"video/vp8","clockRate":90000,"payloadType":102,"rtcpFeedback":[]}],"encodings":[{"ssrc":123123}]}}}
// 音频转为PCM
// ffmpeg.exe -i .\a.m4a -f s16le a.pcm
// ffmpeg.exe -i .\a.m4a -f s16le -ac 2 -ar 8000 a.pcm
// ffplay.exe -ar 48000 -ac 2 -f s16le -i a.pcm
// ffmpeg不支持rtcpMux
// ffmpeg -re -i video.mp4 -c:v vp8 -map 0:0 -f tee "[select=v:f=rtp:ssrc=123123:payload_type=102]rtp://192.168.1.110:40793?rtcpport=47218"
// ffmpeg -re -i video.mp4 -c:v libvpx -map 0:0 -f tee "[select=v:f=rtp:ssrc=123123:payload_type=102]rtp://192.168.1.110:40793?rtcpport=47218"
// 音频视频同时传输
// ffmpeg -re -i video.mp4 -c:a libopus -vn -f rtp rtp://192.168.1.110:8888 -c:v libx264 -an -f rtp rtp://192.168.1.110:9999 -sdp_file taoyao.sdp
// ffplay -protocol_whitelist "file,rtp,udp" -i taoyao.sdp
// ffmpeg -protocol_whitelist "file,rtp,udp" -i taoyao.sdp taoyao.mp4
final Scanner scanner = new Scanner(System.in);
do {
if(StringUtils.isEmpty(line)) {
break;
}
try {
final byte[] bytes = line.getBytes();
final byte[] encryptBytes = encrypt.doFinal(bytes);
final ByteBuffer buffer = ByteBuffer.allocateDirect(Short.BYTES + encryptBytes.length);
buffer.putShort((short) encryptBytes.length);
buffer.put(encryptBytes);
buffer.flip();
final byte[] message = new byte[buffer.capacity()];
buffer.get(message);
outputStream.write(message);
} catch (Exception e) {
log.error("发送异常", e);
}
} while((line = scanner.next()) != null);
socket.close();
scanner.close();
}
}

View File

@@ -15,29 +15,29 @@ import lombok.extern.slf4j.Slf4j;
//@SpringBootTest(classes = TaoyaoApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class IdServiceTest {
@Autowired
private IdService idService;
@Autowired
private IdService idService;
@Test
// @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS)
// @Rollback()
// @RepeatedTest(10)
void testId() {
final long id = this.idService.buildId();
log.info("生成ID{}", id);
log.info("生成ID{}", String.valueOf(id).length());
}
@Test
// @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS)
// @Rollback()
// @RepeatedTest(10)
void testId() {
final long id = this.idService.buildId();
log.info("生成ID{}", id);
log.info("生成ID{}", String.valueOf(id).length());
}
@Test
@CostedTest(count = 100000, thread = 10)
void testIdCosted() {
this.idService.buildId();
}
@Test
@CostedTest(count = 100000, thread = 10)
void testIdCosted() {
this.idService.buildId();
}
@Test
@CostedTest(count = 100000, thread = 10)
void testUuidCosted() {
this.idService.buildUuid();
}
@Test
@CostedTest(count = 100000, thread = 10)
void testUuidCosted() {
this.idService.buildUuid();
}
}