diff --git a/README.md b/README.md index fd62d3f..b8449e8 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,18 @@ # 桃夭 基于WebRTC实现信令服务,实现Mesh、MCU和SFU三种媒体通信架构,支持直播会议两种场景。 +项目提供WebRTC服务信令,终端已有H5示例,其他终端需要自己实现。 + +## 授权 + +开源公益免费,商用需要购买授权。 ## 模块 |模块|名称|描述| |:--|:--|:--| |taoyao|桃夭|桃之夭夭灼灼其华| -|taoyao-nat|内网穿透|STUN/TURN| -|taoyao-boot|基础|启动模块| +|taoyao-boot|启动模块|基础模块| |taoyao-live|直播|直播、连麦| |taoyao-test|测试|测试工具| |taoyao-media|媒体|录制、视频(美颜、AI识别)、音频(混音、变声、降噪)| @@ -16,12 +20,41 @@ |taoyao-server|服务|启动服务| |taoyao-meeting|会议|会议模式、广播模式、单人对讲| |taoyao-webrtc|WebRTC模块|WebRTC模块| -|taoyao-webrtc-jni|WebRTC JNI|WebRTC本地接口| |taoyao-webrtc-sfu|WebRTC SFU架构|SFU架构| |taoyao-webrtc-mcu|WebRTC MCU架构|MCU架构| |taoyao-webrtc-mesh|WebRTC MESH架构|MESH架构| +|taoyao-webrtc-jitsi|WebRTC协议簇jitsi实现|WebRTC协议簇jitsi实现| +|taoyao-webrtc-kurento|WebRTC协议簇kurento实现|WebRTC协议簇kurento实现| -## STUN/TURN公共服务 +> 终端负责推流,服务端负责处理媒体流,这些功能也可以在终端实现。主次码流没在终端实现,服务端实现可以有更多选择。 + +## 模块关系 + +``` ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| taoyao-server | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| taoyao-live | taoyao-meeting | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| taoyao-signal | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| taoyao-media | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| taoyao-mcu | taoyao-sfu | | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ taoyao-mesh + +| taoyao-jitsi | taoyao-kurento | | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| taoyao-boot | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +``` + +## 内网穿透 + +请用公共STUN/TURN服务或者自行搭建coturn服务。 + +> 只有公网Mesh架构才需要真正的内网穿透 + +### STUN/TURN公共服务地址 ``` stun:stun1.l.google.com:19302 @@ -33,20 +66,35 @@ stun:stun.stunprotocol.org:3478 ## 信令 -|功能|描述| -|:--|:--| -|注册|终端注册(同步信息)| -|关闭|终端关闭(注销)| -|心跳|终端心跳| -|进入会议|没有会议自动创建| -|离开会议|离开会议| -|关闭会议|关闭会议(所有人员离开)| -|邀请终端|会议邀请终端| -|踢出终端|会议踢出终端| -|推流|控制终端推流| -|暂停推流|控制终端暂停推流| -|订阅(分流)|控制终端暂停推流| -|暂停订阅(分流)|控制终端暂停推流| +|功能|描述|标识|响应| +|:--|:--|:--|:--| +|注册|终端注册(同步信息)||| +|关闭|终端关闭(注销)||| +|心跳|终端心跳||| +|创建会议|创建会议||返回会议ID| +|进入会议|没有会议自动创建||返回会议终端同时广播进入消息| +|离开会议|离开会议||广播离开消息| +|关闭会议|关闭会议(踢出所有人员)||广播关闭消息| +|终端列表|||返回所有终端列表| +|会议终端列表|||返回所有会议终端列表| +|直播终端列表|||返回所有直播终端列表| +|邀请终端|会议邀请终端(主动/被动)||单播邀请| +|踢出终端|会议踢出终端||单播踢出| +|开启直播|||| +|关闭直播|||| +|发布|控制终端推流||| +|取消发布|控制终端暂停推流||| +|订阅|订阅终端媒体流||| +|取消订阅|取消订阅终端媒体流||| +|暂停媒体流|暂停终端媒体流分流(不关媒体流通道)||| +|恢复媒体流|恢复终端媒体流分流(不关媒体流通道)||| +|开启录像|||| +|关闭录像|||| +|终端状态|||| +|单播消息|发送指定终端||| +|广播消息|广播排除自己的所有终端||| +|全员广播消息|广播包括自己的所有终端||| +|异常|异常信息||| ## 直播 @@ -58,6 +106,8 @@ stun:stun.stunprotocol.org:3478 流媒体点对点连接,不经过服务端。 +> 录制、AI识别等等功能只能在终端实现。 + ### MCU 终端推流到服务端,由服务端分流并且混音。 @@ -70,4 +120,4 @@ stun:stun.stunprotocol.org:3478 ``` keytool -genkeypair -keyalg RSA -dname "CN=localhost, OU=acgist, O=taoyao, L=GZ, ST=GD, C=CN" -alias taoyao -validity 3650 -ext ku:c=dig,keyE -ext eku=serverAuth -ext SAN=dns:localhost,ip:127.0.0.1 -keystore taoyao.jks -keypass 123456 -storepass 123456 -``` \ No newline at end of file +``` diff --git a/docs/assembly/dev.xml b/docs/assembly/dev.xml index 602a2b5..949ffa3 100644 --- a/docs/assembly/dev.xml +++ b/docs/assembly/dev.xml @@ -12,14 +12,14 @@ - ${system.maven.basedir}/docs + ${taoyao.maven.basedir}/docs ./ README.md - ${system.maven.basedir}/docs/bin + ${taoyao.maven.basedir}/docs/bin bin 0755 true diff --git a/docs/assembly/release.xml b/docs/assembly/release.xml index 57c1398..81e48b1 100644 --- a/docs/assembly/release.xml +++ b/docs/assembly/release.xml @@ -12,14 +12,14 @@ - ${system.maven.basedir}/docs + ${taoyao.maven.basedir}/docs ./ README.md - ${system.maven.basedir}/docs/bin + ${taoyao.maven.basedir}/docs/bin bin 0755 true diff --git a/docs/assembly/test.xml b/docs/assembly/test.xml index 94fb775..61689d0 100644 --- a/docs/assembly/test.xml +++ b/docs/assembly/test.xml @@ -12,14 +12,14 @@ - ${system.maven.basedir}/docs + ${taoyao.maven.basedir}/docs ./ README.md - ${system.maven.basedir}/docs/bin + ${taoyao.maven.basedir}/docs/bin bin 0755 true diff --git a/docs/bin/startup.sh b/docs/bin/startup.sh index 2dc7253..ed209cd 100644 --- a/docs/bin/startup.sh +++ b/docs/bin/startup.sh @@ -20,10 +20,10 @@ fi # 启动参数 JAVA_OPTS_GC="-XX:+UseG1GC -Xlog:gc:./logs/gc.log:time,level" -JAVA_OPTS_MEM="-server ${system.maven.jvm.mem}" -JAVA_OPTS_EXT="-Dfile.encoding=${system.maven.encoding} -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true" +JAVA_OPTS_MEM="-server ${taoyao.maven.jvm.mem}" +JAVA_OPTS_EXT="-Dfile.encoding=${taoyao.maven.encoding} -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true" JAVA_OPTS_APP="-Dspring.profiles.active=${profile}" -JAVA_OPTS="$JAVA_OPTS_MEM $JAVA_OPTS_EXT $JAVA_OPTS_APP ${system.maven.jvm.arg}" +JAVA_OPTS="$JAVA_OPTS_MEM $JAVA_OPTS_EXT $JAVA_OPTS_APP ${taoyao.maven.jvm.arg}" echo "启动参数:$JAVA_OPTS" # 启动应用 diff --git a/docs/taoyao-v1.0.zip b/docs/taoyao-v1.0.zip new file mode 100644 index 0000000..42cd575 Binary files /dev/null and b/docs/taoyao-v1.0.zip differ diff --git a/pom.xml b/pom.xml index 1ddc91c..ff411f5 100644 --- a/pom.xml +++ b/pom.xml @@ -24,18 +24,19 @@ 17 1.18.24 - 1.0.32006 + 6.18.0 1.6.12 1.5.3.Final 4.4 + 3.0-59-g71e244d + 1.1-22-g5c9346c5 - ${project.basedir} - UTF-8 - true + ${project.basedir} + UTF-8 + true - taoyao-nat taoyao-boot taoyao-live taoyao-test @@ -103,11 +104,6 @@ - - com.acgist - taoyao-nat - ${project.version} - com.acgist taoyao-boot @@ -148,11 +144,6 @@ taoyao-webrtc ${project.version} - - com.acgist - taoyao-webrtc-jni - ${project.version} - com.acgist taoyao-webrtc-sfu @@ -168,11 +159,32 @@ taoyao-webrtc-mesh ${project.version} - - org.webrtc - google-webrtc - ${webrtc.version} + com.acgist + taoyao-webrtc-jitsi + ${project.version} + + + com.acgist + taoyao-webrtc-kurento + ${project.version} + + + + org.jitsi + ice4j + ${jitsi.ice4j.version} + + + org.jitsi + libjitsi + ${jitsi.libjitsi.version} + + + + org.kurento + kurento-client + ${kurento.version} @@ -243,7 +255,7 @@ ${java.version} ${java.version} - ${system.maven.encoding} + ${taoyao.maven.encoding} @@ -276,7 +288,7 @@ false - ${system.maven.skip.assembly} + ${taoyao.maven.skip.assembly} false @@ -294,8 +306,8 @@ dev - - -Xms512M -Xmx1024M -XX:NewRatio=1 -XX:SurvivorRatio=2 + + -Xms512M -Xmx1024M -XX:NewRatio=1 -XX:SurvivorRatio=2 @@ -304,7 +316,7 @@ maven-assembly-plugin - ${system.maven.basedir}/docs/assembly/dev.xml + ${taoyao.maven.basedir}/docs/assembly/dev.xml @@ -324,8 +336,8 @@ test test - - -Xms512M -Xmx1024M -XX:NewRatio=1 -XX:SurvivorRatio=2 + + -Xms512M -Xmx1024M -XX:NewRatio=1 -XX:SurvivorRatio=2 @@ -334,7 +346,7 @@ maven-assembly-plugin - ${system.maven.basedir}/docs/assembly/test.xml + ${taoyao.maven.basedir}/docs/assembly/test.xml @@ -355,8 +367,8 @@ release release - -Dtaoyao.password=123456 - -Xms2048M -Xmx4096M -XX:NewRatio=1 -XX:SurvivorRatio=2 + -Dtaoyao.password=123456 + -Xms2048M -Xmx4096M -XX:NewRatio=1 -XX:SurvivorRatio=2 @@ -365,7 +377,7 @@ maven-assembly-plugin - ${system.maven.basedir}/docs/assembly/release.xml + ${taoyao.maven.basedir}/docs/assembly/release.xml diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/BootAutoConfiguration.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/BootAutoConfiguration.java index bcbc8c0..dc399e3 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/BootAutoConfiguration.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/BootAutoConfiguration.java @@ -75,7 +75,7 @@ import lombok.extern.slf4j.Slf4j; @Configuration @EnableScheduling @EnableAspectJAutoProxy(exposeProxy = true) -@EnableConfigurationProperties({ IdProperties.class, TaoyaoProperties.class, WebrtcProperties.class, SecurityProperties.class }) +@EnableConfigurationProperties({ IdProperties.class, MediaProperties.class, TaoyaoProperties.class, WebrtcProperties.class, SecurityProperties.class }) public class BootAutoConfiguration { @Value("${spring.application.name:taoyao}") diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/MediaAudioProperties.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/MediaAudioProperties.java new file mode 100644 index 0000000..646a747 --- /dev/null +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/MediaAudioProperties.java @@ -0,0 +1,56 @@ +package com.acgist.taoyao.boot.config; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +/** + * 音频配置 + * + * @author acgist + */ +@Getter +@Setter +@Schema(title = "音频配置", description = "音频配置") +public class MediaAudioProperties { + + /** + * 音频格式 + * + * @author acgist + */ + public enum Format { + + /** + * ACC + */ + ACC, + /** + * PCM + */ + PCM, + /** + * OPUS + */ + OPUS; + + } + + /** + * 格式 + */ + @Schema(title = "格式", description = "格式") + private Format format; + /** + * 采样率 + * 8000|16000|32000|48000 + */ + @Schema(title = "采样率", description = "采样率", example = "8000|16000|32000|48000") + private Integer samplerate; + /** + * 采样数 + */ + @Schema(title = "采样数", description = "采样数", example = "16") + private Integer samplesize; + +} diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/MediaProperties.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/MediaProperties.java new file mode 100644 index 0000000..a3f13cb --- /dev/null +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/MediaProperties.java @@ -0,0 +1,29 @@ +package com.acgist.taoyao.boot.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +/** + * 媒体配置 + * + * @author acgist + */ +@Getter +@Setter +@Schema(title = "媒体配置", description = "媒体配置") +@ConfigurationProperties(prefix = "taoyao.media") +public class MediaProperties { + + /** + * 音频配置 + */ + private MediaAudioProperties audio; + /** + * 视频配置 + */ + private MediaVideoProperties video; + +} diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/MediaVideoProperties.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/MediaVideoProperties.java new file mode 100644 index 0000000..7f9c6ac --- /dev/null +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/MediaVideoProperties.java @@ -0,0 +1,96 @@ +package com.acgist.taoyao.boot.config; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +/** + * 视频配置 + * + * @author acgist + */ +@Getter +@Setter +@Schema(title = "视频配置", description = "视频配置") +public class MediaVideoProperties { + + /** + * 视频格式 + * + * @author acgist + */ + public enum Format { + + /** + * VP8 + */ + VP8, + /** + * VP9 + */ + VP9, + /** + * H264 + */ + H264, + /** + * H265 + */ + H265; + + } + + /** + * 格式 + */ + @Schema(title = "格式", description = "格式") + private Format format; + /** + * 码率(画质) + */ + @Schema(title = "码率", description = "码率影响画质", example = "600|1200|1500|1800") + private Integer bitrate; + /** + * 帧率(流畅) + */ + @Schema(title = "帧率", description = "帧率影响流程", example = "20|24|30|60") + private Integer framerate; + /** + * 分辨率(画面大小) + */ + @Schema(title = "分辨率", description = "分辨率影响画面大小", example = "1920*1080|1280*720|480*360") + private String resolution; + /** + * 宽度 + */ + @Schema(title = "宽度", description = "宽度") + private Integer width; + /** + * 高度 + */ + @Schema(title = "高度", description = "高度") + private Integer height; + + /** + * @return 宽度 + */ + public Integer getWidth() { + if(this.width == null) { + final int index = this.resolution.indexOf('*'); + this.width = Integer.valueOf(this.resolution.substring(0, index).strip()); + } + return this.width; + } + + /** + * @return 高度 + */ + public Integer getHeight() { + if(this.height == null) { + final int index = this.resolution.indexOf('*'); + this.height = Integer.valueOf(this.resolution.substring(index + 1).strip()); + } + return this.height; + } + +} diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/SecurityProperties.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/SecurityProperties.java index f402ca6..31b18c3 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/SecurityProperties.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/SecurityProperties.java @@ -29,7 +29,7 @@ public class SecurityProperties { */ private String[] permit; /** - * 用户 + * 名称 */ private String username; /** diff --git a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/WebrtcProperties.java b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/WebrtcProperties.java index ae15457..ce2021d 100644 --- a/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/WebrtcProperties.java +++ b/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/WebrtcProperties.java @@ -18,11 +18,11 @@ import lombok.Setter; public class WebrtcProperties { /** - * 架构类型 + * 架构模型 * * @author acgist */ - public enum Type { + public enum Model { /** * SFU架构 @@ -40,10 +40,33 @@ public class WebrtcProperties { } /** - * 类型 + * 基础框架 + * + * @author acgist */ - @Schema(title = "架构类型", description = "WebRTC架构类型") - private Type type; + public enum Framework { + + /** + * jitsi + */ + JITSI, + /** + * kurento + */ + KURENTO; + + } + + /** + * 模型 + */ + @Schema(title = "架构模型", description = "WebRTC架构模型") + private Model model; + /** + * 框架 + */ + @Schema(title = "基础框架", description = "WebRTC基础框架") + private Framework framework; /** * stun服务器 */ diff --git a/taoyao-boot/src/main/resources/logback-spring.xml b/taoyao-boot/src/main/resources/logback-spring.xml index 55e868c..f386a52 100644 --- a/taoyao-boot/src/main/resources/logback-spring.xml +++ b/taoyao-boot/src/main/resources/logback-spring.xml @@ -1,27 +1,27 @@ - + - ${system.name} - - - - - - + ${log.name} + + + + + + - ${system.path}/${system.name}.debug.log + ${log.path}/${log.name}.debug.log - ${system.history} - ${system.path}/%d{yyyy-MM, aux}/${system.name}.debug.%d{yyyy-MM-dd}.log.gz + ${log.history} + ${log.path}/%d{yyyy-MM, aux}/${log.name}.debug.%d{yyyy-MM-dd}.log.gz - ${system.buffer} + ${log.buffer} false - ${system.charset} - ${system.pattern} + ${log.charset} + ${log.pattern} DEBUG @@ -29,22 +29,22 @@ - ${system.queue} + ${log.queue} true 0 - ${system.path}/${system.name}.info.log + ${log.path}/${log.name}.info.log - ${system.history} - ${system.path}/%d{yyyy-MM, aux}/${system.name}.info.%d{yyyy-MM-dd}.log.gz + ${log.history} + ${log.path}/%d{yyyy-MM, aux}/${log.name}.info.%d{yyyy-MM-dd}.log.gz - ${system.buffer} + ${log.buffer} false - ${system.charset} - ${system.pattern} + ${log.charset} + ${log.pattern} INFO @@ -52,22 +52,22 @@ - ${system.queue} + ${log.queue} true 0 - ${system.path}/${system.name}.error.log + ${log.path}/${log.name}.error.log - ${system.history} - ${system.path}/%d{yyyy-MM, aux}/${system.name}.error.%d{yyyy-MM-dd}.log.gz + ${log.history} + ${log.path}/%d{yyyy-MM, aux}/${log.name}.error.%d{yyyy-MM-dd}.log.gz - ${system.buffer} + ${log.buffer} false - ${system.charset} - ${system.pattern} + ${log.charset} + ${log.pattern} ERROR @@ -75,15 +75,15 @@ - ${system.queue} + ${log.queue} true 0 - ${system.charset} - ${system.pattern} + ${log.charset} + ${log.pattern} INFO diff --git a/taoyao-live/pom.xml b/taoyao-live/pom.xml index 633c0cd..dba5e74 100644 --- a/taoyao-live/pom.xml +++ b/taoyao-live/pom.xml @@ -18,8 +18,8 @@ - org.springframework.boot - spring-boot-starter-web + com.acgist + taoyao-signal diff --git a/taoyao-media/pom.xml b/taoyao-media/pom.xml index e67ef7c..0445f84 100644 --- a/taoyao-media/pom.xml +++ b/taoyao-media/pom.xml @@ -14,8 +14,29 @@ jar taoyao-media - 媒体:录制、视频(美颜、AI识别)、音频(混音、变声) + 媒体:录制、视频(美颜、AI识别)、音频(混音、变声、降噪) - + + + com.acgist + taoyao-webrtc-mcu + + + com.acgist + taoyao-webrtc-sfu + + + com.acgist + taoyao-webrtc-mesh + + + com.acgist + taoyao-webrtc-jitsi + + + com.acgist + taoyao-webrtc-kurento + + \ No newline at end of file diff --git a/taoyao-meeting/pom.xml b/taoyao-meeting/pom.xml index 6b454ab..289a424 100644 --- a/taoyao-meeting/pom.xml +++ b/taoyao-meeting/pom.xml @@ -18,13 +18,8 @@ - org.springdoc - springdoc-openapi-ui - true - - - org.springframework.boot - spring-boot-starter-web + com.acgist + taoyao-signal diff --git a/taoyao-meeting/src/main/java/com/acgist/taoyao/meeting/room/Room.java b/taoyao-meeting/src/main/java/com/acgist/taoyao/meeting/room/Room.java new file mode 100644 index 0000000..0dcf674 --- /dev/null +++ b/taoyao-meeting/src/main/java/com/acgist/taoyao/meeting/room/Room.java @@ -0,0 +1,10 @@ +package com.acgist.taoyao.meeting.room; + +/** + * 房间 + * + * @author acgist + */ +public class Room { + +} diff --git a/taoyao-nat/README.md b/taoyao-nat/README.md deleted file mode 100644 index 6b4627f..0000000 --- a/taoyao-nat/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# 内网穿透 - -请用公共STUN/TURN服务或者自行搭建coturn服务。 diff --git a/taoyao-nat/pom.xml b/taoyao-nat/pom.xml deleted file mode 100644 index c489356..0000000 --- a/taoyao-nat/pom.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - 4.0.0 - - - com.acgist - taoyao - 1.0.0 - - - taoyao-nat - jar - - taoyao-net - 内网穿透:STUN/TURN - - - - \ No newline at end of file diff --git a/taoyao-server/pom.xml b/taoyao-server/pom.xml index 442ad00..93f78b1 100644 --- a/taoyao-server/pom.xml +++ b/taoyao-server/pom.xml @@ -17,8 +17,8 @@ 服务:启动服务 - ${project.parent.basedir} - false + ${project.parent.basedir} + false @@ -34,18 +34,6 @@ com.acgist taoyao-meeting - - com.acgist - taoyao-webrtc-sfu - - - com.acgist - taoyao-webrtc-mcu - - - com.acgist - taoyao-webrtc-mesh - org.springdoc springdoc-openapi-ui diff --git a/taoyao-server/src/main/java/com/acgist/taoyao/controller/ConfigController.java b/taoyao-server/src/main/java/com/acgist/taoyao/controller/ConfigController.java index d3d6192..d965f0c 100644 --- a/taoyao-server/src/main/java/com/acgist/taoyao/controller/ConfigController.java +++ b/taoyao-server/src/main/java/com/acgist/taoyao/controller/ConfigController.java @@ -5,6 +5,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import com.acgist.taoyao.boot.config.MediaProperties; import com.acgist.taoyao.boot.config.WebrtcProperties; import io.swagger.v3.oas.annotations.Operation; @@ -20,9 +21,17 @@ import io.swagger.v3.oas.annotations.tags.Tag; @RequestMapping("/config") public class ConfigController { + @Autowired + private MediaProperties mediaProperties; @Autowired private WebrtcProperties webrtcProperties; + @Operation(summary = "媒体配置", description = "媒体配置") + @GetMapping("/media") + public MediaProperties media() { + return this.mediaProperties; + } + @Operation(summary = "WebRTC配置", description = "WebRTC配置") @GetMapping("/webrtc") public WebrtcProperties webrtc() { diff --git a/taoyao-server/src/main/resources/application.yml b/taoyao-server/src/main/resources/application.yml index 369adc8..39ddcae 100644 --- a/taoyao-server/src/main/resources/application.yml +++ b/taoyao-server/src/main/resources/application.yml @@ -53,8 +53,20 @@ taoyao: id: sn: 0 max-index: 999999 + media: + audio: + format: OPUS + samplesize: 16 + samplerate: 32000 + video: + format: H264 + bitrate: 1200 + framerate: 24 + resolution: 1280*760 + quality: high|standard|quick webrtc: - type: SFU + model: SFU + framework: JITSI stun: - stun:stun1.l.google.com:19302 - stun:stun2.l.google.com:19302 diff --git a/taoyao-server/src/main/resources/static/client.html b/taoyao-server/src/main/resources/static/client.html deleted file mode 100644 index 42676a7..0000000 --- a/taoyao-server/src/main/resources/static/client.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - -终端 - - - - - \ No newline at end of file diff --git a/taoyao-server/src/main/resources/static/css/font.min.css b/taoyao-server/src/main/resources/static/css/font.min.css new file mode 100644 index 0000000..a656ebe --- /dev/null +++ b/taoyao-server/src/main/resources/static/css/font.min.css @@ -0,0 +1 @@ +@font-face{font-family:taoyao;src:url(../fonts/taoyao.ttf?oc7k8r) format("truetype"),url(../fonts/taoyao.woff?oc7k8r) format("woff"),url(../fonts/taoyao.svg?oc7k8r#taoyao) format("svg");font-weight:400;font-style:normal;font-display:block}[class*=" icon-"],[class^=icon-]{font-family:taoyao!important;speak:never;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-home:before{content:"\e900"}.icon-home2:before{content:"\e901"}.icon-home3:before{content:"\e902"}.icon-office:before{content:"\e903"}.icon-newspaper:before{content:"\e904"}.icon-pencil:before{content:"\e905"}.icon-pencil2:before{content:"\e906"}.icon-quill:before{content:"\e907"}.icon-pen:before{content:"\e908"}.icon-blog:before{content:"\e909"}.icon-eyedropper:before{content:"\e90a"}.icon-droplet:before{content:"\e90b"}.icon-paint-format:before{content:"\e90c"}.icon-image:before{content:"\e90d"}.icon-images:before{content:"\e90e"}.icon-camera:before{content:"\e90f"}.icon-headphones:before{content:"\e910"}.icon-music:before{content:"\e911"}.icon-play:before{content:"\e912"}.icon-film:before{content:"\e913"}.icon-video-camera:before{content:"\e914"}.icon-dice:before{content:"\e915"}.icon-pacman:before{content:"\e916"}.icon-spades:before{content:"\e917"}.icon-clubs:before{content:"\e918"}.icon-diamonds:before{content:"\e919"}.icon-bullhorn:before{content:"\e91a"}.icon-connection:before{content:"\e91b"}.icon-podcast:before{content:"\e91c"}.icon-feed:before{content:"\e91d"}.icon-mic:before{content:"\e91e"}.icon-book:before{content:"\e91f"}.icon-books:before{content:"\e920"}.icon-library:before{content:"\e921"}.icon-file-text:before{content:"\e922"}.icon-profile:before{content:"\e923"}.icon-file-empty:before{content:"\e924"}.icon-files-empty:before{content:"\e925"}.icon-file-text2:before{content:"\e926"}.icon-file-picture:before{content:"\e927"}.icon-file-music:before{content:"\e928"}.icon-file-play:before{content:"\e929"}.icon-file-video:before{content:"\e92a"}.icon-file-zip:before{content:"\e92b"}.icon-copy:before{content:"\e92c"}.icon-paste:before{content:"\e92d"}.icon-stack:before{content:"\e92e"}.icon-folder:before{content:"\e92f"}.icon-folder-open:before{content:"\e930"}.icon-folder-plus:before{content:"\e931"}.icon-folder-minus:before{content:"\e932"}.icon-folder-download:before{content:"\e933"}.icon-folder-upload:before{content:"\e934"}.icon-price-tag:before{content:"\e935"}.icon-price-tags:before{content:"\e936"}.icon-barcode:before{content:"\e937"}.icon-qrcode:before{content:"\e938"}.icon-ticket:before{content:"\e939"}.icon-cart:before{content:"\e93a"}.icon-coin-dollar:before{content:"\e93b"}.icon-coin-euro:before{content:"\e93c"}.icon-coin-pound:before{content:"\e93d"}.icon-coin-yen:before{content:"\e93e"}.icon-credit-card:before{content:"\e93f"}.icon-calculator:before{content:"\e940"}.icon-lifebuoy:before{content:"\e941"}.icon-phone:before{content:"\e942"}.icon-phone-hang-up:before{content:"\e943"}.icon-address-book:before{content:"\e944"}.icon-envelop:before{content:"\e945"}.icon-pushpin:before{content:"\e946"}.icon-location:before{content:"\e947"}.icon-location2:before{content:"\e948"}.icon-compass:before{content:"\e949"}.icon-compass2:before{content:"\e94a"}.icon-map:before{content:"\e94b"}.icon-map2:before{content:"\e94c"}.icon-history:before{content:"\e94d"}.icon-clock:before{content:"\e94e"}.icon-clock2:before{content:"\e94f"}.icon-alarm:before{content:"\e950"}.icon-bell:before{content:"\e951"}.icon-stopwatch:before{content:"\e952"}.icon-calendar:before{content:"\e953"}.icon-printer:before{content:"\e954"}.icon-keyboard:before{content:"\e955"}.icon-display:before{content:"\e956"}.icon-laptop:before{content:"\e957"}.icon-mobile:before{content:"\e958"}.icon-mobile2:before{content:"\e959"}.icon-tablet:before{content:"\e95a"}.icon-tv:before{content:"\e95b"}.icon-drawer:before{content:"\e95c"}.icon-drawer2:before{content:"\e95d"}.icon-box-add:before{content:"\e95e"}.icon-box-remove:before{content:"\e95f"}.icon-download:before{content:"\e960"}.icon-upload:before{content:"\e961"}.icon-floppy-disk:before{content:"\e962"}.icon-drive:before{content:"\e963"}.icon-database:before{content:"\e964"}.icon-undo:before{content:"\e965"}.icon-redo:before{content:"\e966"}.icon-undo2:before{content:"\e967"}.icon-redo2:before{content:"\e968"}.icon-forward:before{content:"\e969"}.icon-reply:before{content:"\e96a"}.icon-bubble:before{content:"\e96b"}.icon-bubbles:before{content:"\e96c"}.icon-bubbles2:before{content:"\e96d"}.icon-bubble2:before{content:"\e96e"}.icon-bubbles3:before{content:"\e96f"}.icon-bubbles4:before{content:"\e970"}.icon-user:before{content:"\e971"}.icon-users:before{content:"\e972"}.icon-user-plus:before{content:"\e973"}.icon-user-minus:before{content:"\e974"}.icon-user-check:before{content:"\e975"}.icon-user-tie:before{content:"\e976"}.icon-quotes-left:before{content:"\e977"}.icon-quotes-right:before{content:"\e978"}.icon-hour-glass:before{content:"\e979"}.icon-spinner:before{content:"\e97a"}.icon-spinner2:before{content:"\e97b"}.icon-spinner3:before{content:"\e97c"}.icon-spinner4:before{content:"\e97d"}.icon-spinner5:before{content:"\e97e"}.icon-spinner6:before{content:"\e97f"}.icon-spinner7:before{content:"\e980"}.icon-spinner8:before{content:"\e981"}.icon-spinner9:before{content:"\e982"}.icon-spinner10:before{content:"\e983"}.icon-spinner11:before{content:"\e984"}.icon-binoculars:before{content:"\e985"}.icon-search:before{content:"\e986"}.icon-zoom-in:before{content:"\e987"}.icon-zoom-out:before{content:"\e988"}.icon-enlarge:before{content:"\e989"}.icon-shrink:before{content:"\e98a"}.icon-enlarge2:before{content:"\e98b"}.icon-shrink2:before{content:"\e98c"}.icon-key:before{content:"\e98d"}.icon-key2:before{content:"\e98e"}.icon-lock:before{content:"\e98f"}.icon-unlocked:before{content:"\e990"}.icon-wrench:before{content:"\e991"}.icon-equalizer:before{content:"\e992"}.icon-equalizer2:before{content:"\e993"}.icon-cog:before{content:"\e994"}.icon-cogs:before{content:"\e995"}.icon-hammer:before{content:"\e996"}.icon-magic-wand:before{content:"\e997"}.icon-aid-kit:before{content:"\e998"}.icon-bug:before{content:"\e999"}.icon-pie-chart:before{content:"\e99a"}.icon-stats-dots:before{content:"\e99b"}.icon-stats-bars:before{content:"\e99c"}.icon-stats-bars2:before{content:"\e99d"}.icon-trophy:before{content:"\e99e"}.icon-gift:before{content:"\e99f"}.icon-glass:before{content:"\e9a0"}.icon-glass2:before{content:"\e9a1"}.icon-mug:before{content:"\e9a2"}.icon-spoon-knife:before{content:"\e9a3"}.icon-leaf:before{content:"\e9a4"}.icon-rocket:before{content:"\e9a5"}.icon-meter:before{content:"\e9a6"}.icon-meter2:before{content:"\e9a7"}.icon-hammer2:before{content:"\e9a8"}.icon-fire:before{content:"\e9a9"}.icon-lab:before{content:"\e9aa"}.icon-magnet:before{content:"\e9ab"}.icon-bin:before{content:"\e9ac"}.icon-bin2:before{content:"\e9ad"}.icon-briefcase:before{content:"\e9ae"}.icon-airplane:before{content:"\e9af"}.icon-truck:before{content:"\e9b0"}.icon-road:before{content:"\e9b1"}.icon-accessibility:before{content:"\e9b2"}.icon-target:before{content:"\e9b3"}.icon-shield:before{content:"\e9b4"}.icon-power:before{content:"\e9b5"}.icon-switch:before{content:"\e9b6"}.icon-power-cord:before{content:"\e9b7"}.icon-clipboard:before{content:"\e9b8"}.icon-list-numbered:before{content:"\e9b9"}.icon-list:before{content:"\e9ba"}.icon-list2:before{content:"\e9bb"}.icon-tree:before{content:"\e9bc"}.icon-menu:before{content:"\e9bd"}.icon-menu2:before{content:"\e9be"}.icon-menu3:before{content:"\e9bf"}.icon-menu4:before{content:"\e9c0"}.icon-cloud:before{content:"\e9c1"}.icon-cloud-download:before{content:"\e9c2"}.icon-cloud-upload:before{content:"\e9c3"}.icon-cloud-check:before{content:"\e9c4"}.icon-download2:before{content:"\e9c5"}.icon-upload2:before{content:"\e9c6"}.icon-download3:before{content:"\e9c7"}.icon-upload3:before{content:"\e9c8"}.icon-sphere:before{content:"\e9c9"}.icon-earth:before{content:"\e9ca"}.icon-link:before{content:"\e9cb"}.icon-flag:before{content:"\e9cc"}.icon-attachment:before{content:"\e9cd"}.icon-eye:before{content:"\e9ce"}.icon-eye-plus:before{content:"\e9cf"}.icon-eye-minus:before{content:"\e9d0"}.icon-eye-blocked:before{content:"\e9d1"}.icon-bookmark:before{content:"\e9d2"}.icon-bookmarks:before{content:"\e9d3"}.icon-sun:before{content:"\e9d4"}.icon-contrast:before{content:"\e9d5"}.icon-brightness-contrast:before{content:"\e9d6"}.icon-star-empty:before{content:"\e9d7"}.icon-star-half:before{content:"\e9d8"}.icon-star-full:before{content:"\e9d9"}.icon-heart:before{content:"\e9da"}.icon-heart-broken:before{content:"\e9db"}.icon-man:before{content:"\e9dc"}.icon-woman:before{content:"\e9dd"}.icon-man-woman:before{content:"\e9de"}.icon-happy:before{content:"\e9df"}.icon-happy2:before{content:"\e9e0"}.icon-smile:before{content:"\e9e1"}.icon-smile2:before{content:"\e9e2"}.icon-tongue:before{content:"\e9e3"}.icon-tongue2:before{content:"\e9e4"}.icon-sad:before{content:"\e9e5"}.icon-sad2:before{content:"\e9e6"}.icon-wink:before{content:"\e9e7"}.icon-wink2:before{content:"\e9e8"}.icon-grin:before{content:"\e9e9"}.icon-grin2:before{content:"\e9ea"}.icon-cool:before{content:"\e9eb"}.icon-cool2:before{content:"\e9ec"}.icon-angry:before{content:"\e9ed"}.icon-angry2:before{content:"\e9ee"}.icon-evil:before{content:"\e9ef"}.icon-evil2:before{content:"\e9f0"}.icon-shocked:before{content:"\e9f1"}.icon-shocked2:before{content:"\e9f2"}.icon-baffled:before{content:"\e9f3"}.icon-baffled2:before{content:"\e9f4"}.icon-confused:before{content:"\e9f5"}.icon-confused2:before{content:"\e9f6"}.icon-neutral:before{content:"\e9f7"}.icon-neutral2:before{content:"\e9f8"}.icon-hipster:before{content:"\e9f9"}.icon-hipster2:before{content:"\e9fa"}.icon-wondering:before{content:"\e9fb"}.icon-wondering2:before{content:"\e9fc"}.icon-sleepy:before{content:"\e9fd"}.icon-sleepy2:before{content:"\e9fe"}.icon-frustrated:before{content:"\e9ff"}.icon-frustrated2:before{content:"\ea00"}.icon-crying:before{content:"\ea01"}.icon-crying2:before{content:"\ea02"}.icon-point-up:before{content:"\ea03"}.icon-point-right:before{content:"\ea04"}.icon-point-down:before{content:"\ea05"}.icon-point-left:before{content:"\ea06"}.icon-warning:before{content:"\ea07"}.icon-notification:before{content:"\ea08"}.icon-question:before{content:"\ea09"}.icon-plus:before{content:"\ea0a"}.icon-minus:before{content:"\ea0b"}.icon-info:before{content:"\ea0c"}.icon-cancel-circle:before{content:"\ea0d"}.icon-blocked:before{content:"\ea0e"}.icon-cross:before{content:"\ea0f"}.icon-checkmark:before{content:"\ea10"}.icon-checkmark2:before{content:"\ea11"}.icon-spell-check:before{content:"\ea12"}.icon-enter:before{content:"\ea13"}.icon-exit:before{content:"\ea14"}.icon-play2:before{content:"\ea15"}.icon-pause:before{content:"\ea16"}.icon-stop:before{content:"\ea17"}.icon-previous:before{content:"\ea18"}.icon-next:before{content:"\ea19"}.icon-backward:before{content:"\ea1a"}.icon-forward2:before{content:"\ea1b"}.icon-play3:before{content:"\ea1c"}.icon-pause2:before{content:"\ea1d"}.icon-stop2:before{content:"\ea1e"}.icon-backward2:before{content:"\ea1f"}.icon-forward3:before{content:"\ea20"}.icon-first:before{content:"\ea21"}.icon-last:before{content:"\ea22"}.icon-previous2:before{content:"\ea23"}.icon-next2:before{content:"\ea24"}.icon-eject:before{content:"\ea25"}.icon-volume-high:before{content:"\ea26"}.icon-volume-medium:before{content:"\ea27"}.icon-volume-low:before{content:"\ea28"}.icon-volume-mute:before{content:"\ea29"}.icon-volume-mute2:before{content:"\ea2a"}.icon-volume-increase:before{content:"\ea2b"}.icon-volume-decrease:before{content:"\ea2c"}.icon-loop:before{content:"\ea2d"}.icon-loop2:before{content:"\ea2e"}.icon-infinite:before{content:"\ea2f"}.icon-shuffle:before{content:"\ea30"}.icon-arrow-up-left:before{content:"\ea31"}.icon-arrow-up:before{content:"\ea32"}.icon-arrow-up-right:before{content:"\ea33"}.icon-arrow-right:before{content:"\ea34"}.icon-arrow-down-right:before{content:"\ea35"}.icon-arrow-down:before{content:"\ea36"}.icon-arrow-down-left:before{content:"\ea37"}.icon-arrow-left:before{content:"\ea38"}.icon-arrow-up-left2:before{content:"\ea39"}.icon-arrow-up2:before{content:"\ea3a"}.icon-arrow-up-right2:before{content:"\ea3b"}.icon-arrow-right2:before{content:"\ea3c"}.icon-arrow-down-right2:before{content:"\ea3d"}.icon-arrow-down2:before{content:"\ea3e"}.icon-arrow-down-left2:before{content:"\ea3f"}.icon-arrow-left2:before{content:"\ea40"}.icon-circle-up:before{content:"\ea41"}.icon-circle-right:before{content:"\ea42"}.icon-circle-down:before{content:"\ea43"}.icon-circle-left:before{content:"\ea44"}.icon-tab:before{content:"\ea45"}.icon-move-up:before{content:"\ea46"}.icon-move-down:before{content:"\ea47"}.icon-sort-alpha-asc:before{content:"\ea48"}.icon-sort-alpha-desc:before{content:"\ea49"}.icon-sort-numeric-asc:before{content:"\ea4a"}.icon-sort-numberic-desc:before{content:"\ea4b"}.icon-sort-amount-asc:before{content:"\ea4c"}.icon-sort-amount-desc:before{content:"\ea4d"}.icon-command:before{content:"\ea4e"}.icon-shift:before{content:"\ea4f"}.icon-ctrl:before{content:"\ea50"}.icon-opt:before{content:"\ea51"}.icon-checkbox-checked:before{content:"\ea52"}.icon-checkbox-unchecked:before{content:"\ea53"}.icon-radio-checked:before{content:"\ea54"}.icon-radio-checked2:before{content:"\ea55"}.icon-radio-unchecked:before{content:"\ea56"}.icon-crop:before{content:"\ea57"}.icon-make-group:before{content:"\ea58"}.icon-ungroup:before{content:"\ea59"}.icon-scissors:before{content:"\ea5a"}.icon-filter:before{content:"\ea5b"}.icon-font:before{content:"\ea5c"}.icon-ligature:before{content:"\ea5d"}.icon-ligature2:before{content:"\ea5e"}.icon-text-height:before{content:"\ea5f"}.icon-text-width:before{content:"\ea60"}.icon-font-size:before{content:"\ea61"}.icon-bold:before{content:"\ea62"}.icon-underline:before{content:"\ea63"}.icon-italic:before{content:"\ea64"}.icon-strikethrough:before{content:"\ea65"}.icon-omega:before{content:"\ea66"}.icon-sigma:before{content:"\ea67"}.icon-page-break:before{content:"\ea68"}.icon-superscript:before{content:"\ea69"}.icon-subscript:before{content:"\ea6a"}.icon-superscript2:before{content:"\ea6b"}.icon-subscript2:before{content:"\ea6c"}.icon-text-color:before{content:"\ea6d"}.icon-pagebreak:before{content:"\ea6e"}.icon-clear-formatting:before{content:"\ea6f"}.icon-table:before{content:"\ea70"}.icon-table2:before{content:"\ea71"}.icon-insert-template:before{content:"\ea72"}.icon-pilcrow:before{content:"\ea73"}.icon-ltr:before{content:"\ea74"}.icon-rtl:before{content:"\ea75"}.icon-section:before{content:"\ea76"}.icon-paragraph-left:before{content:"\ea77"}.icon-paragraph-center:before{content:"\ea78"}.icon-paragraph-right:before{content:"\ea79"}.icon-paragraph-justify:before{content:"\ea7a"}.icon-indent-increase:before{content:"\ea7b"}.icon-indent-decrease:before{content:"\ea7c"}.icon-share:before{content:"\ea7d"}.icon-new-tab:before{content:"\ea7e"}.icon-embed:before{content:"\ea7f"}.icon-embed2:before{content:"\ea80"}.icon-terminal:before{content:"\ea81"}.icon-share2:before{content:"\ea82"}.icon-mail:before{content:"\ea83"}.icon-mail2:before{content:"\ea84"}.icon-mail3:before{content:"\ea85"}.icon-mail4:before{content:"\ea86"}.icon-amazon:before{content:"\ea87"}.icon-google:before{content:"\ea88"}.icon-google2:before{content:"\ea89"}.icon-google3:before{content:"\ea8a"}.icon-google-plus:before{content:"\ea8b"}.icon-google-plus2:before{content:"\ea8c"}.icon-google-plus3:before{content:"\ea8d"}.icon-hangouts:before{content:"\ea8e"}.icon-google-drive:before{content:"\ea8f"}.icon-facebook:before{content:"\ea90"}.icon-facebook2:before{content:"\ea91"}.icon-instagram:before{content:"\ea92"}.icon-whatsapp:before{content:"\ea93"}.icon-spotify:before{content:"\ea94"}.icon-telegram:before{content:"\ea95"}.icon-twitter:before{content:"\ea96"}.icon-vine:before{content:"\ea97"}.icon-vk:before{content:"\ea98"}.icon-renren:before{content:"\ea99"}.icon-sina-weibo:before{content:"\ea9a"}.icon-rss:before{content:"\ea9b"}.icon-rss2:before{content:"\ea9c"}.icon-youtube:before{content:"\ea9d"}.icon-youtube2:before{content:"\ea9e"}.icon-twitch:before{content:"\ea9f"}.icon-vimeo:before{content:"\eaa0"}.icon-vimeo2:before{content:"\eaa1"}.icon-lanyrd:before{content:"\eaa2"}.icon-flickr:before{content:"\eaa3"}.icon-flickr2:before{content:"\eaa4"}.icon-flickr3:before{content:"\eaa5"}.icon-flickr4:before{content:"\eaa6"}.icon-dribbble:before{content:"\eaa7"}.icon-behance:before{content:"\eaa8"}.icon-behance2:before{content:"\eaa9"}.icon-deviantart:before{content:"\eaaa"}.icon-500px:before{content:"\eaab"}.icon-steam:before{content:"\eaac"}.icon-steam2:before{content:"\eaad"}.icon-dropbox:before{content:"\eaae"}.icon-onedrive:before{content:"\eaaf"}.icon-github:before{content:"\eab0"}.icon-npm:before{content:"\eab1"}.icon-basecamp:before{content:"\eab2"}.icon-trello:before{content:"\eab3"}.icon-wordpress:before{content:"\eab4"}.icon-joomla:before{content:"\eab5"}.icon-ello:before{content:"\eab6"}.icon-blogger:before{content:"\eab7"}.icon-blogger2:before{content:"\eab8"}.icon-tumblr:before{content:"\eab9"}.icon-tumblr2:before{content:"\eaba"}.icon-yahoo:before{content:"\eabb"}.icon-yahoo2:before{content:"\eabc"}.icon-tux:before{content:"\eabd"}.icon-appleinc:before{content:"\eabe"}.icon-finder:before{content:"\eabf"}.icon-android:before{content:"\eac0"}.icon-windows:before{content:"\eac1"}.icon-windows8:before{content:"\eac2"}.icon-soundcloud:before{content:"\eac3"}.icon-soundcloud2:before{content:"\eac4"}.icon-skype:before{content:"\eac5"}.icon-reddit:before{content:"\eac6"}.icon-hackernews:before{content:"\eac7"}.icon-wikipedia:before{content:"\eac8"}.icon-linkedin:before{content:"\eac9"}.icon-linkedin2:before{content:"\eaca"}.icon-lastfm:before{content:"\eacb"}.icon-lastfm2:before{content:"\eacc"}.icon-delicious:before{content:"\eacd"}.icon-stumbleupon:before{content:"\eace"}.icon-stumbleupon2:before{content:"\eacf"}.icon-stackoverflow:before{content:"\ead0"}.icon-pinterest:before{content:"\ead1"}.icon-pinterest2:before{content:"\ead2"}.icon-xing:before{content:"\ead3"}.icon-xing2:before{content:"\ead4"}.icon-flattr:before{content:"\ead5"}.icon-foursquare:before{content:"\ead6"}.icon-yelp:before{content:"\ead7"}.icon-paypal:before{content:"\ead8"}.icon-chrome:before{content:"\ead9"}.icon-firefox:before{content:"\eada"}.icon-IE:before{content:"\eadb"}.icon-edge:before{content:"\eadc"}.icon-safari:before{content:"\eadd"}.icon-opera:before{content:"\eade"}.icon-file-pdf:before{content:"\eadf"}.icon-file-openoffice:before{content:"\eae0"}.icon-file-word:before{content:"\eae1"}.icon-file-excel:before{content:"\eae2"}.icon-libreoffice:before{content:"\eae3"}.icon-html-five:before{content:"\eae4"}.icon-html-five2:before{content:"\eae5"}.icon-css3:before{content:"\eae6"}.icon-git:before{content:"\eae7"}.icon-codepen:before{content:"\eae8"}.icon-svg:before{content:"\eae9"}.icon-IcoMoon:before{content:"\eaea"} \ No newline at end of file diff --git a/taoyao-server/src/main/resources/static/css/style.css b/taoyao-server/src/main/resources/static/css/style.css new file mode 100644 index 0000000..d69ee02 --- /dev/null +++ b/taoyao-server/src/main/resources/static/css/style.css @@ -0,0 +1,36 @@ +@charset "UTF-8"; +/**文本选择*/ +::selection{background:#222;color:#fff;} +/**字体大小*/ +@media screen and (min-width:800px){html{font-size:16px;}} +@media screen and (min-width:1200px){html{font-size:18px;}} +@media screen and (min-width:1600px){html{font-size:20px;}} +/**默认样式*/ +*{margin:0;padding:0;border:none;outline:none;box-sizing:content-box;} +html{background:#EBEBEB;} +html,body{font-family:Arial,Consolas,SimSun,"宋体";color:#222;font-weight:normal;} +body{width:100%;height:100%;-webkit-tap-highlight-color:rgba(0,0,0,0);font-size:1rem;line-height:1.4em;} +a{color:#1155AA;text-decoration:none;} +a:link{text-decoration:none;} +a:hover{color:#4477EE;text-decoration:none;} +a:visited{text-decoration:none;} +img{border:0;} +ol,ul,li{list-style:none;} +input[type=text],textarea{box-shadow:0px 0px 3px 0px rgba(0,0,0,0.1) inset;border:1px solid rgba(0,0,0,0.1)!important;} +input[type=text]:focus,textarea:focus,input[type=text]:hover,textarea:hover{border:1px solid #1155AA!important;} +input::-webkit-calendar-picker-indicator{color:#1155AA;background:none;} +/**容器*/ +.taoyao{text-align:center;} +/**直播*/ +.taoyao .live > .video{width:100%;height:100%;} +.taoyao .live .handler{position:fixed;width:100%;bottom:2rem;font-size:2rem;} +/**会议*/ +.taoyao .handler a{cursor:pointer;} +.taoyao > .handler{font-size:2rem;padding:1rem 0;width:100%;} +.taoyao .list{width:90vw;margin:auto;} +.taoyao .meeting{float:left;overflow:hidden;position:relative;width:calc(25% - 2rem);border:1rem solid #fff;} +.taoyao .me,.taoyao .meeting:hover{border-color:#060;} +.taoyao .meeting > .video{height:15vw;} +.taoyao .meeting > .video video{width:100%;height:100%;} +.taoyao .meeting .handler{position:absolute;bottom:0rem;text-align:center;width:100%;background:rgba(0,0,0,0.2);padding:0.2rem 0;} +.taoyao .meeting .handler a{color:#fff;} diff --git a/taoyao-server/src/main/resources/static/fonts/taoyao.svg b/taoyao-server/src/main/resources/static/fonts/taoyao.svg new file mode 100644 index 0000000..b9f52b6 --- /dev/null +++ b/taoyao-server/src/main/resources/static/fonts/taoyao.svg @@ -0,0 +1,501 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/taoyao-server/src/main/resources/static/fonts/taoyao.ttf b/taoyao-server/src/main/resources/static/fonts/taoyao.ttf new file mode 100644 index 0000000..99a412b Binary files /dev/null and b/taoyao-server/src/main/resources/static/fonts/taoyao.ttf differ diff --git a/taoyao-server/src/main/resources/static/fonts/taoyao.woff b/taoyao-server/src/main/resources/static/fonts/taoyao.woff new file mode 100644 index 0000000..56bbac8 Binary files /dev/null and b/taoyao-server/src/main/resources/static/fonts/taoyao.woff differ diff --git a/taoyao-server/src/main/resources/static/index.html b/taoyao-server/src/main/resources/static/index.html index 18bf524..0b8b9ed 100644 --- a/taoyao-server/src/main/resources/static/index.html +++ b/taoyao-server/src/main/resources/static/index.html @@ -3,8 +3,16 @@ 桃夭 + + + - + 直播 + 会议 \ No newline at end of file diff --git a/taoyao-server/src/main/resources/static/javascript/taoyao.js b/taoyao-server/src/main/resources/static/javascript/taoyao.js new file mode 100644 index 0000000..65316c3 --- /dev/null +++ b/taoyao-server/src/main/resources/static/javascript/taoyao.js @@ -0,0 +1,327 @@ +/** + * 桃夭WebRTC终端示例 + */ +/** 音频配置 */ +const defaultAudioConfig = { + // 音量:0~1 + volume: 0.5, + // 设备 + // deviceId : '', + // 采样率:8000|16000|32000|48000 + sampleRate: 32000, + // 采样数:16 + sampleSize: 16, + // 延迟大小(单位毫秒):500毫秒以内较好 + latency: 0.3, + // 声道数量:1|2 + channelCount : 1, + // 是否开启自动增益:true|false + autoGainControl: false, + // 是否开启降噪功能:true|false + noiseSuppression: true, + // 是否开启回音消除:true|false + echoCancellation: true, + // 消除回音方式:system|browser + echoCancellationType: 'system' +}; +/** 视频配置 */ +const defaultVideoConfig = { + // 宽度 + width: 1280, + // 高度 + height: 720, + // 设备 + // deviceId: '', + // 帧率 + frameRate: 30, + // 裁切 + // resizeMode: '', + // 选摄像头:user|left|right|environment + facingMode: 'environment' +} +/** 兼容 */ +const PeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection; +/** 桃夭 */ +function Taoyao( + webSocket, + iceServer +) { + this.webSocket = webSocket; + this.iceServer = iceServer; + this.audioStatus = true; + this.videoStatus = true; + this.audioStreamId = null; + this.videoStreamId = null; + this.audioConfig = defaultAudioConfig; + this.videoConfig = defaultVideoConfig; + /** 初始 */ + this.init = function() { + if(navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) { + navigator.mediaDevices.enumerateDevices() + .then(list => { + let audioDevice = false; + let videoDevice = false; + list.forEach(v => { + console.log('终端媒体设备', v.kind, v.label); + if(v.kind === 'audioinput') { + audioDevice = true; + } else if(v.kind === 'videoinput') { + videoDevice = true; + } + }); + if(!audioDevice) { + console.log('终端没有音频输入设备'); + this.audioConfig = false; + } + if(!videoDevice) { + console.log('终端没有视频输入设备'); + this.videoConfig = false; + } + }) + .catch(e => console.log('获取终端设备失败', e)); + } + return this; + }; + /** 媒体 */ + this.buildUserMedia = function() { + return new Promise((resolve, reject) => { + console.log("获取终端媒体:", this.audioConfig, this.videoConfig); + if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { + navigator.mediaDevices.getUserMedia({ + audio: this.audioConfig, + video: this.videoConfig + }) + .then(resolve) + .catch(reject); + } else if(navigator.getUserMedia) { + navigator.getUserMedia({ + audio: this.audioConfig, + video: this.videoConfig + }, resolve, reject); + } else { + reject("获取终端媒体失败"); + } + }); + }; + /** 本地 */ + this.local = async function(localVideoId, stream) { + const localVideo = document.getElementById(localVideoId); + if ('srcObject' in localVideo) { + localVideo.srcObject = stream; + } else { + localVideo.src = URL.createObjectURL(stream);; + } + await localVideo.play(); + }; + /** 连接 */ + this.connect = function() { + }; + /** 重连 */ + /** 定时 */ + /** 媒体 */ + /** 视频 */ + /** 心跳 */ +} +/* +var peer; +var socket; // WebSocket +var supportStream = false; // 是否支持使用数据流 +var localVideo; // 本地视频 +var localVideoStream; // 本地视频流 +var remoteVideo; // 远程视频 +var remoteVideoStream; // 远程视频流 +var initiator = false; // 是否已经有人在等待 +var started = false; // 是否开始 +var channelReady = false; // 是否打开WebSocket通道 +// 初始 +function initialize() { + console.log("初始聊天"); + // 获取视频 + localVideo = document.getElementById("localVideo"); + remoteVideo = document.getElementById("remoteVideo"); + supportStream = "srcObject" in localVideo; + // 显示状态 + if (initiator) { + setNotice("开始连接"); + } else { + setNotice("加入聊天:https://www.acgist.com/demo/video/?oid=FFB85D84AC56DAF88B7E22AFFA7533D3"); + } + // 打开WebSocket + openChannel(); + // 创建终端媒体 + buildUserMedia(); +} +function openChannel() { + console.log("打开WebSocket"); + socket = new WebSocket("wss://www.acgist.com/video.ws/FFB85D84AC56DAF88B7E22AFFA7533D3"); + socket.onopen = channelOpened; + socket.onmessage = channelMessage; + socket.onclose = channelClosed; + socket.onerror = channelError; +} +function channelOpened() { + console.log("打开WebSocket成功"); + channelReady = true; +} +function channelMessage(message) { + console.log("收到消息:" + message.data); + var msg = JSON.parse(message.data); + if (msg.type === "offer") { // 处理Offer消息 + if (!initiator && !started) { + connectPeer(); + } + peer.setRemoteDescription(new RTCSessionDescription(msg)); + peer.createAnswer().then(buildLocalDescription); + } else if (msg.type === "answer" && started) { // 处理Answer消息 + peer.setRemoteDescription(new RTCSessionDescription(msg)); + } else if (msg.type === "candidate" && started) { + var candidate = new RTCIceCandidate({ + sdpMLineIndex : msg.label, + candidate : msg.candidate + }); + peer.addIceCandidate(candidate); + } else if (msg.type === "bye" && started) { + onRemoteClose(); + setNotice("对方已断开!"); + } else if(msg.type === "nowaiting") { + onRemoteClose(); + setNotice("对方已离开!"); + } +} +function channelClosed() { + console.log("关闭WebSocket"); + openChannel(); // 重新打开WebSocket +} +function channelError(event) { + console.log("WebSocket异常:" + event); +} +function buildUserMedia() { + console.log("获取终端媒体"); + if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { + navigator.mediaDevices.getUserMedia({ + "audio" : true, + "video" : true + }) + .then(onUserMediaSuccess) + .catch(onUserMediaError); + } else { + navigator.getUserMedia({ + "audio" : true, + "video" : true + }, onUserMediaSuccess, onUserMediaError); + } +} +function onUserMediaSuccess(stream) { + localVideoStream = stream; + if (supportStream) { + localVideo.srcObject = localVideoStream; + } else { + localVideo.src = URL.createObjectURL(localVideoStream); + } + if (initiator) { + connectPeer(); + } +} +function onUserMediaError(error) { + alert("请打开摄像头!"); +} +function connectPeer() { + if (!started && localVideoStream && channelReady) { + console.log("开始连接Peer"); + started = true; + buildPeerConnection(); + peer.addStream(localVideoStream); + if (initiator) { + peer.createOffer().then(buildLocalDescription); + } + } +} +function buildPeerConnection() { + //var server = {"iceServers" : [{"url" : "stun:stun.l.google.com:19302"}]}; + var server = {"iceServers" : [{"url" : "stun:stun1.l.google.com:19302"}]}; + peer = new PeerConnection(server); + peer.onicecandidate = peerIceCandidate; + peer.onconnecting = peerConnecting; + peer.onopen = peerOpened; + peer.onaddstream = peerAddStream; + peer.onremovestream = peerRemoveStream; +} +function peerIceCandidate(event) { + if (event.candidate) { + sendMessage({ + type : "candidate", + id : event.candidate.sdpMid, + label : event.candidate.sdpMLineIndex, + candidate : event.candidate.candidate + }); + } else { + console.log("不支持的candidate"); + } +} +function peerConnecting(message) { + console.log("Peer连接"); +} +function peerOpened(message) { + console.log("Peer打开"); +} +function peerAddStream(event) { + console.log("远程视频添加"); + remoteVideoStream = event.stream; + if(supportStream) { + remoteVideo.srcObject = remoteVideoStream; + } else { + remoteVideo.src = URL.createObjectURL(remoteVideoStream); + } + setNotice("连接成功"); + waitForRemoteVideo(); +} +function peerRemoveStream(event) { + console.log("远程视频移除"); +} +function buildLocalDescription(description) { + peer.setLocalDescription(description); + sendMessage(description); +} +function sendMessage(message) { + var msgJson = JSON.stringify(message); + socket.send(msgJson); + console.log("发送信息:" + msgJson); +} +function setNotice(msg) { + document.getElementById("footer").innerHTML = msg; +} +function onRemoteClose() { + started = false; + initiator = false; + if(supportStream) { + remoteVideo.srcObject = null; + } else { + remoteVideo.src = null; + } + peer.close(); +} +function waitForRemoteVideo() { + if (remoteVideo.currentTime > 0) { // 判断远程视频长度 + setNotice("连接成功!"); + } else { + setTimeout(waitForRemoteVideo, 100); + } +} +window.onbeforeunload = function() { + sendMessage({type : "bye"}); + if(peer) { + peer.close(); + } + socket.close(); +} +if(!WebSocket) { + alert("你的浏览器不支持WebSocket!"); +} else if(!PeerConnection) { + alert("你的浏览器不支持RTCPeerConnection!"); +} else { + setTimeout(initialize, 100); // 加载完成调用初始化方法 +} +window.onbeforeunload = function() { + socket.close(); +} +*/ \ No newline at end of file diff --git a/taoyao-server/src/main/resources/static/live.html b/taoyao-server/src/main/resources/static/live.html new file mode 100644 index 0000000..3c54656 --- /dev/null +++ b/taoyao-server/src/main/resources/static/live.html @@ -0,0 +1,28 @@ + + + + +直播 + + + + + +
+
+
+
+
+ + + + + +
+
+
+ + + \ No newline at end of file diff --git a/taoyao-server/src/main/resources/static/meeting.html b/taoyao-server/src/main/resources/static/meeting.html new file mode 100644 index 0000000..7ea8301 --- /dev/null +++ b/taoyao-server/src/main/resources/static/meeting.html @@ -0,0 +1,60 @@ + + + + +会议 + + + + + +
+
+ + + + + +
+
+
+
+ +
+
+ + + + +
+
+
+
+ + + \ No newline at end of file diff --git a/taoyao-server/src/main/resources/static/room.html b/taoyao-server/src/main/resources/static/room.html deleted file mode 100644 index f9cfbfe..0000000 --- a/taoyao-server/src/main/resources/static/room.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - -房间 - - - - - \ No newline at end of file diff --git a/taoyao-signal/pom.xml b/taoyao-signal/pom.xml index 49d3adb..5965627 100644 --- a/taoyao-signal/pom.xml +++ b/taoyao-signal/pom.xml @@ -19,7 +19,7 @@ com.acgist - taoyao-boot + taoyao-media org.springframework.boot diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/config/SignalAutoConfiguration.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/config/SignalAutoConfiguration.java index 090ff50..24bfb65 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/config/SignalAutoConfiguration.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/config/SignalAutoConfiguration.java @@ -3,6 +3,7 @@ package com.acgist.taoyao.signal.config; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.server.standard.ServerEndpointExporter; import com.acgist.taoyao.signal.session.websocket.WebSocketSignal; @@ -13,6 +14,7 @@ import com.acgist.taoyao.signal.session.websocket.WebSocketSignal; * @author acgist */ @Configuration +@EnableWebSocket public class SignalAutoConfiguration { @Bean diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaHandler.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaHandler.java index 4cab741..df19260 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaHandler.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaHandler.java @@ -9,22 +9,30 @@ public interface ClientMediaHandler { /** * 打开 + * + * @param id 终端媒体流ID */ void open(String id); /** * 暂停 + * + * @param id 终端媒体流ID */ - void pause(); + void pause(String id); /** * 恢复 + * + * @param id 终端媒体流ID */ - void resume(); + void resume(String id); /** * 关闭 + * + * @param id 终端媒体流ID */ - void close(); + void close(String id); } diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaPublisher.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaPublisher.java index 3283317..7bc9d03 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaPublisher.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaPublisher.java @@ -1,14 +1,81 @@ package com.acgist.taoyao.signal.media; -/** - * 终端推流 - */ -public class ClientMediaPublisher { +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import com.acgist.taoyao.signal.media.stream.ClientMediaStream; + +import lombok.extern.slf4j.Slf4j; + +/** + * 终端媒体流发布者(终端推流) + * + * @author acgist + */ +@Slf4j +public class ClientMediaPublisher implements ClientMediaHandler { + + /** + * 发布终端媒体流 + */ + private Map streams = new ConcurrentHashMap<>(); + + + /** + * 发布 + * + * @param id 终端媒体流ID + * + * @see #open(String) + */ public void publish(String id) { + this.open(id); } + /** + * 取消发布 + * + * @param id 终端媒体流ID + * + * @see #close(String) + */ public void unpublish(String id) { + this.close(id); + } + + @Override + public void open(String id) { + // TODO Auto-generated method stub + + } + + @Override + public void pause(String id) { + // TODO Auto-generated method stub + + } + + @Override + public void resume(String id) { + final ClientMediaStream stream = this.streams.get(id); + if(stream != null) { + try { + stream.resume(); + } catch (IOException e) { + log.error("终端媒体流恢复异常:{}", id, e); + } + } + } + + @Override + public void close(String id) { + final ClientMediaStream stream = this.streams.get(id); + try { + stream.close(); + } catch (IOException e) { + log.error("终端媒体流关闭异常:{}", id, e); + } } } diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaSubscriber.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaSubscriber.java index 4531dcb..9322c5a 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaSubscriber.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/ClientMediaSubscriber.java @@ -1,5 +1,10 @@ package com.acgist.taoyao.signal.media; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import com.acgist.taoyao.signal.media.stream.ClientMediaStream; + /** * 终端媒体订阅者(终端拉流) * @@ -7,10 +12,31 @@ package com.acgist.taoyao.signal.media; */ public class ClientMediaSubscriber implements ClientMediaHandler { + /** + * 订阅终端媒体流 + */ + private List streams = new CopyOnWriteArrayList<>(); + + /** + * 订阅 + * + * @param id 终端媒体流ID + * + * @see #open(String) + */ public void subscribe(String id) { + this.open(id); } + /** + * 取消订阅 + * + * @param id 终端媒体流ID + * + * @see #close(String) + */ public void unsubscribe(String id) { + this.close(id); } @Override @@ -20,19 +46,19 @@ public class ClientMediaSubscriber implements ClientMediaHandler { } @Override - public void pause() { + public void pause(String id) { // TODO Auto-generated method stub } @Override - public void resume() { + public void resume(String id) { // TODO Auto-generated method stub } @Override - public void close() { + public void close(String id) { // TODO Auto-generated method stub } diff --git a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/stream/ClientMediaStream.java b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/stream/ClientMediaStream.java index bc2616b..8ec5de7 100644 --- a/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/stream/ClientMediaStream.java +++ b/taoyao-signal/src/main/java/com/acgist/taoyao/signal/media/stream/ClientMediaStream.java @@ -1,5 +1,7 @@ package com.acgist.taoyao.signal.media.stream; +import java.io.IOException; + /** * 终端媒体流 * @@ -58,23 +60,31 @@ public interface ClientMediaStream { /** * 打开终端媒体流 + * + * @throws IO异常 */ - void open(); + void open() throws IOException; /** * 暂停终端媒体流 + * + * @throws IO异常 */ - void pause(); + void pause() throws IOException; /** * 恢复终端媒体流 + * + * @throws IO异常 */ - void resume(); + void resume() throws IOException; /** * 关闭终端媒体流 + * + * @throws IO异常 */ - void close(); + void close() throws IOException; /** * @return 终端媒体流类型 diff --git a/taoyao-webrtc/README.md b/taoyao-webrtc/README.md index ce1c112..e16485d 100644 --- a/taoyao-webrtc/README.md +++ b/taoyao-webrtc/README.md @@ -1,7 +1,57 @@ # WebRTC -## 安装 +## WebRTC协议栈 -## 观察者 +|协议|描述| +|:--|:--| +|UDP|基础协议| +|DTLS|UDP数据包传输层安全性协议| +|RTP|实时传输协议(音频视频)| +|SRTP|RTP + DTLS| +|RTCP|RTP传输控制协议(监控数据传输质量并给予数据发送方反馈)| +|SRTCP|RTCP + DTLS| +|SCTP|流控制传输协议(自定义的应用数据传输)| +|STUN/TURN|内网穿透协议| -订阅发布 +## ICE/SIP/SDP + +ICE信息的描述格式通常采用标准的SDP,其全称为Session Description Protocol,即会话描述协议。 +SDP只是一种信息格式的描述标准,不属于传输协议,但是可以被其他传输协议用来交换必要的信息,例如:SIP、RTSP等等。 + +## 协议关系 + +``` ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| HTTPS/WSS | | SCTP | SRTP/SRTCP | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ICE/SIP/SDP +-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| TLS | | DTLS | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| HTTP/WS | STUN/TURN | RTP/RTCP | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| TCP | UDP | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| IPv4/IPv6 | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +``` + +## 其他协议 + +|协议|描述| +|:--|:--| +|HLS|基于HTTP的自适应码率流媒体传输协议| +|RTSP|可以控制媒体(点播)| +|RTMP|实时消息传送协议| + +## 通道 + +|通道类型|协议| +|:--|:--| +|信令通道|自己实现| +|会话通道|SIP/SDP| +|媒体通道|RTP/RTCP/SRTP/SRTCP| + +## WebRTC资料 + +[GB28181](https://blog.csdn.net/jisuanji111111/article/details/121634199) +[WebRTC协议](http://www.manoner.com/post/音视频基础/WebRTC核心组件和协议栈/) +[WebRTC开源项目](https://blog.csdn.net/ababab12345/article/details/115585378) diff --git a/taoyao-webrtc/pom.xml b/taoyao-webrtc/pom.xml index 7eb2e3d..79dbf4c 100644 --- a/taoyao-webrtc/pom.xml +++ b/taoyao-webrtc/pom.xml @@ -17,10 +17,18 @@ WebRTC模块 - taoyao-webrtc-jni taoyao-webrtc-sfu taoyao-webrtc-mcu taoyao-webrtc-mesh + taoyao-webrtc-jitsi + taoyao-webrtc-kurento - + + + + com.acgist + taoyao-boot + + + \ No newline at end of file diff --git a/taoyao-webrtc/taoyao-webrtc-jitsi/README.md b/taoyao-webrtc/taoyao-webrtc-jitsi/README.md new file mode 100644 index 0000000..e69de29 diff --git a/taoyao-webrtc/taoyao-webrtc-jitsi/pom.xml b/taoyao-webrtc/taoyao-webrtc-jitsi/pom.xml new file mode 100644 index 0000000..6d4f064 --- /dev/null +++ b/taoyao-webrtc/taoyao-webrtc-jitsi/pom.xml @@ -0,0 +1,30 @@ + + + + + 4.0.0 + + + com.acgist + taoyao-webrtc + 1.0.0 + + + taoyao-webrtc-jitsi + jar + + taoyao-webrtc-jitsi + WebRTC协议簇实现:jitsi + + + + org.jitsi + ice4j + + + org.jitsi + libjitsi + + + + \ No newline at end of file diff --git a/taoyao-webrtc/taoyao-webrtc-kurento/README.md b/taoyao-webrtc/taoyao-webrtc-kurento/README.md new file mode 100644 index 0000000..e69de29 diff --git a/taoyao-webrtc/taoyao-webrtc-jni/pom.xml b/taoyao-webrtc/taoyao-webrtc-kurento/pom.xml similarity index 65% rename from taoyao-webrtc/taoyao-webrtc-jni/pom.xml rename to taoyao-webrtc/taoyao-webrtc-kurento/pom.xml index a81f0f8..e823445 100644 --- a/taoyao-webrtc/taoyao-webrtc-jni/pom.xml +++ b/taoyao-webrtc/taoyao-webrtc-kurento/pom.xml @@ -10,13 +10,17 @@ 1.0.0 - taoyao-webrtc-jni + taoyao-webrtc-kurento jar - taoyao-webrtc-jni - WebRTC JNI:WebRTC本地接口 + taoyao-webrtc-kurento + WebRTC协议簇实现:kurento + + org.kurento + kurento-client + \ No newline at end of file diff --git a/taoyao-webrtc/taoyao-webrtc-mcu/pom.xml b/taoyao-webrtc/taoyao-webrtc-mcu/pom.xml index 47581d4..f73295e 100644 --- a/taoyao-webrtc/taoyao-webrtc-mcu/pom.xml +++ b/taoyao-webrtc/taoyao-webrtc-mcu/pom.xml @@ -19,7 +19,11 @@ com.acgist - taoyao-webrtc-jni + taoyao-webrtc-jitsi + + + com.acgist + taoyao-webrtc-kurento diff --git a/taoyao-webrtc/taoyao-webrtc-sfu/pom.xml b/taoyao-webrtc/taoyao-webrtc-sfu/pom.xml index a3ad050..fd76782 100644 --- a/taoyao-webrtc/taoyao-webrtc-sfu/pom.xml +++ b/taoyao-webrtc/taoyao-webrtc-sfu/pom.xml @@ -19,7 +19,11 @@ com.acgist - taoyao-webrtc-jni + taoyao-webrtc-jitsi + + + com.acgist + taoyao-webrtc-kurento