Commit 5077713ed944a02a971c941bb1827fa45de454b0
1 parent
d76da120
修改
Showing
150 changed files
with
3703 additions
and
5457 deletions
pom.xml
| ... | ... | @@ -104,7 +104,16 @@ |
| 104 | 104 | <artifactId>netty-all</artifactId> |
| 105 | 105 | <version>4.1.42.Final</version> |
| 106 | 106 | </dependency> |
| 107 | - | |
| 107 | + <!-- forrest工具 --> | |
| 108 | + <dependency> | |
| 109 | + <groupId>com.dtflys.forest</groupId> | |
| 110 | + <artifactId>forest-spring-boot-starter</artifactId> | |
| 111 | + <version>1.5.36</version> | |
| 112 | + </dependency> | |
| 113 | + <dependency> | |
| 114 | + <groupId>org.projectlombok</groupId> | |
| 115 | + <artifactId>lombok</artifactId> | |
| 116 | + </dependency> | |
| 108 | 117 | <dependency> |
| 109 | 118 | <groupId>de.sciss</groupId> |
| 110 | 119 | <artifactId>jump3r</artifactId> |
| ... | ... | @@ -402,43 +411,43 @@ |
| 402 | 411 | </configuration> |
| 403 | 412 | </plugin> |
| 404 | 413 | |
| 405 | -<!-- <plugin>--> | |
| 406 | -<!-- <groupId>org.apache.maven.plugins</groupId>--> | |
| 407 | -<!-- <artifactId>maven-jar-plugin</artifactId>--> | |
| 408 | -<!-- <version>3.3.0</version>--> | |
| 409 | -<!-- <configuration>--> | |
| 410 | -<!-- <excludes>--> | |
| 411 | -<!-- <exclude>**/all-application.yml</exclude>--> | |
| 412 | -<!-- <exclude>**/application.yml</exclude>--> | |
| 413 | -<!-- <exclude>**/application-*.yml</exclude>--> | |
| 414 | -<!-- <exclude>**/local.jks</exclude>--> | |
| 415 | -<!-- </excludes>--> | |
| 416 | -<!-- </configuration>--> | |
| 417 | -<!-- </plugin>--> | |
| 418 | -<!-- <plugin>--> | |
| 419 | -<!-- <artifactId>maven-resources-plugin</artifactId>--> | |
| 420 | -<!-- <executions>--> | |
| 421 | -<!-- <execution> <!– 复制配置文件 –>--> | |
| 422 | -<!-- <id>copy-resources</id>--> | |
| 423 | -<!-- <phase>package</phase>--> | |
| 424 | -<!-- <goals>--> | |
| 425 | -<!-- <goal>copy-resources</goal>--> | |
| 426 | -<!-- </goals>--> | |
| 427 | -<!-- <configuration>--> | |
| 428 | -<!-- <resources>--> | |
| 429 | -<!-- <resource>--> | |
| 430 | -<!-- <directory>src/main/resources</directory>--> | |
| 431 | -<!-- <includes>--> | |
| 432 | -<!-- <include>application.yml</include>--> | |
| 433 | -<!-- <include>application-*.yml</include>--> | |
| 434 | -<!-- </includes>--> | |
| 435 | -<!-- </resource>--> | |
| 436 | -<!-- </resources>--> | |
| 437 | -<!-- <outputDirectory>${project.build.directory}</outputDirectory>--> | |
| 438 | -<!-- </configuration>--> | |
| 439 | -<!-- </execution>--> | |
| 440 | -<!-- </executions>--> | |
| 441 | -<!-- </plugin>--> | |
| 414 | + <!-- <plugin>--> | |
| 415 | + <!-- <groupId>org.apache.maven.plugins</groupId>--> | |
| 416 | + <!-- <artifactId>maven-jar-plugin</artifactId>--> | |
| 417 | + <!-- <version>3.3.0</version>--> | |
| 418 | + <!-- <configuration>--> | |
| 419 | + <!-- <excludes>--> | |
| 420 | + <!-- <exclude>**/all-application.yml</exclude>--> | |
| 421 | + <!-- <exclude>**/application.yml</exclude>--> | |
| 422 | + <!-- <exclude>**/application-*.yml</exclude>--> | |
| 423 | + <!-- <exclude>**/local.jks</exclude>--> | |
| 424 | + <!-- </excludes>--> | |
| 425 | + <!-- </configuration>--> | |
| 426 | + <!-- </plugin>--> | |
| 427 | + <!-- <plugin>--> | |
| 428 | + <!-- <artifactId>maven-resources-plugin</artifactId>--> | |
| 429 | + <!-- <executions>--> | |
| 430 | + <!-- <execution> <!– 复制配置文件 –>--> | |
| 431 | + <!-- <id>copy-resources</id>--> | |
| 432 | + <!-- <phase>package</phase>--> | |
| 433 | + <!-- <goals>--> | |
| 434 | + <!-- <goal>copy-resources</goal>--> | |
| 435 | + <!-- </goals>--> | |
| 436 | + <!-- <configuration>--> | |
| 437 | + <!-- <resources>--> | |
| 438 | + <!-- <resource>--> | |
| 439 | + <!-- <directory>src/main/resources</directory>--> | |
| 440 | + <!-- <includes>--> | |
| 441 | + <!-- <include>application.yml</include>--> | |
| 442 | + <!-- <include>application-*.yml</include>--> | |
| 443 | + <!-- </includes>--> | |
| 444 | + <!-- </resource>--> | |
| 445 | + <!-- </resources>--> | |
| 446 | + <!-- <outputDirectory>${project.build.directory}</outputDirectory>--> | |
| 447 | + <!-- </configuration>--> | |
| 448 | + <!-- </execution>--> | |
| 449 | + <!-- </executions>--> | |
| 450 | + <!-- </plugin>--> | |
| 442 | 451 | </plugins> |
| 443 | 452 | <resources> |
| 444 | 453 | <resource> | ... | ... |
src/main/java/com/genersoft/iot/vmp/LengthCalculator.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp; | |
| 2 | + | |
| 3 | +import java.io.IOException; | |
| 4 | +import java.io.InputStream; | |
| 5 | +import java.io.OutputStream; | |
| 6 | +import java.net.Socket; | |
| 7 | + | |
| 8 | +public class LengthCalculator extends Thread{ | |
| 9 | + //socket为成员变量,来接收服务端socket实例 | |
| 10 | + private Socket socket; | |
| 11 | + | |
| 12 | + public LengthCalculator(Socket socket){ | |
| 13 | + this.socket = socket; | |
| 14 | + } | |
| 15 | + | |
| 16 | + // run()保存了所有的业务逻辑 | |
| 17 | + public void run(){ | |
| 18 | + try { | |
| 19 | + //获取socket的输出流 | |
| 20 | + OutputStream os = socket.getOutputStream(); | |
| 21 | + //获取socket的输入流 | |
| 22 | + InputStream is = socket.getInputStream(); | |
| 23 | + int ch = 0; | |
| 24 | + //buff用来读取输入的内容,存成byte数组,ch用来获取读取数组的字节数 | |
| 25 | + byte[] buff = new byte[1024]; | |
| 26 | + ch = is.read(buff); | |
| 27 | + //将接收流的byte数组转换成字符串,这里获取的内容是客户端发送过来的字节数组 | |
| 28 | + String content = new String(buff,0,ch); | |
| 29 | + System.out.println(content); | |
| 30 | + //往输出流里写入获得的字符串的长度,回发给客户端 | |
| 31 | + os.write(String.valueOf(content.length()).getBytes()); | |
| 32 | + //一定要关闭输入输出流以及socket | |
| 33 | + is.close(); | |
| 34 | + os.close(); | |
| 35 | + socket.close(); | |
| 36 | + } catch (IOException e) { | |
| 37 | + throw new RuntimeException(e); | |
| 38 | + } | |
| 39 | + } | |
| 40 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/TCPClient.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp; | |
| 2 | + | |
| 3 | +import java.io.InputStream; | |
| 4 | +import java.io.OutputStream; | |
| 5 | +import java.net.Socket; | |
| 6 | + | |
| 7 | +public class TCPClient { | |
| 8 | + public static void main(String[] args) throws Exception{ | |
| 9 | + //创建socket,并指定连接的是本机的端口号为65000的服务器socket | |
| 10 | + Socket socket = new Socket("118.113.164.50",3333); | |
| 11 | + //获取输出流 | |
| 12 | + OutputStream os = socket.getOutputStream(); | |
| 13 | + //获取输入流 | |
| 14 | + InputStream is = socket.getInputStream(); | |
| 15 | + // 将要传递给server的字符串参数转换称byte数组,并将数组写入到输出流中 | |
| 16 | + os.write(new String("hello world").getBytes()); | |
| 17 | + int ch = 0; | |
| 18 | + byte[] buff = new byte[1024]; | |
| 19 | + // buff主要用来读取输入的内容,存成byte数组,ch主要用来获取读取数组的长度(与服务端作用相同) | |
| 20 | + ch = is.read(buff); | |
| 21 | + //将接收流的byte数组转换成字符串,这里是从服务端回发的字符串参数的长度 | |
| 22 | + String content = new String(buff,0,ch); | |
| 23 | + System.out.println(content); | |
| 24 | + //一定要关闭输入输出流及socket | |
| 25 | + is.close(); | |
| 26 | + os.close(); | |
| 27 | + socket.close(); | |
| 28 | + } | |
| 29 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/TCPServer.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp; | |
| 2 | + | |
| 3 | +import java.net.ServerSocket; | |
| 4 | +import java.net.Socket; | |
| 5 | + | |
| 6 | +public class TCPServer { | |
| 7 | + public static void main(String[] args) throws Exception{ | |
| 8 | + //创建socket,并将socket绑定到65000端口 | |
| 9 | + ServerSocket ss = new ServerSocket(30020); | |
| 10 | + //死循环,使得socket一直等待并处理客户端发送过来的请求 | |
| 11 | + while(true){ | |
| 12 | + //监听65000端口,直到客户端返回连接信息后才返回 | |
| 13 | + Socket socket = ss.accept(); | |
| 14 | + //获取客户端的请求信息后,启动一个新线程执行相关业务逻辑 | |
| 15 | + new LengthCalculator(socket).start(); | |
| 16 | + } | |
| 17 | + } | |
| 18 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java
| 1 | 1 | package com.genersoft.iot.vmp; |
| 2 | 2 | |
| 3 | +import com.dtflys.forest.springboot.annotation.ForestScan; | |
| 4 | +import com.genersoft.iot.vmp.jtt1078.app.VideoServerApp; | |
| 3 | 5 | import com.genersoft.iot.vmp.utils.GitUtil; |
| 4 | 6 | import com.genersoft.iot.vmp.utils.SpringBeanFactory; |
| 5 | 7 | import org.slf4j.Logger; |
| ... | ... | @@ -9,7 +11,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; |
| 9 | 11 | import org.springframework.boot.builder.SpringApplicationBuilder; |
| 10 | 12 | import org.springframework.boot.web.servlet.ServletComponentScan; |
| 11 | 13 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; |
| 12 | -import org.springframework.context.ConfigurableApplicationContext; | |
| 14 | +import org.springframework.context.ApplicationContext; | |
| 13 | 15 | import org.springframework.scheduling.annotation.EnableScheduling; |
| 14 | 16 | |
| 15 | 17 | import javax.servlet.ServletContext; |
| ... | ... | @@ -25,25 +27,27 @@ import java.util.Objects; |
| 25 | 27 | @ServletComponentScan("com.genersoft.iot.vmp.conf") |
| 26 | 28 | @SpringBootApplication |
| 27 | 29 | @EnableScheduling |
| 30 | +@ForestScan(basePackages = "com.genersoft.iot.vmp.vmanager.jt1078.platform.remote") | |
| 28 | 31 | public class VManageBootstrap extends SpringBootServletInitializer { |
| 29 | 32 | |
| 30 | 33 | private final static Logger logger = LoggerFactory.getLogger(VManageBootstrap.class); |
| 31 | 34 | |
| 32 | 35 | private static String[] args; |
| 33 | - private static ConfigurableApplicationContext context; | |
| 36 | + private static ApplicationContext context; | |
| 34 | 37 | public static void main(String[] args) { |
| 35 | 38 | VManageBootstrap.args = args; |
| 36 | 39 | VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args); |
| 37 | - GitUtil gitUtil1 = SpringBeanFactory.getBean("gitUtil"); | |
| 40 | + VideoServerApp videoServerApp = context.getBean(VideoServerApp.class); | |
| 41 | + try { | |
| 42 | + videoServerApp.run(args); | |
| 43 | + } catch (Exception e) { | |
| 44 | + throw new RuntimeException(e); | |
| 45 | + } | |
| 46 | + GitUtil gitUtil1 = SpringBeanFactory.getBean("gitUtil"); | |
| 38 | 47 | logger.info("构建版本: {}", gitUtil1.getBuildVersion()); |
| 39 | 48 | logger.info("构建时间: {}", gitUtil1.getBuildDate()); |
| 40 | 49 | logger.info("GIT最后提交时间: {}", gitUtil1.getCommitTime()); |
| 41 | 50 | } |
| 42 | - // 项目重启 | |
| 43 | - public static void restart() { | |
| 44 | - context.close(); | |
| 45 | - VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args); | |
| 46 | - } | |
| 47 | 51 | |
| 48 | 52 | @Override |
| 49 | 53 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java
| 1 | 1 | package com.genersoft.iot.vmp.conf; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.common.ApiSaveConstant; |
| 4 | +import com.genersoft.iot.vmp.conf.security.IpWhitelistFilter; | |
| 4 | 5 | import com.genersoft.iot.vmp.conf.security.SecurityUtils; |
| 6 | +import com.genersoft.iot.vmp.conf.security.WebSecurityConfig; | |
| 5 | 7 | import com.genersoft.iot.vmp.service.ILogService; |
| 6 | 8 | import com.genersoft.iot.vmp.storager.dao.dto.LogDto; |
| 7 | 9 | import com.genersoft.iot.vmp.utils.DateUtil; |
| ... | ... | @@ -21,6 +23,8 @@ import javax.servlet.http.HttpServletRequest; |
| 21 | 23 | import javax.servlet.http.HttpServletResponse; |
| 22 | 24 | import java.io.IOException; |
| 23 | 25 | |
| 26 | +import static com.genersoft.iot.vmp.conf.security.IpWhitelistFilter.verifyIpAndPath; | |
| 27 | + | |
| 24 | 28 | /** |
| 25 | 29 | * @author lin |
| 26 | 30 | */ |
| ... | ... | @@ -40,6 +44,10 @@ public class ApiAccessFilter extends OncePerRequestFilter { |
| 40 | 44 | |
| 41 | 45 | @Override |
| 42 | 46 | protected void doFilterInternal(HttpServletRequest servletRequest, HttpServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException { |
| 47 | + if (verifyIpAndPath(servletRequest)){ | |
| 48 | + filterChain.doFilter(servletRequest, servletResponse); | |
| 49 | + return; | |
| 50 | + } | |
| 43 | 51 | String username = null; |
| 44 | 52 | if (SecurityUtils.getUserInfo() == null) { |
| 45 | 53 | username = servletRequest.getParameter("username"); |
| ... | ... | @@ -66,8 +74,6 @@ public class ApiAccessFilter extends OncePerRequestFilter { |
| 66 | 74 | logDto.setUri(servletRequest.getRequestURI()); |
| 67 | 75 | logDto.setCreateTime(DateUtil.getNow()); |
| 68 | 76 | logService.add(logDto); |
| 69 | - | |
| 70 | - | |
| 71 | 77 | } |
| 72 | 78 | } |
| 73 | 79 | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
| 1 | 1 | package com.genersoft.iot.vmp.conf; |
| 2 | 2 | |
| 3 | +import org.apache.commons.collections4.CollectionUtils; | |
| 3 | 4 | import org.apache.commons.lang3.ObjectUtils; |
| 5 | +import org.ehcache.core.util.CollectionUtil; | |
| 4 | 6 | import org.slf4j.Logger; |
| 5 | 7 | import org.slf4j.LoggerFactory; |
| 8 | +import org.springframework.data.redis.cache.RedisCache; | |
| 9 | +import org.springframework.data.redis.core.RedisTemplate; | |
| 6 | 10 | import org.springframework.scheduling.annotation.Scheduled; |
| 7 | 11 | import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; |
| 8 | 12 | import org.springframework.stereotype.Component; |
| 9 | 13 | |
| 10 | 14 | import javax.annotation.PostConstruct; |
| 15 | +import javax.annotation.Resource; | |
| 11 | 16 | import java.time.Instant; |
| 12 | 17 | import java.util.Date; |
| 13 | 18 | import java.util.Map; |
| ... | ... | @@ -18,6 +23,7 @@ import java.util.concurrent.TimeUnit; |
| 18 | 23 | |
| 19 | 24 | /** |
| 20 | 25 | * 动态定时任务 |
| 26 | + * | |
| 21 | 27 | * @author lin |
| 22 | 28 | */ |
| 23 | 29 | @Component |
| ... | ... | @@ -30,6 +36,9 @@ public class DynamicTask { |
| 30 | 36 | private final Map<String, ScheduledFuture<?>> futureMap = new ConcurrentHashMap<>(); |
| 31 | 37 | private final Map<String, Runnable> runnableMap = new ConcurrentHashMap<>(); |
| 32 | 38 | |
| 39 | + @Resource | |
| 40 | + private RedisTemplate<String, String> redisTemplate; | |
| 41 | + | |
| 33 | 42 | @PostConstruct |
| 34 | 43 | public void DynamicTask() { |
| 35 | 44 | threadPoolTaskScheduler = new ThreadPoolTaskScheduler(); |
| ... | ... | @@ -37,17 +46,23 @@ public class DynamicTask { |
| 37 | 46 | threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true); |
| 38 | 47 | threadPoolTaskScheduler.setAwaitTerminationSeconds(10); |
| 39 | 48 | threadPoolTaskScheduler.initialize(); |
| 49 | + Set<String> keys = redisTemplate.keys("jt1078:server:port:*"); | |
| 50 | + if (CollectionUtils.isNotEmpty(keys)) { | |
| 51 | + redisTemplate.delete(keys); | |
| 52 | + } | |
| 53 | + | |
| 40 | 54 | } |
| 41 | 55 | |
| 42 | 56 | /** |
| 43 | 57 | * 循环执行的任务 |
| 44 | - * @param key 任务ID | |
| 45 | - * @param task 任务 | |
| 58 | + * | |
| 59 | + * @param key 任务ID | |
| 60 | + * @param task 任务 | |
| 46 | 61 | * @param cycleForCatalog 间隔 毫秒 |
| 47 | 62 | * @return |
| 48 | 63 | */ |
| 49 | 64 | public void startCron(String key, Runnable task, int cycleForCatalog) { |
| 50 | - if(ObjectUtils.isEmpty(key)) { | |
| 65 | + if (ObjectUtils.isEmpty(key)) { | |
| 51 | 66 | return; |
| 52 | 67 | } |
| 53 | 68 | ScheduledFuture<?> future = futureMap.get(key); |
| ... | ... | @@ -62,24 +77,25 @@ public class DynamicTask { |
| 62 | 77 | // scheduleWithFixedDelay 必须等待上一个任务结束才开始计时period, cycleForCatalog表示执行的间隔 |
| 63 | 78 | |
| 64 | 79 | future = threadPoolTaskScheduler.scheduleAtFixedRate(task, new Date(System.currentTimeMillis() + cycleForCatalog), cycleForCatalog); |
| 65 | - if (future != null){ | |
| 80 | + if (future != null) { | |
| 66 | 81 | futureMap.put(key, future); |
| 67 | 82 | runnableMap.put(key, task); |
| 68 | 83 | logger.debug("任务【{}】启动成功!!!", key); |
| 69 | - }else { | |
| 84 | + } else { | |
| 70 | 85 | logger.debug("任务【{}】启动失败!!!", key); |
| 71 | 86 | } |
| 72 | 87 | } |
| 73 | 88 | |
| 74 | 89 | /** |
| 75 | 90 | * 延时任务 |
| 76 | - * @param key 任务ID | |
| 77 | - * @param task 任务 | |
| 91 | + * | |
| 92 | + * @param key 任务ID | |
| 93 | + * @param task 任务 | |
| 78 | 94 | * @param delay 延时 /毫秒 |
| 79 | 95 | * @return |
| 80 | 96 | */ |
| 81 | 97 | public void startDelay(String key, Runnable task, int delay) { |
| 82 | - if(ObjectUtils.isEmpty(key)) { | |
| 98 | + if (ObjectUtils.isEmpty(key)) { | |
| 83 | 99 | return; |
| 84 | 100 | } |
| 85 | 101 | stop(key); |
| ... | ... | @@ -98,17 +114,17 @@ public class DynamicTask { |
| 98 | 114 | } |
| 99 | 115 | // scheduleWithFixedDelay 必须等待上一个任务结束才开始计时period, cycleForCatalog表示执行的间隔 |
| 100 | 116 | future = threadPoolTaskScheduler.schedule(task, startInstant); |
| 101 | - if (future != null){ | |
| 117 | + if (future != null) { | |
| 102 | 118 | futureMap.put(key, future); |
| 103 | 119 | runnableMap.put(key, task); |
| 104 | 120 | logger.debug("任务【{}】启动成功!!!", key); |
| 105 | - }else { | |
| 121 | + } else { | |
| 106 | 122 | logger.debug("任务【{}】启动失败!!!", key); |
| 107 | 123 | } |
| 108 | 124 | } |
| 109 | 125 | |
| 110 | 126 | public boolean stop(String key) { |
| 111 | - if(ObjectUtils.isEmpty(key)) { | |
| 127 | + if (ObjectUtils.isEmpty(key)) { | |
| 112 | 128 | return false; |
| 113 | 129 | } |
| 114 | 130 | boolean result = false; |
| ... | ... | @@ -121,7 +137,7 @@ public class DynamicTask { |
| 121 | 137 | } |
| 122 | 138 | |
| 123 | 139 | public boolean contains(String key) { |
| 124 | - if(ObjectUtils.isEmpty(key)) { | |
| 140 | + if (ObjectUtils.isEmpty(key)) { | |
| 125 | 141 | return false; |
| 126 | 142 | } |
| 127 | 143 | return futureMap.get(key) != null; |
| ... | ... | @@ -132,7 +148,7 @@ public class DynamicTask { |
| 132 | 148 | } |
| 133 | 149 | |
| 134 | 150 | public Runnable get(String key) { |
| 135 | - if(ObjectUtils.isEmpty(key)) { | |
| 151 | + if (ObjectUtils.isEmpty(key)) { | |
| 136 | 152 | return null; |
| 137 | 153 | } |
| 138 | 154 | return runnableMap.get(key); |
| ... | ... | @@ -141,8 +157,8 @@ public class DynamicTask { |
| 141 | 157 | /** |
| 142 | 158 | * 每五分钟检查失效的任务,并移除 |
| 143 | 159 | */ |
| 144 | - @Scheduled(cron="0 0/5 * * * ?") | |
| 145 | - public void execute(){ | |
| 160 | + @Scheduled(cron = "0 0/5 * * * ?") | |
| 161 | + public void execute() { | |
| 146 | 162 | if (futureMap.size() > 0) { |
| 147 | 163 | for (String key : futureMap.keySet()) { |
| 148 | 164 | ScheduledFuture<?> future = futureMap.get(key); | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/security/IpWhitelistFilter.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.conf.security; | |
| 2 | + | |
| 3 | +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | |
| 4 | +import org.springframework.security.core.context.SecurityContextHolder; | |
| 5 | +import org.springframework.web.filter.OncePerRequestFilter; | |
| 6 | + | |
| 7 | +import javax.servlet.FilterChain; | |
| 8 | +import javax.servlet.ServletException; | |
| 9 | +import javax.servlet.http.HttpServletRequest; | |
| 10 | +import javax.servlet.http.HttpServletResponse; | |
| 11 | +import java.io.IOException; | |
| 12 | +import java.util.Arrays; | |
| 13 | +import java.util.Collections; | |
| 14 | +import java.util.List; | |
| 15 | + | |
| 16 | +public class IpWhitelistFilter extends OncePerRequestFilter { | |
| 17 | + | |
| 18 | + public static final List<String> PATH_ARRAY = Arrays.asList("/api/jt1078/query/send/request/getPlay"); | |
| 19 | + | |
| 20 | + @Override | |
| 21 | + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) | |
| 22 | + throws ServletException, IOException { | |
| 23 | + if (verifyIpAndPath(request)) { | |
| 24 | + // 如果IP在白名单中,则直接设置用户为已认证状态并放行请求 | |
| 25 | + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( | |
| 26 | + "whitelisted-ip", null, Collections.emptyList()); | |
| 27 | + SecurityContextHolder.getContext().setAuthentication(authentication); | |
| 28 | + | |
| 29 | + // 直接返回,不再继续执行链中的其他过滤器 | |
| 30 | + chain.doFilter(request, response); | |
| 31 | + return; | |
| 32 | + } | |
| 33 | + | |
| 34 | + // 对于非白名单IP,继续执行链中的下一个过滤器 | |
| 35 | + chain.doFilter(request, response); | |
| 36 | + } | |
| 37 | + | |
| 38 | + private boolean isAllowedIp(String ip) { | |
| 39 | + return WebSecurityConfig.ALLOWED_IPS.contains(ip); | |
| 40 | + } | |
| 41 | + | |
| 42 | + private boolean isAllowedPath(String path) { | |
| 43 | + return PATH_ARRAY.contains(path); | |
| 44 | + } | |
| 45 | + | |
| 46 | + public static String getClientIp(HttpServletRequest request) { | |
| 47 | + String xfHeader = request.getHeader("X-Forwarded-For"); | |
| 48 | + if (xfHeader == null) { | |
| 49 | + return request.getRemoteAddr(); | |
| 50 | + } | |
| 51 | + return xfHeader.split(",")[0]; | |
| 52 | + } | |
| 53 | + | |
| 54 | + public static Boolean verifyIpAndPath(HttpServletRequest request) throws ServletException, IOException { | |
| 55 | + String requestURI = request.getRequestURI(); | |
| 56 | + String clientIp = IpWhitelistFilter.getClientIp(request); | |
| 57 | + String header = request.getHeader("access-token"); | |
| 58 | + return (WebSecurityConfig.ALLOWED_IPS.contains(clientIp) && IpWhitelistFilter.PATH_ARRAY.contains(requestURI)) || JwtUtils.token.equals(header); | |
| 59 | + } | |
| 60 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java
| ... | ... | @@ -34,6 +34,8 @@ public class JwtUtils implements InitializingBean { |
| 34 | 34 | |
| 35 | 35 | private static final String keyId = "3e79646c4dbc408383a9eed09f2b85ae"; |
| 36 | 36 | |
| 37 | + public static final String token = "interior-api-eyJhbGciOiJSUzI1NiIsImtpZCI6IjNlNzk2NDZjNGRiYzQwODM4M2E5ZWVkMDlmMmI4NWFlIn0.eyJqdGkiOiJHUThFUFhtdGtJd01yVTNES3F3bnN3IiwiaWF0IjoxNzM2ODM2Mjk"; | |
| 38 | + | |
| 37 | 39 | /** |
| 38 | 40 | * token过期时间(分钟) |
| 39 | 41 | */ | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/security/SecurityUtils.java
| ... | ... | @@ -54,7 +54,6 @@ public class SecurityUtils { |
| 54 | 54 | if(authentication!=null){ |
| 55 | 55 | Object principal = authentication.getPrincipal(); |
| 56 | 56 | if(principal!=null && !"anonymousUser".equals(principal.toString())){ |
| 57 | - | |
| 58 | 57 | User user = (User) principal; |
| 59 | 58 | return new LoginUser(user, LocalDateTime.now()); |
| 60 | 59 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
| ... | ... | @@ -18,6 +18,7 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur |
| 18 | 18 | import org.springframework.security.config.http.SessionCreationPolicy; |
| 19 | 19 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; |
| 20 | 20 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; |
| 21 | +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; | |
| 21 | 22 | import org.springframework.web.cors.CorsConfiguration; |
| 22 | 23 | import org.springframework.web.cors.CorsConfigurationSource; |
| 23 | 24 | import org.springframework.web.cors.CorsUtils; |
| ... | ... | @@ -26,6 +27,7 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; |
| 26 | 27 | import java.util.ArrayList; |
| 27 | 28 | import java.util.Arrays; |
| 28 | 29 | import java.util.Collections; |
| 30 | +import java.util.List; | |
| 29 | 31 | |
| 30 | 32 | /** |
| 31 | 33 | * 配置Spring Security |
| ... | ... | @@ -58,6 +60,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { |
| 58 | 60 | @Autowired |
| 59 | 61 | private JwtAuthenticationFilter jwtAuthenticationFilter; |
| 60 | 62 | |
| 63 | + public static final List<String> ALLOWED_IPS = Arrays.asList("192.169.1.88", "127.0.0.1"); | |
| 64 | + | |
| 61 | 65 | |
| 62 | 66 | /** |
| 63 | 67 | * 描述: 静态资源放行,这里的放行,是不走 Spring Security 过滤器链 |
| ... | ... | @@ -88,6 +92,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { |
| 88 | 92 | } |
| 89 | 93 | } |
| 90 | 94 | |
| 95 | + | |
| 91 | 96 | /** |
| 92 | 97 | * 配置认证方式 |
| 93 | 98 | * |
| ... | ... | @@ -113,21 +118,20 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { |
| 113 | 118 | .and().csrf().disable() |
| 114 | 119 | .sessionManagement() |
| 115 | 120 | .sessionCreationPolicy(SessionCreationPolicy.STATELESS) |
| 116 | - | |
| 117 | - // 配置拦截规则 | |
| 118 | 121 | .and() |
| 122 | + // 配置拦截规则 | |
| 119 | 123 | .authorizeRequests() |
| 120 | 124 | .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() |
| 121 | 125 | .antMatchers(userSetting.getInterfaceAuthenticationExcludes().toArray(new String[0])).permitAll() |
| 122 | 126 | .antMatchers("/api/user/login", "/index/hook/**", "/swagger-ui/**", "/doc.html").permitAll() |
| 123 | 127 | .anyRequest().authenticated() |
| 124 | - // 异常处理器 | |
| 125 | 128 | .and() |
| 129 | + .addFilterBefore(new IpWhitelistFilter(), BasicAuthenticationFilter.class) | |
| 130 | + // 异常处理器 | |
| 126 | 131 | .exceptionHandling() |
| 127 | 132 | .authenticationEntryPoint(anonymousAuthenticationEntryPoint) |
| 128 | 133 | .and().logout().logoutUrl("/api/user/logout").permitAll() |
| 129 | - .logoutSuccessHandler(logoutHandler) | |
| 130 | - ; | |
| 134 | + .logoutSuccessHandler(logoutHandler); | |
| 131 | 135 | http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); |
| 132 | 136 | |
| 133 | 137 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
| ... | ... | @@ -37,6 +37,10 @@ public class SipLayer implements CommandLineRunner { |
| 37 | 37 | private final Map<String, SipProviderImpl> tcpSipProviderMap = new ConcurrentHashMap<>(); |
| 38 | 38 | private final Map<String, SipProviderImpl> udpSipProviderMap = new ConcurrentHashMap<>(); |
| 39 | 39 | |
| 40 | + /** | |
| 41 | + * 获取监听的IP | |
| 42 | + * @param args | |
| 43 | + */ | |
| 40 | 44 | @Override |
| 41 | 45 | public void run(String... args) { |
| 42 | 46 | List<String> monitorIps = new ArrayList<>(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/annotation/MsgId.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.annotation; | |
| 2 | - | |
| 3 | -import java.lang.annotation.*; | |
| 4 | - | |
| 5 | -/** | |
| 6 | - * @author QingtaiJiang | |
| 7 | - * @date 2023/4/27 18:31 | |
| 8 | - * @email qingtaij@163.com | |
| 9 | - */ | |
| 10 | -@Target(ElementType.TYPE) | |
| 11 | -@Retention(RetentionPolicy.RUNTIME) | |
| 12 | -@Documented | |
| 13 | -public @interface MsgId { | |
| 14 | - String id(); | |
| 15 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/app/CacheMapUtil.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.app; | |
| 2 | - | |
| 3 | -import io.netty.channel.Channel; | |
| 4 | - | |
| 5 | -import java.util.HashMap; | |
| 6 | -import java.util.Map; | |
| 7 | - | |
| 8 | -public class CacheMapUtil { | |
| 9 | - public Map<Integer, VideoServerApp.VideoServer> videoServerMap = new HashMap(); | |
| 10 | - public Map<Integer, Channel> portChannel = new HashMap(); | |
| 11 | - | |
| 12 | - private static CacheMapUtil cacheMapUtil; | |
| 13 | - | |
| 14 | - public static CacheMapUtil getCacheMapUtil() { | |
| 15 | - if (null == cacheMapUtil) { | |
| 16 | - cacheMapUtil = new CacheMapUtil(); | |
| 17 | - } | |
| 18 | - return cacheMapUtil; | |
| 19 | - } | |
| 20 | - | |
| 21 | - private CacheMapUtil() { | |
| 22 | - | |
| 23 | - } | |
| 24 | - | |
| 25 | - | |
| 26 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/app/VideoServerApp.java deleted
100644 → 0
| 1 | -// | |
| 2 | -// Source code recreated from a .class file by IntelliJ IDEA | |
| 3 | -// (powered by FernFlower decompiler) | |
| 4 | -// | |
| 5 | - | |
| 6 | -package com.genersoft.iot.vmp.jt1078.app; | |
| 7 | - | |
| 8 | -import com.genersoft.iot.vmp.jt1078.http.GeneralResponseWriter; | |
| 9 | -import com.genersoft.iot.vmp.jt1078.http.NettyHttpServerHandler; | |
| 10 | -import com.genersoft.iot.vmp.jt1078.publisher.PublishManager; | |
| 11 | -import com.genersoft.iot.vmp.jt1078.server.Jtt1078Handler; | |
| 12 | -import com.genersoft.iot.vmp.jt1078.server.Jtt1078MessageDecoder; | |
| 13 | -import com.genersoft.iot.vmp.jt1078.util.Configs; | |
| 14 | -import io.netty.bootstrap.ServerBootstrap; | |
| 15 | -import io.netty.channel.Channel; | |
| 16 | -import io.netty.channel.ChannelFuture; | |
| 17 | -import io.netty.channel.ChannelHandler; | |
| 18 | -import io.netty.channel.ChannelInitializer; | |
| 19 | -import io.netty.channel.ChannelOption; | |
| 20 | -import io.netty.channel.ChannelPipeline; | |
| 21 | -import io.netty.channel.EventLoopGroup; | |
| 22 | -import io.netty.channel.nio.NioEventLoopGroup; | |
| 23 | -import io.netty.channel.socket.SocketChannel; | |
| 24 | -import io.netty.channel.socket.nio.NioServerSocketChannel; | |
| 25 | - | |
| 26 | -import java.net.InetAddress; | |
| 27 | -import java.util.Date; | |
| 28 | -import java.util.HashMap; | |
| 29 | -import java.util.Map; | |
| 30 | -import java.util.Objects; | |
| 31 | - | |
| 32 | -import io.netty.handler.codec.http.HttpObjectAggregator; | |
| 33 | -import io.netty.handler.codec.http.HttpRequestDecoder; | |
| 34 | -import io.netty.handler.codec.http.HttpResponseEncoder; | |
| 35 | -import org.apache.commons.collections4.MapUtils; | |
| 36 | -import org.slf4j.Logger; | |
| 37 | -import org.slf4j.LoggerFactory; | |
| 38 | -import sun.misc.Signal; | |
| 39 | -import sun.misc.SignalHandler; | |
| 40 | - | |
| 41 | -public class VideoServerApp { | |
| 42 | - private static Logger logger = LoggerFactory.getLogger(VideoServerApp.class); | |
| 43 | - | |
| 44 | - public VideoServerApp() { | |
| 45 | - } | |
| 46 | - | |
| 47 | - public void createListenter() throws Exception { | |
| 48 | - Configs.init("/app.properties"); | |
| 49 | - PublishManager.init(); | |
| 50 | - String tagMapping = null; | |
| 51 | - final VideoServer videoServer = new VideoServer(); | |
| 52 | - final HttpServer httpServer = new HttpServer(); | |
| 53 | - Signal.handle(new Signal("TERM"), new SignalHandler() { | |
| 54 | - public void handle(Signal signal) { | |
| 55 | - videoServer.shutdown(); | |
| 56 | - HttpServer var10000 = httpServer; | |
| 57 | - VideoServerApp.HttpServer.shutdown(); | |
| 58 | - } | |
| 59 | - }); | |
| 60 | - VideoServerApp.VideoServer.getInstance().start(11078, (String) tagMapping, 3333); | |
| 61 | - VideoServerApp.HttpServer.start((String) tagMapping, 3333); | |
| 62 | - } | |
| 63 | - | |
| 64 | - public void newVideoServer(final String key, int port, final int httpPort) throws Exception { | |
| 65 | - VideoServer videoServer = new VideoServer(); | |
| 66 | - HttpServer httpServer = null; | |
| 67 | - boolean videoFlag = false; | |
| 68 | - boolean httpFlag = false; | |
| 69 | - long nw = (new Date()).getTime(); | |
| 70 | - VideoServer sourceVideoServer = (VideoServer) CacheMapUtil.getCacheMapUtil().videoServerMap.get(port); | |
| 71 | - if (Objects.isNull(sourceVideoServer)) { | |
| 72 | - videoServer = new VideoServer(); | |
| 73 | - videoFlag = true; | |
| 74 | - CacheMapUtil.getCacheMapUtil().videoServerMap.put(port, videoServer); | |
| 75 | - } | |
| 76 | - if (videoFlag) { | |
| 77 | - videoServer.start(port, key, httpPort); | |
| 78 | - } | |
| 79 | - } | |
| 80 | - | |
| 81 | - public static void stopServer(int port, Integer httpPort) { | |
| 82 | - stopVideoServer(port); | |
| 83 | -// stopHttpServer(httpPort); | |
| 84 | -// channelMappingMap.remove(httpPort); | |
| 85 | - } | |
| 86 | - | |
| 87 | - public void stopServer2(int port, int httpPort) { | |
| 88 | - stopVideoServer(port); | |
| 89 | -// stopHttpServer(httpPort); | |
| 90 | -// channelMappingMap.remove(httpPort); | |
| 91 | - } | |
| 92 | - | |
| 93 | - | |
| 94 | - private static void stopVideoServer(Integer port) { | |
| 95 | - VideoServer videoServer = (VideoServer) CacheMapUtil.getCacheMapUtil().videoServerMap.get(port); | |
| 96 | - if (Objects.nonNull(videoServer)) { | |
| 97 | - videoServer.shutdown(); | |
| 98 | - CacheMapUtil.getCacheMapUtil().videoServerMap.remove(port); | |
| 99 | - } | |
| 100 | - | |
| 101 | - } | |
| 102 | - | |
| 103 | - private static void stopHttpServer(Integer port) { | |
| 104 | - | |
| 105 | - | |
| 106 | - } | |
| 107 | - | |
| 108 | - static class HttpServer { | |
| 109 | - private static ServerBootstrap serverBootstrap; | |
| 110 | - private static EventLoopGroup bossGroup; | |
| 111 | - private static EventLoopGroup workerGroup; | |
| 112 | - private static Integer httpPort; | |
| 113 | - | |
| 114 | - HttpServer() { | |
| 115 | - } | |
| 116 | - | |
| 117 | - private static void start(final String tagMapping, final int port) throws Exception { | |
| 118 | - bossGroup = new NioEventLoopGroup(); | |
| 119 | - workerGroup = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors()); | |
| 120 | - httpPort = port; | |
| 121 | - ServerBootstrap bootstrap = new ServerBootstrap(); | |
| 122 | - ((ServerBootstrap) ((ServerBootstrap) bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)).childHandler(new ChannelInitializer<SocketChannel>() { | |
| 123 | - public void initChannel(SocketChannel ch) throws Exception { | |
| 124 | - ch.pipeline().addLast(new ChannelHandler[]{new GeneralResponseWriter(), new HttpResponseEncoder(), new HttpRequestDecoder(), new HttpObjectAggregator(65536), new NettyHttpServerHandler(tagMapping, port)}); | |
| 125 | - } | |
| 126 | - }).option(ChannelOption.SO_BACKLOG, 1024)).childOption(ChannelOption.SO_KEEPALIVE, true); | |
| 127 | - | |
| 128 | - try { | |
| 129 | - InterruptedException e; | |
| 130 | - try { | |
| 131 | - ChannelFuture f = bootstrap.bind(InetAddress.getByName("0.0.0.0"), port).sync(); | |
| 132 | - VideoServerApp.logger.info("HTTP Server started at: {}", port); | |
| 133 | - | |
| 134 | - f.channel().closeFuture().sync(); | |
| 135 | - e = null; | |
| 136 | - } catch (InterruptedException var7) { | |
| 137 | - e = var7; | |
| 138 | - VideoServerApp.logger.error("http server error", e); | |
| 139 | - } | |
| 140 | - } finally { | |
| 141 | - shutdown(); | |
| 142 | - } | |
| 143 | - | |
| 144 | - } | |
| 145 | - | |
| 146 | - private static void shutdown() { | |
| 147 | - | |
| 148 | - try { | |
| 149 | - bossGroup.shutdownGracefully(); | |
| 150 | - } catch (Exception e) { | |
| 151 | - e.printStackTrace(); | |
| 152 | - } | |
| 153 | - | |
| 154 | - bossGroup = null; | |
| 155 | - | |
| 156 | - try { | |
| 157 | - workerGroup.shutdownGracefully(); | |
| 158 | - } catch (Exception e) { | |
| 159 | - e.printStackTrace(); | |
| 160 | - } | |
| 161 | - | |
| 162 | - workerGroup = null; | |
| 163 | - } | |
| 164 | - } | |
| 165 | - | |
| 166 | - static class VideoServer { | |
| 167 | - private ServerBootstrap serverBootstrap; | |
| 168 | - private EventLoopGroup bossGroup; | |
| 169 | - private EventLoopGroup workerGroup; | |
| 170 | - private static Integer port; | |
| 171 | - | |
| 172 | - public void start(int port, final String tagMapping, final Integer httpPort) throws Exception { | |
| 173 | - VideoServerApp.VideoServer.port = port; | |
| 174 | - serverBootstrap = new ServerBootstrap(); | |
| 175 | - serverBootstrap.option(ChannelOption.SO_BACKLOG, Configs.getInt("server.backlog", 102400)); | |
| 176 | - bossGroup = new NioEventLoopGroup(Configs.getInt("server.worker-count", Runtime.getRuntime().availableProcessors())); | |
| 177 | - workerGroup = new NioEventLoopGroup(); | |
| 178 | - serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class); | |
| 179 | - serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() { | |
| 180 | - protected void initChannel(SocketChannel channel) throws Exception { | |
| 181 | - ChannelPipeline p = channel.pipeline(); | |
| 182 | - p.addLast(new ChannelHandler[]{new Jtt1078MessageDecoder()}); | |
| 183 | - p.addLast(new ChannelHandler[]{new Jtt1078Handler(tagMapping, httpPort)}); | |
| 184 | - } | |
| 185 | - }); | |
| 186 | - Channel ch = serverBootstrap.bind(InetAddress.getByName("0.0.0.0"), port).sync().channel(); | |
| 187 | - CacheMapUtil.getCacheMapUtil().portChannel.put(port, ch); | |
| 188 | - VideoServerApp.logger.info("Video Server started at: {}", port); | |
| 189 | - ch.closeFuture(); | |
| 190 | - ch = null; | |
| 191 | - CacheMapUtil.getCacheMapUtil().portChannel.remove(port); | |
| 192 | - } | |
| 193 | - | |
| 194 | - public void shutdown() { | |
| 195 | - Channel channel = (Channel) CacheMapUtil.getCacheMapUtil().portChannel.get(port); | |
| 196 | - Exception e; | |
| 197 | - if (Objects.nonNull(channel)) { | |
| 198 | - try { | |
| 199 | - channel.closeFuture(); | |
| 200 | - } catch (Exception var5) { | |
| 201 | - e = var5; | |
| 202 | - e.printStackTrace(); | |
| 203 | - } | |
| 204 | - | |
| 205 | - channel = null; | |
| 206 | - CacheMapUtil.getCacheMapUtil().portChannel.remove(port); | |
| 207 | - } | |
| 208 | - | |
| 209 | - try { | |
| 210 | - bossGroup.shutdownGracefully(); | |
| 211 | - } catch (Exception var4) { | |
| 212 | - e = var4; | |
| 213 | - e.printStackTrace(); | |
| 214 | - } | |
| 215 | - | |
| 216 | - try { | |
| 217 | - workerGroup.shutdownGracefully(); | |
| 218 | - } catch (Exception var3) { | |
| 219 | - e = var3; | |
| 220 | - e.printStackTrace(); | |
| 221 | - } | |
| 222 | - | |
| 223 | - } | |
| 224 | - | |
| 225 | - public static VideoServer getInstance() { | |
| 226 | - return new VideoServer(); | |
| 227 | - } | |
| 228 | - } | |
| 229 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/cmd/JT1078Template.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.cmd; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.proc.entity.Cmd; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.proc.response.*; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.session.SessionManager; | |
| 6 | - | |
| 7 | -import java.util.Random; | |
| 8 | - | |
| 9 | -/** | |
| 10 | - * @author QingtaiJiang | |
| 11 | - * @date 2023/4/27 18:58 | |
| 12 | - * @email qingtaij@163.com | |
| 13 | - */ | |
| 14 | -public class JT1078Template { | |
| 15 | - | |
| 16 | - private final Random random = new Random(); | |
| 17 | - | |
| 18 | - private static final String H9101 = "9101"; | |
| 19 | - private static final String H9102 = "9102"; | |
| 20 | - private static final String H9201 = "9201"; | |
| 21 | - private static final String H9202 = "9202"; | |
| 22 | - private static final String H9205 = "9205"; | |
| 23 | - | |
| 24 | - private static final String H0001 = "0001"; | |
| 25 | - private static final String H1205 = "1205"; | |
| 26 | - | |
| 27 | - /** | |
| 28 | - * 开启直播视频 | |
| 29 | - * | |
| 30 | - * @param devId 设备号 | |
| 31 | - * @param j9101 开启视频参数 | |
| 32 | - */ | |
| 33 | - public String startLive(String devId, J9101 j9101, Integer timeOut) { | |
| 34 | - Cmd cmd = new Cmd.Builder() | |
| 35 | - .setDevId(devId) | |
| 36 | - .setPackageNo(randomInt()) | |
| 37 | - .setMsgId(H9101) | |
| 38 | - .setRespId(H0001) | |
| 39 | - .setRs(j9101) | |
| 40 | - .build(); | |
| 41 | - return SessionManager.INSTANCE.request(cmd, timeOut); | |
| 42 | - } | |
| 43 | - | |
| 44 | - /** | |
| 45 | - * 关闭直播视频 | |
| 46 | - * | |
| 47 | - * @param devId 设备号 | |
| 48 | - * @param j9102 关闭视频参数 | |
| 49 | - */ | |
| 50 | - public String stopLive(String devId, J9102 j9102, Integer timeOut) { | |
| 51 | - Cmd cmd = new Cmd.Builder() | |
| 52 | - .setDevId(devId) | |
| 53 | - .setPackageNo(randomInt()) | |
| 54 | - .setMsgId(H9102) | |
| 55 | - .setRespId(H0001) | |
| 56 | - .setRs(j9102) | |
| 57 | - .build(); | |
| 58 | - return SessionManager.INSTANCE.request(cmd, timeOut); | |
| 59 | - } | |
| 60 | - | |
| 61 | - /** | |
| 62 | - * 查询音视频列表 | |
| 63 | - * | |
| 64 | - * @param devId 设备号 | |
| 65 | - * @param j9205 查询音视频列表 | |
| 66 | - */ | |
| 67 | - public String queryBackTime(String devId, J9205 j9205, Integer timeOut) { | |
| 68 | - Cmd cmd = new Cmd.Builder() | |
| 69 | - .setDevId(devId) | |
| 70 | - .setPackageNo(randomInt()) | |
| 71 | - .setMsgId(H9205) | |
| 72 | - .setRespId(H1205) | |
| 73 | - .setRs(j9205) | |
| 74 | - .build(); | |
| 75 | - return SessionManager.INSTANCE.request(cmd, timeOut); | |
| 76 | - } | |
| 77 | - | |
| 78 | - /** | |
| 79 | - * 开启视频回放 | |
| 80 | - * | |
| 81 | - * @param devId 设备号 | |
| 82 | - * @param j9201 视频回放参数 | |
| 83 | - */ | |
| 84 | - public String startBackLive(String devId, J9201 j9201, Integer timeOut) { | |
| 85 | - Cmd cmd = new Cmd.Builder() | |
| 86 | - .setDevId(devId) | |
| 87 | - .setPackageNo(randomInt()) | |
| 88 | - .setMsgId(H9201) | |
| 89 | - .setRespId(H1205) | |
| 90 | - .setRs(j9201) | |
| 91 | - .build(); | |
| 92 | - return SessionManager.INSTANCE.request(cmd, timeOut); | |
| 93 | - } | |
| 94 | - | |
| 95 | - /** | |
| 96 | - * 视频回放控制 | |
| 97 | - * | |
| 98 | - * @param devId 设备号 | |
| 99 | - * @param j9202 控制视频回放参数 | |
| 100 | - */ | |
| 101 | - public String controlBackLive(String devId, J9202 j9202, Integer timeOut) { | |
| 102 | - Cmd cmd = new Cmd.Builder() | |
| 103 | - .setDevId(devId) | |
| 104 | - .setPackageNo(randomInt()) | |
| 105 | - .setMsgId(H9202) | |
| 106 | - .setRespId(H0001) | |
| 107 | - .setRs(j9202) | |
| 108 | - .build(); | |
| 109 | - return SessionManager.INSTANCE.request(cmd, timeOut); | |
| 110 | - } | |
| 111 | - | |
| 112 | - private Long randomInt() { | |
| 113 | - return (long) random.nextInt(1000) + 1; | |
| 114 | - } | |
| 115 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/codec/decode/Jt808Decoder.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.codec.decode; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.proc.Header; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.proc.factory.CodecFactory; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.proc.request.Re; | |
| 6 | -import com.genersoft.iot.vmp.jt1078.proc.response.Rs; | |
| 7 | -import com.genersoft.iot.vmp.jt1078.session.Session; | |
| 8 | -import io.netty.buffer.ByteBuf; | |
| 9 | -import io.netty.buffer.ByteBufUtil; | |
| 10 | -import io.netty.buffer.CompositeByteBuf; | |
| 11 | -import io.netty.buffer.UnpooledByteBufAllocator; | |
| 12 | -import io.netty.channel.ChannelHandlerContext; | |
| 13 | -import io.netty.handler.codec.ByteToMessageDecoder; | |
| 14 | -import org.slf4j.Logger; | |
| 15 | -import org.slf4j.LoggerFactory; | |
| 16 | - | |
| 17 | -import java.util.ArrayList; | |
| 18 | -import java.util.List; | |
| 19 | - | |
| 20 | -/** | |
| 21 | - * @author QingtaiJiang | |
| 22 | - * @date 2023/4/27 18:10 | |
| 23 | - * @email qingtaij@163.com | |
| 24 | - */ | |
| 25 | -public class Jt808Decoder extends ByteToMessageDecoder { | |
| 26 | - private final static Logger log = LoggerFactory.getLogger(Jt808Decoder.class); | |
| 27 | - | |
| 28 | - @Override | |
| 29 | - protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { | |
| 30 | - Session session = ctx.channel().attr(Session.KEY).get(); | |
| 31 | - log.info("> {} hex:{}", session, ByteBufUtil.hexDump(in)); | |
| 32 | - | |
| 33 | - try { | |
| 34 | - ByteBuf buf = unEscapeAndCheck(in); | |
| 35 | - | |
| 36 | - Header header = new Header(); | |
| 37 | - header.setMsgId(ByteBufUtil.hexDump(buf.readSlice(2))); | |
| 38 | - header.setMsgPro(buf.readUnsignedShort()); | |
| 39 | - if (header.is2019Version()) { | |
| 40 | - header.setVersion(buf.readUnsignedByte()); | |
| 41 | - String devId = ByteBufUtil.hexDump(buf.readSlice(10)); | |
| 42 | - header.setDevId(devId.replaceFirst("^0*", "")); | |
| 43 | - } else { | |
| 44 | - header.setDevId(ByteBufUtil.hexDump(buf.readSlice(6)).replaceFirst("^0*", "")); | |
| 45 | - } | |
| 46 | - header.setSn(buf.readUnsignedShort()); | |
| 47 | - | |
| 48 | - Re handler = CodecFactory.getHandler(header.getMsgId()); | |
| 49 | - if (handler == null) { | |
| 50 | - log.error("get msgId is null {}", header.getMsgId()); | |
| 51 | - return; | |
| 52 | - } | |
| 53 | - Rs decode = handler.decode(buf, header, session); | |
| 54 | - if (decode != null) { | |
| 55 | - out.add(decode); | |
| 56 | - } | |
| 57 | - } finally { | |
| 58 | - in.skipBytes(in.readableBytes()); | |
| 59 | - } | |
| 60 | - | |
| 61 | - | |
| 62 | - } | |
| 63 | - | |
| 64 | - | |
| 65 | - /** | |
| 66 | - * 转义与验证校验码 | |
| 67 | - * | |
| 68 | - * @param byteBuf 转义Buf | |
| 69 | - * @return 转义好的数据 | |
| 70 | - */ | |
| 71 | - public ByteBuf unEscapeAndCheck(ByteBuf byteBuf) throws Exception { | |
| 72 | - int low = byteBuf.readerIndex(); | |
| 73 | - int high = byteBuf.writerIndex(); | |
| 74 | - byte checkSum = 0; | |
| 75 | - int calculationCheckSum = 0; | |
| 76 | - | |
| 77 | - byte aByte = byteBuf.getByte(high - 2); | |
| 78 | - byte protocolEscapeFlag7d = 0x7d; | |
| 79 | - //0x7d转义 | |
| 80 | - byte protocolEscapeFlag01 = 0x01; | |
| 81 | - //0x7e转义 | |
| 82 | - byte protocolEscapeFlag02 = 0x02; | |
| 83 | - if (aByte == protocolEscapeFlag7d) { | |
| 84 | - byte b2 = byteBuf.getByte(high - 1); | |
| 85 | - if (b2 == protocolEscapeFlag01) { | |
| 86 | - checkSum = protocolEscapeFlag7d; | |
| 87 | - } else if (b2 == protocolEscapeFlag02) { | |
| 88 | - checkSum = 0x7e; | |
| 89 | - } else { | |
| 90 | - log.error("转义1异常:{}", ByteBufUtil.hexDump(byteBuf)); | |
| 91 | - throw new Exception("转义错误"); | |
| 92 | - } | |
| 93 | - high = high - 2; | |
| 94 | - } else { | |
| 95 | - high = high - 1; | |
| 96 | - checkSum = byteBuf.getByte(high); | |
| 97 | - } | |
| 98 | - List<ByteBuf> bufList = new ArrayList<>(); | |
| 99 | - int index = low; | |
| 100 | - while (index < high) { | |
| 101 | - byte b = byteBuf.getByte(index); | |
| 102 | - if (b == protocolEscapeFlag7d) { | |
| 103 | - byte c = byteBuf.getByte(index + 1); | |
| 104 | - if (c == protocolEscapeFlag01) { | |
| 105 | - ByteBuf slice = slice0x01(byteBuf, low, index); | |
| 106 | - bufList.add(slice); | |
| 107 | - b = protocolEscapeFlag7d; | |
| 108 | - } else if (c == protocolEscapeFlag02) { | |
| 109 | - ByteBuf slice = slice0x02(byteBuf, low, index); | |
| 110 | - bufList.add(slice); | |
| 111 | - b = 0x7e; | |
| 112 | - } else { | |
| 113 | - log.error("转义2异常:{}", ByteBufUtil.hexDump(byteBuf)); | |
| 114 | - throw new Exception("转义错误"); | |
| 115 | - } | |
| 116 | - index += 2; | |
| 117 | - low = index; | |
| 118 | - } else { | |
| 119 | - index += 1; | |
| 120 | - } | |
| 121 | - calculationCheckSum = calculationCheckSum ^ b; | |
| 122 | - } | |
| 123 | - | |
| 124 | - if (calculationCheckSum == checkSum) { | |
| 125 | - if (bufList.size() == 0) { | |
| 126 | - return byteBuf.slice(low, high); | |
| 127 | - } else { | |
| 128 | - bufList.add(byteBuf.slice(low, high - low)); | |
| 129 | - return new CompositeByteBuf(UnpooledByteBufAllocator.DEFAULT, false, bufList.size(), bufList); | |
| 130 | - } | |
| 131 | - } else { | |
| 132 | - log.info("{} 解析校验码:{}--计算校验码:{}", ByteBufUtil.hexDump(byteBuf), checkSum, calculationCheckSum); | |
| 133 | - throw new Exception("校验码错误!"); | |
| 134 | - } | |
| 135 | - } | |
| 136 | - | |
| 137 | - | |
| 138 | - private ByteBuf slice0x01(ByteBuf buf, int low, int sign) { | |
| 139 | - return buf.slice(low, sign - low + 1); | |
| 140 | - } | |
| 141 | - | |
| 142 | - private ByteBuf slice0x02(ByteBuf buf, int low, int sign) { | |
| 143 | - buf.setByte(sign, 0x7e); | |
| 144 | - return buf.slice(low, sign - low + 1); | |
| 145 | - } | |
| 146 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/codec/encode/Jt808Encoder.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.codec.encode; | |
| 2 | - | |
| 3 | - | |
| 4 | -import com.genersoft.iot.vmp.jt1078.proc.response.Rs; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.session.Session; | |
| 6 | -import io.netty.buffer.ByteBuf; | |
| 7 | -import io.netty.buffer.ByteBufUtil; | |
| 8 | -import io.netty.channel.ChannelHandlerContext; | |
| 9 | -import io.netty.handler.codec.MessageToByteEncoder; | |
| 10 | -import org.slf4j.Logger; | |
| 11 | -import org.slf4j.LoggerFactory; | |
| 12 | - | |
| 13 | -/** | |
| 14 | - * @author QingtaiJiang | |
| 15 | - * @date 2023/4/27 18:10 | |
| 16 | - * @email qingtaij@163.com | |
| 17 | - */ | |
| 18 | -public class Jt808Encoder extends MessageToByteEncoder<Rs> { | |
| 19 | - private final static Logger log = LoggerFactory.getLogger(Jt808Encoder.class); | |
| 20 | - | |
| 21 | - @Override | |
| 22 | - protected void encode(ChannelHandlerContext ctx, Rs msg, ByteBuf out) throws Exception { | |
| 23 | - Session session = ctx.channel().attr(Session.KEY).get(); | |
| 24 | - | |
| 25 | - ByteBuf encode = Jt808EncoderCmd.encode(msg, session, session.nextSerialNo()); | |
| 26 | - if(encode!=null){ | |
| 27 | - log.info("< {} hex:{}", session, ByteBufUtil.hexDump(encode)); | |
| 28 | - out.writeBytes(encode); | |
| 29 | - } | |
| 30 | - } | |
| 31 | - | |
| 32 | - | |
| 33 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/codec/encode/Jt808EncoderCmd.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.codec.encode; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.annotation.MsgId; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.proc.Header; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.proc.entity.Cmd; | |
| 6 | -import com.genersoft.iot.vmp.jt1078.proc.response.Rs; | |
| 7 | -import com.genersoft.iot.vmp.jt1078.session.Session; | |
| 8 | -import com.genersoft.iot.vmp.jt1078.util.Bin; | |
| 9 | -import io.netty.buffer.ByteBuf; | |
| 10 | -import io.netty.buffer.ByteBufUtil; | |
| 11 | -import io.netty.buffer.CompositeByteBuf; | |
| 12 | -import io.netty.buffer.Unpooled; | |
| 13 | -import io.netty.channel.ChannelHandlerContext; | |
| 14 | -import io.netty.handler.codec.MessageToByteEncoder; | |
| 15 | -import io.netty.util.ByteProcessor; | |
| 16 | -import org.slf4j.Logger; | |
| 17 | -import org.slf4j.LoggerFactory; | |
| 18 | -import org.springframework.util.StringUtils; | |
| 19 | - | |
| 20 | -import java.util.LinkedList; | |
| 21 | - | |
| 22 | -/** | |
| 23 | - * @author QingtaiJiang | |
| 24 | - * @date 2023/4/27 18:25 | |
| 25 | - * @email qingtaij@163.com | |
| 26 | - */ | |
| 27 | -public class Jt808EncoderCmd extends MessageToByteEncoder<Cmd> { | |
| 28 | - private final static Logger log = LoggerFactory.getLogger(Jt808EncoderCmd.class); | |
| 29 | - | |
| 30 | - @Override | |
| 31 | - protected void encode(ChannelHandlerContext ctx, Cmd cmd, ByteBuf out) throws Exception { | |
| 32 | - Session session = ctx.channel().attr(Session.KEY).get(); | |
| 33 | - Rs msg = cmd.getRs(); | |
| 34 | - ByteBuf encode = encode(msg, session, cmd.getPackageNo().intValue()); | |
| 35 | - if (encode != null) { | |
| 36 | - log.info("< {} hex:{}", session, ByteBufUtil.hexDump(encode)); | |
| 37 | - out.writeBytes(encode); | |
| 38 | - } | |
| 39 | - } | |
| 40 | - | |
| 41 | - | |
| 42 | - public static ByteBuf encode(Rs msg, Session session, Integer packageNo) { | |
| 43 | - String id = msg.getClass().getAnnotation(MsgId.class).id(); | |
| 44 | - if (!StringUtils.hasLength(id)) { | |
| 45 | - log.error("Not find msgId"); | |
| 46 | - return null; | |
| 47 | - } | |
| 48 | - | |
| 49 | - ByteBuf byteBuf = Unpooled.buffer(); | |
| 50 | - | |
| 51 | - byteBuf.writeBytes(ByteBufUtil.decodeHexDump(id)); | |
| 52 | - | |
| 53 | - ByteBuf encode = msg.encode(); | |
| 54 | - | |
| 55 | - Header header = msg.getHeader(); | |
| 56 | - if (header == null) { | |
| 57 | - header = session.getHeader(); | |
| 58 | - } | |
| 59 | - | |
| 60 | - if (header.is2019Version()) { | |
| 61 | - // 消息体属性 | |
| 62 | - byteBuf.writeShort(encode.readableBytes() | 1 << 14); | |
| 63 | - | |
| 64 | - // 版本号 | |
| 65 | - byteBuf.writeByte(header.getVersion()); | |
| 66 | - | |
| 67 | - // 终端手机号 | |
| 68 | - byteBuf.writeBytes(ByteBufUtil.decodeHexDump(Bin.strHexPaddingLeft(header.getDevId(), 20))); | |
| 69 | - } else { | |
| 70 | - // 消息体属性 | |
| 71 | - byteBuf.writeShort(encode.readableBytes()); | |
| 72 | - | |
| 73 | - byteBuf.writeBytes(ByteBufUtil.decodeHexDump(Bin.strHexPaddingLeft(header.getDevId(), 12))); | |
| 74 | - } | |
| 75 | - | |
| 76 | - // 消息体流水号 | |
| 77 | - byteBuf.writeShort(packageNo); | |
| 78 | - | |
| 79 | - // 写入消息体 | |
| 80 | - byteBuf.writeBytes(encode); | |
| 81 | - | |
| 82 | - // 计算校验码,并反转义 | |
| 83 | - byteBuf = escapeAndCheck0(byteBuf); | |
| 84 | - return byteBuf; | |
| 85 | - } | |
| 86 | - | |
| 87 | - | |
| 88 | - private static final ByteProcessor searcher = value -> !(value == 0x7d || value == 0x7e); | |
| 89 | - | |
| 90 | - //转义与校验 | |
| 91 | - public static ByteBuf escapeAndCheck0(ByteBuf source) { | |
| 92 | - | |
| 93 | - sign(source); | |
| 94 | - | |
| 95 | - int low = source.readerIndex(); | |
| 96 | - int high = source.writerIndex(); | |
| 97 | - | |
| 98 | - LinkedList<ByteBuf> bufList = new LinkedList<>(); | |
| 99 | - int mark, len; | |
| 100 | - while ((mark = source.forEachByte(low, high - low, searcher)) > 0) { | |
| 101 | - | |
| 102 | - len = mark + 1 - low; | |
| 103 | - ByteBuf[] slice = slice(source, low, len); | |
| 104 | - bufList.add(slice[0]); | |
| 105 | - bufList.add(slice[1]); | |
| 106 | - low += len; | |
| 107 | - } | |
| 108 | - | |
| 109 | - if (bufList.size() > 0) { | |
| 110 | - bufList.add(source.slice(low, high - low)); | |
| 111 | - } else { | |
| 112 | - bufList.add(source); | |
| 113 | - } | |
| 114 | - | |
| 115 | - ByteBuf delimiter = Unpooled.buffer(1, 1).writeByte(0x7e).retain(); | |
| 116 | - bufList.addFirst(delimiter); | |
| 117 | - bufList.addLast(delimiter); | |
| 118 | - | |
| 119 | - CompositeByteBuf byteBufLs = Unpooled.compositeBuffer(bufList.size()); | |
| 120 | - byteBufLs.addComponents(true, bufList); | |
| 121 | - return byteBufLs; | |
| 122 | - } | |
| 123 | - | |
| 124 | - public static void sign(ByteBuf buf) { | |
| 125 | - byte checkCode = bcc(buf); | |
| 126 | - buf.writeByte(checkCode); | |
| 127 | - } | |
| 128 | - | |
| 129 | - public static byte bcc(ByteBuf byteBuf) { | |
| 130 | - byte cs = 0; | |
| 131 | - while (byteBuf.isReadable()) | |
| 132 | - cs ^= byteBuf.readByte(); | |
| 133 | - byteBuf.resetReaderIndex(); | |
| 134 | - return cs; | |
| 135 | - } | |
| 136 | - | |
| 137 | - protected static ByteBuf[] slice(ByteBuf byteBuf, int index, int length) { | |
| 138 | - byte first = byteBuf.getByte(index + length - 1); | |
| 139 | - | |
| 140 | - ByteBuf[] byteBufList = new ByteBuf[2]; | |
| 141 | - byteBufList[0] = byteBuf.retainedSlice(index, length); | |
| 142 | - | |
| 143 | - if (first == 0x7d) { | |
| 144 | - byteBufList[1] = Unpooled.buffer(1, 1).writeByte(0x01); | |
| 145 | - } else { | |
| 146 | - byteBuf.setByte(index + length - 1, 0x7d); | |
| 147 | - byteBufList[1] = Unpooled.buffer(1, 1).writeByte(0x02); | |
| 148 | - } | |
| 149 | - return byteBufList; | |
| 150 | - } | |
| 151 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/codec/netty/Jt808Handler.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.codec.netty; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.proc.response.Rs; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.session.Session; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.session.SessionManager; | |
| 6 | -import io.netty.channel.Channel; | |
| 7 | -import io.netty.channel.ChannelHandlerContext; | |
| 8 | -import io.netty.channel.ChannelInboundHandlerAdapter; | |
| 9 | -import io.netty.handler.timeout.IdleState; | |
| 10 | -import io.netty.handler.timeout.IdleStateEvent; | |
| 11 | -import org.slf4j.Logger; | |
| 12 | -import org.slf4j.LoggerFactory; | |
| 13 | - | |
| 14 | -/** | |
| 15 | - * @author QingtaiJiang | |
| 16 | - * @date 2023/4/27 18:14 | |
| 17 | - * @email qingtaij@163.com | |
| 18 | - */ | |
| 19 | -public class Jt808Handler extends ChannelInboundHandlerAdapter { | |
| 20 | - | |
| 21 | - private final static Logger log = LoggerFactory.getLogger(Jt808Handler.class); | |
| 22 | - | |
| 23 | - @Override | |
| 24 | - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { | |
| 25 | - if (msg instanceof Rs) { | |
| 26 | - ctx.writeAndFlush(msg); | |
| 27 | - } else { | |
| 28 | - ctx.fireChannelRead(msg); | |
| 29 | - } | |
| 30 | - } | |
| 31 | - | |
| 32 | - @Override | |
| 33 | - public void channelActive(ChannelHandlerContext ctx) { | |
| 34 | - Channel channel = ctx.channel(); | |
| 35 | - Session session = SessionManager.INSTANCE.newSession(channel); | |
| 36 | - channel.attr(Session.KEY).set(session); | |
| 37 | - log.info("> Tcp connect {}", session); | |
| 38 | - } | |
| 39 | - | |
| 40 | - @Override | |
| 41 | - public void channelInactive(ChannelHandlerContext ctx) { | |
| 42 | - Session session = ctx.channel().attr(Session.KEY).get(); | |
| 43 | - log.info("< Tcp disconnect {}", session); | |
| 44 | - ctx.close(); | |
| 45 | - } | |
| 46 | - | |
| 47 | - @Override | |
| 48 | - public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) { | |
| 49 | - Session session = ctx.channel().attr(Session.KEY).get(); | |
| 50 | - String message = e.getMessage(); | |
| 51 | - if (message.toLowerCase().contains("Connection reset by peer".toLowerCase())) { | |
| 52 | - log.info("< exception{} {}", session, e.getMessage()); | |
| 53 | - } else { | |
| 54 | - log.info("< exception{} {}", session, e.getMessage(), e); | |
| 55 | - } | |
| 56 | - | |
| 57 | - } | |
| 58 | - | |
| 59 | - @Override | |
| 60 | - public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { | |
| 61 | - if (evt instanceof IdleStateEvent) { | |
| 62 | - IdleStateEvent event = (IdleStateEvent) evt; | |
| 63 | - IdleState state = event.state(); | |
| 64 | - if (state == IdleState.READER_IDLE || state == IdleState.WRITER_IDLE) { | |
| 65 | - Session session = ctx.channel().attr(Session.KEY).get(); | |
| 66 | - log.warn("< Proactively disconnect{}", session); | |
| 67 | - ctx.close(); | |
| 68 | - } | |
| 69 | - } | |
| 70 | - } | |
| 71 | - | |
| 72 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/codec/netty/TcpServer.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.codec.netty; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.codec.decode.Jt808Decoder; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.codec.encode.Jt808Encoder; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.codec.encode.Jt808EncoderCmd; | |
| 6 | -import com.genersoft.iot.vmp.jt1078.proc.factory.CodecFactory; | |
| 7 | -import io.netty.bootstrap.ServerBootstrap; | |
| 8 | -import io.netty.buffer.ByteBuf; | |
| 9 | -import io.netty.buffer.Unpooled; | |
| 10 | -import io.netty.channel.ChannelFuture; | |
| 11 | -import io.netty.channel.ChannelInitializer; | |
| 12 | -import io.netty.channel.EventLoopGroup; | |
| 13 | -import io.netty.channel.nio.NioEventLoopGroup; | |
| 14 | -import io.netty.channel.socket.nio.NioChannelOption; | |
| 15 | -import io.netty.channel.socket.nio.NioServerSocketChannel; | |
| 16 | -import io.netty.channel.socket.nio.NioSocketChannel; | |
| 17 | -import io.netty.handler.codec.DelimiterBasedFrameDecoder; | |
| 18 | -import io.netty.handler.timeout.IdleStateHandler; | |
| 19 | -import io.netty.util.concurrent.Future; | |
| 20 | -import org.slf4j.Logger; | |
| 21 | -import org.slf4j.LoggerFactory; | |
| 22 | - | |
| 23 | -import java.util.concurrent.TimeUnit; | |
| 24 | - | |
| 25 | -/** | |
| 26 | - * @author QingtaiJiang | |
| 27 | - * @date 2023/4/27 18:01 | |
| 28 | - * @email qingtaij@163.com | |
| 29 | - */ | |
| 30 | - | |
| 31 | -public class TcpServer { | |
| 32 | - private final static Logger log = LoggerFactory.getLogger(TcpServer.class); | |
| 33 | - | |
| 34 | - private final Integer port; | |
| 35 | - private boolean isRunning = false; | |
| 36 | - private EventLoopGroup bossGroup = null; | |
| 37 | - private EventLoopGroup workerGroup = null; | |
| 38 | - | |
| 39 | - private final ByteBuf DECODER_JT808 = Unpooled.wrappedBuffer(new byte[]{0x7e}); | |
| 40 | - | |
| 41 | - public TcpServer(Integer port) { | |
| 42 | - this.port = port; | |
| 43 | - } | |
| 44 | - | |
| 45 | - private void startTcpServer() { | |
| 46 | - try { | |
| 47 | - CodecFactory.init(); | |
| 48 | - this.bossGroup = new NioEventLoopGroup(); | |
| 49 | - this.workerGroup = new NioEventLoopGroup(); | |
| 50 | - ServerBootstrap bootstrap = new ServerBootstrap(); | |
| 51 | - bootstrap.channel(NioServerSocketChannel.class); | |
| 52 | - bootstrap.group(bossGroup, workerGroup); | |
| 53 | - | |
| 54 | - bootstrap.option(NioChannelOption.SO_BACKLOG, 1024) | |
| 55 | - .option(NioChannelOption.SO_REUSEADDR, true) | |
| 56 | - .childOption(NioChannelOption.TCP_NODELAY, true) | |
| 57 | - .childHandler(new ChannelInitializer<NioSocketChannel>() { | |
| 58 | - @Override | |
| 59 | - public void initChannel(NioSocketChannel channel) { | |
| 60 | - channel.pipeline() | |
| 61 | - .addLast(new IdleStateHandler(10, 0, 0, TimeUnit.MINUTES)) | |
| 62 | - .addLast(new DelimiterBasedFrameDecoder(1024 * 2, DECODER_JT808)) | |
| 63 | - .addLast(new Jt808Decoder()) | |
| 64 | - .addLast(new Jt808Encoder()) | |
| 65 | - .addLast(new Jt808EncoderCmd()) | |
| 66 | - .addLast(new Jt808Handler()); | |
| 67 | - } | |
| 68 | - }); | |
| 69 | - ChannelFuture channelFuture = bootstrap.bind(port).sync(); | |
| 70 | - // 监听设备TCP端口是否启动成功 | |
| 71 | - channelFuture.addListener(future -> { | |
| 72 | - if (!future.isSuccess()) { | |
| 73 | - log.error("Binding port:{} fail! cause: {}", port, future.cause().getCause(), future.cause()); | |
| 74 | - } | |
| 75 | - }); | |
| 76 | - log.info("服务:JT808 Server 启动成功, port:{}", port); | |
| 77 | - channelFuture.channel().closeFuture().sync(); | |
| 78 | - } catch (Exception e) { | |
| 79 | - log.warn("服务:JT808 Server 启动异常, port:{},{}", port, e.getMessage(), e); | |
| 80 | - } finally { | |
| 81 | - stop(); | |
| 82 | - } | |
| 83 | - } | |
| 84 | - | |
| 85 | - /** | |
| 86 | - * 开启一个新的线程,拉起来Netty | |
| 87 | - */ | |
| 88 | - public synchronized void start() { | |
| 89 | - if (this.isRunning) { | |
| 90 | - log.warn("服务:JT808 Server 已经启动, port:{}", port); | |
| 91 | - return; | |
| 92 | - } | |
| 93 | - this.isRunning = true; | |
| 94 | - new Thread(this::startTcpServer).start(); | |
| 95 | - } | |
| 96 | - | |
| 97 | - public synchronized void stop() { | |
| 98 | - if (!this.isRunning) { | |
| 99 | - log.warn("服务:JT808 Server 已经停止, port:{}", port); | |
| 100 | - } | |
| 101 | - this.isRunning = false; | |
| 102 | - Future<?> future = this.bossGroup.shutdownGracefully(); | |
| 103 | - if (!future.isSuccess()) { | |
| 104 | - log.warn("bossGroup 无法正常停止", future.cause()); | |
| 105 | - } | |
| 106 | - future = this.workerGroup.shutdownGracefully(); | |
| 107 | - if (!future.isSuccess()) { | |
| 108 | - log.warn("workerGroup 无法正常停止", future.cause()); | |
| 109 | - } | |
| 110 | - log.warn("服务:JT808 Server 已经停止, port:{}", port); | |
| 111 | - } | |
| 112 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/config/JT1078AutoConfiguration.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.config; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.app.VideoServerApp; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.cmd.JT1078Template; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.codec.netty.TcpServer; | |
| 6 | -import org.springframework.beans.factory.annotation.Value; | |
| 7 | -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | |
| 8 | -import org.springframework.context.annotation.Bean; | |
| 9 | -import org.springframework.context.annotation.Configuration; | |
| 10 | -import org.springframework.core.annotation.Order; | |
| 11 | - | |
| 12 | -/** | |
| 13 | - * @author QingtaiJiang | |
| 14 | - * @date 2023/4/27 19:35 | |
| 15 | - * @email qingtaij@163.com | |
| 16 | - */ | |
| 17 | -@Order(Integer.MIN_VALUE) | |
| 18 | -@Configuration | |
| 19 | -@ConditionalOnProperty(value = "jt1078.enable", havingValue = "true") | |
| 20 | -public class JT1078AutoConfiguration { | |
| 21 | - | |
| 22 | -// @Bean(initMethod = "start", destroyMethod = "stop") | |
| 23 | -// public TcpServer jt1078Server(@Value("${jt1078.port}") Integer port) { | |
| 24 | -// return new TcpServer(port); | |
| 25 | -// } | |
| 26 | - | |
| 27 | -// @Bean(initMethod = "start", destroyMethod = "stop") | |
| 28 | - @Bean | |
| 29 | - public VideoServerApp jt1078VideoServerApp(@Value("${jt1078.port}") Integer port) { | |
| 30 | - VideoServerApp videoServerApp = new VideoServerApp(); | |
| 31 | - new Thread(new Runnable() { | |
| 32 | - @Override | |
| 33 | - public void run() { | |
| 34 | - try { | |
| 35 | - videoServerApp.createListenter(); | |
| 36 | - } catch (Exception e) { | |
| 37 | - throw new RuntimeException(e); | |
| 38 | - } | |
| 39 | - } | |
| 40 | - }).start(); | |
| 41 | - | |
| 42 | - return videoServerApp; | |
| 43 | - } | |
| 44 | - @Bean | |
| 45 | - public JT1078Template jt1078Template() { | |
| 46 | - return new JT1078Template(); | |
| 47 | - } | |
| 48 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/config/JT1078Controller.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.config; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.cmd.JT1078Template; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.proc.response.*; | |
| 5 | -import com.genersoft.iot.vmp.vmanager.bean.WVPResult; | |
| 6 | -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | |
| 7 | -import org.springframework.web.bind.annotation.GetMapping; | |
| 8 | -import org.springframework.web.bind.annotation.PathVariable; | |
| 9 | -import org.springframework.web.bind.annotation.RequestMapping; | |
| 10 | -import org.springframework.web.bind.annotation.RestController; | |
| 11 | - | |
| 12 | -import javax.annotation.Resource; | |
| 13 | - | |
| 14 | -/** | |
| 15 | - * curl http://localhost:18080/api/jt1078/start/live/18864197066/1 | |
| 16 | - * | |
| 17 | - * @author QingtaiJiang | |
| 18 | - * @date 2023/4/27 18:12 | |
| 19 | - * @email qingtaij@163.com | |
| 20 | - */ | |
| 21 | -@ConditionalOnProperty(value = "jt1078.enable", havingValue = "true") | |
| 22 | -@RestController | |
| 23 | -@RequestMapping("/api/jt1078") | |
| 24 | -public class JT1078Controller { | |
| 25 | - | |
| 26 | - @Resource | |
| 27 | - JT1078Template jt1078Template; | |
| 28 | - | |
| 29 | - /** | |
| 30 | - * jt1078Template 调用示例 | |
| 31 | - */ | |
| 32 | - @GetMapping("/start/live/{deviceId}/{channelId}") | |
| 33 | - public WVPResult<?> startLive(@PathVariable String deviceId, @PathVariable String channelId) { | |
| 34 | - J9101 j9101 = new J9101(); | |
| 35 | - j9101.setChannel(Integer.valueOf(channelId)); | |
| 36 | - j9101.setIp("192.168.169.100"); | |
| 37 | - j9101.setRate(1); | |
| 38 | - j9101.setTcpPort(7618); | |
| 39 | - j9101.setUdpPort(7618); | |
| 40 | - j9101.setType(0); | |
| 41 | - // TODO 分配ZLM,获取IP、端口 | |
| 42 | - String s = jt1078Template.startLive(deviceId, j9101, 6); | |
| 43 | - // TODO 设备响应成功后,封装拉流结果集 | |
| 44 | - WVPResult<String> wvpResult = new WVPResult<>(); | |
| 45 | - wvpResult.setCode(200); | |
| 46 | - wvpResult.setData(String.format("http://192.168.169.100/rtp/%s_%s.live.mp4", deviceId, channelId)); | |
| 47 | - return wvpResult; | |
| 48 | - } | |
| 49 | - | |
| 50 | -} | |
| 51 | - |
src/main/java/com/genersoft/iot/vmp/jt1078/http/NettyHttpServerHandler.java deleted
100644 → 0
| 1 | -// | |
| 2 | -// Source code recreated from a .class file by IntelliJ IDEA | |
| 3 | -// (powered by FernFlower decompiler) | |
| 4 | -// | |
| 5 | - | |
| 6 | -package com.genersoft.iot.vmp.jt1078.http; | |
| 7 | - | |
| 8 | -import com.genersoft.iot.vmp.jt1078.app.VideoServerApp; | |
| 9 | -import com.genersoft.iot.vmp.jt1078.entity.Media.Type; | |
| 10 | -import com.genersoft.iot.vmp.jt1078.publisher.PublishManager; | |
| 11 | -import com.genersoft.iot.vmp.jt1078.server.Jtt1078Handler; | |
| 12 | -import com.genersoft.iot.vmp.jt1078.server.Session; | |
| 13 | -import com.genersoft.iot.vmp.jt1078.util.FileUtils; | |
| 14 | -import com.genersoft.iot.vmp.jt1078.util.Packet; | |
| 15 | -import io.netty.buffer.ByteBuf; | |
| 16 | -import io.netty.buffer.Unpooled; | |
| 17 | -import io.netty.channel.ChannelHandlerContext; | |
| 18 | -import io.netty.channel.ChannelInboundHandlerAdapter; | |
| 19 | -import io.netty.handler.codec.http.DefaultFullHttpResponse; | |
| 20 | -import io.netty.handler.codec.http.FullHttpRequest; | |
| 21 | -import io.netty.handler.codec.http.FullHttpResponse; | |
| 22 | -import io.netty.handler.codec.http.HttpResponseStatus; | |
| 23 | -import io.netty.handler.codec.http.HttpVersion; | |
| 24 | -import io.netty.util.Attribute; | |
| 25 | -import io.netty.util.AttributeKey; | |
| 26 | -import org.apache.commons.lang3.StringUtils; | |
| 27 | -import org.slf4j.Logger; | |
| 28 | -import org.slf4j.LoggerFactory; | |
| 29 | - | |
| 30 | -import java.io.IOException; | |
| 31 | -import java.net.URISyntaxException; | |
| 32 | -import java.util.Objects; | |
| 33 | - | |
| 34 | -public class NettyHttpServerHandler extends ChannelInboundHandlerAdapter { | |
| 35 | - private String tagMapping; | |
| 36 | - private Integer httpPort; | |
| 37 | - static Logger logger = LoggerFactory.getLogger(NettyHttpServerHandler.class); | |
| 38 | - static final byte[] HTTP_403_DATA = "<h1>403 Forbidden</h1><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding-->".getBytes(); | |
| 39 | - static final byte[] SUCCESS = "{code:0}".getBytes(); | |
| 40 | - static final String HEADER_ENCODING = "ISO-8859-1"; | |
| 41 | - private static final AttributeKey<Session> SESSION_KEY = AttributeKey.valueOf("session"); | |
| 42 | - | |
| 43 | - public NettyHttpServerHandler(String tagMapping, Integer httpPort) { | |
| 44 | - this.tagMapping = tagMapping; | |
| 45 | - this.httpPort = httpPort; | |
| 46 | - } | |
| 47 | - | |
| 48 | - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { | |
| 49 | - FullHttpRequest fhr = (FullHttpRequest) msg; | |
| 50 | - String uri = fhr.uri(); | |
| 51 | - Packet resp = Packet.create(1024); | |
| 52 | - String tagMapping; | |
| 53 | - long wid; | |
| 54 | - if (uri.startsWith("/video/")) { | |
| 55 | - tagMapping = uri.substring("/video/".length()); | |
| 56 | - resp.addBytes("HTTP/1.1 200 OK\r\n".getBytes("ISO-8859-1")); | |
| 57 | - resp.addBytes("Connection: keep-alive\r\n".getBytes("ISO-8859-1")); | |
| 58 | - resp.addBytes("Content-Type: video/x-flv\r\n".getBytes("ISO-8859-1")); | |
| 59 | - resp.addBytes("Transfer-Encoding: chunked\r\n".getBytes("ISO-8859-1")); | |
| 60 | - resp.addBytes("Cache-Control: no-cache\r\n".getBytes("ISO-8859-1")); | |
| 61 | - resp.addBytes("Access-Control-Allow-Origin: *\r\n".getBytes("ISO-8859-1")); | |
| 62 | - resp.addBytes("Access-Control-Allow-Credentials: true\r\n".getBytes("ISO-8859-1")); | |
| 63 | - resp.addBytes("\r\n".getBytes("ISO-8859-1")); | |
| 64 | - ctx.writeAndFlush(resp.getBytes()).await(); | |
| 65 | - logger.info("Thread id:[{}]", Thread.currentThread().getId()); | |
| 66 | - if (StringUtils.isEmpty(this.tagMapping)) { | |
| 67 | - this.tagMapping = tagMapping; | |
| 68 | - } | |
| 69 | - | |
| 70 | - | |
| 71 | - wid = PublishManager.getInstance().subscribe(this.tagMapping, Type.Video, ctx, this.httpPort).getId(); | |
| 72 | - this.setSession(ctx, (new Session()).set("subscriber-id", wid).set("tag", this.tagMapping)); | |
| 73 | -// if (wid == 0) { | |
| 74 | - | |
| 75 | - try { | |
| 76 | - Jtt1078Handler.createStreamProxy(this.tagMapping, httpPort); | |
| 77 | - } catch (URISyntaxException e) { | |
| 78 | - throw new RuntimeException(e); | |
| 79 | - } catch (IOException e) { | |
| 80 | - throw new RuntimeException(e); | |
| 81 | - } | |
| 82 | - | |
| 83 | -// } | |
| 84 | - } else if (uri.equals("/test/multimedia")) { | |
| 85 | - this.responseHTMLFile("/multimedia.html", ctx); | |
| 86 | - } else { | |
| 87 | - String httpPort; | |
| 88 | - if (uri.startsWith("/stop/channel/")) { | |
| 89 | - resp.addBytes("HTTP/1.1 200 OK\r\n".getBytes("ISO-8859-1")); | |
| 90 | - resp.addBytes("Connection: keep-alive\r\n".getBytes("ISO-8859-1")); | |
| 91 | - resp.addBytes("Content-Type: video/x-flv\r\n".getBytes("ISO-8859-1")); | |
| 92 | - resp.addBytes("Transfer-Encoding: chunked\r\n".getBytes("ISO-8859-1")); | |
| 93 | - resp.addBytes("Cache-Control: no-cache\r\n".getBytes("ISO-8859-1")); | |
| 94 | - resp.addBytes("Access-Control-Allow-Origin: *\r\n".getBytes("ISO-8859-1")); | |
| 95 | - resp.addBytes("Access-Control-Allow-Credentials: true\r\n".getBytes("ISO-8859-1")); | |
| 96 | - tagMapping = uri.substring("/stop/channel/".length()); | |
| 97 | - String str = uri.substring("/stop/channel/".length()); | |
| 98 | - int endIndex = StringUtils.indexOf(str, "/"); | |
| 99 | - StringUtils.substring(str, 0, endIndex); | |
| 100 | - Integer startIndex = endIndex + 1; | |
| 101 | - endIndex = StringUtils.indexOf(str, "/", startIndex); | |
| 102 | - httpPort = StringUtils.substring(str, startIndex, endIndex); | |
| 103 | - startIndex = endIndex + 1; | |
| 104 | - httpPort = StringUtils.substring(str, startIndex, str.length()); | |
| 105 | - PublishManager publishManager = PublishManager.getInstance(); | |
| 106 | - publishManager.unsubscribeAndClose(tagMapping); | |
| 107 | - VideoServerApp.stopServer(Integer.parseInt(httpPort), Integer.parseInt(httpPort)); | |
| 108 | - logger.info("{}停流", tagMapping); | |
| 109 | - ByteBuf body = Unpooled.buffer(SUCCESS.length); | |
| 110 | - body.writeBytes(SUCCESS); | |
| 111 | - FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(200), body); | |
| 112 | - response.headers().add("Content-Length", SUCCESS.length); | |
| 113 | - ctx.writeAndFlush(response).await(); | |
| 114 | - ctx.flush(); | |
| 115 | - } else if (uri.startsWith("/new/server/")) { | |
| 116 | - resp.addBytes("HTTP/1.1 200 OK\r\n".getBytes("ISO-8859-1")); | |
| 117 | - resp.addBytes("Connection: keep-alive\r\n".getBytes("ISO-8859-1")); | |
| 118 | - resp.addBytes("Content-Type: video/x-flv\r\n".getBytes("ISO-8859-1")); | |
| 119 | - resp.addBytes("Transfer-Encoding: chunked\r\n".getBytes("ISO-8859-1")); | |
| 120 | - resp.addBytes("Cache-Control: no-cache\r\n".getBytes("ISO-8859-1")); | |
| 121 | - resp.addBytes("Access-Control-Allow-Origin: *\r\n".getBytes("ISO-8859-1")); | |
| 122 | - resp.addBytes("Access-Control-Allow-Credentials: true\r\n".getBytes("ISO-8859-1")); | |
| 123 | - tagMapping = uri.substring("/new/server/".length()); | |
| 124 | - int endIndex = StringUtils.indexOf(tagMapping, "/"); | |
| 125 | - String key = StringUtils.substring(tagMapping, 0, endIndex); | |
| 126 | - Integer startIndex = endIndex + 1; | |
| 127 | - endIndex = StringUtils.indexOf(tagMapping, "/", startIndex); | |
| 128 | - String port = StringUtils.substring(tagMapping, startIndex, endIndex); | |
| 129 | - startIndex = endIndex + 1; | |
| 130 | - httpPort = StringUtils.substring(tagMapping, startIndex, tagMapping.length()); | |
| 131 | - | |
| 132 | - ByteBuf body = Unpooled.buffer(SUCCESS.length); | |
| 133 | - body.writeBytes(SUCCESS); | |
| 134 | - FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(200), body); | |
| 135 | - response.headers().add("Content-Length", SUCCESS.length); | |
| 136 | - ctx.writeAndFlush(response).await(); | |
| 137 | - ctx.flush(); | |
| 138 | - } else if (uri.startsWith("/play/history/")) { | |
| 139 | - tagMapping = uri.substring("/play/history/".length()); | |
| 140 | - resp.addBytes("HTTP/1.1 200 OK\r\n".getBytes("ISO-8859-1")); | |
| 141 | - resp.addBytes("Connection: keep-alive\r\n".getBytes("ISO-8859-1")); | |
| 142 | - resp.addBytes("Content-Type: video/x-flv\r\n".getBytes("ISO-8859-1")); | |
| 143 | - resp.addBytes("Transfer-Encoding: chunked\r\n".getBytes("ISO-8859-1")); | |
| 144 | - resp.addBytes("Cache-Control: no-cache\r\n".getBytes("ISO-8859-1")); | |
| 145 | - resp.addBytes("Access-Control-Allow-Origin: *\r\n".getBytes("ISO-8859-1")); | |
| 146 | - resp.addBytes("Access-Control-Allow-Credentials: true\r\n".getBytes("ISO-8859-1")); | |
| 147 | - resp.addBytes("\r\n".getBytes("ISO-8859-1")); | |
| 148 | - ctx.writeAndFlush(resp.getBytes()).await(); | |
| 149 | - logger.info("Thread id:[{}]", Thread.currentThread().getId()); | |
| 150 | - wid = PublishManager.getInstance().subscribe(tagMapping, Type.Video, ctx, this.httpPort).getId(); | |
| 151 | - this.setSession(ctx, (new Session()).set("subscriber-id", wid).set("tag", tagMapping)); | |
| 152 | - } else { | |
| 153 | - ByteBuf body = Unpooled.buffer(HTTP_403_DATA.length); | |
| 154 | - body.writeBytes(HTTP_403_DATA); | |
| 155 | - FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(403), body); | |
| 156 | - response.headers().add("Content-Length", HTTP_403_DATA.length); | |
| 157 | - ctx.writeAndFlush(response).await(); | |
| 158 | - ctx.flush(); | |
| 159 | - } | |
| 160 | - } | |
| 161 | - | |
| 162 | - } | |
| 163 | - | |
| 164 | - public void channelInactive(ChannelHandlerContext ctx) throws Exception { | |
| 165 | - super.channelInactive(ctx); | |
| 166 | - Session session = this.getSession(ctx); | |
| 167 | - if (session != null && session.has("subscriber-id") && session.has("tag")) { | |
| 168 | - String tag = (String) session.get("tag"); | |
| 169 | - Long wid = (Long) session.get("subscriber-id"); | |
| 170 | - PublishManager.getInstance().unsubscribe(tag, wid); | |
| 171 | - } | |
| 172 | - | |
| 173 | - } | |
| 174 | - | |
| 175 | - private void responseHTMLFile(String htmlFilePath, ChannelHandlerContext ctx) { | |
| 176 | - byte[] fileData = FileUtils.read(NettyHttpServerHandler.class.getResourceAsStream(htmlFilePath)); | |
| 177 | - ByteBuf body = Unpooled.buffer(fileData.length); | |
| 178 | - body.writeBytes(fileData); | |
| 179 | - FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(200), body); | |
| 180 | - response.headers().add("Content-Length", fileData.length); | |
| 181 | - ctx.write(response); | |
| 182 | - ctx.flush(); | |
| 183 | - } | |
| 184 | - | |
| 185 | - public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { | |
| 186 | - ctx.flush(); | |
| 187 | - } | |
| 188 | - | |
| 189 | - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { | |
| 190 | - ctx.close(); | |
| 191 | - cause.printStackTrace(); | |
| 192 | - } | |
| 193 | - | |
| 194 | - public final void setSession(ChannelHandlerContext context, Session session) { | |
| 195 | - context.channel().attr(SESSION_KEY).set(session); | |
| 196 | - } | |
| 197 | - | |
| 198 | - public final Session getSession(ChannelHandlerContext context) { | |
| 199 | - Attribute<Session> attr = context.channel().attr(SESSION_KEY); | |
| 200 | - return null == attr ? null : (Session) attr.get(); | |
| 201 | - } | |
| 202 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/Header.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.util.Bin; | |
| 4 | - | |
| 5 | -/** | |
| 6 | - * @author QingtaiJiang | |
| 7 | - * @date 2023/4/27 18:22 | |
| 8 | - * @email qingtaij@163.com | |
| 9 | - */ | |
| 10 | -public class Header { | |
| 11 | - // 消息ID | |
| 12 | - String msgId; | |
| 13 | - | |
| 14 | - // 消息体属性 | |
| 15 | - Integer msgPro; | |
| 16 | - | |
| 17 | - // 标识 | |
| 18 | - String devId; | |
| 19 | - | |
| 20 | - // 消息体流水号 | |
| 21 | - Integer sn; | |
| 22 | - | |
| 23 | - // 协议版本号 | |
| 24 | - Short version = -1; | |
| 25 | - | |
| 26 | - | |
| 27 | - public String getMsgId() { | |
| 28 | - return msgId; | |
| 29 | - } | |
| 30 | - | |
| 31 | - public void setMsgId(String msgId) { | |
| 32 | - this.msgId = msgId; | |
| 33 | - } | |
| 34 | - | |
| 35 | - public Integer getMsgPro() { | |
| 36 | - return msgPro; | |
| 37 | - } | |
| 38 | - | |
| 39 | - public void setMsgPro(Integer msgPro) { | |
| 40 | - this.msgPro = msgPro; | |
| 41 | - } | |
| 42 | - | |
| 43 | - public String getDevId() { | |
| 44 | - return devId; | |
| 45 | - } | |
| 46 | - | |
| 47 | - public void setDevId(String devId) { | |
| 48 | - this.devId = devId; | |
| 49 | - } | |
| 50 | - | |
| 51 | - public Integer getSn() { | |
| 52 | - return sn; | |
| 53 | - } | |
| 54 | - | |
| 55 | - public void setSn(Integer sn) { | |
| 56 | - this.sn = sn; | |
| 57 | - } | |
| 58 | - | |
| 59 | - public Short getVersion() { | |
| 60 | - return version; | |
| 61 | - } | |
| 62 | - | |
| 63 | - public void setVersion(Short version) { | |
| 64 | - this.version = version; | |
| 65 | - } | |
| 66 | - | |
| 67 | - /** | |
| 68 | - * 判断是否是2019的版本 | |
| 69 | - * | |
| 70 | - * @return true 2019后的版本。false 2013 | |
| 71 | - */ | |
| 72 | - public boolean is2019Version() { | |
| 73 | - return Bin.get(msgPro, 14); | |
| 74 | - } | |
| 75 | - | |
| 76 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/entity/Cmd.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc.entity; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.proc.response.Rs; | |
| 4 | - | |
| 5 | -/** | |
| 6 | - * @author QingtaiJiang | |
| 7 | - * @date 2023/4/27 18:23 | |
| 8 | - * @email qingtaij@163.com | |
| 9 | - */ | |
| 10 | -public class Cmd { | |
| 11 | - String devId; | |
| 12 | - Long packageNo; | |
| 13 | - String msgId; | |
| 14 | - String respId; | |
| 15 | - Rs rs; | |
| 16 | - | |
| 17 | - public Cmd() { | |
| 18 | - } | |
| 19 | - | |
| 20 | - public Cmd(Builder builder) { | |
| 21 | - this.devId = builder.devId; | |
| 22 | - this.packageNo = builder.packageNo; | |
| 23 | - this.msgId = builder.msgId; | |
| 24 | - this.respId = builder.respId; | |
| 25 | - this.rs = builder.rs; | |
| 26 | - } | |
| 27 | - | |
| 28 | - public String getDevId() { | |
| 29 | - return devId; | |
| 30 | - } | |
| 31 | - | |
| 32 | - public void setDevId(String devId) { | |
| 33 | - this.devId = devId; | |
| 34 | - } | |
| 35 | - | |
| 36 | - public Long getPackageNo() { | |
| 37 | - return packageNo; | |
| 38 | - } | |
| 39 | - | |
| 40 | - public void setPackageNo(Long packageNo) { | |
| 41 | - this.packageNo = packageNo; | |
| 42 | - } | |
| 43 | - | |
| 44 | - public String getMsgId() { | |
| 45 | - return msgId; | |
| 46 | - } | |
| 47 | - | |
| 48 | - public void setMsgId(String msgId) { | |
| 49 | - this.msgId = msgId; | |
| 50 | - } | |
| 51 | - | |
| 52 | - public String getRespId() { | |
| 53 | - return respId; | |
| 54 | - } | |
| 55 | - | |
| 56 | - public void setRespId(String respId) { | |
| 57 | - this.respId = respId; | |
| 58 | - } | |
| 59 | - | |
| 60 | - public Rs getRs() { | |
| 61 | - return rs; | |
| 62 | - } | |
| 63 | - | |
| 64 | - public void setRs(Rs rs) { | |
| 65 | - this.rs = rs; | |
| 66 | - } | |
| 67 | - | |
| 68 | - public static class Builder { | |
| 69 | - String devId; | |
| 70 | - Long packageNo; | |
| 71 | - String msgId; | |
| 72 | - String respId; | |
| 73 | - Rs rs; | |
| 74 | - | |
| 75 | - public Builder setDevId(String devId) { | |
| 76 | - this.devId = devId.replaceFirst("^0*", ""); | |
| 77 | - return this; | |
| 78 | - } | |
| 79 | - | |
| 80 | - public Builder setPackageNo(Long packageNo) { | |
| 81 | - this.packageNo = packageNo; | |
| 82 | - return this; | |
| 83 | - } | |
| 84 | - | |
| 85 | - public Builder setMsgId(String msgId) { | |
| 86 | - this.msgId = msgId; | |
| 87 | - return this; | |
| 88 | - } | |
| 89 | - | |
| 90 | - public Builder setRespId(String respId) { | |
| 91 | - this.respId = respId; | |
| 92 | - return this; | |
| 93 | - } | |
| 94 | - | |
| 95 | - public Builder setRs(Rs re) { | |
| 96 | - this.rs = re; | |
| 97 | - return this; | |
| 98 | - } | |
| 99 | - | |
| 100 | - public Cmd build() { | |
| 101 | - return new Cmd(this); | |
| 102 | - } | |
| 103 | - } | |
| 104 | - | |
| 105 | - | |
| 106 | - @Override | |
| 107 | - public String toString() { | |
| 108 | - return "Cmd{" + | |
| 109 | - "devId='" + devId + '\'' + | |
| 110 | - ", packageNo=" + packageNo + | |
| 111 | - ", msgId='" + msgId + '\'' + | |
| 112 | - ", respId='" + respId + '\'' + | |
| 113 | - ", rs=" + rs + | |
| 114 | - '}'; | |
| 115 | - } | |
| 116 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/factory/CodecFactory.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc.factory; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.annotation.MsgId; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.proc.request.Re; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.util.ClassUtil; | |
| 6 | -import org.slf4j.Logger; | |
| 7 | -import org.slf4j.LoggerFactory; | |
| 8 | - | |
| 9 | -import java.util.HashMap; | |
| 10 | -import java.util.List; | |
| 11 | -import java.util.Map; | |
| 12 | - | |
| 13 | -/** | |
| 14 | - * @author QingtaiJiang | |
| 15 | - * @date 2023/4/27 18:29 | |
| 16 | - * @email qingtaij@163.com | |
| 17 | - */ | |
| 18 | - | |
| 19 | -public class CodecFactory { | |
| 20 | - private final static Logger log = LoggerFactory.getLogger(CodecFactory.class); | |
| 21 | - | |
| 22 | - private static Map<String, Class<?>> protocolHash; | |
| 23 | - | |
| 24 | - public static void init() { | |
| 25 | - protocolHash = new HashMap<>(); | |
| 26 | - List<Class<?>> classList = ClassUtil.getClassList("com.genersoft.iot.vmp.jt1078.proc", MsgId.class); | |
| 27 | - for (Class<?> handlerClass : classList) { | |
| 28 | - String id = handlerClass.getAnnotation(MsgId.class).id(); | |
| 29 | - protocolHash.put(id, handlerClass); | |
| 30 | - } | |
| 31 | - if (log.isDebugEnabled()) { | |
| 32 | - log.debug("消息ID缓存表 protocolHash:{}", protocolHash); | |
| 33 | - } | |
| 34 | - } | |
| 35 | - | |
| 36 | - public static Re getHandler(String msgId) { | |
| 37 | - Class<?> aClass = protocolHash.get(msgId); | |
| 38 | - Object bean = ClassUtil.getBean(aClass); | |
| 39 | - if (bean instanceof Re) { | |
| 40 | - return (Re) bean; | |
| 41 | - } | |
| 42 | - return null; | |
| 43 | - } | |
| 44 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/J0001.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc.request; | |
| 2 | - | |
| 3 | -import com.alibaba.fastjson2.JSON; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.annotation.MsgId; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.proc.Header; | |
| 6 | -import com.genersoft.iot.vmp.jt1078.proc.response.Rs; | |
| 7 | -import com.genersoft.iot.vmp.jt1078.session.Session; | |
| 8 | -import com.genersoft.iot.vmp.jt1078.session.SessionManager; | |
| 9 | -import io.netty.buffer.ByteBuf; | |
| 10 | -import io.netty.buffer.ByteBufUtil; | |
| 11 | - | |
| 12 | -/** | |
| 13 | - * 终端通用应答 | |
| 14 | - * | |
| 15 | - * @author QingtaiJiang | |
| 16 | - * @date 2023/4/27 18:04 | |
| 17 | - * @email qingtaij@163.com | |
| 18 | - */ | |
| 19 | -@MsgId(id = "0001") | |
| 20 | -public class J0001 extends Re { | |
| 21 | - int respNo; | |
| 22 | - String respId; | |
| 23 | - int result; | |
| 24 | - | |
| 25 | - @Override | |
| 26 | - protected Rs decode0(ByteBuf buf, Header header, Session session) { | |
| 27 | - respNo = buf.readUnsignedShort(); | |
| 28 | - respId = ByteBufUtil.hexDump(buf.readSlice(2)); | |
| 29 | - result = buf.readUnsignedByte(); | |
| 30 | - return null; | |
| 31 | - } | |
| 32 | - | |
| 33 | - @Override | |
| 34 | - protected Rs handler(Header header, Session session) { | |
| 35 | - SessionManager.INSTANCE.response(header.getDevId(), "0001", (long) respNo, JSON.toJSONString(this)); | |
| 36 | - return null; | |
| 37 | - } | |
| 38 | - | |
| 39 | - public int getRespNo() { | |
| 40 | - return respNo; | |
| 41 | - } | |
| 42 | - | |
| 43 | - public String getRespId() { | |
| 44 | - return respId; | |
| 45 | - } | |
| 46 | - | |
| 47 | - public int getResult() { | |
| 48 | - return result; | |
| 49 | - } | |
| 50 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/J0002.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc.request; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.annotation.MsgId; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.proc.Header; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.proc.response.J8001; | |
| 6 | -import com.genersoft.iot.vmp.jt1078.proc.response.Rs; | |
| 7 | -import com.genersoft.iot.vmp.jt1078.session.Session; | |
| 8 | -import io.netty.buffer.ByteBuf; | |
| 9 | - | |
| 10 | -/** | |
| 11 | - * 终端心跳 | |
| 12 | - * | |
| 13 | - * @author QingtaiJiang | |
| 14 | - * @date 2023/4/27 18:04 | |
| 15 | - * @email qingtaij@163.com | |
| 16 | - */ | |
| 17 | -@MsgId(id = "0002") | |
| 18 | -public class J0002 extends Re { | |
| 19 | - @Override | |
| 20 | - protected Rs decode0(ByteBuf buf, Header header, Session session) { | |
| 21 | - return null; | |
| 22 | - } | |
| 23 | - | |
| 24 | - @Override | |
| 25 | - protected Rs handler(Header header, Session session) { | |
| 26 | - J8001 j8001 = new J8001(); | |
| 27 | - j8001.setRespNo(header.getSn()); | |
| 28 | - j8001.setRespId(header.getMsgId()); | |
| 29 | - j8001.setResult(J8001.SUCCESS); | |
| 30 | - return j8001; | |
| 31 | - } | |
| 32 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/J0004.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc.request; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.annotation.MsgId; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.proc.Header; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.proc.response.Rs; | |
| 6 | -import com.genersoft.iot.vmp.jt1078.session.Session; | |
| 7 | -import io.netty.buffer.ByteBuf; | |
| 8 | - | |
| 9 | -/** | |
| 10 | - * 查询服务器时间 | |
| 11 | - * | |
| 12 | - * @author QingtaiJiang | |
| 13 | - * @date 2023/4/27 18:06 | |
| 14 | - * @email qingtaij@163.com | |
| 15 | - */ | |
| 16 | -@MsgId(id = "0004") | |
| 17 | -public class J0004 extends Re { | |
| 18 | - @Override | |
| 19 | - protected Rs decode0(ByteBuf buf, Header header, Session session) { | |
| 20 | - return null; | |
| 21 | - } | |
| 22 | - | |
| 23 | - @Override | |
| 24 | - protected Rs handler(Header header, Session session) { | |
| 25 | - return null; | |
| 26 | - } | |
| 27 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/J0100.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc.request; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.annotation.MsgId; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.proc.Header; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.proc.response.J8100; | |
| 6 | -import com.genersoft.iot.vmp.jt1078.proc.response.Rs; | |
| 7 | -import com.genersoft.iot.vmp.jt1078.session.Session; | |
| 8 | -import io.netty.buffer.ByteBuf; | |
| 9 | - | |
| 10 | -/** | |
| 11 | - * 终端注册 | |
| 12 | - * | |
| 13 | - * @author QingtaiJiang | |
| 14 | - * @date 2023/4/27 18:06 | |
| 15 | - * @email qingtaij@163.com | |
| 16 | - */ | |
| 17 | -@MsgId(id = "0100") | |
| 18 | -public class J0100 extends Re { | |
| 19 | - | |
| 20 | - private int provinceId; | |
| 21 | - | |
| 22 | - private int cityId; | |
| 23 | - | |
| 24 | - private String makerId; | |
| 25 | - | |
| 26 | - private String deviceModel; | |
| 27 | - | |
| 28 | - private String deviceId; | |
| 29 | - | |
| 30 | - private int plateColor; | |
| 31 | - | |
| 32 | - private String plateNo; | |
| 33 | - | |
| 34 | - @Override | |
| 35 | - protected Rs decode0(ByteBuf buf, Header header, Session session) { | |
| 36 | - Short version = header.getVersion(); | |
| 37 | - provinceId = buf.readUnsignedShort(); | |
| 38 | - if (version > 1) { | |
| 39 | - cityId = buf.readUnsignedShort(); | |
| 40 | - // decode as 2019 | |
| 41 | - } else { | |
| 42 | - int i = buf.readUnsignedShort(); | |
| 43 | - // decode as 2013 | |
| 44 | - } | |
| 45 | - return null; | |
| 46 | - } | |
| 47 | - | |
| 48 | - @Override | |
| 49 | - protected Rs handler(Header header, Session session) { | |
| 50 | - J8100 j8100 = new J8100(); | |
| 51 | - j8100.setRespNo(header.getSn()); | |
| 52 | - j8100.setResult(J8100.SUCCESS); | |
| 53 | - j8100.setCode("WVP_YYDS"); | |
| 54 | - return j8100; | |
| 55 | - } | |
| 56 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/J0102.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc.request; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.annotation.MsgId; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.proc.Header; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.proc.response.J8001; | |
| 6 | -import com.genersoft.iot.vmp.jt1078.proc.response.Rs; | |
| 7 | -import com.genersoft.iot.vmp.jt1078.session.Session; | |
| 8 | -import io.netty.buffer.ByteBuf; | |
| 9 | - | |
| 10 | -/** | |
| 11 | - * 终端鉴权 | |
| 12 | - * | |
| 13 | - * @author QingtaiJiang | |
| 14 | - * @date 2023/4/27 18:06 | |
| 15 | - * @email qingtaij@163.com | |
| 16 | - */ | |
| 17 | -@MsgId(id = "0102") | |
| 18 | -public class J0102 extends Re { | |
| 19 | - @Override | |
| 20 | - protected Rs decode0(ByteBuf buf, Header header, Session session) { | |
| 21 | - int lenCode = buf.readUnsignedByte(); | |
| 22 | -// String code = buf.readCharSequence(lenCode, CharsetUtil.UTF_8).toString(); | |
| 23 | - // if 2019 to decode next | |
| 24 | - return null; | |
| 25 | - } | |
| 26 | - | |
| 27 | - @Override | |
| 28 | - protected Rs handler(Header header, Session session) { | |
| 29 | - J8001 j8001 = new J8001(); | |
| 30 | - j8001.setRespNo(header.getSn()); | |
| 31 | - j8001.setRespId(header.getMsgId()); | |
| 32 | - j8001.setResult(J8001.SUCCESS); | |
| 33 | - return j8001; | |
| 34 | - } | |
| 35 | - | |
| 36 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/J0200.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc.request; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.annotation.MsgId; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.proc.Header; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.proc.response.J8001; | |
| 6 | -import com.genersoft.iot.vmp.jt1078.proc.response.Rs; | |
| 7 | -import com.genersoft.iot.vmp.jt1078.session.Session; | |
| 8 | -import io.netty.buffer.ByteBuf; | |
| 9 | - | |
| 10 | -/** | |
| 11 | - * 实时消息上报 | |
| 12 | - * | |
| 13 | - * @author QingtaiJiang | |
| 14 | - * @date 2023/4/27 18:06 | |
| 15 | - * @email qingtaij@163.com | |
| 16 | - */ | |
| 17 | -@MsgId(id = "0200") | |
| 18 | -public class J0200 extends Re { | |
| 19 | - @Override | |
| 20 | - protected Rs decode0(ByteBuf buf, Header header, Session session) { | |
| 21 | - return null; | |
| 22 | - } | |
| 23 | - | |
| 24 | - @Override | |
| 25 | - protected Rs handler(Header header, Session session) { | |
| 26 | - J8001 j8001 = new J8001(); | |
| 27 | - j8001.setRespNo(header.getSn()); | |
| 28 | - j8001.setRespId(header.getMsgId()); | |
| 29 | - j8001.setResult(J8001.SUCCESS); | |
| 30 | - return j8001; | |
| 31 | - } | |
| 32 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/J1205.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc.request; | |
| 2 | - | |
| 3 | -import com.alibaba.fastjson2.JSON; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.annotation.MsgId; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.proc.Header; | |
| 6 | -import com.genersoft.iot.vmp.jt1078.proc.response.J8001; | |
| 7 | -import com.genersoft.iot.vmp.jt1078.proc.response.Rs; | |
| 8 | -import com.genersoft.iot.vmp.jt1078.session.Session; | |
| 9 | -import com.genersoft.iot.vmp.jt1078.session.SessionManager; | |
| 10 | -import io.netty.buffer.ByteBuf; | |
| 11 | -import io.netty.buffer.ByteBufUtil; | |
| 12 | - | |
| 13 | -import java.util.ArrayList; | |
| 14 | -import java.util.List; | |
| 15 | - | |
| 16 | -/** | |
| 17 | - * 终端上传音视频资源列表 | |
| 18 | - * | |
| 19 | - * @author QingtaiJiang | |
| 20 | - * @date 2023/4/28 10:36 | |
| 21 | - * @email qingtaij@163.com | |
| 22 | - */ | |
| 23 | -@MsgId(id = "1205") | |
| 24 | -public class J1205 extends Re { | |
| 25 | - Integer respNo; | |
| 26 | - | |
| 27 | - private List<JRecordItem> recordList = new ArrayList<JRecordItem>(); | |
| 28 | - | |
| 29 | - @Override | |
| 30 | - protected Rs decode0(ByteBuf buf, Header header, Session session) { | |
| 31 | - respNo = buf.readUnsignedShort(); | |
| 32 | - long size = buf.readUnsignedInt(); | |
| 33 | - | |
| 34 | - for (int i = 0; i < size; i++) { | |
| 35 | - JRecordItem item = new JRecordItem(); | |
| 36 | - item.setChannelId(buf.readUnsignedByte()); | |
| 37 | - item.setStartTime(ByteBufUtil.hexDump(buf.readSlice(6))); | |
| 38 | - item.setEndTime(ByteBufUtil.hexDump(buf.readSlice(6))); | |
| 39 | - item.setWarn(buf.readLong()); | |
| 40 | - item.setMediaType(buf.readUnsignedByte()); | |
| 41 | - item.setStreamType(buf.readUnsignedByte()); | |
| 42 | - item.setStorageType(buf.readUnsignedByte()); | |
| 43 | - item.setSize(buf.readUnsignedInt()); | |
| 44 | - recordList.add(item); | |
| 45 | - } | |
| 46 | - | |
| 47 | - return null; | |
| 48 | - } | |
| 49 | - | |
| 50 | - @Override | |
| 51 | - protected Rs handler(Header header, Session session) { | |
| 52 | - SessionManager.INSTANCE.response(header.getDevId(), "1205", (long) respNo, JSON.toJSONString(this)); | |
| 53 | - | |
| 54 | - J8001 j8001 = new J8001(); | |
| 55 | - j8001.setRespNo(header.getSn()); | |
| 56 | - j8001.setRespId(header.getMsgId()); | |
| 57 | - j8001.setResult(J8001.SUCCESS); | |
| 58 | - return j8001; | |
| 59 | - } | |
| 60 | - | |
| 61 | - | |
| 62 | - public Integer getRespNo() { | |
| 63 | - return respNo; | |
| 64 | - } | |
| 65 | - | |
| 66 | - public void setRespNo(Integer respNo) { | |
| 67 | - this.respNo = respNo; | |
| 68 | - } | |
| 69 | - | |
| 70 | - public List<JRecordItem> getRecordList() { | |
| 71 | - return recordList; | |
| 72 | - } | |
| 73 | - | |
| 74 | - public void setRecordList(List<JRecordItem> recordList) { | |
| 75 | - this.recordList = recordList; | |
| 76 | - } | |
| 77 | - | |
| 78 | - public static class JRecordItem { | |
| 79 | - | |
| 80 | - // 逻辑通道号 | |
| 81 | - private int channelId; | |
| 82 | - | |
| 83 | - // 开始时间 | |
| 84 | - private String startTime; | |
| 85 | - | |
| 86 | - // 结束时间 | |
| 87 | - private String endTime; | |
| 88 | - | |
| 89 | - // 报警标志 | |
| 90 | - private long warn; | |
| 91 | - | |
| 92 | - // 音视频资源类型 | |
| 93 | - private int mediaType; | |
| 94 | - | |
| 95 | - // 码流类型 | |
| 96 | - private int streamType = 1; | |
| 97 | - | |
| 98 | - // 存储器类型 | |
| 99 | - private int storageType; | |
| 100 | - | |
| 101 | - // 文件大小 | |
| 102 | - private long size; | |
| 103 | - | |
| 104 | - public int getChannelId() { | |
| 105 | - return channelId; | |
| 106 | - } | |
| 107 | - | |
| 108 | - public void setChannelId(int channelId) { | |
| 109 | - this.channelId = channelId; | |
| 110 | - } | |
| 111 | - | |
| 112 | - public String getStartTime() { | |
| 113 | - return startTime; | |
| 114 | - } | |
| 115 | - | |
| 116 | - public void setStartTime(String startTime) { | |
| 117 | - this.startTime = startTime; | |
| 118 | - } | |
| 119 | - | |
| 120 | - public String getEndTime() { | |
| 121 | - return endTime; | |
| 122 | - } | |
| 123 | - | |
| 124 | - public void setEndTime(String endTime) { | |
| 125 | - this.endTime = endTime; | |
| 126 | - } | |
| 127 | - | |
| 128 | - public long getWarn() { | |
| 129 | - return warn; | |
| 130 | - } | |
| 131 | - | |
| 132 | - public void setWarn(long warn) { | |
| 133 | - this.warn = warn; | |
| 134 | - } | |
| 135 | - | |
| 136 | - public int getMediaType() { | |
| 137 | - return mediaType; | |
| 138 | - } | |
| 139 | - | |
| 140 | - public void setMediaType(int mediaType) { | |
| 141 | - this.mediaType = mediaType; | |
| 142 | - } | |
| 143 | - | |
| 144 | - public int getStreamType() { | |
| 145 | - return streamType; | |
| 146 | - } | |
| 147 | - | |
| 148 | - public void setStreamType(int streamType) { | |
| 149 | - this.streamType = streamType; | |
| 150 | - } | |
| 151 | - | |
| 152 | - public int getStorageType() { | |
| 153 | - return storageType; | |
| 154 | - } | |
| 155 | - | |
| 156 | - public void setStorageType(int storageType) { | |
| 157 | - this.storageType = storageType; | |
| 158 | - } | |
| 159 | - | |
| 160 | - public long getSize() { | |
| 161 | - return size; | |
| 162 | - } | |
| 163 | - | |
| 164 | - public void setSize(long size) { | |
| 165 | - this.size = size; | |
| 166 | - } | |
| 167 | - | |
| 168 | - @Override | |
| 169 | - public String toString() { | |
| 170 | - return "JRecordItem{" + | |
| 171 | - "channelId=" + channelId + | |
| 172 | - ", startTime='" + startTime + '\'' + | |
| 173 | - ", endTime='" + endTime + '\'' + | |
| 174 | - ", warn=" + warn + | |
| 175 | - ", mediaType=" + mediaType + | |
| 176 | - ", streamType=" + streamType + | |
| 177 | - ", storageType=" + storageType + | |
| 178 | - ", size=" + size + | |
| 179 | - '}'; | |
| 180 | - } | |
| 181 | - } | |
| 182 | - | |
| 183 | - @Override | |
| 184 | - public String toString() { | |
| 185 | - return "J1205{" + | |
| 186 | - "respNo=" + respNo + | |
| 187 | - ", recordList=" + recordList + | |
| 188 | - '}'; | |
| 189 | - } | |
| 190 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/Re.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc.request; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.proc.Header; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.proc.response.Rs; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.session.Session; | |
| 6 | -import io.netty.buffer.ByteBuf; | |
| 7 | -import org.slf4j.Logger; | |
| 8 | -import org.slf4j.LoggerFactory; | |
| 9 | -import org.springframework.util.StringUtils; | |
| 10 | - | |
| 11 | -/** | |
| 12 | - * @author QingtaiJiang | |
| 13 | - * @date 2023/4/27 18:50 | |
| 14 | - * @email qingtaij@163.com | |
| 15 | - */ | |
| 16 | -public abstract class Re { | |
| 17 | - private final static Logger log = LoggerFactory.getLogger(Re.class); | |
| 18 | - | |
| 19 | - protected abstract Rs decode0(ByteBuf buf, Header header, Session session); | |
| 20 | - | |
| 21 | - protected abstract Rs handler(Header header, Session session); | |
| 22 | - | |
| 23 | - public Rs decode(ByteBuf buf, Header header, Session session) { | |
| 24 | - if (session != null && !StringUtils.hasLength(session.getDevId())) { | |
| 25 | - session.register(header.getDevId(), (int) header.getVersion(), header); | |
| 26 | - } | |
| 27 | - Rs rs = decode0(buf, header, session); | |
| 28 | - Rs rsHand = handler(header, session); | |
| 29 | - if (rs == null && rsHand != null) { | |
| 30 | - rs = rsHand; | |
| 31 | - } else if (rs != null && rsHand != null) { | |
| 32 | - log.warn("decode0:{} 与 handler:{} 返回值冲突,采用decode0返回值", rs, rsHand); | |
| 33 | - } | |
| 34 | - if (rs != null) { | |
| 35 | - rs.setHeader(header); | |
| 36 | - } | |
| 37 | - | |
| 38 | - return rs; | |
| 39 | - } | |
| 40 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/response/J8001.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc.response; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.annotation.MsgId; | |
| 4 | -import io.netty.buffer.ByteBuf; | |
| 5 | -import io.netty.buffer.ByteBufUtil; | |
| 6 | -import io.netty.buffer.Unpooled; | |
| 7 | - | |
| 8 | -/** | |
| 9 | - * @author QingtaiJiang | |
| 10 | - * @date 2023/4/27 18:48 | |
| 11 | - * @email qingtaij@163.com | |
| 12 | - */ | |
| 13 | -@MsgId(id = "8001") | |
| 14 | -public class J8001 extends Rs { | |
| 15 | - public static final Integer SUCCESS = 0; | |
| 16 | - | |
| 17 | - Integer respNo; | |
| 18 | - String respId; | |
| 19 | - Integer result; | |
| 20 | - | |
| 21 | - @Override | |
| 22 | - public ByteBuf encode() { | |
| 23 | - ByteBuf buffer = Unpooled.buffer(); | |
| 24 | - buffer.writeShort(respNo); | |
| 25 | - buffer.writeBytes(ByteBufUtil.decodeHexDump(respId)); | |
| 26 | - buffer.writeByte(result); | |
| 27 | - | |
| 28 | - return buffer; | |
| 29 | - } | |
| 30 | - | |
| 31 | - | |
| 32 | - public void setRespNo(Integer respNo) { | |
| 33 | - this.respNo = respNo; | |
| 34 | - } | |
| 35 | - | |
| 36 | - public void setRespId(String respId) { | |
| 37 | - this.respId = respId; | |
| 38 | - } | |
| 39 | - | |
| 40 | - public void setResult(Integer result) { | |
| 41 | - this.result = result; | |
| 42 | - } | |
| 43 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/response/J8100.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc.response; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.annotation.MsgId; | |
| 4 | -import io.netty.buffer.ByteBuf; | |
| 5 | -import io.netty.buffer.Unpooled; | |
| 6 | -import io.netty.util.CharsetUtil; | |
| 7 | - | |
| 8 | -/** | |
| 9 | - * @author QingtaiJiang | |
| 10 | - * @date 2023/4/27 18:40 | |
| 11 | - * @email qingtaij@163.com | |
| 12 | - */ | |
| 13 | -@MsgId(id = "8100") | |
| 14 | -public class J8100 extends Rs { | |
| 15 | - public static final Integer SUCCESS = 0; | |
| 16 | - | |
| 17 | - Integer respNo; | |
| 18 | - Integer result; | |
| 19 | - String code; | |
| 20 | - | |
| 21 | - @Override | |
| 22 | - public ByteBuf encode() { | |
| 23 | - ByteBuf buffer = Unpooled.buffer(); | |
| 24 | - buffer.writeShort(respNo); | |
| 25 | - buffer.writeByte(result); | |
| 26 | - buffer.writeCharSequence(code, CharsetUtil.UTF_8); | |
| 27 | - return buffer; | |
| 28 | - } | |
| 29 | - | |
| 30 | - public void setRespNo(Integer respNo) { | |
| 31 | - this.respNo = respNo; | |
| 32 | - } | |
| 33 | - | |
| 34 | - public void setResult(Integer result) { | |
| 35 | - this.result = result; | |
| 36 | - } | |
| 37 | - | |
| 38 | - public void setCode(String code) { | |
| 39 | - this.code = code; | |
| 40 | - } | |
| 41 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/response/J9101.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc.response; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.annotation.MsgId; | |
| 4 | -import io.netty.buffer.ByteBuf; | |
| 5 | -import io.netty.buffer.Unpooled; | |
| 6 | -import io.netty.util.CharsetUtil; | |
| 7 | - | |
| 8 | -/** | |
| 9 | - * 实时音视频传输请求 | |
| 10 | - * | |
| 11 | - * @author QingtaiJiang | |
| 12 | - * @date 2023/4/27 18:25 | |
| 13 | - * @email qingtaij@163.com | |
| 14 | - */ | |
| 15 | -@MsgId(id = "9101") | |
| 16 | -public class J9101 extends Rs { | |
| 17 | - String ip; | |
| 18 | - | |
| 19 | - // TCP端口 | |
| 20 | - Integer tcpPort; | |
| 21 | - | |
| 22 | - // UDP端口 | |
| 23 | - Integer udpPort; | |
| 24 | - | |
| 25 | - // 逻辑通道号 | |
| 26 | - Integer channel; | |
| 27 | - | |
| 28 | - // 数据类型 | |
| 29 | - /** | |
| 30 | - * 0:音视频,1:视频,2:双向对讲,3:监听,4:中心广播,5:透传 | |
| 31 | - */ | |
| 32 | - Integer type; | |
| 33 | - | |
| 34 | - // 码流类型 | |
| 35 | - /** | |
| 36 | - * 0:主码流,1:子码流 | |
| 37 | - */ | |
| 38 | - Integer rate; | |
| 39 | - | |
| 40 | - @Override | |
| 41 | - public ByteBuf encode() { | |
| 42 | - ByteBuf buffer = Unpooled.buffer(); | |
| 43 | - buffer.writeByte(ip.getBytes().length); | |
| 44 | - buffer.writeCharSequence(ip, CharsetUtil.UTF_8); | |
| 45 | - buffer.writeShort(tcpPort); | |
| 46 | - buffer.writeShort(udpPort); | |
| 47 | - buffer.writeByte(channel); | |
| 48 | - buffer.writeByte(type); | |
| 49 | - buffer.writeByte(rate); | |
| 50 | - return buffer; | |
| 51 | - } | |
| 52 | - | |
| 53 | - public String getIp() { | |
| 54 | - return ip; | |
| 55 | - } | |
| 56 | - | |
| 57 | - public void setIp(String ip) { | |
| 58 | - this.ip = ip; | |
| 59 | - } | |
| 60 | - | |
| 61 | - public Integer getTcpPort() { | |
| 62 | - return tcpPort; | |
| 63 | - } | |
| 64 | - | |
| 65 | - public void setTcpPort(Integer tcpPort) { | |
| 66 | - this.tcpPort = tcpPort; | |
| 67 | - } | |
| 68 | - | |
| 69 | - public Integer getUdpPort() { | |
| 70 | - return udpPort; | |
| 71 | - } | |
| 72 | - | |
| 73 | - public void setUdpPort(Integer udpPort) { | |
| 74 | - this.udpPort = udpPort; | |
| 75 | - } | |
| 76 | - | |
| 77 | - public Integer getChannel() { | |
| 78 | - return channel; | |
| 79 | - } | |
| 80 | - | |
| 81 | - public void setChannel(Integer channel) { | |
| 82 | - this.channel = channel; | |
| 83 | - } | |
| 84 | - | |
| 85 | - public Integer getType() { | |
| 86 | - return type; | |
| 87 | - } | |
| 88 | - | |
| 89 | - public void setType(Integer type) { | |
| 90 | - this.type = type; | |
| 91 | - } | |
| 92 | - | |
| 93 | - public Integer getRate() { | |
| 94 | - return rate; | |
| 95 | - } | |
| 96 | - | |
| 97 | - public void setRate(Integer rate) { | |
| 98 | - this.rate = rate; | |
| 99 | - } | |
| 100 | - | |
| 101 | - @Override | |
| 102 | - public String toString() { | |
| 103 | - return "J9101{" + | |
| 104 | - "ip='" + ip + '\'' + | |
| 105 | - ", tcpPort=" + tcpPort + | |
| 106 | - ", udpPort=" + udpPort + | |
| 107 | - ", channel=" + channel + | |
| 108 | - ", type=" + type + | |
| 109 | - ", rate=" + rate + | |
| 110 | - '}'; | |
| 111 | - } | |
| 112 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/response/J9102.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc.response; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.annotation.MsgId; | |
| 4 | -import io.netty.buffer.ByteBuf; | |
| 5 | -import io.netty.buffer.Unpooled; | |
| 6 | - | |
| 7 | -/** | |
| 8 | - * 音视频实时传输控制 | |
| 9 | - * | |
| 10 | - * @author QingtaiJiang | |
| 11 | - * @date 2023/4/27 18:49 | |
| 12 | - * @email qingtaij@163.com | |
| 13 | - */ | |
| 14 | -@MsgId(id = "9102") | |
| 15 | -public class J9102 extends Rs { | |
| 16 | - | |
| 17 | - // 通道号 | |
| 18 | - Integer channel; | |
| 19 | - | |
| 20 | - // 控制指令 | |
| 21 | - /** | |
| 22 | - * 0:关闭音视频传输指令; | |
| 23 | - * 1:切换码流(增加暂停和继续); | |
| 24 | - * 2:暂停该通道所有流的发送; | |
| 25 | - * 3:恢复暂停前流的发送,与暂停前的流类型一致; | |
| 26 | - * 4:关闭双向对讲 | |
| 27 | - */ | |
| 28 | - Integer command; | |
| 29 | - | |
| 30 | - // 数据类型 | |
| 31 | - /** | |
| 32 | - * 0:关闭该通道有关的音视频数据; | |
| 33 | - * 1:只关闭该通道有关的音频,保留该通道 | |
| 34 | - * 有关的视频; | |
| 35 | - * 2:只关闭该通道有关的视频,保留该通道 | |
| 36 | - * 有关的音频 | |
| 37 | - */ | |
| 38 | - Integer closeType; | |
| 39 | - | |
| 40 | - // 数据类型 | |
| 41 | - /** | |
| 42 | - * 0:主码流; | |
| 43 | - * 1:子码流 | |
| 44 | - */ | |
| 45 | - Integer streamType; | |
| 46 | - | |
| 47 | - @Override | |
| 48 | - public ByteBuf encode() { | |
| 49 | - ByteBuf buffer = Unpooled.buffer(); | |
| 50 | - buffer.writeByte(channel); | |
| 51 | - buffer.writeByte(command); | |
| 52 | - buffer.writeByte(closeType); | |
| 53 | - buffer.writeByte(streamType); | |
| 54 | - return buffer; | |
| 55 | - } | |
| 56 | - | |
| 57 | - | |
| 58 | - public Integer getChannel() { | |
| 59 | - return channel; | |
| 60 | - } | |
| 61 | - | |
| 62 | - public void setChannel(Integer channel) { | |
| 63 | - this.channel = channel; | |
| 64 | - } | |
| 65 | - | |
| 66 | - public Integer getCommand() { | |
| 67 | - return command; | |
| 68 | - } | |
| 69 | - | |
| 70 | - public void setCommand(Integer command) { | |
| 71 | - this.command = command; | |
| 72 | - } | |
| 73 | - | |
| 74 | - public Integer getCloseType() { | |
| 75 | - return closeType; | |
| 76 | - } | |
| 77 | - | |
| 78 | - public void setCloseType(Integer closeType) { | |
| 79 | - this.closeType = closeType; | |
| 80 | - } | |
| 81 | - | |
| 82 | - public Integer getStreamType() { | |
| 83 | - return streamType; | |
| 84 | - } | |
| 85 | - | |
| 86 | - public void setStreamType(Integer streamType) { | |
| 87 | - this.streamType = streamType; | |
| 88 | - } | |
| 89 | - | |
| 90 | - @Override | |
| 91 | - public String toString() { | |
| 92 | - return "J9102{" + | |
| 93 | - "channel=" + channel + | |
| 94 | - ", command=" + command + | |
| 95 | - ", closeType=" + closeType + | |
| 96 | - ", streamType=" + streamType + | |
| 97 | - '}'; | |
| 98 | - } | |
| 99 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/response/J9201.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc.response; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.annotation.MsgId; | |
| 4 | -import io.netty.buffer.ByteBuf; | |
| 5 | -import io.netty.buffer.ByteBufUtil; | |
| 6 | -import io.netty.buffer.Unpooled; | |
| 7 | -import io.netty.util.CharsetUtil; | |
| 8 | - | |
| 9 | -/** | |
| 10 | - * 回放请求 | |
| 11 | - * | |
| 12 | - * @author QingtaiJiang | |
| 13 | - * @date 2023/4/28 10:37 | |
| 14 | - * @email qingtaij@163.com | |
| 15 | - */ | |
| 16 | -@MsgId(id = "9201") | |
| 17 | -public class J9201 extends Rs { | |
| 18 | - // 服务器IP地址 | |
| 19 | - private String ip; | |
| 20 | - | |
| 21 | - // 实时视频服务器TCP端口号 | |
| 22 | - private int tcpPort; | |
| 23 | - | |
| 24 | - // 实时视频服务器UDP端口号 | |
| 25 | - private int udpPort; | |
| 26 | - | |
| 27 | - // 逻辑通道号 | |
| 28 | - private int channel; | |
| 29 | - | |
| 30 | - // 音视频资源类型:0.音视频 1.音频 2.视频 3.视频或音视频 | |
| 31 | - private int type; | |
| 32 | - | |
| 33 | - // 码流类型:0.所有码流 1.主码流 2.子码流(如果此通道只传输音频,此字段置0) | |
| 34 | - private int rate; | |
| 35 | - | |
| 36 | - // 存储器类型:0.所有存储器 1.主存储器 2.灾备存储器" | |
| 37 | - private int storageType; | |
| 38 | - | |
| 39 | - // 回放方式:0.正常回放 1.快进回放 2.关键帧快退回放 3.关键帧播放 4.单帧上传 | |
| 40 | - private int playbackType; | |
| 41 | - | |
| 42 | - // 快进或快退倍数:0.无效 1.1倍 2.2倍 3.4倍 4.8倍 5.16倍 (回放控制为1和2时,此字段内容有效,否则置0) | |
| 43 | - private int playbackSpeed; | |
| 44 | - | |
| 45 | - // 开始时间YYMMDDHHMMSS,回放方式为4时,该字段表示单帧上传时间 | |
| 46 | - private String startTime; | |
| 47 | - | |
| 48 | - // 结束时间YYMMDDHHMMSS,回放方式为4时,该字段无效,为0表示一直回放 | |
| 49 | - private String endTime; | |
| 50 | - | |
| 51 | - @Override | |
| 52 | - public ByteBuf encode() { | |
| 53 | - ByteBuf buffer = Unpooled.buffer(); | |
| 54 | - buffer.writeByte(ip.getBytes().length); | |
| 55 | - buffer.writeCharSequence(ip, CharsetUtil.UTF_8); | |
| 56 | - buffer.writeShort(tcpPort); | |
| 57 | - buffer.writeShort(udpPort); | |
| 58 | - buffer.writeByte(channel); | |
| 59 | - buffer.writeByte(type); | |
| 60 | - buffer.writeByte(rate); | |
| 61 | - buffer.writeByte(storageType); | |
| 62 | - buffer.writeByte(playbackType); | |
| 63 | - buffer.writeByte(playbackSpeed); | |
| 64 | - buffer.writeBytes(ByteBufUtil.decodeHexDump(startTime)); | |
| 65 | - buffer.writeBytes(ByteBufUtil.decodeHexDump(endTime)); | |
| 66 | - return buffer; | |
| 67 | - } | |
| 68 | - | |
| 69 | - public String getIp() { | |
| 70 | - return ip; | |
| 71 | - } | |
| 72 | - | |
| 73 | - public void setIp(String ip) { | |
| 74 | - this.ip = ip; | |
| 75 | - } | |
| 76 | - | |
| 77 | - public int getTcpPort() { | |
| 78 | - return tcpPort; | |
| 79 | - } | |
| 80 | - | |
| 81 | - public void setTcpPort(int tcpPort) { | |
| 82 | - this.tcpPort = tcpPort; | |
| 83 | - } | |
| 84 | - | |
| 85 | - public int getUdpPort() { | |
| 86 | - return udpPort; | |
| 87 | - } | |
| 88 | - | |
| 89 | - public void setUdpPort(int udpPort) { | |
| 90 | - this.udpPort = udpPort; | |
| 91 | - } | |
| 92 | - | |
| 93 | - public int getChannel() { | |
| 94 | - return channel; | |
| 95 | - } | |
| 96 | - | |
| 97 | - public void setChannel(int channel) { | |
| 98 | - this.channel = channel; | |
| 99 | - } | |
| 100 | - | |
| 101 | - public int getType() { | |
| 102 | - return type; | |
| 103 | - } | |
| 104 | - | |
| 105 | - public void setType(int type) { | |
| 106 | - this.type = type; | |
| 107 | - } | |
| 108 | - | |
| 109 | - public int getRate() { | |
| 110 | - return rate; | |
| 111 | - } | |
| 112 | - | |
| 113 | - public void setRate(int rate) { | |
| 114 | - this.rate = rate; | |
| 115 | - } | |
| 116 | - | |
| 117 | - public int getStorageType() { | |
| 118 | - return storageType; | |
| 119 | - } | |
| 120 | - | |
| 121 | - public void setStorageType(int storageType) { | |
| 122 | - this.storageType = storageType; | |
| 123 | - } | |
| 124 | - | |
| 125 | - public int getPlaybackType() { | |
| 126 | - return playbackType; | |
| 127 | - } | |
| 128 | - | |
| 129 | - public void setPlaybackType(int playbackType) { | |
| 130 | - this.playbackType = playbackType; | |
| 131 | - } | |
| 132 | - | |
| 133 | - public int getPlaybackSpeed() { | |
| 134 | - return playbackSpeed; | |
| 135 | - } | |
| 136 | - | |
| 137 | - public void setPlaybackSpeed(int playbackSpeed) { | |
| 138 | - this.playbackSpeed = playbackSpeed; | |
| 139 | - } | |
| 140 | - | |
| 141 | - public String getStartTime() { | |
| 142 | - return startTime; | |
| 143 | - } | |
| 144 | - | |
| 145 | - public void setStartTime(String startTime) { | |
| 146 | - this.startTime = startTime; | |
| 147 | - } | |
| 148 | - | |
| 149 | - public String getEndTime() { | |
| 150 | - return endTime; | |
| 151 | - } | |
| 152 | - | |
| 153 | - public void setEndTime(String endTime) { | |
| 154 | - this.endTime = endTime; | |
| 155 | - } | |
| 156 | - | |
| 157 | - @Override | |
| 158 | - public String toString() { | |
| 159 | - return "J9201{" + | |
| 160 | - "ip='" + ip + '\'' + | |
| 161 | - ", tcpPort=" + tcpPort + | |
| 162 | - ", udpPort=" + udpPort + | |
| 163 | - ", channel=" + channel + | |
| 164 | - ", type=" + type + | |
| 165 | - ", rate=" + rate + | |
| 166 | - ", storageType=" + storageType + | |
| 167 | - ", playbackType=" + playbackType + | |
| 168 | - ", playbackSpeed=" + playbackSpeed + | |
| 169 | - ", startTime='" + startTime + '\'' + | |
| 170 | - ", endTime='" + endTime + '\'' + | |
| 171 | - '}'; | |
| 172 | - } | |
| 173 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/response/J9202.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc.response; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.annotation.MsgId; | |
| 4 | -import io.netty.buffer.ByteBuf; | |
| 5 | -import io.netty.buffer.ByteBufUtil; | |
| 6 | -import io.netty.buffer.Unpooled; | |
| 7 | - | |
| 8 | -/** | |
| 9 | - * 平台下发远程录像回放控制 | |
| 10 | - * | |
| 11 | - * @author QingtaiJiang | |
| 12 | - * @date 2023/4/28 10:37 | |
| 13 | - * @email qingtaij@163.com | |
| 14 | - */ | |
| 15 | -@MsgId(id = "9202") | |
| 16 | -public class J9202 extends Rs { | |
| 17 | - // 逻辑通道号 | |
| 18 | - private int channel; | |
| 19 | - | |
| 20 | - // 回放控制:0.开始回放 1.暂停回放 2.结束回放 3.快进回放 4.关键帧快退回放 5.拖动回放 6.关键帧播放 | |
| 21 | - private int playbackType; | |
| 22 | - | |
| 23 | - // 快进或快退倍数:0.无效 1.1倍 2.2倍 3.4倍 4.8倍 5.16倍 (回放控制为3和4时,此字段内容有效,否则置0) | |
| 24 | - private int playbackSpeed; | |
| 25 | - | |
| 26 | - // 拖动回放位置(YYMMDDHHMMSS,回放控制为5时,此字段有效) | |
| 27 | - private String playbackTime; | |
| 28 | - | |
| 29 | - @Override | |
| 30 | - public ByteBuf encode() { | |
| 31 | - ByteBuf buffer = Unpooled.buffer(); | |
| 32 | - buffer.writeByte(channel); | |
| 33 | - buffer.writeByte(playbackType); | |
| 34 | - buffer.writeByte(playbackSpeed); | |
| 35 | - buffer.writeBytes(ByteBufUtil.decodeHexDump(playbackTime)); | |
| 36 | - return buffer; | |
| 37 | - } | |
| 38 | - | |
| 39 | - public int getChannel() { | |
| 40 | - return channel; | |
| 41 | - } | |
| 42 | - | |
| 43 | - public void setChannel(int channel) { | |
| 44 | - this.channel = channel; | |
| 45 | - } | |
| 46 | - | |
| 47 | - public int getPlaybackType() { | |
| 48 | - return playbackType; | |
| 49 | - } | |
| 50 | - | |
| 51 | - public void setPlaybackType(int playbackType) { | |
| 52 | - this.playbackType = playbackType; | |
| 53 | - } | |
| 54 | - | |
| 55 | - public int getPlaybackSpeed() { | |
| 56 | - return playbackSpeed; | |
| 57 | - } | |
| 58 | - | |
| 59 | - public void setPlaybackSpeed(int playbackSpeed) { | |
| 60 | - this.playbackSpeed = playbackSpeed; | |
| 61 | - } | |
| 62 | - | |
| 63 | - public String getPlaybackTime() { | |
| 64 | - return playbackTime; | |
| 65 | - } | |
| 66 | - | |
| 67 | - public void setPlaybackTime(String playbackTime) { | |
| 68 | - this.playbackTime = playbackTime; | |
| 69 | - } | |
| 70 | - | |
| 71 | - @Override | |
| 72 | - public String toString() { | |
| 73 | - return "J9202{" + | |
| 74 | - "channel=" + channel + | |
| 75 | - ", playbackType=" + playbackType + | |
| 76 | - ", playbackSpeed=" + playbackSpeed + | |
| 77 | - ", playbackTime='" + playbackTime + '\'' + | |
| 78 | - '}'; | |
| 79 | - } | |
| 80 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/response/J9205.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc.response; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.annotation.MsgId; | |
| 4 | -import io.netty.buffer.ByteBuf; | |
| 5 | -import io.netty.buffer.ByteBufUtil; | |
| 6 | -import io.netty.buffer.Unpooled; | |
| 7 | - | |
| 8 | -/** | |
| 9 | - * 查询资源列表 | |
| 10 | - * | |
| 11 | - * @author QingtaiJiang | |
| 12 | - * @date 2023/4/28 10:36 | |
| 13 | - * @email qingtaij@163.com | |
| 14 | - */ | |
| 15 | -@MsgId(id = "9205") | |
| 16 | -public class J9205 extends Rs { | |
| 17 | - // 逻辑通道号 | |
| 18 | - private int channelId; | |
| 19 | - | |
| 20 | - // 开始时间YYMMDDHHMMSS,全0表示无起始时间 | |
| 21 | - private String startTime; | |
| 22 | - | |
| 23 | - // 结束时间YYMMDDHHMMSS,全0表示无终止时间 | |
| 24 | - private String endTime; | |
| 25 | - | |
| 26 | - // 报警标志 | |
| 27 | - private final int warnType = 0; | |
| 28 | - | |
| 29 | - // 音视频资源类型:0.音视频 1.音频 2.视频 3.视频或音视频 | |
| 30 | - private int mediaType; | |
| 31 | - | |
| 32 | - // 码流类型:0.所有码流 1.主码流 2.子码流 | |
| 33 | - private int streamType = 0; | |
| 34 | - | |
| 35 | - // 存储器类型:0.所有存储器 1.主存储器 2.灾备存储器 | |
| 36 | - private int storageType = 0; | |
| 37 | - | |
| 38 | - @Override | |
| 39 | - public ByteBuf encode() { | |
| 40 | - ByteBuf buffer = Unpooled.buffer(); | |
| 41 | - | |
| 42 | - buffer.writeByte(channelId); | |
| 43 | - buffer.writeBytes(ByteBufUtil.decodeHexDump(startTime)); | |
| 44 | - buffer.writeBytes(ByteBufUtil.decodeHexDump(endTime)); | |
| 45 | - buffer.writeLong(warnType); | |
| 46 | - buffer.writeByte(mediaType); | |
| 47 | - buffer.writeByte(streamType); | |
| 48 | - buffer.writeByte(storageType); | |
| 49 | - | |
| 50 | - return buffer; | |
| 51 | - } | |
| 52 | - | |
| 53 | - | |
| 54 | - public void setChannelId(int channelId) { | |
| 55 | - this.channelId = channelId; | |
| 56 | - } | |
| 57 | - | |
| 58 | - public void setStartTime(String startTime) { | |
| 59 | - this.startTime = startTime; | |
| 60 | - } | |
| 61 | - | |
| 62 | - public void setEndTime(String endTime) { | |
| 63 | - this.endTime = endTime; | |
| 64 | - } | |
| 65 | - | |
| 66 | - public void setMediaType(int mediaType) { | |
| 67 | - this.mediaType = mediaType; | |
| 68 | - } | |
| 69 | - | |
| 70 | - public void setStreamType(int streamType) { | |
| 71 | - this.streamType = streamType; | |
| 72 | - } | |
| 73 | - | |
| 74 | - public void setStorageType(int storageType) { | |
| 75 | - this.storageType = storageType; | |
| 76 | - } | |
| 77 | - | |
| 78 | - public int getWarnType() { | |
| 79 | - return warnType; | |
| 80 | - } | |
| 81 | - | |
| 82 | - @Override | |
| 83 | - public String toString() { | |
| 84 | - return "J9205{" + | |
| 85 | - "channelId=" + channelId + | |
| 86 | - ", startTime='" + startTime + '\'' + | |
| 87 | - ", endTime='" + endTime + '\'' + | |
| 88 | - ", warnType=" + warnType + | |
| 89 | - ", mediaType=" + mediaType + | |
| 90 | - ", streamType=" + streamType + | |
| 91 | - ", storageType=" + storageType + | |
| 92 | - '}'; | |
| 93 | - } | |
| 94 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/proc/response/Rs.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.proc.response; | |
| 2 | - | |
| 3 | - | |
| 4 | -import com.genersoft.iot.vmp.jt1078.proc.Header; | |
| 5 | -import io.netty.buffer.ByteBuf; | |
| 6 | - | |
| 7 | - | |
| 8 | -/** | |
| 9 | - * @author QingtaiJiang | |
| 10 | - * @date 2021/8/30 18:54 | |
| 11 | - * @email qingtaij@163.com | |
| 12 | - */ | |
| 13 | - | |
| 14 | -public abstract class Rs { | |
| 15 | - private Header header; | |
| 16 | - | |
| 17 | - public abstract ByteBuf encode(); | |
| 18 | - | |
| 19 | - | |
| 20 | - public Header getHeader() { | |
| 21 | - return header; | |
| 22 | - } | |
| 23 | - | |
| 24 | - public void setHeader(Header header) { | |
| 25 | - this.header = header; | |
| 26 | - } | |
| 27 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/publisher/Channel.java deleted
100644 → 0
| 1 | -// | |
| 2 | -// Source code recreated from a .class file by IntelliJ IDEA | |
| 3 | -// (powered by FernFlower decompiler) | |
| 4 | -// | |
| 5 | - | |
| 6 | -package com.genersoft.iot.vmp.jt1078.publisher; | |
| 7 | - | |
| 8 | -import com.genersoft.iot.vmp.jt1078.codec.AudioCodec; | |
| 9 | -import com.genersoft.iot.vmp.jt1078.entity.MediaEncoding; | |
| 10 | -import com.genersoft.iot.vmp.jt1078.entity.Media.Type; | |
| 11 | -import com.genersoft.iot.vmp.jt1078.flv.FlvEncoder; | |
| 12 | -import com.genersoft.iot.vmp.jt1078.server.Jtt1078Handler; | |
| 13 | -import com.genersoft.iot.vmp.jt1078.subscriber.RTMPPublisher; | |
| 14 | -import com.genersoft.iot.vmp.jt1078.subscriber.Subscriber; | |
| 15 | -import com.genersoft.iot.vmp.jt1078.subscriber.VideoSubscriber; | |
| 16 | -import com.genersoft.iot.vmp.jt1078.util.ByteHolder; | |
| 17 | -import com.genersoft.iot.vmp.jt1078.util.Configs; | |
| 18 | -import io.netty.channel.ChannelHandlerContext; | |
| 19 | - | |
| 20 | -import java.io.IOException; | |
| 21 | -import java.net.URISyntaxException; | |
| 22 | -import java.util.Iterator; | |
| 23 | -import java.util.concurrent.ConcurrentLinkedQueue; | |
| 24 | - | |
| 25 | -import org.apache.commons.lang3.StringUtils; | |
| 26 | -import org.slf4j.Logger; | |
| 27 | -import org.slf4j.LoggerFactory; | |
| 28 | - | |
| 29 | -public class Channel { | |
| 30 | - static Logger logger = LoggerFactory.getLogger(Channel.class); | |
| 31 | - ConcurrentLinkedQueue<Subscriber> subscribers; | |
| 32 | - RTMPPublisher rtmpPublisher; | |
| 33 | - String tag; | |
| 34 | - boolean publishing; | |
| 35 | - ByteHolder buffer; | |
| 36 | - AudioCodec audioCodec; | |
| 37 | - FlvEncoder flvEncoder; | |
| 38 | - private long firstTimestamp = -1L; | |
| 39 | - private Integer httpPort; | |
| 40 | - private boolean flag = true; | |
| 41 | - | |
| 42 | - public Channel(String tag, Integer httpPort) { | |
| 43 | - | |
| 44 | - this.tag = tag; | |
| 45 | - this.subscribers = new ConcurrentLinkedQueue(); | |
| 46 | - this.flvEncoder = new FlvEncoder(true, true); | |
| 47 | - this.buffer = new ByteHolder(204800); | |
| 48 | - this.httpPort = httpPort; | |
| 49 | - if (!StringUtils.isEmpty(Configs.get("rtmp.url"))) { | |
| 50 | - this.rtmpPublisher = new RTMPPublisher(tag, httpPort); | |
| 51 | - this.rtmpPublisher.start(); | |
| 52 | - } | |
| 53 | - | |
| 54 | - } | |
| 55 | - | |
| 56 | - public boolean isPublishing() { | |
| 57 | - return this.publishing; | |
| 58 | - } | |
| 59 | - | |
| 60 | - public Subscriber subscribe(ChannelHandlerContext ctx) { | |
| 61 | - logger.info("channel: {} -> {}, subscriber: {}", new Object[]{Long.toHexString((long)this.hashCode() & 4294967295L), this.tag, ctx.channel().remoteAddress().toString()}); | |
| 62 | - Subscriber subscriber = new VideoSubscriber(this.tag, ctx); | |
| 63 | - this.subscribers.add(subscriber); | |
| 64 | - | |
| 65 | - | |
| 66 | - return subscriber; | |
| 67 | - } | |
| 68 | - | |
| 69 | - public void writeAudio(long timestamp, int pt, byte[] data) { | |
| 70 | - if (this.audioCodec == null) { | |
| 71 | - this.audioCodec = AudioCodec.getCodec(pt); | |
| 72 | - logger.info("audio codec: {}", MediaEncoding.getEncoding(Type.Audio, pt)); | |
| 73 | - } | |
| 74 | - | |
| 75 | - this.broadcastAudio(timestamp, this.audioCodec.toPCM(data)); | |
| 76 | - } | |
| 77 | - | |
| 78 | - public void writeVideo(long sequence, long timeoffset, int payloadType, byte[] h264) { | |
| 79 | - if (this.firstTimestamp == -1L) { | |
| 80 | - this.firstTimestamp = timeoffset; | |
| 81 | - } | |
| 82 | - | |
| 83 | - this.publishing = true; | |
| 84 | - this.buffer.write(h264); | |
| 85 | - | |
| 86 | - while(true) { | |
| 87 | - byte[] nalu = this.readNalu(); | |
| 88 | - if (nalu == null) { | |
| 89 | - return; | |
| 90 | - } | |
| 91 | - | |
| 92 | - if (nalu.length >= 4) { | |
| 93 | - byte[] flvTag = this.flvEncoder.write(nalu, (int)(timeoffset - this.firstTimestamp)); | |
| 94 | - if (flvTag != null) { | |
| 95 | - this.broadcastVideo(timeoffset, flvTag); | |
| 96 | - } | |
| 97 | - } | |
| 98 | - } | |
| 99 | - } | |
| 100 | - | |
| 101 | - public void broadcastVideo(long timeoffset, byte[] flvTag) { | |
| 102 | - Iterator var4 = this.subscribers.iterator(); | |
| 103 | - | |
| 104 | - while(var4.hasNext()) { | |
| 105 | - Subscriber subscriber = (Subscriber)var4.next(); | |
| 106 | - subscriber.onVideoData(timeoffset, flvTag, this.flvEncoder); | |
| 107 | - } | |
| 108 | - | |
| 109 | - } | |
| 110 | - | |
| 111 | - public void broadcastAudio(long timeoffset, byte[] flvTag) { | |
| 112 | - Iterator var4 = this.subscribers.iterator(); | |
| 113 | - | |
| 114 | - while(var4.hasNext()) { | |
| 115 | - Subscriber subscriber = (Subscriber)var4.next(); | |
| 116 | - subscriber.onAudioData(timeoffset, flvTag, this.flvEncoder); | |
| 117 | - } | |
| 118 | - | |
| 119 | - } | |
| 120 | - | |
| 121 | - public void unsubscribe(long watcherId) { | |
| 122 | - Iterator<Subscriber> itr = this.subscribers.iterator(); | |
| 123 | - | |
| 124 | - Subscriber subscriber; | |
| 125 | - do { | |
| 126 | - if (!itr.hasNext()) { | |
| 127 | - return; | |
| 128 | - } | |
| 129 | - | |
| 130 | - subscriber = (Subscriber)itr.next(); | |
| 131 | - } while(subscriber.getId() != watcherId); | |
| 132 | - | |
| 133 | - itr.remove(); | |
| 134 | - subscriber.close(); | |
| 135 | - } | |
| 136 | - | |
| 137 | - public long getWatcherId(String tag) { | |
| 138 | - Iterator<Subscriber> itr = this.subscribers.iterator(); | |
| 139 | - | |
| 140 | - Subscriber subscriber; | |
| 141 | - do { | |
| 142 | - if (!itr.hasNext()) { | |
| 143 | - return -1100L; | |
| 144 | - } | |
| 145 | - | |
| 146 | - subscriber = (Subscriber)itr.next(); | |
| 147 | - } while(!StringUtils.equals(tag, subscriber.getTag())); | |
| 148 | - | |
| 149 | - return subscriber.getId(); | |
| 150 | - } | |
| 151 | - | |
| 152 | - public void close() { | |
| 153 | - Iterator<Subscriber> itr = this.subscribers.iterator(); | |
| 154 | - | |
| 155 | - while(itr.hasNext()) { | |
| 156 | - Subscriber subscriber = (Subscriber)itr.next(); | |
| 157 | - subscriber.close(); | |
| 158 | - itr.remove(); | |
| 159 | - } | |
| 160 | - | |
| 161 | - if (this.rtmpPublisher != null) { | |
| 162 | - this.rtmpPublisher.close(); | |
| 163 | - } | |
| 164 | - | |
| 165 | - } | |
| 166 | - | |
| 167 | - private byte[] readNalu() { | |
| 168 | - for(int i = 0; i < this.buffer.size(); ++i) { | |
| 169 | - int a = this.buffer.get(i + 0) & 255; | |
| 170 | - int b = this.buffer.get(i + 1) & 255; | |
| 171 | - int c = this.buffer.get(i + 2) & 255; | |
| 172 | - int d = this.buffer.get(i + 3) & 255; | |
| 173 | - if (a == 0 && b == 0 && c == 0 && d == 1 && i != 0) { | |
| 174 | - byte[] nalu = new byte[i]; | |
| 175 | - this.buffer.sliceInto(nalu, i); | |
| 176 | - return nalu; | |
| 177 | - } | |
| 178 | - } | |
| 179 | - | |
| 180 | - return null; | |
| 181 | - } | |
| 182 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/publisher/PublishManager.java deleted
100644 → 0
| 1 | -// | |
| 2 | -// Source code recreated from a .class file by IntelliJ IDEA | |
| 3 | -// (powered by FernFlower decompiler) | |
| 4 | -// | |
| 5 | - | |
| 6 | -package com.genersoft.iot.vmp.jt1078.publisher; | |
| 7 | - | |
| 8 | -import com.genersoft.iot.vmp.jt1078.entity.Media; | |
| 9 | -import com.genersoft.iot.vmp.jt1078.entity.Media.Type; | |
| 10 | -import com.genersoft.iot.vmp.jt1078.server.Jtt1078Handler; | |
| 11 | -import com.genersoft.iot.vmp.jt1078.subscriber.Subscriber; | |
| 12 | -import io.netty.channel.ChannelHandlerContext; | |
| 13 | - | |
| 14 | -import java.io.IOException; | |
| 15 | -import java.net.URISyntaxException; | |
| 16 | -import java.util.Objects; | |
| 17 | -import java.util.concurrent.ConcurrentHashMap; | |
| 18 | -import org.slf4j.Logger; | |
| 19 | -import org.slf4j.LoggerFactory; | |
| 20 | - | |
| 21 | -public final class PublishManager { | |
| 22 | - static Logger logger = LoggerFactory.getLogger(PublishManager.class); | |
| 23 | - ConcurrentHashMap<String, Channel> channels = new ConcurrentHashMap(); | |
| 24 | - static final PublishManager instance = new PublishManager(); | |
| 25 | - private Integer httpPort; | |
| 26 | - | |
| 27 | - private PublishManager() { | |
| 28 | - } | |
| 29 | - | |
| 30 | - public Subscriber subscribe(String tag, Media.Type type, ChannelHandlerContext ctx, Integer httpPort) { | |
| 31 | - Channel chl = (Channel)this.channels.get(tag); | |
| 32 | - if (chl == null) { | |
| 33 | - chl = new Channel(tag, httpPort); | |
| 34 | - this.channels.put(tag, chl); | |
| 35 | - } | |
| 36 | - this.httpPort = httpPort; | |
| 37 | - | |
| 38 | - Subscriber subscriber = null; | |
| 39 | - if (type.equals(Type.Video)) { | |
| 40 | - subscriber = chl.subscribe(ctx); | |
| 41 | - subscriber.setName("subscriber-" + tag + "-" + subscriber.getId()); | |
| 42 | - subscriber.start(); | |
| 43 | - return subscriber; | |
| 44 | - } else { | |
| 45 | - throw new RuntimeException("unknown media type: " + type); | |
| 46 | - } | |
| 47 | - } | |
| 48 | - | |
| 49 | - public void publishAudio(String tag, int sequence, long timestamp, int payloadType, byte[] data) { | |
| 50 | - Channel chl = (Channel)this.channels.get(tag); | |
| 51 | - if (chl != null) { | |
| 52 | - chl.writeAudio(timestamp, payloadType, data); | |
| 53 | - } | |
| 54 | - | |
| 55 | - } | |
| 56 | - | |
| 57 | - public void publishVideo(String tag, int sequence, long timestamp, int payloadType, byte[] data) { | |
| 58 | - int length = data.length; | |
| 59 | - StringBuilder builder = new StringBuilder(); | |
| 60 | - | |
| 61 | - for(int i = 0; i < length; ++i) { | |
| 62 | - builder.append(this.valu(data, i)); | |
| 63 | - } | |
| 64 | - | |
| 65 | - Channel chl = (Channel)this.channels.get(tag); | |
| 66 | - if (chl != null) { | |
| 67 | - chl.writeVideo((long)sequence, timestamp, payloadType, data); | |
| 68 | - } | |
| 69 | - | |
| 70 | - } | |
| 71 | - | |
| 72 | - public String valu(byte[] data, int index) { | |
| 73 | - byte val = data[index++]; | |
| 74 | - int ch1 = val >> 4 & 15; | |
| 75 | - int ch2 = val & 15; | |
| 76 | - return ch1 + "" + ch2; | |
| 77 | - } | |
| 78 | - | |
| 79 | - public Channel open(String tag, Integer httpPort) { | |
| 80 | - Channel chl = (Channel)this.channels.get(tag); | |
| 81 | - if (chl == null) { | |
| 82 | - chl = new Channel(tag, httpPort); | |
| 83 | - this.channels.put(tag, chl); | |
| 84 | - } | |
| 85 | - | |
| 86 | - logger.info("Thread id:[{}]", Thread.currentThread().getId()); | |
| 87 | - if (chl.isPublishing()) { | |
| 88 | - throw new RuntimeException("channel already publishing"); | |
| 89 | - } else { | |
| 90 | - return chl; | |
| 91 | - } | |
| 92 | - } | |
| 93 | - | |
| 94 | - public void close(String tag) { | |
| 95 | - Channel chl = (Channel)this.channels.remove(tag); | |
| 96 | - if (chl != null) { | |
| 97 | - chl.close(); | |
| 98 | - } | |
| 99 | - | |
| 100 | - } | |
| 101 | - | |
| 102 | - public void unsubscribe(String tag, long watcherId) { | |
| 103 | - Channel chl = (Channel)this.channels.get(tag); | |
| 104 | - if (chl != null) { | |
| 105 | - chl.unsubscribe(watcherId); | |
| 106 | - } | |
| 107 | - | |
| 108 | - | |
| 109 | - logger.info("unsubscribe: {} - {}", tag, watcherId); | |
| 110 | - } | |
| 111 | - | |
| 112 | - public void unsubscribeAndClose(String tag) { | |
| 113 | - try { | |
| 114 | - Channel chl = (Channel)this.channels.get(tag); | |
| 115 | - if (chl != null) { | |
| 116 | - long watcherId = chl.getWatcherId(tag); | |
| 117 | - this.unsubscribe(tag, watcherId); | |
| 118 | - } | |
| 119 | - } catch (Exception var6) { | |
| 120 | - logger.error("unsubscribeAndClose unsubscribe error;[{}]", tag); | |
| 121 | - } | |
| 122 | - | |
| 123 | - try { | |
| 124 | - this.close(tag); | |
| 125 | - } catch (Exception var5) { | |
| 126 | - logger.error("unsubscribeAndClose close error;[{}]", tag); | |
| 127 | - } | |
| 128 | - | |
| 129 | - } | |
| 130 | - | |
| 131 | - public static void init() { | |
| 132 | - } | |
| 133 | - | |
| 134 | - public static PublishManager getInstance() { | |
| 135 | - return instance; | |
| 136 | - } | |
| 137 | - | |
| 138 | - private void createChannel(String tag, String tagMapping) { | |
| 139 | - Channel chl = (Channel)this.channels.get(tag); | |
| 140 | - } | |
| 141 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/rtp/H264Packeter.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.rtp; | |
| 2 | - | |
| 3 | -import java.nio.ByteBuffer; | |
| 4 | -import java.util.ArrayList; | |
| 5 | -import java.util.Arrays; | |
| 6 | -import java.util.List; | |
| 7 | - | |
| 8 | -public class H264Packeter { | |
| 9 | - | |
| 10 | - private final int MAX_PACKAGE_SIZE = 1400; | |
| 11 | - | |
| 12 | - private byte[] buffer; | |
| 13 | - | |
| 14 | - private long firstTimestamp = 0; | |
| 15 | - | |
| 16 | - private int seq = 0; | |
| 17 | - | |
| 18 | - private int lastPosition = 0; | |
| 19 | - | |
| 20 | - public List<byte[]> packet(byte[] h264, long timestamp) { | |
| 21 | - List<byte[]> streams = new ArrayList<>(); | |
| 22 | - if (buffer == null) { | |
| 23 | - buffer = Arrays.copyOf(h264, h264.length); | |
| 24 | - } else { | |
| 25 | - byte[] nbuffer = new byte[buffer.length - lastPosition + h264.length]; | |
| 26 | - System.arraycopy(buffer, lastPosition, nbuffer, 0, buffer.length - lastPosition); | |
| 27 | - //System.out.println(toHex(nbuffer)); | |
| 28 | - System.arraycopy(h264, 0, nbuffer, buffer.length - lastPosition, h264.length); | |
| 29 | - //System.out.println(toHex(nbuffer)); | |
| 30 | - buffer = nbuffer; | |
| 31 | - } | |
| 32 | - lastPosition = 0; | |
| 33 | - //System.out.println(buffer.length); | |
| 34 | - if (firstTimestamp == 0) { | |
| 35 | - firstTimestamp = timestamp; | |
| 36 | - } | |
| 37 | - while (lastPosition < buffer.length - 4) { | |
| 38 | - byte[] nalu = readNalu(); | |
| 39 | - if (nalu == null) { | |
| 40 | - break; | |
| 41 | - } | |
| 42 | - ByteBuffer buffer = null; | |
| 43 | - byte[] header = new byte[14]; | |
| 44 | - header[0] = (byte) (header[0] | 0x80); | |
| 45 | - header[1] = (byte) (header[1] | 96); | |
| 46 | - header[11] = 15; | |
| 47 | - if (nalu.length <= MAX_PACKAGE_SIZE) { | |
| 48 | - buffer = ByteBuffer.allocate(16 + nalu.length); | |
| 49 | - header[1] = (byte) (header[1] | 0x80); | |
| 50 | - buffer.put((byte) 0x24); | |
| 51 | - buffer.put((byte) 0); | |
| 52 | - buffer.putShort((short) (12 + nalu.length)); | |
| 53 | - buffer.put(header, 0, 2); | |
| 54 | - buffer.putShort((short) ++seq); | |
| 55 | - buffer.putInt((int) (timestamp - firstTimestamp)); | |
| 56 | - buffer.put(header, 8, 4); | |
| 57 | - buffer.put(nalu); | |
| 58 | - //System.out.println("完整: " + toHex(buffer.array())); | |
| 59 | - streams.add(buffer.array()); | |
| 60 | - } else { | |
| 61 | - int tail = nalu.length % MAX_PACKAGE_SIZE, group = nalu.length / MAX_PACKAGE_SIZE + (tail > 0 ? 1 : 0); | |
| 62 | - for (int i = 0; i < group; i++) { | |
| 63 | - buffer = ByteBuffer.allocate(18 + MAX_PACKAGE_SIZE); | |
| 64 | - if (i == 0) { | |
| 65 | - buffer = ByteBuffer.allocate(17 + MAX_PACKAGE_SIZE); | |
| 66 | - header[1] = (byte) (header[1] & 0x7F); | |
| 67 | - header[12] = (byte) (header[12] | ((byte) (nalu[0] & 0x80)) << 7); | |
| 68 | - header[12] = (byte) (header[12] | ((byte) ((nalu[0] & 0x60) >> 5)) << 5); | |
| 69 | - header[12] = (byte) (header[12] | ((byte) 28)); | |
| 70 | - header[13] = (byte) (header[13] & 0xBF); | |
| 71 | - header[13] = (byte) (header[13] & 0xDF); | |
| 72 | - header[13] = (byte) (header[13] | 0x80); | |
| 73 | - header[13] = (byte) (header[13] | ((byte) (nalu[0] & 0x1F))); | |
| 74 | - buffer.put((byte) 0x24); | |
| 75 | - buffer.put((byte) 0); | |
| 76 | - buffer.putShort((short) (13 + MAX_PACKAGE_SIZE)); | |
| 77 | - buffer.put(header, 0, 2); | |
| 78 | - buffer.putShort((short) ++seq); | |
| 79 | - buffer.putInt((int) (timestamp - firstTimestamp)); | |
| 80 | - buffer.put(header, 8, 6); | |
| 81 | - buffer.put(nalu, i * MAX_PACKAGE_SIZE + 1, MAX_PACKAGE_SIZE - 1); | |
| 82 | - //System.out.println(String.format("Nalu header:%02X", nalu[0])); | |
| 83 | - //System.out.println("第一分片: " + toHex(buffer.array())); | |
| 84 | - } else if (i == group - 1) { | |
| 85 | - buffer = ByteBuffer.allocate(18 + tail); | |
| 86 | - header[1] = (byte) (header[1] | 0x80); | |
| 87 | - header[12] = (byte) (header[12] | ((byte) (nalu[0] & 0x80)) << 7); | |
| 88 | - header[12] = (byte) (header[12] | ((byte) ((nalu[0] & 0x60) >> 5)) << 5); | |
| 89 | - header[12] = (byte) (header[12] | ((byte) 28)); | |
| 90 | - header[13] = (byte) (header[13] & 0xDF); | |
| 91 | - header[13] = (byte) (header[13] & 0x7F); | |
| 92 | - header[13] = (byte) (header[13] | 0x40); | |
| 93 | - header[13] = (byte) (header[13] | ((byte) (nalu[0] & 0x1F))); | |
| 94 | - buffer.put((byte) 0x24); | |
| 95 | - buffer.put((byte) 0); | |
| 96 | - buffer.putShort((short) (14 + tail)); | |
| 97 | - buffer.put(header, 0, 2); | |
| 98 | - buffer.putShort((short) ++seq); | |
| 99 | - buffer.putInt((int) (timestamp - firstTimestamp)); | |
| 100 | - buffer.put(header, 8, 6); | |
| 101 | - buffer.put(nalu, i * MAX_PACKAGE_SIZE, tail); | |
| 102 | - //System.out.println("最后分片: " + toHex(buffer.array())); | |
| 103 | - } else { | |
| 104 | - header[1] = (byte) (header[1] & 0x7F); | |
| 105 | - header[12] = (byte) (header[12] | ((byte) (nalu[0] & 0x80)) << 7); | |
| 106 | - header[12] = (byte) (header[12] | ((byte) ((nalu[0] & 0x60) >> 5)) << 5); | |
| 107 | - header[12] = (byte) (header[12] | ((byte) 28)); | |
| 108 | - header[13] = (byte) (header[13] & 0xDF); | |
| 109 | - header[13] = (byte) (header[13] & 0x7F); | |
| 110 | - header[13] = (byte) (header[13] & 0xBF); | |
| 111 | - header[13] = (byte) (header[13] | ((byte) (nalu[0] & 0x1F))); | |
| 112 | - buffer.put((byte) 0x24); | |
| 113 | - buffer.put((byte) 0); | |
| 114 | - buffer.putShort((short) (14 + MAX_PACKAGE_SIZE)); | |
| 115 | - buffer.put(header, 0, 2); | |
| 116 | - buffer.putShort((short) ++seq); | |
| 117 | - buffer.putInt((int) (timestamp - firstTimestamp)); | |
| 118 | - buffer.put(header, 8, 6); | |
| 119 | - buffer.put(nalu, i * MAX_PACKAGE_SIZE, MAX_PACKAGE_SIZE); | |
| 120 | - //System.out.println("中间分片: " + toHex(buffer.array())); | |
| 121 | - } | |
| 122 | - streams.add(buffer.array()); | |
| 123 | - } | |
| 124 | - } | |
| 125 | - } | |
| 126 | - | |
| 127 | - return streams; | |
| 128 | - } | |
| 129 | - | |
| 130 | - public byte[] readNalu() { | |
| 131 | - for (int i = (lastPosition == 0 ? 0 : lastPosition + 1); i < buffer.length - 3; i++) { | |
| 132 | - if (buffer[i] == 0 && buffer[i + 1] == 0 && buffer[i + 2] == 0 && buffer[i + 3] == 1) { | |
| 133 | - if (i != 0) { | |
| 134 | - byte[] nalu = new byte[i - lastPosition - 4]; | |
| 135 | - System.arraycopy(buffer, lastPosition + 4, nalu, 0, i - lastPosition - 4); | |
| 136 | - lastPosition = i; | |
| 137 | - //System.out.println(toHex(nalu)); | |
| 138 | - | |
| 139 | - return nalu; | |
| 140 | - } | |
| 141 | - } | |
| 142 | - } | |
| 143 | - | |
| 144 | - return null; | |
| 145 | - } | |
| 146 | - | |
| 147 | - public String toHex(byte[] bytes) { | |
| 148 | - StringBuilder sb = new StringBuilder(); | |
| 149 | - for (byte b : bytes) { | |
| 150 | - sb.append(String.format("%02X ", b)); | |
| 151 | - } | |
| 152 | - | |
| 153 | - return sb.toString(); | |
| 154 | - } | |
| 155 | - | |
| 156 | - public static void main(String[] args) { | |
| 157 | - byte[] bytes = new byte[]{(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x01,(byte)0x67,(byte)0x4D,(byte)0x00,(byte)0x1F,(byte)0x96,(byte)0x35,(byte)0x41,(byte)0xE0,(byte)0x24,(byte)0xD3,(byte)0x70,(byte)0x50,(byte)0x10,(byte)0x50,(byte)0x20,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x01,(byte)0x68,(byte)0xEE,(byte)0x31,(byte)0xB2,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x01,(byte)0x06,(byte)0xE5,(byte)0x01,(byte)0x4A,(byte)0x80,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x01,(byte)0x65,(byte)0xB8,(byte)0x00,(byte)0x00,(byte)0x0C,(byte)0x16,(byte)0x90,(byte)0x00,(byte)0x00,(byte)0xBF,(byte)0xFE,(byte)0xD4,(byte)0xA7,(byte)0x99,(byte)0x63,(byte)0xE6,(byte)0xF9,(byte)0x5A,(byte)0x75,(byte)0xCE,(byte)0xDB,(byte)0x0C,(byte)0xD3,(byte)0xA6,(byte)0x31,(byte)0x05,(byte)0x66,(byte)0x6C,(byte)0x18,(byte)0x87,(byte)0xD0,(byte)0xF9,(byte)0xD0,(byte)0xCC,(byte)0xA3,(byte)0x57,(byte)0x07,(byte)0xDF,(byte)0x7C,(byte)0x6F,(byte)0x42,(byte)0xE9,(byte)0x8B,(byte)0x1B,(byte)0xA2,(byte)0x70,(byte)0x8C,(byte)0x80,(byte)0x00,(byte)0x00,(byte)0x1A,(byte)0xD6,(byte)0xEB,(byte)0x80,(byte)0xDE,(byte)0xE6,(byte)0xE2,(byte)0xF5,(byte)0xFF,(byte)0x33,(byte)0x98,(byte)0x97,(byte)0xCD,(byte)0xEB,(byte)0xEB,(byte)0xE5,(byte)0x60,(byte)0x00,(byte)0x00,(byte)0x0F,(byte)0xFB,(byte)0x49,(byte)0x08,(byte)0x9C,(byte)0x75,(byte)0xB4,(byte)0xDB,(byte)0xCE,(byte)0x58,(byte)0x08,(byte)0xB4,(byte)0x68,(byte)0x22,(byte)0x16,(byte)0x51,(byte)0x47,(byte)0xF3,(byte)0xD3,(byte)0x56,(byte)0xC2,(byte)0x4F,(byte)0x12,(byte)0xFD,(byte)0x2B,(byte)0xC9,(byte)0x45,(byte)0x80,(byte)0xDB,(byte)0xA4,(byte)0x62,(byte)0xEB,(byte)0xC3,(byte)0x6D,(byte)0xFE,(byte)0x36,(byte)0x20,(byte)0xAE,(byte)0xD9,(byte)0xD2,(byte)0x4C,(byte)0x9E,(byte)0x06,(byte)0xA0,(byte)0x8B,(byte)0x42,(byte)0x35,(byte)0xEC,(byte)0x64,(byte)0x03,(byte)0x22,(byte)0x29,(byte)0x26,(byte)0x19,(byte)0x70,(byte)0xCA,(byte)0x18,(byte)0xC0,(byte)0x7E,(byte)0x08,(byte)0x4F,(byte)0xEB,(byte)0xFD,(byte)0x5D,(byte)0x90,(byte)0x31,(byte)0x62,(byte)0x02,(byte)0x2E,(byte)0xBE,(byte)0x53,(byte)0xCF,(byte)0xC0,(byte)0xA8,(byte)0xAC,(byte)0xF3,(byte)0x92,(byte)0xC8,(byte)0x76,(byte)0x77,(byte)0x84,(byte)0x2F,(byte)0x76,(byte)0x45,(byte)0xF3,(byte)0xBF,(byte)0x07,(byte)0x1F,(byte)0x6D,(byte)0xC6,(byte)0x11,(byte)0xB9,(byte)0x83,(byte)0xF6,(byte)0xDF,(byte)0xA1,(byte)0x6D,(byte)0x56,(byte)0x6D,(byte)0xE0,(byte)0xFA,(byte)0xC1,(byte)0x7E,(byte)0xC5,(byte)0xC5,(byte)0x3C,(byte)0x69,(byte)0x57,(byte)0x61,(byte)0xCA,(byte)0x17,(byte)0x40,(byte)0x30,(byte)0xAE,(byte)0x4E,(byte)0x4C,(byte)0x61,(byte)0xC3,(byte)0xAF,(byte)0x6F,(byte)0xB4,(byte)0x48,(byte)0x33,(byte)0x4F,(byte)0x59,(byte)0x6D,(byte)0x88,(byte)0xA0,(byte)0x3B,(byte)0x9C,(byte)0x39,(byte)0x67,(byte)0xAD,(byte)0x0C,(byte)0xC0,(byte)0x64,(byte)0x8A,(byte)0xDB,(byte)0x95,(byte)0xB3,(byte)0xEF,(byte)0x6A,(byte)0xC0,(byte)0x9B,(byte)0xAF,(byte)0x44,(byte)0xBF,(byte)0x69,(byte)0x77,(byte)0x7D,(byte)0x2B,(byte)0xDB,(byte)0x47,(byte)0x78,(byte)0xD0,(byte)0x9C,(byte)0x79,(byte)0xA1,(byte)0xFE,(byte)0xC4,(byte)0xC4,(byte)0xAF,(byte)0x6A,(byte)0x2C,(byte)0x2D,(byte)0xF4,(byte)0xB6,(byte)0x27,(byte)0xC6,(byte)0x3C,(byte)0x71,(byte)0xC1,(byte)0x5E,(byte)0xB0,(byte)0x22,(byte)0x93,(byte)0x88,(byte)0x9C,(byte)0x98,(byte)0x3A,(byte)0x8D,(byte)0x7F,(byte)0x2E,(byte)0x48,(byte)0x53,(byte)0x2D,(byte)0xF5,(byte)0x7A,(byte)0xD0,(byte)0xC2,(byte)0x68,(byte)0xAF,(byte)0xB7,(byte)0x8C,(byte)0xF4,(byte)0xD4,(byte)0x99,(byte)0x96,(byte)0x24,(byte)0x47,(byte)0x2B,(byte)0x28,(byte)0x26,(byte)0xE4,(byte)0xBD,(byte)0xFA,(byte)0x65,(byte)0x7C,(byte)0xB3,(byte)0xA8,(byte)0x3E,(byte)0x43,(byte)0xF4,(byte)0x6D,(byte)0x50,(byte)0x7F,(byte)0xE3,(byte)0xF5,(byte)0x73,(byte)0xE6,(byte)0xF2,(byte)0x23,(byte)0x3A,(byte)0x22,(byte)0x74,(byte)0x7B,(byte)0x1E,(byte)0xDC,(byte)0xFB,(byte)0xF4,(byte)0xA8,(byte)0x97,(byte)0xB9,(byte)0x3A,(byte)0x73,(byte)0x8B,(byte)0x78,(byte)0x64,(byte)0x03,(byte)0x55,(byte)0x6E,(byte)0x52,(byte)0x7D,(byte)0x4C,(byte)0x28,(byte)0x00,(byte)0x43,(byte)0x72,(byte)0x84,(byte)0xF1,(byte)0x81,(byte)0x55,(byte)0x7B,(byte)0x8D,(byte)0x0F,(byte)0x7F,(byte)0xB4,(byte)0xEB,(byte)0xAB,(byte)0x69,(byte)0x65,(byte)0x7B,(byte)0x92,(byte)0xAC,(byte)0xB6,(byte)0xB4,(byte)0x33,(byte)0x5D,(byte)0x33,(byte)0x5D,(byte)0xC2,(byte)0xF8,(byte)0x25,(byte)0x7E,(byte)0x1D,(byte)0x1D,(byte)0xDB,(byte)0x1C,(byte)0xF8,(byte)0xBE,(byte)0x4B,(byte)0x25,(byte)0xA9,(byte)0xB5,(byte)0x8A,(byte)0x8D,(byte)0x67,(byte)0x61,(byte)0xFF,(byte)0xE3,(byte)0x18,(byte)0x1C,(byte)0x8F,(byte)0x7F,(byte)0xBA,(byte)0x50,(byte)0x47,(byte)0x10,(byte)0x5D,(byte)0xD5,(byte)0x97,(byte)0x62,(byte)0x06,(byte)0x09,(byte)0x52,(byte)0xC3,(byte)0x81,(byte)0x1A,(byte)0x58,(byte)0x87,(byte)0xFC,(byte)0x30,(byte)0x61,(byte)0x89,(byte)0xF5,(byte)0x2C,(byte)0x58,(byte)0x04,(byte)0x32,(byte)0x8B,(byte)0x3E,(byte)0x79,(byte)0xA3,(byte)0x10,(byte)0xFD,(byte)0x11,(byte)0x59,(byte)0xCA,(byte)0x08,(byte)0x48,(byte)0x24,(byte)0xDF,(byte)0x5F,(byte)0x02,(byte)0x12,(byte)0x2F,(byte)0x4C,(byte)0xDC,(byte)0xE9,(byte)0xFE,(byte)0xF0,(byte)0x21,(byte)0x5B,(byte)0xD3,(byte)0x0C,(byte)0xA7,(byte)0xF6,(byte)0xEF,(byte)0xFD,(byte)0xA4,(byte)0xB0,(byte)0xEF,(byte)0x47,(byte)0xC6,(byte)0x8F,(byte)0xB7,(byte)0x90,(byte)0xE3,(byte)0x03,(byte)0xBE,(byte)0x85,(byte)0x51,(byte)0x56,(byte)0x65,(byte)0xD3,(byte)0x6B,(byte)0xC4,(byte)0x8F,(byte)0x00,(byte)0x09,(byte)0xCC,(byte)0x0C,(byte)0x7C,(byte)0x69,(byte)0x42,(byte)0x68,(byte)0x05,(byte)0x97,(byte)0x5D,(byte)0xD8,(byte)0x66,(byte)0x8E,(byte)0x1D,(byte)0x2E,(byte)0x65,(byte)0x0B,(byte)0xCC,(byte)0x24,(byte)0x15,(byte)0xE4,(byte)0x10,(byte)0x23,(byte)0x4D,(byte)0xAE,(byte)0x01,(byte)0xCB,(byte)0xEB,(byte)0x16,(byte)0xAE,(byte)0x5A,(byte)0xA9,(byte)0xA0,(byte)0xFD,(byte)0xE8,(byte)0x62,(byte)0x57,(byte)0x8E,(byte)0x8F,(byte)0x57,(byte)0xA7,(byte)0xCC,(byte)0x6B,(byte)0xEB,(byte)0xDF,(byte)0xC1,(byte)0xBD,(byte)0xA6,(byte)0x40,(byte)0x40,(byte)0x07,(byte)0xAC,(byte)0x0A,(byte)0x40,(byte)0xD1,(byte)0xA7,(byte)0x9F,(byte)0x8D,(byte)0xE8,(byte)0x36,(byte)0xD8,(byte)0x53,(byte)0x54,(byte)0x66,(byte)0x14,(byte)0x5B,(byte)0x38,(byte)0x23,(byte)0xC5,(byte)0x72,(byte)0xA1,(byte)0x9D,(byte)0x3B,(byte)0xDD,(byte)0xD3,(byte)0xD6,(byte)0x46,(byte)0xE9,(byte)0x7D,(byte)0x0D,(byte)0xA7,(byte)0x22,(byte)0x00,(byte)0x87,(byte)0x7C,(byte)0x4E,(byte)0x4E,(byte)0x56,(byte)0xE1,(byte)0x03,(byte)0x99,(byte)0x4A,(byte)0xB5,(byte)0x09,(byte)0xD7,(byte)0xC1,(byte)0x0F,(byte)0xDD,(byte)0xB5,(byte)0x91,(byte)0xF8,(byte)0x3D,(byte)0x19,(byte)0x63,(byte)0xAD,(byte)0xC1,(byte)0x21,(byte)0x46,(byte)0x2F,(byte)0x2A,(byte)0xE8,(byte)0x11,(byte)0xFA,(byte)0x56,(byte)0xCD,(byte)0x16,(byte)0xB2,(byte)0x1C,(byte)0xA0,(byte)0xB1,(byte)0xBC,(byte)0xB4,(byte)0x99,(byte)0xBC,(byte)0xFB,(byte)0x60,(byte)0x48,(byte)0x45,(byte)0xFB,(byte)0x52,(byte)0x5A,(byte)0xE5,(byte)0x1A,(byte)0x43,(byte)0x6B,(byte)0x26,(byte)0xC3,(byte)0xD8,(byte)0xE6,(byte)0x1F,(byte)0x0F,(byte)0x1D,(byte)0x77,(byte)0x92,(byte)0xB7,(byte)0x05,(byte)0x15,(byte)0x8A,(byte)0xEE,(byte)0xB8,(byte)0x62,(byte)0x82,(byte)0x9D,(byte)0x98,(byte)0x94,(byte)0xA7,(byte)0xBA,(byte)0x7B,(byte)0x19,(byte)0x8B,(byte)0x8E,(byte)0x3F,(byte)0xB4,(byte)0x1B,(byte)0x9B,(byte)0x4D,(byte)0xD3,(byte)0xA2,(byte)0x28,(byte)0x05,(byte)0x99,(byte)0xC8,(byte)0xF7,(byte)0x2A,(byte)0x6F,(byte)0xB9,(byte)0xC9,(byte)0x96,(byte)0xF6,(byte)0x03,(byte)0xC6,(byte)0x10,(byte)0xBF,(byte)0xF2,(byte)0xD5,(byte)0xAE,(byte)0x7F,(byte)0x93,(byte)0xE4,(byte)0xB6,(byte)0x4D,(byte)0xE0,(byte)0xE5,(byte)0x06,(byte)0x4E,(byte)0x4C,(byte)0xC5,(byte)0xD5,(byte)0xD9,(byte)0xF8,(byte)0x1E,(byte)0x36,(byte)0x38,(byte)0x01,(byte)0x7C,(byte)0xBC,(byte)0x1C,(byte)0x71,(byte)0x46,(byte)0x2C,(byte)0xCE,(byte)0xBD,(byte)0x23,(byte)0x14,(byte)0x37,(byte)0xBB,(byte)0x70,(byte)0xC6,(byte)0x7A,(byte)0xF7,(byte)0x73,(byte)0xA8,(byte)0xA9,(byte)0xDC,(byte)0xC2,(byte)0xC0,(byte)0x7A,(byte)0xDA,(byte)0x74,(byte)0xFF,(byte)0x25,(byte)0x73,(byte)0x31,(byte)0xD8,(byte)0xF9,(byte)0x4D,(byte)0x66,(byte)0xD3,(byte)0x5E,(byte)0x98,(byte)0xC6,(byte)0xC4,(byte)0x55,(byte)0x0B,(byte)0xC4,(byte)0xB1,(byte)0xED,(byte)0x0F,(byte)0x74,(byte)0x5D,(byte)0x1B,(byte)0x7A,(byte)0x05,(byte)0xDB,(byte)0x7C,(byte)0x0D,(byte)0xDF,(byte)0xE2,(byte)0x6B,(byte)0xAF,(byte)0x22,(byte)0x3B,(byte)0x11,(byte)0x35,(byte)0xE3,(byte)0x51,(byte)0x13,(byte)0x07,(byte)0xD3,(byte)0x6E,(byte)0xAE,(byte)0x91,(byte)0xE2,(byte)0x98,(byte)0x02,(byte)0x6D,(byte)0xD9,(byte)0xD9,(byte)0xBD,(byte)0x7C,(byte)0x8E,(byte)0xBF,(byte)0xBE,(byte)0xB7,(byte)0x79,(byte)0xCA,(byte)0xC1,(byte)0x66,(byte)0x89,(byte)0x17,(byte)0x9B,(byte)0x77,(byte)0xBE,(byte)0xA7,(byte)0xED,(byte)0x3E,(byte)0xCC,(byte)0x86,(byte)0x44,(byte)0x42,(byte)0x38,(byte)0x50,(byte)0x8D,(byte)0xC3,(byte)0x58,(byte)0x07,(byte)0x42,(byte)0xBF,(byte)0x7C,(byte)0xC3,(byte)0x72,(byte)0x81,(byte)0x6E,(byte)0xFC,(byte)0xC8,(byte)0x63,(byte)0x8B,(byte)0x2E,(byte)0x63,(byte)0xA6,(byte)0x17,(byte)0x62,(byte)0x3C,(byte)0xED,(byte)0x29,(byte)0xFE,(byte)0xBC,(byte)0x4E,(byte)0x8B,(byte)0x94,(byte)0x4B,(byte)0x46,(byte)0xE6,(byte)0xC7,(byte)0x1A,(byte)0x32,(byte)0xE7,(byte)0xC8,(byte)0x44,(byte)0x47,(byte)0x1C,(byte)0xE8,(byte)0xC7,(byte)0x8C,(byte)0x1F,(byte)0x9E,(byte)0x16,(byte)0xED,(byte)0x12,(byte)0x8D,(byte)0x66,(byte)0x71,(byte)0xF4,(byte)0x1E,(byte)0x22,(byte)0xAB,(byte)0xD9,(byte)0xF5,(byte)0x22,(byte)0xC3,(byte)0x31,(byte)0x0B,(byte)0xD6,(byte)0x12,(byte)0x46,(byte)0x99,(byte)0x13,(byte)0xD2,(byte)0x02,(byte)0x34,(byte)0x7E,(byte)0x01,(byte)0x25,(byte)0xAC,(byte)0xB6,(byte)0xF1,(byte)0xF1,(byte)0x46,(byte)0xBE,(byte)0x90,(byte)0x79,(byte)0xBA,(byte)0x5B,(byte)0x36,(byte)0xF7,(byte)0x81,(byte)0x70,(byte)0x4A,(byte)0xDC,(byte)0xF1,(byte)0x24,(byte)0x9A,(byte)0x87,(byte)0x1E,(byte)0x59,(byte)0xE1,(byte)0x46,(byte)0xDC,(byte)0x0E,(byte)0x71,(byte)0xB4,(byte)0xE5,(byte)0x48,(byte)0x0E,(byte)0x11,(byte)0x87,(byte)0x99,(byte)0x2A,(byte)0x5C,(byte)0x61,(byte)0x75,(byte)0x3C,(byte)0x5B,(byte)0xF8,(byte)0xE6,(byte)0xE4,(byte)0x01,(byte)0xA2,(byte)0x01,(byte)0xE5,(byte)0x79,(byte)0x52,(byte)0x0B,(byte)0xC7,(byte)0xF7,(byte)0xED,(byte)0x0B,(byte)0x52,(byte)0x47,(byte)0x77,(byte)0xAD,(byte)0x45,(byte)0x72,(byte)0x21,(byte)0x0E,(byte)0xBE,(byte)0xA5,(byte)0x3D,(byte)0xEA,(byte)0xBF,(byte)0x44,(byte)0x7E,(byte)0x75,(byte)0x8C,(byte)0xF0,(byte)0x05,(byte)0xBB,(byte)0xDD,(byte)0xE3,(byte)0x53,(byte)0x4E,(byte)0x1B,(byte)0xB4,(byte)0x2F,(byte)0x65,(byte)0xCE,(byte)0x44,(byte)0x95,(byte)0x4F,(byte)0x44,(byte)0x1D,(byte)0x0D,(byte)0x54,(byte)0xF9,(byte)0xCD,(byte)0x30,(byte)0x00,(byte)0x81,(byte)0x2C,(byte)0x5C,(byte)0xFF,(byte)0xBE}; | |
| 158 | - H264Packeter packeter = new H264Packeter(); | |
| 159 | - packeter.packet(bytes, 0); | |
| 160 | - } | |
| 161 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/rtsp/RtspRequest.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.rtsp; | |
| 2 | - | |
| 3 | -import io.netty.handler.codec.http.DefaultFullHttpRequest; | |
| 4 | -import io.netty.handler.codec.http.FullHttpRequest; | |
| 5 | -import io.netty.handler.codec.rtsp.RtspHeaderNames; | |
| 6 | -import io.netty.handler.codec.rtsp.RtspMethods; | |
| 7 | -import io.netty.handler.codec.rtsp.RtspVersions; | |
| 8 | -import io.netty.util.internal.StringUtil; | |
| 9 | - | |
| 10 | -/** | |
| 11 | - * Rtsp请求 | |
| 12 | - */ | |
| 13 | -public class RtspRequest { | |
| 14 | - | |
| 15 | - private final String CRLF = "\r\n"; | |
| 16 | - | |
| 17 | - private final String VERSION = "RTSP/1.0"; | |
| 18 | - | |
| 19 | - private int seq = 0; | |
| 20 | - | |
| 21 | - private String host; | |
| 22 | - | |
| 23 | - private int port; | |
| 24 | - | |
| 25 | - private String path; | |
| 26 | - | |
| 27 | - private String sessionID; | |
| 28 | - | |
| 29 | - public RtspRequest(String host, int port, String path) { | |
| 30 | - this.host = host; | |
| 31 | - this.port = port; | |
| 32 | - this.path = path; | |
| 33 | - } | |
| 34 | - | |
| 35 | - public String getHost() { | |
| 36 | - return host; | |
| 37 | - } | |
| 38 | - | |
| 39 | - public void setHost(String host) { | |
| 40 | - this.host = host; | |
| 41 | - } | |
| 42 | - | |
| 43 | - public int getPort() { | |
| 44 | - return port; | |
| 45 | - } | |
| 46 | - | |
| 47 | - public void setPort(int port) { | |
| 48 | - this.port = port; | |
| 49 | - } | |
| 50 | - | |
| 51 | - public String getPath() { | |
| 52 | - return path; | |
| 53 | - } | |
| 54 | - | |
| 55 | - public void setPath(String path) { | |
| 56 | - this.path = path; | |
| 57 | - } | |
| 58 | - | |
| 59 | - public String getSessionID() { | |
| 60 | - return sessionID; | |
| 61 | - } | |
| 62 | - | |
| 63 | - public void setSessionID(String sessionID) { | |
| 64 | - this.sessionID = sessionID; | |
| 65 | - } | |
| 66 | - | |
| 67 | - public FullHttpRequest option() { | |
| 68 | - FullHttpRequest request = new DefaultFullHttpRequest(RtspVersions.RTSP_1_0, RtspMethods.OPTIONS, String.format("rtsp://%s:%d%s", host, port, path)); | |
| 69 | - request.headers().set(RtspHeaderNames.CSEQ, ++seq); | |
| 70 | - | |
| 71 | - return request; | |
| 72 | - } | |
| 73 | - | |
| 74 | - public FullHttpRequest announce() { | |
| 75 | - StringBuilder body = new StringBuilder(); | |
| 76 | - FullHttpRequest request = new DefaultFullHttpRequest(RtspVersions.RTSP_1_0, RtspMethods.ANNOUNCE, String.format("rtsp://%s:%d%s", host, port, path)); | |
| 77 | - request.headers().set(RtspHeaderNames.CSEQ, ++seq); | |
| 78 | - request.headers().set(RtspHeaderNames.CONTENT_TYPE, "application/sdp"); | |
| 79 | - | |
| 80 | - body.append("v=0").append(CRLF) | |
| 81 | - .append("o=- 0 0 IN IP4 127.0.0.1").append(CRLF) | |
| 82 | - .append("s=No Name").append(CRLF) | |
| 83 | - .append("c=IN IP4 ").append(this.host).append(CRLF) | |
| 84 | - .append("t=0 0").append(CRLF) | |
| 85 | - .append("a=tool:libavformat 61.9.100").append(CRLF) | |
| 86 | - .append("m=video 0 RTP/AVP 96").append(CRLF) | |
| 87 | - .append("b=AS:3943").append(CRLF) | |
| 88 | - .append("a=rtpmap:96 H264/90000").append(CRLF) | |
| 89 | - .append("a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z00AKp2oHgCJ+WbgICAoAAADAAgAAAMBlCA=,aO48gA==; profile-level-id=4D002A").append(CRLF) | |
| 90 | - .append("a=control:streamid=0").append(CRLF); | |
| 91 | - request.content().writeBytes(body.toString().getBytes()); | |
| 92 | - request.headers().set(RtspHeaderNames.CONTENT_LENGTH, body.toString().getBytes().length); | |
| 93 | - | |
| 94 | - return request; | |
| 95 | - } | |
| 96 | - | |
| 97 | - public FullHttpRequest setup() { | |
| 98 | - FullHttpRequest request = new DefaultFullHttpRequest(RtspVersions.RTSP_1_0, RtspMethods.SETUP, String.format("rtsp://%s:%d%s/streamid=0", host, port, path)); | |
| 99 | - request.headers().set(RtspHeaderNames.CSEQ, ++seq); | |
| 100 | - request.headers().set(RtspHeaderNames.TRANSPORT, "RTP/AVP/TCP;unicast;interleaved=0-1;mode=record"); | |
| 101 | - request.headers().set(RtspHeaderNames.SESSION, sessionID); | |
| 102 | - | |
| 103 | - return request; | |
| 104 | - } | |
| 105 | - | |
| 106 | - public FullHttpRequest record() { | |
| 107 | - FullHttpRequest request = new DefaultFullHttpRequest(RtspVersions.RTSP_1_0, RtspMethods.RECORD, String.format("rtsp://%s:%d%s/streamid=0", host, port, path)); | |
| 108 | - request.headers().set(RtspHeaderNames.CSEQ, ++seq); | |
| 109 | - request.headers().set(RtspHeaderNames.RANGE, "npt=0.000-"); | |
| 110 | - request.headers().set(RtspHeaderNames.SESSION, sessionID); | |
| 111 | - | |
| 112 | - return request; | |
| 113 | - } | |
| 114 | - | |
| 115 | - public String teardown() { | |
| 116 | - StringBuilder sb = new StringBuilder(); | |
| 117 | - | |
| 118 | - return sb.toString(); | |
| 119 | - } | |
| 120 | - | |
| 121 | - private String header(int length) { | |
| 122 | - StringBuilder sb = new StringBuilder(); | |
| 123 | - | |
| 124 | - return sb.append("CSeq: ").append(++seq).append(CRLF) | |
| 125 | - .append("User-Agent: jt1078").append(CRLF) | |
| 126 | - .append("Content-Length: ").append(length).append(CRLF) | |
| 127 | - .append(StringUtil.isNullOrEmpty(sessionID) ? "" : "Session: ").append(StringUtil.isNullOrEmpty(sessionID) ? "" : sessionID).append(StringUtil.isNullOrEmpty(sessionID) ? "" : CRLF).append(CRLF).toString(); | |
| 128 | - } | |
| 129 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/rtsp/RtspSessionManager.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.rtsp; | |
| 2 | - | |
| 3 | -import io.netty.channel.Channel; | |
| 4 | - | |
| 5 | -import java.util.Map; | |
| 6 | -import java.util.concurrent.ConcurrentHashMap; | |
| 7 | - | |
| 8 | -/** | |
| 9 | - * Rtsp会话 | |
| 10 | - */ | |
| 11 | -public class RtspSessionManager { | |
| 12 | - | |
| 13 | - private static Map<String, Object> channel2register = new ConcurrentHashMap<>(); | |
| 14 | - | |
| 15 | - private static Map<String, Channel> channel2push = new ConcurrentHashMap<>(); | |
| 16 | - | |
| 17 | - public static void register(String channel) { | |
| 18 | - channel2register.put(channel, System.currentTimeMillis()); | |
| 19 | - } | |
| 20 | - | |
| 21 | - public static void unregister(String channel) { | |
| 22 | - channel2register.remove(channel); | |
| 23 | - } | |
| 24 | - | |
| 25 | - public static boolean isRegistered(String channel) { | |
| 26 | - return channel2register.containsKey(channel); | |
| 27 | - } | |
| 28 | - | |
| 29 | - public static void setPush(String channel, Channel push) { | |
| 30 | - channel2push.put(channel, push); | |
| 31 | - } | |
| 32 | - | |
| 33 | - public static Channel getPush(String channel) { | |
| 34 | - return channel2push.get(channel); | |
| 35 | - } | |
| 36 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/server/Jtt1078Handler.java deleted
100644 → 0
| 1 | -// | |
| 2 | -// Source code recreated from a .class file by IntelliJ IDEA | |
| 3 | -// (powered by FernFlower decompiler) | |
| 4 | -// | |
| 5 | - | |
| 6 | -package com.genersoft.iot.vmp.jt1078.server; | |
| 7 | - | |
| 8 | -import com.genersoft.iot.vmp.VManageBootstrap; | |
| 9 | -import com.genersoft.iot.vmp.conf.MediaConfig; | |
| 10 | -import com.genersoft.iot.vmp.jt1078.app.VideoServerApp; | |
| 11 | -import com.genersoft.iot.vmp.jt1078.publisher.Channel; | |
| 12 | -import com.genersoft.iot.vmp.jt1078.publisher.PublishManager; | |
| 13 | -import com.genersoft.iot.vmp.jt1078.util.Packet; | |
| 14 | -import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; | |
| 15 | -import com.genersoft.iot.vmp.service.IStreamProxyService; | |
| 16 | -import com.genersoft.iot.vmp.utils.SpringBeanFactory; | |
| 17 | -import com.genersoft.iot.vmp.vmanager.jt1078.platform.config.Jt1078ConfigBean; | |
| 18 | -import com.genersoft.iot.vmp.vmanager.streamProxy.StreamProxyController; | |
| 19 | -import io.lettuce.core.support.caching.RedisCache; | |
| 20 | -import io.netty.channel.ChannelHandlerContext; | |
| 21 | -import io.netty.channel.SimpleChannelInboundHandler; | |
| 22 | -import io.netty.util.Attribute; | |
| 23 | -import io.netty.util.AttributeKey; | |
| 24 | - | |
| 25 | -import java.io.IOException; | |
| 26 | -import java.net.URISyntaxException; | |
| 27 | -import java.util.Date; | |
| 28 | -import java.util.Iterator; | |
| 29 | -import java.util.Map; | |
| 30 | -import java.util.Objects; | |
| 31 | -import java.util.concurrent.TimeUnit; | |
| 32 | - | |
| 33 | -import org.apache.commons.lang3.StringUtils; | |
| 34 | -import org.slf4j.Logger; | |
| 35 | -import org.slf4j.LoggerFactory; | |
| 36 | -import org.springframework.data.redis.core.RedisTemplate; | |
| 37 | -import org.springframework.data.redis.core.StringRedisTemplate; | |
| 38 | - | |
| 39 | -public class Jtt1078Handler extends SimpleChannelInboundHandler<Packet> { | |
| 40 | - static Logger logger = LoggerFactory.getLogger(Jtt1078Handler.class); | |
| 41 | - private static final AttributeKey<Session> SESSION_KEY = AttributeKey.valueOf("session-key"); | |
| 42 | - private ChannelHandlerContext context; | |
| 43 | - private String tagMapping; | |
| 44 | - private Integer httpPort; | |
| 45 | - | |
| 46 | - public Jtt1078Handler(String tagMapping, Integer httpPort) { | |
| 47 | - this.tagMapping = tagMapping; | |
| 48 | - this.httpPort = httpPort; | |
| 49 | - } | |
| 50 | - | |
| 51 | - protected void channelRead0(ChannelHandlerContext ctx, Packet packet) throws Exception { | |
| 52 | - this.context = ctx; | |
| 53 | - packet.seek(8); | |
| 54 | - String sim = packet.nextBCD() + packet.nextBCD() + packet.nextBCD() + packet.nextBCD() + packet.nextBCD() + packet.nextBCD(); | |
| 55 | - int channel = packet.nextByte() & 255; | |
| 56 | - String tag = sim + "-" + channel; | |
| 57 | - if (StringUtils.isEmpty(this.tagMapping)) { | |
| 58 | - this.tagMapping = tag; | |
| 59 | - } | |
| 60 | - | |
| 61 | - if (!StringUtils.endsWith(this.tagMapping, ".flv")) { | |
| 62 | - endWithMapping(this.tagMapping); | |
| 63 | - } | |
| 64 | - | |
| 65 | - | |
| 66 | - Session session = this.getSession(); | |
| 67 | - if (null == session) { | |
| 68 | - this.setSession(session = new Session()); | |
| 69 | - Channel chl = PublishManager.getInstance().open(this.tagMapping, this.httpPort); | |
| 70 | - session.set("tag", this.tagMapping); | |
| 71 | - logger.info("start publishing: {} -> {}-{}", new Object[]{Long.toHexString((long) chl.hashCode() & 4294967295L), sim, channel}); | |
| 72 | - } | |
| 73 | - | |
| 74 | - Integer sequence = (Integer) session.get("video-sequence"); | |
| 75 | - if (sequence == null) { | |
| 76 | - sequence = 0; | |
| 77 | - } | |
| 78 | - | |
| 79 | - int lengthOffset = 28; | |
| 80 | - int dataType = packet.seek(15).nextByte() >> 4 & 15; | |
| 81 | - int pkType = packet.seek(15).nextByte() & 15; | |
| 82 | - if (dataType == 4) { | |
| 83 | - lengthOffset = 16; | |
| 84 | - } else if (dataType == 3) { | |
| 85 | - lengthOffset = 24; | |
| 86 | - } | |
| 87 | - | |
| 88 | - int pt = packet.seek(5).nextByte() & 127; | |
| 89 | - long timestamp; | |
| 90 | - if (dataType != 0 && dataType != 1 && dataType != 2) { | |
| 91 | - if (dataType == 3) { | |
| 92 | - timestamp = packet.seek(16).nextLong(); | |
| 93 | - byte[] data = packet.seek(lengthOffset + 2).nextBytes(); | |
| 94 | - PublishManager.getInstance().publishVideo(this.tagMapping, sequence, timestamp, pt, data); | |
| 95 | - } | |
| 96 | - } else { | |
| 97 | - if (pkType == 0 || pkType == 2) { | |
| 98 | - sequence = sequence + 1; | |
| 99 | - session.set("video-sequence", sequence); | |
| 100 | - } | |
| 101 | - | |
| 102 | - timestamp = packet.seek(16).nextLong(); | |
| 103 | - PublishManager.getInstance().publishVideo(this.tagMapping, sequence, timestamp, pt, packet.seek(lengthOffset + 2).nextBytes()); | |
| 104 | - } | |
| 105 | - | |
| 106 | - } | |
| 107 | - | |
| 108 | - private byte[] convert(String str) { | |
| 109 | - byte[] bytes = str.getBytes(); | |
| 110 | - new StringBuilder(); | |
| 111 | - int length = bytes.length; | |
| 112 | - byte[] bys = new byte[length]; | |
| 113 | - | |
| 114 | - for (int i = 0; i < length; ++i) { | |
| 115 | - bys[i] = Byte.valueOf(Integer.toBinaryString(bytes[i]) + ""); | |
| 116 | - } | |
| 117 | - | |
| 118 | - return bys; | |
| 119 | - } | |
| 120 | - | |
| 121 | - public final Session getSession() { | |
| 122 | - Attribute<Session> attr = this.context.channel().attr(SESSION_KEY); | |
| 123 | - return null == attr ? null : (Session) attr.get(); | |
| 124 | - } | |
| 125 | - | |
| 126 | - public void channelInactive(ChannelHandlerContext ctx) throws Exception { | |
| 127 | - super.channelInactive(ctx); | |
| 128 | - this.release(); | |
| 129 | - } | |
| 130 | - | |
| 131 | - public final void setSession(Session session) { | |
| 132 | - this.context.channel().attr(SESSION_KEY).set(session); | |
| 133 | - } | |
| 134 | - | |
| 135 | - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { | |
| 136 | - cause.printStackTrace(); | |
| 137 | - this.release(); | |
| 138 | - ctx.close(); | |
| 139 | - } | |
| 140 | - | |
| 141 | - private void release() { | |
| 142 | - String tag = (String) this.getSession().get("tag"); | |
| 143 | - if (tag != null) { | |
| 144 | - logger.info("close netty channel: {}", tag); | |
| 145 | - PublishManager.getInstance().close(tag); | |
| 146 | - } | |
| 147 | - | |
| 148 | - } | |
| 149 | - | |
| 150 | - public static void createStreamProxy(String stream, Integer port) throws URISyntaxException, IOException { | |
| 151 | - Jt1078ConfigBean jt1078ConfigBean = VManageBootstrap.getBean(Jt1078ConfigBean.class); | |
| 152 | - MediaConfig mediaConfig = VManageBootstrap.getBean(MediaConfig.class); | |
| 153 | - StreamProxyController streamProxyController = VManageBootstrap.getBean(StreamProxyController.class); | |
| 154 | - | |
| 155 | - if (StringUtils.endsWith(stream, ".flv")) { | |
| 156 | - stream = StringUtils.substringBeforeLast(stream, ".flv"); | |
| 157 | - } | |
| 158 | - if(Objects.isNull(jt1078ConfigBean)){ | |
| 159 | - return; | |
| 160 | - } | |
| 161 | - String url = StringUtils.replace(jt1078ConfigBean.getGetURL(), "{stream}", stream); | |
| 162 | - url = StringUtils.replace(url, "{port}", port + ""); | |
| 163 | - if (!StringUtils.endsWith(url, ".flv")) { | |
| 164 | - url = url + ".flv"; | |
| 165 | - } | |
| 166 | - StreamProxyItem item = new StreamProxyItem(); | |
| 167 | - item.setApp("schedule"); | |
| 168 | - item.setEnable(true); | |
| 169 | - item.setEnableAudio(true); | |
| 170 | - item.setRtpType("default"); | |
| 171 | - item.setStream(stream); | |
| 172 | - item.setMediaServerId(mediaConfig.getId()); | |
| 173 | - item.setUrl(url); | |
| 174 | - item.setFfmpegCmdKey("ffmpeg.cmd"); | |
| 175 | - item.setEnable(true); | |
| 176 | - item.setEnableAudio(true); | |
| 177 | - item.setEnableMp4(false); | |
| 178 | - item.setEnableRemoveNoneReader(false); | |
| 179 | - item.setEnableDisableNoneReader(false); | |
| 180 | - item.setName(stream); | |
| 181 | - | |
| 182 | - StringRedisTemplate redisTemplate = VManageBootstrap.getBean(StringRedisTemplate.class); | |
| 183 | - String key = "jtt1078:" + stream; | |
| 184 | - String closeKey = "jt1078:count:"+stream; | |
| 185 | - String timeoutKey = "timeout:"+stream; | |
| 186 | - Object timeOutVal = redisTemplate.opsForValue().get(timeoutKey); | |
| 187 | - if(Objects.equals("2",timeOutVal)){ | |
| 188 | - IStreamProxyService streamProxyService = VManageBootstrap.getBean(IStreamProxyService.class); | |
| 189 | - streamProxyService.stop1("schedule",stream); | |
| 190 | - redisTemplate.delete(timeoutKey); | |
| 191 | - } | |
| 192 | - | |
| 193 | - if(redisTemplate.hasKey(closeKey)){ | |
| 194 | - IStreamProxyService streamProxyService = VManageBootstrap.getBean(IStreamProxyService.class); | |
| 195 | - streamProxyService.del("schedule",stream); | |
| 196 | - }else if (redisTemplate.hasKey(key)) { | |
| 197 | - redisTemplate.opsForValue().set(key, "1", 300, TimeUnit.SECONDS); | |
| 198 | - } else { | |
| 199 | - try { | |
| 200 | - streamProxyController.save(item); | |
| 201 | - }catch (Exception e){ | |
| 202 | - logger.error(e.getMessage()); | |
| 203 | - } | |
| 204 | - timeOutVal = redisTemplate.opsForValue().get(timeoutKey); | |
| 205 | - if(Objects.equals("2",timeOutVal)) { | |
| 206 | - IStreamProxyService streamProxyService = VManageBootstrap.getBean(IStreamProxyService.class); | |
| 207 | - streamProxyService.stop1("schedule", stream); | |
| 208 | - redisTemplate.delete(timeoutKey); | |
| 209 | - } | |
| 210 | - | |
| 211 | - } | |
| 212 | - } | |
| 213 | - | |
| 214 | - private synchronized String endWithMapping(String tagMapping) throws URISyntaxException, IOException { | |
| 215 | - if (!StringUtils.endsWith(this.tagMapping, ".flv")) { | |
| 216 | - this.tagMapping = this.tagMapping + ".flv"; | |
| 217 | - } | |
| 218 | - return this.tagMapping; | |
| 219 | - } | |
| 220 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/server/RTSPHandler.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.server; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.rtsp.RtspRequest; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.rtsp.RtspSessionManager; | |
| 5 | -import io.netty.bootstrap.Bootstrap; | |
| 6 | -import io.netty.buffer.ByteBuf; | |
| 7 | -import io.netty.channel.*; | |
| 8 | -import io.netty.channel.nio.NioEventLoopGroup; | |
| 9 | -import io.netty.channel.socket.SocketChannel; | |
| 10 | -import io.netty.channel.socket.nio.NioSocketChannel; | |
| 11 | -import io.netty.handler.codec.http.DefaultHttpContent; | |
| 12 | -import io.netty.handler.codec.http.DefaultHttpResponse; | |
| 13 | -import io.netty.handler.codec.http.HttpMethod; | |
| 14 | -import io.netty.handler.codec.rtsp.*; | |
| 15 | -import io.netty.util.internal.StringUtil; | |
| 16 | -import org.slf4j.Logger; | |
| 17 | -import org.slf4j.LoggerFactory; | |
| 18 | - | |
| 19 | -import java.net.InetSocketAddress; | |
| 20 | -import java.util.*; | |
| 21 | - | |
| 22 | -public class RTSPHandler extends ChannelInboundHandlerAdapter { | |
| 23 | - | |
| 24 | - private final static Logger log = LoggerFactory.getLogger(RTSPHandler.class); | |
| 25 | - | |
| 26 | - private String channelId = "122223333444-1"; | |
| 27 | - | |
| 28 | - private HttpMethod currentMethod = RtspMethods.OPTIONS; | |
| 29 | - | |
| 30 | - private List<HttpMethod> methods = Arrays.asList(RtspMethods.OPTIONS, RtspMethods.ANNOUNCE, RtspMethods.SETUP, RtspMethods.RECORD, null); | |
| 31 | - | |
| 32 | - private RtspRequest rtspRequest = new RtspRequest("192.168.169.100", 9555, String.format("/schedule/%s?sign=41db35390ddad33f83944f44b8b75ded", channelId)); | |
| 33 | - | |
| 34 | - /* | |
| 35 | - When notified that the channel is active, sends a message. A channel is active | |
| 36 | - when a connection has been established, so the method is invoked when the connections | |
| 37 | - is established. | |
| 38 | - */ | |
| 39 | - @Override | |
| 40 | - public void channelActive(final ChannelHandlerContext ctx) { | |
| 41 | - log.debug("channelActive, connection established: {}", ctx); | |
| 42 | - log.debug("Sending request to the server"); | |
| 43 | - ctx.writeAndFlush(rtspRequest.option()); | |
| 44 | - } | |
| 45 | - | |
| 46 | - @Override | |
| 47 | - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { | |
| 48 | - log.info("exceptionCaught: {}", cause); | |
| 49 | - ctx.close(); | |
| 50 | - } | |
| 51 | - | |
| 52 | - @Override | |
| 53 | - public void channelRead(ChannelHandlerContext ctx, Object msg) { | |
| 54 | - log.info("Received from RTSP Server: {}", ctx); | |
| 55 | - log.info("Received from RTSP msg: {}", msg.toString()); | |
| 56 | - log.debug("Received Class Type: {}", msg.getClass().getTypeName()); | |
| 57 | - if (msg instanceof DefaultHttpResponse) { | |
| 58 | - DefaultHttpResponse res = (DefaultHttpResponse) msg; | |
| 59 | - if (RtspResponseStatuses.OK.equals(res.status())) { | |
| 60 | - log.debug("{}: {}", currentMethod, res.status()); | |
| 61 | - if (res.headers().contains(RtspHeaderNames.SESSION)) { | |
| 62 | - rtspRequest.setSessionID(res.headers().get(RtspHeaderNames.SESSION)); | |
| 63 | - } | |
| 64 | - nextMethod(ctx); | |
| 65 | - } else { | |
| 66 | - ctx.close(); | |
| 67 | - } | |
| 68 | - } else if (msg instanceof DefaultHttpContent) { | |
| 69 | - DefaultHttpContent content = (DefaultHttpContent) msg; | |
| 70 | - log.info("Content: {}", content); | |
| 71 | - | |
| 72 | - ByteBuf byteBuf = content.content(); | |
| 73 | - } else { | |
| 74 | - log.debug("dataType error: {}", msg.getClass().getTypeName()); | |
| 75 | - } | |
| 76 | - } | |
| 77 | - | |
| 78 | - private void nextMethod(ChannelHandlerContext ctx) { | |
| 79 | - for (int i = 0;i < methods.size(); i++) { | |
| 80 | - if (methods.get(i).equals(currentMethod) && i < methods.size() - 1) { | |
| 81 | - currentMethod = methods.get(i + 1); | |
| 82 | - break; | |
| 83 | - } | |
| 84 | - } | |
| 85 | - if (currentMethod == null) { | |
| 86 | - RtspSessionManager.register(channelId); | |
| 87 | - return; | |
| 88 | - } | |
| 89 | - if (currentMethod == RtspMethods.ANNOUNCE) { | |
| 90 | - ctx.writeAndFlush(rtspRequest.announce()); | |
| 91 | - } | |
| 92 | - if (currentMethod == RtspMethods.SETUP) { | |
| 93 | - ctx.writeAndFlush(rtspRequest.setup()); | |
| 94 | - } | |
| 95 | - if (currentMethod == RtspMethods.RECORD) { | |
| 96 | - ctx.writeAndFlush(rtspRequest.record()); | |
| 97 | - } | |
| 98 | - } | |
| 99 | - | |
| 100 | - private void parseSdp(String sdp) { | |
| 101 | - log.debug("Parsing SDP: {}", sdp); | |
| 102 | - Map<String, List<String>> mediaMap = new HashMap<>(10); | |
| 103 | - String[] array = sdp.split("\\n"); | |
| 104 | - String mediaName = ""; | |
| 105 | - for (int i = 0; i < array.length; i++) { | |
| 106 | - String line = array[i]; | |
| 107 | - if (line.startsWith("m=")) { | |
| 108 | - mediaName = line.substring(line.indexOf("=") + 1, line.indexOf(" ")); | |
| 109 | - if (mediaName.equals("video") || mediaName.equals("audio")) { | |
| 110 | - mediaMap.put(mediaName, new ArrayList<>()); | |
| 111 | - } else { | |
| 112 | - mediaName = ""; | |
| 113 | - } | |
| 114 | - } else if (!StringUtil.isNullOrEmpty(mediaName)) { | |
| 115 | - if (line.startsWith("b=") || line.startsWith("a=")) { | |
| 116 | - List<String> medialist = mediaMap.get(mediaName); | |
| 117 | - medialist.add(line); | |
| 118 | - } | |
| 119 | - } | |
| 120 | - } | |
| 121 | - for (String mediaKey : mediaMap.keySet()) { | |
| 122 | - StringBuilder stringBuilder = new StringBuilder(); | |
| 123 | - List<String> mediaInfo = mediaMap.get(mediaKey); | |
| 124 | - mediaInfo.forEach((s) -> { | |
| 125 | - stringBuilder.append("\n"); | |
| 126 | - stringBuilder.append(s); | |
| 127 | - }); | |
| 128 | - log.info("[>>>>> {} <<<<<] {}", mediaKey, stringBuilder.toString()); | |
| 129 | - } | |
| 130 | - } | |
| 131 | - | |
| 132 | - public static void main(String[] args) { | |
| 133 | - EventLoopGroup group = new NioEventLoopGroup(); | |
| 134 | - try { | |
| 135 | - Bootstrap clientBootstrap = new Bootstrap(); | |
| 136 | - clientBootstrap.group(group) | |
| 137 | - .option(ChannelOption.TCP_NODELAY, true) | |
| 138 | - .channel(NioSocketChannel.class) | |
| 139 | - .remoteAddress(new InetSocketAddress("192.168.169.100", 9555)) | |
| 140 | - .handler(new ChannelInitializer<SocketChannel>() { | |
| 141 | - @Override | |
| 142 | - protected void initChannel(SocketChannel socketChannel) { | |
| 143 | - socketChannel.pipeline() | |
| 144 | - .addLast(new RtspEncoder()) | |
| 145 | - .addLast(new RtspDecoder()) | |
| 146 | - .addLast(new RTSPHandler()); | |
| 147 | - } | |
| 148 | - }); | |
| 149 | - ChannelFuture f = null; | |
| 150 | - while (true) { | |
| 151 | - log.info("Waiting for server connection"); | |
| 152 | - f = clientBootstrap.connect(); | |
| 153 | - f.awaitUninterruptibly(); | |
| 154 | - if (f.isSuccess()) { | |
| 155 | - log.info("RTSP Connection success!"); | |
| 156 | - break; | |
| 157 | - } | |
| 158 | - Thread.sleep(1000); | |
| 159 | - } | |
| 160 | - | |
| 161 | - // Wait for the server to close the connection. | |
| 162 | - f.channel().closeFuture().sync(); | |
| 163 | - } catch (Exception e) { | |
| 164 | - log.error("Error ->", e); | |
| 165 | - log.error("<- Error"); | |
| 166 | - } finally { | |
| 167 | - // Shut down executor threads to exit.Ahkk | |
| 168 | - try { | |
| 169 | - log.info("ShutdownGracefully the connection group"); | |
| 170 | - group.shutdownGracefully().sync(); | |
| 171 | - } catch (InterruptedException e) { | |
| 172 | - log.error("", e); | |
| 173 | - } | |
| 174 | - } | |
| 175 | - } | |
| 176 | -} | |
| 177 | 0 | \ No newline at end of file |
src/main/java/com/genersoft/iot/vmp/jt1078/session/Session.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.session; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.proc.Header; | |
| 4 | -import io.netty.channel.Channel; | |
| 5 | -import io.netty.util.AttributeKey; | |
| 6 | -import org.slf4j.Logger; | |
| 7 | -import org.slf4j.LoggerFactory; | |
| 8 | - | |
| 9 | -import java.util.concurrent.atomic.AtomicInteger; | |
| 10 | - | |
| 11 | -/** | |
| 12 | - * @author QingtaiJiang | |
| 13 | - * @date 2023/4/27 18:54 | |
| 14 | - * @email qingtaij@163.com | |
| 15 | - */ | |
| 16 | -public class Session { | |
| 17 | - private final static Logger log = LoggerFactory.getLogger(Session.class); | |
| 18 | - | |
| 19 | - public static final AttributeKey<Session> KEY = AttributeKey.newInstance(Session.class.getName()); | |
| 20 | - | |
| 21 | - // Netty的channel | |
| 22 | - protected final Channel channel; | |
| 23 | - | |
| 24 | - // 原子类的自增ID | |
| 25 | - private final AtomicInteger serialNo = new AtomicInteger(0); | |
| 26 | - | |
| 27 | - // 是否注册成功 | |
| 28 | - private boolean registered = false; | |
| 29 | - | |
| 30 | - // 设备ID | |
| 31 | - private String devId; | |
| 32 | - | |
| 33 | - // 创建时间 | |
| 34 | - private final long creationTime; | |
| 35 | - | |
| 36 | - // 协议版本号 | |
| 37 | - private Integer protocolVersion; | |
| 38 | - | |
| 39 | - private Header header; | |
| 40 | - | |
| 41 | - protected Session(Channel channel) { | |
| 42 | - this.channel = channel; | |
| 43 | - this.creationTime = System.currentTimeMillis(); | |
| 44 | - } | |
| 45 | - | |
| 46 | - public void writeObject(Object message) { | |
| 47 | - log.info("<<<<<<<<<< cmd{},{}", this, message); | |
| 48 | - channel.writeAndFlush(message); | |
| 49 | - } | |
| 50 | - | |
| 51 | - /** | |
| 52 | - * 获得下一个流水号 | |
| 53 | - * | |
| 54 | - * @return 流水号 | |
| 55 | - */ | |
| 56 | - public int nextSerialNo() { | |
| 57 | - int current; | |
| 58 | - int next; | |
| 59 | - do { | |
| 60 | - current = serialNo.get(); | |
| 61 | - next = current > 0xffff ? 0 : current; | |
| 62 | - } while (!serialNo.compareAndSet(current, next + 1)); | |
| 63 | - return next; | |
| 64 | - } | |
| 65 | - | |
| 66 | - /** | |
| 67 | - * 注册session | |
| 68 | - * | |
| 69 | - * @param devId 设备ID | |
| 70 | - */ | |
| 71 | - public void register(String devId, Integer version, Header header) { | |
| 72 | - this.devId = devId; | |
| 73 | - this.registered = true; | |
| 74 | - this.protocolVersion = version; | |
| 75 | - this.header = header; | |
| 76 | - SessionManager.INSTANCE.put(devId, this); | |
| 77 | - } | |
| 78 | - | |
| 79 | - /** | |
| 80 | - * 获取设备号 | |
| 81 | - * | |
| 82 | - * @return 设备号 | |
| 83 | - */ | |
| 84 | - public String getDevId() { | |
| 85 | - return devId; | |
| 86 | - } | |
| 87 | - | |
| 88 | - | |
| 89 | - public boolean isRegistered() { | |
| 90 | - return registered; | |
| 91 | - } | |
| 92 | - | |
| 93 | - public long getCreationTime() { | |
| 94 | - return creationTime; | |
| 95 | - } | |
| 96 | - | |
| 97 | - public Integer getProtocolVersion() { | |
| 98 | - return protocolVersion; | |
| 99 | - } | |
| 100 | - | |
| 101 | - public Header getHeader() { | |
| 102 | - return header; | |
| 103 | - } | |
| 104 | - | |
| 105 | - @Override | |
| 106 | - public String toString() { | |
| 107 | - return "[" + | |
| 108 | - "devId=" + devId + | |
| 109 | - ", reg=" + registered + | |
| 110 | - ", version=" + protocolVersion + | |
| 111 | - ",ip=" + channel.remoteAddress() + | |
| 112 | - ']'; | |
| 113 | - } | |
| 114 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/session/SessionManager.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.session; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.proc.entity.Cmd; | |
| 4 | -import io.netty.channel.Channel; | |
| 5 | -import org.slf4j.Logger; | |
| 6 | -import org.slf4j.LoggerFactory; | |
| 7 | - | |
| 8 | -import java.util.Map; | |
| 9 | -import java.util.concurrent.ConcurrentHashMap; | |
| 10 | -import java.util.concurrent.SynchronousQueue; | |
| 11 | -import java.util.concurrent.TimeUnit; | |
| 12 | - | |
| 13 | - | |
| 14 | -/** | |
| 15 | - * @author QingtaiJiang | |
| 16 | - * @date 2023/4/27 19:54 | |
| 17 | - * @email qingtaij@163.com | |
| 18 | - */ | |
| 19 | -public enum SessionManager { | |
| 20 | - INSTANCE; | |
| 21 | - private final static Logger log = LoggerFactory.getLogger(SessionManager.class); | |
| 22 | - | |
| 23 | - // 用与消息的缓存 | |
| 24 | - private final Map<String, SynchronousQueue<String>> topicSubscribers = new ConcurrentHashMap<>(); | |
| 25 | - | |
| 26 | - // session的缓存 | |
| 27 | - private final Map<Object, Session> sessionMap; | |
| 28 | - | |
| 29 | - SessionManager() { | |
| 30 | - this.sessionMap = new ConcurrentHashMap<>(); | |
| 31 | - } | |
| 32 | - | |
| 33 | - /** | |
| 34 | - * 创建新的Session | |
| 35 | - * | |
| 36 | - * @param channel netty通道 | |
| 37 | - * @return 创建的session对象 | |
| 38 | - */ | |
| 39 | - public Session newSession(Channel channel) { | |
| 40 | - return new Session(channel); | |
| 41 | - } | |
| 42 | - | |
| 43 | - | |
| 44 | - /** | |
| 45 | - * 获取指定设备的Session | |
| 46 | - * | |
| 47 | - * @param clientId 设备Id | |
| 48 | - * @return Session | |
| 49 | - */ | |
| 50 | - public Session get(Object clientId) { | |
| 51 | - return sessionMap.get(clientId); | |
| 52 | - } | |
| 53 | - | |
| 54 | - /** | |
| 55 | - * 放入新设备连接的session | |
| 56 | - * | |
| 57 | - * @param clientId 设备ID | |
| 58 | - * @param newSession session | |
| 59 | - */ | |
| 60 | - protected void put(Object clientId, Session newSession) { | |
| 61 | - sessionMap.put(clientId, newSession); | |
| 62 | - } | |
| 63 | - | |
| 64 | - | |
| 65 | - /** | |
| 66 | - * 发送同步消息,接收响应 | |
| 67 | - * 默认超时时间6秒 | |
| 68 | - */ | |
| 69 | - public String request(Cmd cmd) { | |
| 70 | - // 默认6秒 | |
| 71 | - int timeOut = 6000; | |
| 72 | - return request(cmd, timeOut); | |
| 73 | - } | |
| 74 | - | |
| 75 | - public String request(Cmd cmd, Integer timeOut) { | |
| 76 | - Session session = this.get(cmd.getDevId()); | |
| 77 | - if (session == null) { | |
| 78 | - log.error("DevId: {} not online!", cmd.getDevId()); | |
| 79 | - return null; | |
| 80 | - } | |
| 81 | - String requestKey = requestKey(cmd.getDevId(), cmd.getRespId(), cmd.getPackageNo()); | |
| 82 | - SynchronousQueue<String> subscribe = subscribe(requestKey); | |
| 83 | - if (subscribe == null) { | |
| 84 | - log.error("DevId: {} key:{} send repaid", cmd.getDevId(), requestKey); | |
| 85 | - return null; | |
| 86 | - } | |
| 87 | - session.writeObject(cmd); | |
| 88 | - try { | |
| 89 | - return subscribe.poll(timeOut, TimeUnit.SECONDS); | |
| 90 | - } catch (InterruptedException e) { | |
| 91 | - log.warn("<<<<<<<<<< timeout" + session, e); | |
| 92 | - } finally { | |
| 93 | - this.unsubscribe(requestKey); | |
| 94 | - } | |
| 95 | - return null; | |
| 96 | - } | |
| 97 | - | |
| 98 | - public Boolean response(String devId, String respId, Long responseNo, String data) { | |
| 99 | - String requestKey = requestKey(devId, respId, responseNo); | |
| 100 | - SynchronousQueue<String> queue = topicSubscribers.get(requestKey); | |
| 101 | - if (queue != null) { | |
| 102 | - try { | |
| 103 | - return queue.offer(data, 2, TimeUnit.SECONDS); | |
| 104 | - } catch (InterruptedException e) { | |
| 105 | - log.error("{}", e.getMessage(), e); | |
| 106 | - } | |
| 107 | - } | |
| 108 | - log.warn("Not find response,key:{} data:{} ", requestKey, data); | |
| 109 | - return false; | |
| 110 | - } | |
| 111 | - | |
| 112 | - private void unsubscribe(String key) { | |
| 113 | - topicSubscribers.remove(key); | |
| 114 | - } | |
| 115 | - | |
| 116 | - private SynchronousQueue<String> subscribe(String key) { | |
| 117 | - SynchronousQueue<String> queue = null; | |
| 118 | - if (!topicSubscribers.containsKey(key)) | |
| 119 | - topicSubscribers.put(key, queue = new SynchronousQueue<String>()); | |
| 120 | - return queue; | |
| 121 | - } | |
| 122 | - | |
| 123 | - private String requestKey(String devId, String respId, Long requestNo) { | |
| 124 | - return String.join("_", devId.replaceFirst("^0*", ""), respId, requestNo.toString()); | |
| 125 | - } | |
| 126 | - | |
| 127 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/test/AudioTest.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.test; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.codec.G711Codec; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.server.Jtt1078Decoder; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.util.ByteUtils; | |
| 6 | -import com.genersoft.iot.vmp.jt1078.util.Packet; | |
| 7 | - | |
| 8 | -import java.io.FileInputStream; | |
| 9 | -import java.io.FileOutputStream; | |
| 10 | - | |
| 11 | -/** | |
| 12 | - * Created by matrixy on 2019/12/21. | |
| 13 | - */ | |
| 14 | -public class AudioTest | |
| 15 | -{ | |
| 16 | - public static void main(String[] args) throws Exception | |
| 17 | - { | |
| 18 | - int len = -1; | |
| 19 | - byte[] block = new byte[1024]; | |
| 20 | - FileInputStream fis = new FileInputStream("e:\\test\\streaming.hex"); | |
| 21 | - Jtt1078Decoder decoder = new Jtt1078Decoder(); | |
| 22 | - G711Codec codec = new G711Codec(); | |
| 23 | - FileOutputStream fos = new FileOutputStream("e:\\test\\fuckfuckfuck1111.pcm"); | |
| 24 | - while ((len = fis.read(block)) > -1) | |
| 25 | - { | |
| 26 | - decoder.write(block, 0, len); | |
| 27 | - while (true) | |
| 28 | - { | |
| 29 | - Packet p = decoder.decode(); | |
| 30 | - if (p == null) break; | |
| 31 | - | |
| 32 | - int lengthOffset = 28; | |
| 33 | - int dataType = (p.seek(15).nextByte() >> 4) & 0x0f; | |
| 34 | - // 透传数据类型:0100,没有后面的时间以及Last I Frame Interval和Last Frame Interval字段 | |
| 35 | - if (dataType == 0x04) lengthOffset = 28 - 8 - 2 - 2; | |
| 36 | - else if (dataType == 0x03) lengthOffset = 28 - 4; | |
| 37 | - | |
| 38 | - if (dataType == 0x03) | |
| 39 | - { | |
| 40 | - byte[] pcmData = codec.toPCM(p.seek(lengthOffset + 2).nextBytes()); | |
| 41 | - fos.write(pcmData); | |
| 42 | - fos.flush(); | |
| 43 | - } | |
| 44 | - } | |
| 45 | - } | |
| 46 | - fos.close(); | |
| 47 | - fis.close(); | |
| 48 | - } | |
| 49 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/test/ChannelTest.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.test; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.util.ByteHolder; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.util.ByteUtils; | |
| 5 | - | |
| 6 | -import java.io.ByteArrayOutputStream; | |
| 7 | -import java.io.IOException; | |
| 8 | -import java.nio.ByteBuffer; | |
| 9 | -import java.nio.channels.ByteChannel; | |
| 10 | - | |
| 11 | -/** | |
| 12 | - * Created by matrixy on 2020/1/9. | |
| 13 | - */ | |
| 14 | -public class ChannelTest implements ByteChannel | |
| 15 | -{ | |
| 16 | - byte[] temp = new byte[4]; | |
| 17 | - ByteHolder buffer = new ByteHolder(1024); | |
| 18 | - | |
| 19 | - // 读出,存入dst | |
| 20 | - @Override | |
| 21 | - public int read(ByteBuffer dst) throws IOException | |
| 22 | - { | |
| 23 | - dst.flip(); | |
| 24 | - int len = Math.min(4, buffer.size()); | |
| 25 | - if (dst.remaining() > len) | |
| 26 | - { | |
| 27 | - buffer.sliceInto(temp, len); | |
| 28 | - dst.put(temp, 0, len); | |
| 29 | - } | |
| 30 | - else | |
| 31 | - { | |
| 32 | - // 丢掉??? | |
| 33 | - } | |
| 34 | - dst.flip(); | |
| 35 | - return len; | |
| 36 | - } | |
| 37 | - | |
| 38 | - // 从src读出,写入进来 | |
| 39 | - @Override | |
| 40 | - public int write(ByteBuffer src) throws IOException | |
| 41 | - { | |
| 42 | - int len = -1; | |
| 43 | - // src.flip(); | |
| 44 | - len = Math.min(4, src.limit()); | |
| 45 | - src.get(temp, 0, len); | |
| 46 | - buffer.write(temp, 0, len); | |
| 47 | - // src.flip(); | |
| 48 | - System.out.println("write: " + len); | |
| 49 | - return len; | |
| 50 | - } | |
| 51 | - | |
| 52 | - @Override | |
| 53 | - public boolean isOpen() | |
| 54 | - { | |
| 55 | - return true; | |
| 56 | - } | |
| 57 | - | |
| 58 | - @Override | |
| 59 | - public void close() throws IOException | |
| 60 | - { | |
| 61 | - | |
| 62 | - } | |
| 63 | - | |
| 64 | - public byte[] array() | |
| 65 | - { | |
| 66 | - return buffer.array(); | |
| 67 | - } | |
| 68 | - | |
| 69 | - public static void main(String[] args) throws Exception | |
| 70 | - { | |
| 71 | - ChannelTest chl = new ChannelTest(); | |
| 72 | - ByteBuffer buffer = ByteBuffer.allocate(4); | |
| 73 | - java.nio.ByteBuffer xx; | |
| 74 | - System.out.println(buffer.getClass().getName()); | |
| 75 | - for (int i = 0; i < 4096; i++) | |
| 76 | - buffer.put((byte)'f'); | |
| 77 | - /* | |
| 78 | - buffer.putLong(0x1122334455667788L); | |
| 79 | - buffer.flip(); | |
| 80 | - // flip太迷惑了 | |
| 81 | - buffer.isReadOnly(); | |
| 82 | - int len = chl.write(buffer); | |
| 83 | - len = chl.write(buffer); | |
| 84 | - ByteUtils.dump(chl.array()); | |
| 85 | - */ | |
| 86 | - } | |
| 87 | - | |
| 88 | - static final class ByteBufferWrapper | |
| 89 | - { | |
| 90 | - boolean writeMode; | |
| 91 | - ByteBuffer buffer; | |
| 92 | - | |
| 93 | - private ByteBufferWrapper(int size) | |
| 94 | - { | |
| 95 | - this.buffer = ByteBuffer.allocate(size); | |
| 96 | - } | |
| 97 | - | |
| 98 | - // 控制写入,代理过来 | |
| 99 | - public void write() | |
| 100 | - { | |
| 101 | - | |
| 102 | - } | |
| 103 | - | |
| 104 | - // 写出就无所谓了 | |
| 105 | - | |
| 106 | - public static ByteBufferWrapper create(int size) | |
| 107 | - { | |
| 108 | - return new ByteBufferWrapper(size); | |
| 109 | - } | |
| 110 | - } | |
| 111 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/test/FuckTest.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.test; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.util.ByteUtils; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.util.Packet; | |
| 5 | - | |
| 6 | -import java.io.DataInputStream; | |
| 7 | -import java.io.FileInputStream; | |
| 8 | - | |
| 9 | -/** | |
| 10 | - * Created by matrixy on 2020/3/19. | |
| 11 | - */ | |
| 12 | -public class FuckTest | |
| 13 | -{ | |
| 14 | - public static void main(String[] args) throws Exception | |
| 15 | - { | |
| 16 | - String line; | |
| 17 | - DataInputStream dis = new DataInputStream(new FileInputStream("d:\\temp\\rtp.txt")); | |
| 18 | - while ((line = dis.readLine()) != null) | |
| 19 | - { | |
| 20 | - byte[] rtp = ByteUtils.parse(line); | |
| 21 | - Packet packet = Packet.create(rtp); | |
| 22 | - | |
| 23 | - int lengthOffset = 28; | |
| 24 | - int dataType = (packet.seek(15).nextByte() >> 4) & 0x0f; | |
| 25 | - int pkType = packet.seek(15).nextByte() & 0x0f; | |
| 26 | - // 透传数据类型:0100,没有后面的时间以及Last I Frame Interval和Last Frame Interval字段 | |
| 27 | - if (dataType == 0x04) lengthOffset = 28 - 8 - 2 - 2; | |
| 28 | - else if (dataType == 0x03) lengthOffset = 28 - 4; | |
| 29 | - | |
| 30 | - if (dataType <= 0x02) | |
| 31 | - { | |
| 32 | - if (dataType == 0x00) System.out.println("I Frame---------------------------------"); | |
| 33 | - if (dataType == 0x01) System.out.println("P Frame"); | |
| 34 | - if (dataType == 0x02) System.out.println("B Frame"); | |
| 35 | - } | |
| 36 | - } | |
| 37 | - } | |
| 38 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/test/G711ATest.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.test; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.codec.G711Codec; | |
| 4 | - | |
| 5 | -import java.io.FileInputStream; | |
| 6 | -import java.io.FileOutputStream; | |
| 7 | - | |
| 8 | -/** | |
| 9 | - * Created by matrixy on 2019/12/21. | |
| 10 | - */ | |
| 11 | -public class G711ATest | |
| 12 | -{ | |
| 13 | - public static void main(String[] args) throws Exception | |
| 14 | - { | |
| 15 | - int len = -1; | |
| 16 | - byte[] block = new byte[1024]; | |
| 17 | - FileInputStream fis = new FileInputStream("E:\\workspace\\enc_dec_audio\\g711\\encode_out.g711a"); | |
| 18 | - FileOutputStream fos = new FileOutputStream("E:\\test\\fuckfuckfuck111.pcm"); | |
| 19 | - G711Codec codec = new G711Codec(); | |
| 20 | - while ((len = fis.read(block)) > -1) | |
| 21 | - { | |
| 22 | - byte[] pcmData = null; | |
| 23 | - if (len == 1024) | |
| 24 | - { | |
| 25 | - pcmData = codec.toPCM(block); | |
| 26 | - } | |
| 27 | - else | |
| 28 | - { | |
| 29 | - byte[] temp = new byte[len]; | |
| 30 | - System.arraycopy(block, 0, temp, 0, len); | |
| 31 | - pcmData = codec.toPCM(temp); | |
| 32 | - } | |
| 33 | - fos.write(pcmData); | |
| 34 | - fos.flush(); | |
| 35 | - } | |
| 36 | - fis.close(); | |
| 37 | - fos.close(); | |
| 38 | - } | |
| 39 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/test/MP3Test.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.test; | |
| 2 | - | |
| 3 | -import de.sciss.jump3r.lowlevel.LameEncoder; | |
| 4 | -import de.sciss.jump3r.mp3.Lame; | |
| 5 | - | |
| 6 | -import javax.sound.sampled.AudioFormat; | |
| 7 | -import java.io.ByteArrayOutputStream; | |
| 8 | -import java.io.FileInputStream; | |
| 9 | -import java.io.FileOutputStream; | |
| 10 | - | |
| 11 | -/** | |
| 12 | - * Created by matrixy on 2020/4/27. | |
| 13 | - */ | |
| 14 | -public class MP3Test | |
| 15 | -{ | |
| 16 | - public static void main(String[] args) throws Exception | |
| 17 | - { | |
| 18 | - AudioFormat sourceFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 8000, 16, 1, 1 * 2, -1, false); | |
| 19 | - LameEncoder encoder = new LameEncoder(sourceFormat, 256, 3, Lame.MEDIUM, false); | |
| 20 | - | |
| 21 | - byte[] block = new byte[320]; | |
| 22 | - int len = -1; | |
| 23 | - FileInputStream fis = new FileInputStream("d:\\temp\\hello.pcm"); | |
| 24 | - ByteArrayOutputStream mp3 = new ByteArrayOutputStream(encoder.getOutputBufferSize()); | |
| 25 | - byte[] buffer = new byte[encoder.getPCMBufferSize()]; | |
| 26 | - int bytesToTransfer = 0; | |
| 27 | - int bytesWritten; | |
| 28 | - int currentPcmPosition = 0; | |
| 29 | - | |
| 30 | - FileOutputStream fos = new FileOutputStream("d:\\temp\\fuck.mp3"); | |
| 31 | - | |
| 32 | - while ((len = fis.read(block)) > -1) | |
| 33 | - { | |
| 34 | - bytesToTransfer = len; | |
| 35 | - currentPcmPosition = 0; | |
| 36 | - while (0 < (bytesWritten = encoder.encodeBuffer(block, currentPcmPosition, bytesToTransfer, buffer))) | |
| 37 | - { | |
| 38 | - currentPcmPosition += bytesToTransfer; | |
| 39 | - bytesToTransfer = Math.min(buffer.length, len - currentPcmPosition); | |
| 40 | - | |
| 41 | - mp3.write(buffer, 0, bytesWritten); | |
| 42 | - fos.write(buffer, 0, bytesWritten); | |
| 43 | - | |
| 44 | - System.out.println(String.format("pcm data: %4d, written: %4d, pos: %4d", len, bytesWritten, currentPcmPosition)); | |
| 45 | - } | |
| 46 | - System.out.println(); | |
| 47 | - } | |
| 48 | - | |
| 49 | - fos.close(); | |
| 50 | - fis.close(); | |
| 51 | - | |
| 52 | - encoder.close(); | |
| 53 | - } | |
| 54 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/test/RTPGenerate.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.test; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.flv.FlvEncoder; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.server.Jtt1078Decoder; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.util.ByteHolder; | |
| 6 | -import com.genersoft.iot.vmp.jt1078.util.ByteUtils; | |
| 7 | -import com.genersoft.iot.vmp.jt1078.util.Packet; | |
| 8 | - | |
| 9 | -import java.io.FileInputStream; | |
| 10 | -import java.io.FileOutputStream; | |
| 11 | -import java.io.InputStream; | |
| 12 | -import java.io.OutputStream; | |
| 13 | -import java.util.LinkedList; | |
| 14 | - | |
| 15 | -/** | |
| 16 | - * Created by matrixy on 2019/12/16. | |
| 17 | - */ | |
| 18 | -public class RTPGenerate | |
| 19 | -{ | |
| 20 | - public static void main(String[] args) throws Exception | |
| 21 | - { | |
| 22 | - InputStream input = new FileInputStream("d:\\test\\1078\\streamax-20191209.bin"); | |
| 23 | - LinkedList<Packet> packets = readPackets(input); | |
| 24 | - | |
| 25 | - for (int i = 0; i < 100; i++) | |
| 26 | - { | |
| 27 | - String sim = String.format("013800138%03d", i); | |
| 28 | - int channel = 1; | |
| 29 | - | |
| 30 | - try (OutputStream output = new FileOutputStream("d:\\test\\1078\\temp\\" + sim + "-" + channel + ".bin")) | |
| 31 | - { | |
| 32 | - for (Packet p : packets) | |
| 33 | - { | |
| 34 | - p.seek(8).putBytes(toBCD(sim)); | |
| 35 | - p.seek(14).putByte((byte)channel); | |
| 36 | - output.write(p.getBytes()); | |
| 37 | - } | |
| 38 | - System.out.println(String.format(" -> %s-%d generated...", sim, channel)); | |
| 39 | - } | |
| 40 | - catch(Exception ex) | |
| 41 | - { | |
| 42 | - ex.printStackTrace(); | |
| 43 | - System.out.println(ex); | |
| 44 | - } | |
| 45 | - } | |
| 46 | - | |
| 47 | - input.close(); | |
| 48 | - } | |
| 49 | - | |
| 50 | - public static LinkedList<Packet> readPackets(InputStream input) throws Exception | |
| 51 | - { | |
| 52 | - int len = -1; | |
| 53 | - byte[] block = new byte[1024]; | |
| 54 | - Jtt1078Decoder decoder = new Jtt1078Decoder(); | |
| 55 | - | |
| 56 | - LinkedList<Packet> packets = new LinkedList(); | |
| 57 | - | |
| 58 | - while ((len = input.read(block)) > -1) | |
| 59 | - { | |
| 60 | - decoder.write(block, 0, len); | |
| 61 | - while (true) | |
| 62 | - { | |
| 63 | - Packet p = decoder.decode(); | |
| 64 | - if (p == null) break; | |
| 65 | - | |
| 66 | - packets.add(p); | |
| 67 | - } | |
| 68 | - } | |
| 69 | - | |
| 70 | - return packets; | |
| 71 | - } | |
| 72 | - | |
| 73 | - public static byte[] toBCD(String sim) | |
| 74 | - { | |
| 75 | - byte[] bcd = new byte[sim.length() / 2]; | |
| 76 | - for (int i = 0, k = 0, l = sim.length(); i < l; i+=2) | |
| 77 | - { | |
| 78 | - char a = (char)(sim.charAt(i) - '0'); | |
| 79 | - char b = (char)(sim.charAt(i + 1) - '0'); | |
| 80 | - bcd[k++] = ((byte)(a << 4 | b)); | |
| 81 | - } | |
| 82 | - return bcd; | |
| 83 | - } | |
| 84 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/test/UnPack.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.test; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.server.Jtt1078Decoder; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.util.Packet; | |
| 5 | - | |
| 6 | -import java.io.FileInputStream; | |
| 7 | -import java.io.FileOutputStream; | |
| 8 | - | |
| 9 | -public class UnPack | |
| 10 | -{ | |
| 11 | - public static void main(String[] args) throws Exception | |
| 12 | - { | |
| 13 | - FileInputStream input = new FileInputStream("d:\\test\\1078\\d.bin"); | |
| 14 | - FileOutputStream output = new FileOutputStream("d:\\test\\1078\\fuck.1078.xxx"); | |
| 15 | - | |
| 16 | - int len = -1; | |
| 17 | - byte[] block = new byte[1024]; | |
| 18 | - Jtt1078Decoder decoder = new Jtt1078Decoder(); | |
| 19 | - while (true) | |
| 20 | - { | |
| 21 | - len = input.read(block); | |
| 22 | - if (len == -1) break; | |
| 23 | - decoder.write(block, 0, len); | |
| 24 | - | |
| 25 | - while (true) | |
| 26 | - { | |
| 27 | - Packet p = decoder.decode(); | |
| 28 | - if (p == null) break; | |
| 29 | - | |
| 30 | - int lengthOffset = 28; | |
| 31 | - int dataType = (p.seek(15).nextByte() >> 4) & 0x0f; | |
| 32 | - // 透传数据类型:0100,没有后面的时间以及Last I Frame Interval和Last Frame Interval字段 | |
| 33 | - if (dataType == 0x04) lengthOffset = 28 - 8 - 2 - 2; | |
| 34 | - else if (dataType == 0x03) lengthOffset = 28 - 4; | |
| 35 | - | |
| 36 | - // FFMpegManager.getInstance().feed(publisherId, packet.seek(lengthOffset + 2).nextBytes()); | |
| 37 | - if (dataType == 0x00 || dataType == 0x01 || dataType == 0x02) | |
| 38 | - { | |
| 39 | - // 视频 | |
| 40 | - // p.seek(lengthOffset + 2).nextBytes() | |
| 41 | - // output.write(p.seek(lengthOffset + 2).nextBytes()); | |
| 42 | - System.out.println(p.seek(lengthOffset).nextShort()); | |
| 43 | - } | |
| 44 | - else | |
| 45 | - { | |
| 46 | - // 音频 | |
| 47 | - // p.seek(lengthOffset + 2).nextBytes() | |
| 48 | - } | |
| 49 | - } | |
| 50 | - } | |
| 51 | - output.flush(); | |
| 52 | - output.close(); | |
| 53 | - input.close(); | |
| 54 | - } | |
| 55 | -} | |
| 56 | 0 | \ No newline at end of file |
src/main/java/com/genersoft/iot/vmp/jt1078/test/VideoPushTest.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.test; | |
| 2 | - | |
| 3 | -import java.io.FileInputStream; | |
| 4 | -import java.io.InputStream; | |
| 5 | -import java.io.OutputStream; | |
| 6 | -import java.net.Socket; | |
| 7 | - | |
| 8 | -/** | |
| 9 | - * Created by matrixy on 2019/4/10. | |
| 10 | - */ | |
| 11 | -public class VideoPushTest | |
| 12 | -{ | |
| 13 | - public static void main(String[] args) throws Exception | |
| 14 | - { | |
| 15 | - Socket conn = new Socket("localhost", 1078); | |
| 16 | - OutputStream os = conn.getOutputStream(); | |
| 17 | - | |
| 18 | - // InputStream fis = new FileInputStream("e:\\workspace\\enc_dec_audio\\streamax.bin"); | |
| 19 | - // InputStream fis = new FileInputStream("e:\\test\\streaming.hex"); | |
| 20 | - InputStream fis = VideoPushTest.class.getResourceAsStream("/tcpdump.bin"); | |
| 21 | - int len = -1; | |
| 22 | - byte[] block = new byte[512]; | |
| 23 | - while ((len = fis.read(block)) > -1) | |
| 24 | - { | |
| 25 | - os.write(block, 0, len); | |
| 26 | - os.flush(); | |
| 27 | - Thread.sleep(20); | |
| 28 | - System.out.println("sending..."); | |
| 29 | - } | |
| 30 | - os.close(); | |
| 31 | - fis.close(); | |
| 32 | - conn.close(); | |
| 33 | - } | |
| 34 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/test/VideoServer.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.test; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.server.Jtt1078Decoder; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.util.Packet; | |
| 5 | - | |
| 6 | -import java.io.FileOutputStream; | |
| 7 | -import java.io.InputStream; | |
| 8 | -import java.net.ServerSocket; | |
| 9 | -import java.net.Socket; | |
| 10 | -import java.util.LinkedList; | |
| 11 | - | |
| 12 | -/** | |
| 13 | - * Created by houcheng on 2019-12-10. | |
| 14 | - */ | |
| 15 | -public class VideoServer | |
| 16 | -{ | |
| 17 | - public static void main(String[] args) throws Exception | |
| 18 | - { | |
| 19 | - System.out.println("started..."); | |
| 20 | - | |
| 21 | - String command = ("ffmpeg -f h264 -i /opt/test/xxoo.Video -f sln -ar 8000 -ac 1 -i /opt/test/xxoo.Audio -vcodec copy -acodec aac -map 0:v:0 -map 1:a:0 -probesize 512 -analyzeduration 100 -f flv rtmp://localhost/live/fuck"); | |
| 22 | - Process process = Runtime.getRuntime().exec(command); | |
| 23 | - new Reader(process.getErrorStream()).start(); | |
| 24 | - | |
| 25 | - Thread.sleep(2000); | |
| 26 | - | |
| 27 | - ServerSocket server = new ServerSocket(1078, 100); | |
| 28 | - Socket conn = server.accept(); | |
| 29 | - System.out.println("Connected from: " + conn.getRemoteSocketAddress()); | |
| 30 | - InputStream input = conn.getInputStream(); | |
| 31 | - | |
| 32 | - Publisher videoPublisher = new VideoPublisher(); | |
| 33 | - Publisher audioPublisher = new AudioPublisher(); | |
| 34 | - | |
| 35 | - videoPublisher.start(); | |
| 36 | - audioPublisher.start(); | |
| 37 | - | |
| 38 | - int len = -1; | |
| 39 | - byte[] block = new byte[1024]; | |
| 40 | - Jtt1078Decoder decoder = new Jtt1078Decoder(); | |
| 41 | - while (true) | |
| 42 | - { | |
| 43 | - len = input.read(block); | |
| 44 | - if (len == -1) break; | |
| 45 | - decoder.write(block, 0, len); | |
| 46 | - | |
| 47 | - while (true) | |
| 48 | - { | |
| 49 | - Packet p = decoder.decode(); | |
| 50 | - if (p == null) break; | |
| 51 | - | |
| 52 | - int lengthOffset = 28; | |
| 53 | - int dataType = (p.seek(15).nextByte() >> 4) & 0x0f; | |
| 54 | - // 透传数据类型:0100,没有后面的时间以及Last I Frame Interval和Last Frame Interval字段 | |
| 55 | - if (dataType == 0x04) lengthOffset = 28 - 8 - 2 - 2; | |
| 56 | - else if (dataType == 0x03) lengthOffset = 28 - 4; | |
| 57 | - | |
| 58 | - // FFMpegManager.getInstance().feed(publisherId, packet.seek(lengthOffset + 2).nextBytes()); | |
| 59 | - if (dataType == 0x00 || dataType == 0x01 || dataType == 0x02) | |
| 60 | - { | |
| 61 | - videoPublisher.publish(p.seek(lengthOffset + 2).nextBytes()); | |
| 62 | - } | |
| 63 | - else | |
| 64 | - { | |
| 65 | - audioPublisher.publish(p.seek(lengthOffset + 2).nextBytes()); | |
| 66 | - } | |
| 67 | - } | |
| 68 | - } | |
| 69 | - | |
| 70 | - System.in.read(); | |
| 71 | - } | |
| 72 | - | |
| 73 | - | |
| 74 | - | |
| 75 | - static class Reader extends Thread | |
| 76 | - { | |
| 77 | - InputStream stdout = null; | |
| 78 | - public Reader(InputStream is) | |
| 79 | - { | |
| 80 | - this.stdout = is; | |
| 81 | - } | |
| 82 | - | |
| 83 | - public void run() | |
| 84 | - { | |
| 85 | - int len = -1; | |
| 86 | - byte[] block = new byte[512]; | |
| 87 | - try | |
| 88 | - { | |
| 89 | - while ((len = stdout.read(block)) > -1) | |
| 90 | - { | |
| 91 | - System.out.print(new String(block, 0, len)); | |
| 92 | - } | |
| 93 | - } | |
| 94 | - catch(Exception ex) | |
| 95 | - { | |
| 96 | - ex.printStackTrace(); | |
| 97 | - } | |
| 98 | - } | |
| 99 | - } | |
| 100 | - | |
| 101 | - static class Publisher extends Thread | |
| 102 | - { | |
| 103 | - Object lock = new Object(); | |
| 104 | - LinkedList<byte[]> messages = new LinkedList(); | |
| 105 | - | |
| 106 | - public void publish(byte[] msg) | |
| 107 | - { | |
| 108 | - synchronized (lock) | |
| 109 | - { | |
| 110 | - messages.add(msg); | |
| 111 | - lock.notify(); | |
| 112 | - } | |
| 113 | - } | |
| 114 | - | |
| 115 | - public byte[] peek() | |
| 116 | - { | |
| 117 | - byte[] msg = null; | |
| 118 | - synchronized (lock) | |
| 119 | - { | |
| 120 | - while (messages.size() == 0) try { lock.wait(); } catch(Exception e) { } | |
| 121 | - msg = messages.removeFirst(); | |
| 122 | - } | |
| 123 | - return msg; | |
| 124 | - } | |
| 125 | - | |
| 126 | - public FileOutputStream open(String fname) | |
| 127 | - { | |
| 128 | - try | |
| 129 | - { | |
| 130 | - return new FileOutputStream(fname); | |
| 131 | - } | |
| 132 | - catch(Exception ex) | |
| 133 | - { | |
| 134 | - throw new RuntimeException(ex); | |
| 135 | - } | |
| 136 | - } | |
| 137 | - } | |
| 138 | - | |
| 139 | - static class VideoPublisher extends Publisher | |
| 140 | - { | |
| 141 | - public void run() | |
| 142 | - { | |
| 143 | - FileOutputStream fos = open("/opt/test/xxoo.Video"); | |
| 144 | - while (!this.isInterrupted()) | |
| 145 | - { | |
| 146 | - try | |
| 147 | - { | |
| 148 | - byte[] msg = peek(); | |
| 149 | - fos.write(msg); | |
| 150 | - fos.flush(); | |
| 151 | - } | |
| 152 | - catch(Exception ex) | |
| 153 | - { | |
| 154 | - ex.printStackTrace(); | |
| 155 | - break; | |
| 156 | - } | |
| 157 | - } | |
| 158 | - } | |
| 159 | - } | |
| 160 | - | |
| 161 | - static class AudioPublisher extends Publisher | |
| 162 | - { | |
| 163 | - public void run() | |
| 164 | - { | |
| 165 | - FileOutputStream fos = open("/opt/test/xxoo.Audio"); | |
| 166 | - while (!this.isInterrupted()) | |
| 167 | - { | |
| 168 | - try | |
| 169 | - { | |
| 170 | - byte[] msg = peek(); | |
| 171 | - fos.write(msg); | |
| 172 | - fos.flush(); | |
| 173 | - } | |
| 174 | - catch(Exception ex) | |
| 175 | - { | |
| 176 | - ex.printStackTrace(); | |
| 177 | - break; | |
| 178 | - } | |
| 179 | - } | |
| 180 | - } | |
| 181 | - } | |
| 182 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/test/WAVTest.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.test; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.util.ByteUtils; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.util.Packet; | |
| 5 | - | |
| 6 | -import java.io.FileInputStream; | |
| 7 | -import java.io.FileOutputStream; | |
| 8 | - | |
| 9 | -/** | |
| 10 | - * Created by matrixy on 2019/12/18. | |
| 11 | - */ | |
| 12 | -public class WAVTest | |
| 13 | -{ | |
| 14 | - public static void main(String[] args) throws Exception | |
| 15 | - { | |
| 16 | - int len; | |
| 17 | - byte[] block = new byte[1024 * 2048]; | |
| 18 | - FileInputStream fis = new FileInputStream("d:\\temp\\xxoo.pcm"); | |
| 19 | - Packet p = Packet.create(1024 * 2048); | |
| 20 | - while ((len = fis.read(block)) > -1) | |
| 21 | - { | |
| 22 | - p.reset(); | |
| 23 | - p.addBytes("RIFF".getBytes()) | |
| 24 | - .addBytes(ByteUtils.toLEBytes(len + 36)) | |
| 25 | - .addBytes("WAVE".getBytes()) // wave type | |
| 26 | - .addBytes("fmt ".getBytes()) // fmt id | |
| 27 | - .addInt(0x10000000) // fmt chunk size | |
| 28 | - .addShort((short)0x0100) // format: 1 -> PCM | |
| 29 | - .addShort((short)0x0100) // channels: 1 | |
| 30 | - .addBytes(ByteUtils.toLEBytes(8000)) // samples per second | |
| 31 | - .addBytes(ByteUtils.toLEBytes(1 * 8000 * 16 / 8)) // BPSecond | |
| 32 | - .addBytes(ByteUtils.toLEBytes((short)(1 * 16 / 8))) // BPSample | |
| 33 | - .addBytes(ByteUtils.toLEBytes((short)(1 * 16))) // bPSecond | |
| 34 | - .addBytes("data".getBytes()) // data id | |
| 35 | - .addBytes(ByteUtils.toLEBytes(len)); // data chunk size | |
| 36 | - | |
| 37 | - p.addBytes(block, len); | |
| 38 | - | |
| 39 | - FileOutputStream fos = new FileOutputStream("d:\\fuck.wav"); | |
| 40 | - fos.write(p.getBytes()); | |
| 41 | - fos.flush(); | |
| 42 | - fos.close(); | |
| 43 | - } | |
| 44 | - } | |
| 45 | -} |
src/main/java/com/genersoft/iot/vmp/jt1078/util/ClassUtil.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.jt1078.util; | |
| 2 | - | |
| 3 | -import org.slf4j.Logger; | |
| 4 | -import org.slf4j.LoggerFactory; | |
| 5 | -import org.springframework.core.io.Resource; | |
| 6 | -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; | |
| 7 | -import org.springframework.core.io.support.ResourcePatternResolver; | |
| 8 | - | |
| 9 | -import java.lang.annotation.Annotation; | |
| 10 | -import java.util.LinkedList; | |
| 11 | -import java.util.List; | |
| 12 | - | |
| 13 | -public class ClassUtil { | |
| 14 | - | |
| 15 | - private static final Logger logger = LoggerFactory.getLogger(ClassUtil.class); | |
| 16 | - | |
| 17 | - | |
| 18 | - public static Object getBean(Class<?> clazz) { | |
| 19 | - if (clazz != null) { | |
| 20 | - try { | |
| 21 | - return clazz.getDeclaredConstructor().newInstance(); | |
| 22 | - } catch (Exception ex) { | |
| 23 | - logger.error("ClassUtil:找不到指定的类", ex); | |
| 24 | - } | |
| 25 | - } | |
| 26 | - return null; | |
| 27 | - } | |
| 28 | - | |
| 29 | - | |
| 30 | - public static Object getBean(String className) { | |
| 31 | - Class<?> clazz = null; | |
| 32 | - try { | |
| 33 | - clazz = Class.forName(className); | |
| 34 | - } catch (Exception ex) { | |
| 35 | - logger.error("ClassUtil:找不到指定的类"); | |
| 36 | - } | |
| 37 | - if (clazz != null) { | |
| 38 | - try { | |
| 39 | - //获取声明的构造器--》创建实例 | |
| 40 | - return clazz.getDeclaredConstructor().newInstance(); | |
| 41 | - } catch (Exception ex) { | |
| 42 | - logger.error("ClassUtil:找不到指定的类", ex); | |
| 43 | - } | |
| 44 | - } | |
| 45 | - return null; | |
| 46 | - } | |
| 47 | - | |
| 48 | - | |
| 49 | - /** | |
| 50 | - * 获取包下所有带注解的class | |
| 51 | - * | |
| 52 | - * @param packageName 包名 | |
| 53 | - * @param annotationClass 注解类型 | |
| 54 | - * @return list | |
| 55 | - */ | |
| 56 | - public static List<Class<?>> getClassList(String packageName, Class<? extends Annotation> annotationClass) { | |
| 57 | - List<Class<?>> classList = getClassList(packageName); | |
| 58 | - classList.removeIf(next -> !next.isAnnotationPresent(annotationClass)); | |
| 59 | - return classList; | |
| 60 | - } | |
| 61 | - | |
| 62 | - public static List<Class<?>> getClassList(String... packageName) { | |
| 63 | - List<Class<?>> classList = new LinkedList<>(); | |
| 64 | - for (String s : packageName) { | |
| 65 | - List<Class<?>> c = getClassList(s); | |
| 66 | - classList.addAll(c); | |
| 67 | - } | |
| 68 | - return classList; | |
| 69 | - } | |
| 70 | - | |
| 71 | - public static List<Class<?>> getClassList(String packageName) { | |
| 72 | - List<Class<?>> classList = new LinkedList<>(); | |
| 73 | - try { | |
| 74 | - ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); | |
| 75 | - Resource[] resources = resourcePatternResolver.getResources(packageName.replace(".", "/") + "/**/*.class"); | |
| 76 | - for (Resource resource : resources) { | |
| 77 | - String url = resource.getURL().toString(); | |
| 78 | - | |
| 79 | - String[] split = url.split(packageName.replace(".", "/")); | |
| 80 | - String s = split[split.length - 1]; | |
| 81 | - String className = s.replace("/", "."); | |
| 82 | - className = className.substring(0, className.lastIndexOf(".")); | |
| 83 | - doAddClass(classList, packageName + className); | |
| 84 | - } | |
| 85 | - | |
| 86 | - } catch (Exception e) { | |
| 87 | - throw new RuntimeException(e); | |
| 88 | - } | |
| 89 | - return classList; | |
| 90 | - } | |
| 91 | - | |
| 92 | - private static void doAddClass(List<Class<?>> classList, String className) { | |
| 93 | - Class<?> cls = loadClass(className, false); | |
| 94 | - classList.add(cls); | |
| 95 | - } | |
| 96 | - | |
| 97 | - public static Class<?> loadClass(String className, boolean isInitialized) { | |
| 98 | - Class<?> cls; | |
| 99 | - try { | |
| 100 | - cls = Class.forName(className, isInitialized, getClassLoader()); | |
| 101 | - } catch (ClassNotFoundException e) { | |
| 102 | - throw new RuntimeException(e); | |
| 103 | - } | |
| 104 | - return cls; | |
| 105 | - } | |
| 106 | - | |
| 107 | - | |
| 108 | - public static ClassLoader getClassLoader() { | |
| 109 | - return Thread.currentThread().getContextClassLoader(); | |
| 110 | - } | |
| 111 | - | |
| 112 | -} |
src/main/java/com/genersoft/iot/vmp/jtt1078/app/VideoServerApp.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.jtt1078.app; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.jtt1078.http.GeneralResponseWriter; | |
| 4 | +import com.genersoft.iot.vmp.jtt1078.http.NettyHttpServerHandler; | |
| 5 | +import com.genersoft.iot.vmp.jtt1078.publisher.PublishManager; | |
| 6 | +import com.genersoft.iot.vmp.jtt1078.server.Jtt1078Handler; | |
| 7 | +import com.genersoft.iot.vmp.jtt1078.server.Jtt1078MessageDecoder; | |
| 8 | +import com.genersoft.iot.vmp.jtt1078.server.SessionManager; | |
| 9 | +import com.genersoft.iot.vmp.jtt1078.util.Configs; | |
| 10 | +import com.xiaoleilu.hutool.collection.ConcurrentHashSet; | |
| 11 | +import io.netty.bootstrap.ServerBootstrap; | |
| 12 | +import io.netty.channel.*; | |
| 13 | +import io.netty.channel.nio.NioEventLoopGroup; | |
| 14 | +import io.netty.channel.socket.SocketChannel; | |
| 15 | +import io.netty.channel.socket.nio.NioServerSocketChannel; | |
| 16 | +import io.netty.handler.codec.http.HttpObjectAggregator; | |
| 17 | +import io.netty.handler.codec.http.HttpRequestDecoder; | |
| 18 | +import io.netty.handler.codec.http.HttpResponseEncoder; | |
| 19 | +import org.slf4j.Logger; | |
| 20 | +import org.slf4j.LoggerFactory; | |
| 21 | +import org.springframework.beans.factory.annotation.Value; | |
| 22 | +import org.springframework.context.annotation.Configuration; | |
| 23 | +import sun.misc.Signal; | |
| 24 | +import sun.misc.SignalHandler; | |
| 25 | + | |
| 26 | +import java.net.InetAddress; | |
| 27 | + | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * Created by matrixy on 2019/4/9. | |
| 31 | + */ | |
| 32 | +@Configuration | |
| 33 | +public class VideoServerApp | |
| 34 | +{ | |
| 35 | + private static Logger logger = LoggerFactory.getLogger(VideoServerApp.class); | |
| 36 | + | |
| 37 | + public static final ConcurrentHashSet<String> TAG_SET = new ConcurrentHashSet<>(); | |
| 38 | + | |
| 39 | + @Value("${spring.profiles.active}") | |
| 40 | + private String activeProfile; | |
| 41 | + | |
| 42 | + public void run(String... args) throws Exception { | |
| 43 | + try { | |
| 44 | + String configProperties = null; | |
| 45 | + switch (activeProfile){ | |
| 46 | + case "wx-local": | |
| 47 | + configProperties = "/app.properties"; | |
| 48 | + break; | |
| 49 | + case "dev100": | |
| 50 | + configProperties = "/app-dev100.properties"; | |
| 51 | + break; | |
| 52 | + case "dev103": | |
| 53 | + configProperties = "/app-dev103.properties"; | |
| 54 | + break; | |
| 55 | + default: | |
| 56 | + break; | |
| 57 | + } | |
| 58 | + if (configProperties == null) { | |
| 59 | + throw new RuntimeException(String.format("推流配置文件错误 [ %s ]", activeProfile)); | |
| 60 | + } | |
| 61 | + Configs.init(configProperties); | |
| 62 | + PublishManager.init(); | |
| 63 | + SessionManager.init(); | |
| 64 | + int port = Configs.getInt("server.port", 1078); | |
| 65 | + int historyPort = Configs.getInt("server.history.port", 1078); | |
| 66 | + VideoServer videoServer = new VideoServer(port); | |
| 67 | + HttpServer httpServer = new HttpServer(); | |
| 68 | + VideoServer historyVideoServer = new VideoServer(historyPort); | |
| 69 | + | |
| 70 | + Signal.handle(new Signal("TERM"), new SignalHandler() | |
| 71 | + { | |
| 72 | + @Override | |
| 73 | + public void handle(Signal signal) | |
| 74 | + { | |
| 75 | + videoServer.shutdown(); | |
| 76 | + httpServer.shutdown(); | |
| 77 | + historyVideoServer.shutdown(); | |
| 78 | + } | |
| 79 | + }); | |
| 80 | + | |
| 81 | + videoServer.start(); | |
| 82 | + httpServer.start(); | |
| 83 | + historyVideoServer.historyStart(); | |
| 84 | + } catch (Exception e) { | |
| 85 | + logger.error("端口监听异常 ===》 {}",e.getMessage(),e); | |
| 86 | + } | |
| 87 | + } | |
| 88 | + | |
| 89 | + public VideoServer getVideoServer(Integer port) { | |
| 90 | + return new VideoServer(port); | |
| 91 | + } | |
| 92 | + | |
| 93 | + public class VideoServer | |
| 94 | + { | |
| 95 | + private ServerBootstrap serverBootstrap; | |
| 96 | + | |
| 97 | + private EventLoopGroup bossGroup; | |
| 98 | + private EventLoopGroup workerGroup; | |
| 99 | + private final Integer port; | |
| 100 | + | |
| 101 | + public VideoServer(Integer port) { | |
| 102 | + this.port = port; | |
| 103 | + } | |
| 104 | + | |
| 105 | + private void start() throws Exception | |
| 106 | + { | |
| 107 | + serverBootstrap = new ServerBootstrap(); | |
| 108 | + serverBootstrap.option(ChannelOption.SO_BACKLOG, Configs.getInt("server.backlog", 102400)); | |
| 109 | + bossGroup = new NioEventLoopGroup(Configs.getInt("server.worker-count", Runtime.getRuntime().availableProcessors())); | |
| 110 | + workerGroup = new NioEventLoopGroup(); | |
| 111 | + serverBootstrap.group(bossGroup, workerGroup) | |
| 112 | + .option(ChannelOption.SO_KEEPALIVE, true) | |
| 113 | + .channel(NioServerSocketChannel.class) | |
| 114 | + .childHandler(new ChannelInitializer<SocketChannel>() { | |
| 115 | + @Override | |
| 116 | + protected void initChannel(final SocketChannel channel) throws Exception { | |
| 117 | + ChannelPipeline p = channel.pipeline(); | |
| 118 | + // p.addLast(new IdleStateHandler(10,0,0, TimeUnit.SECONDS)); | |
| 119 | + p.addLast(new Jtt1078MessageDecoder()); | |
| 120 | + // p.addLast(new Jtt808MessageEncoder()); | |
| 121 | + // p.addLast(new JTT808Handler()); | |
| 122 | + p.addLast(new Jtt1078Handler()); | |
| 123 | + } | |
| 124 | + }); | |
| 125 | + | |
| 126 | +// int historyPort = Configs.getInt("server.history.port", 30001); | |
| 127 | + Channel ch = serverBootstrap.bind(InetAddress.getByName("0.0.0.0"), port).sync().channel(); | |
| 128 | +// Channel historyCh = serverBootstrap.bind(InetAddress.getByName("0.0.0.0"), historyPort).sync().channel(); | |
| 129 | + logger.info("Video Server started at: {}", port); | |
| 130 | +// logger.info("Video history Server started at: {}", historyPort); | |
| 131 | + ch.closeFuture(); | |
| 132 | +// historyCh.closeFuture(); | |
| 133 | + } | |
| 134 | + | |
| 135 | + public void historyStart() throws Exception | |
| 136 | + { | |
| 137 | + serverBootstrap = new ServerBootstrap(); | |
| 138 | + serverBootstrap.option(ChannelOption.SO_BACKLOG, Configs.getInt("server.backlog", 102400)); | |
| 139 | + bossGroup = new NioEventLoopGroup(Configs.getInt("server.worker-count", Runtime.getRuntime().availableProcessors())); | |
| 140 | + workerGroup = new NioEventLoopGroup(); | |
| 141 | + serverBootstrap.group(bossGroup, workerGroup) | |
| 142 | + .option(ChannelOption.SO_KEEPALIVE, true) | |
| 143 | + .channel(NioServerSocketChannel.class) | |
| 144 | + .childHandler(new ChannelInitializer<SocketChannel>() { | |
| 145 | + @Override | |
| 146 | + protected void initChannel(final SocketChannel channel) throws Exception { | |
| 147 | + ChannelPipeline p = channel.pipeline(); | |
| 148 | + // p.addLast(new IdleStateHandler(10,0,0, TimeUnit.SECONDS)); | |
| 149 | + p.addLast(new Jtt1078MessageDecoder()); | |
| 150 | + // p.addLast(new Jtt808MessageEncoder()); | |
| 151 | + // p.addLast(new JTT808Handler()); | |
| 152 | + p.addLast(new Jtt1078Handler(port)); | |
| 153 | + } | |
| 154 | + }); | |
| 155 | + Channel ch = serverBootstrap.bind(InetAddress.getByName("0.0.0.0"), port).sync().channel(); | |
| 156 | + logger.info("Video Server started at: {}", port); | |
| 157 | + ch.closeFuture(); | |
| 158 | + } | |
| 159 | + | |
| 160 | + public void shutdown() | |
| 161 | + { | |
| 162 | + try | |
| 163 | + { | |
| 164 | + bossGroup.shutdownGracefully(); | |
| 165 | + workerGroup.shutdownGracefully(); | |
| 166 | + } | |
| 167 | + catch(Exception e) | |
| 168 | + { | |
| 169 | + e.printStackTrace(); | |
| 170 | + } | |
| 171 | + } | |
| 172 | + } | |
| 173 | + | |
| 174 | + class HttpServer | |
| 175 | + { | |
| 176 | + private ServerBootstrap serverBootstrap; | |
| 177 | + | |
| 178 | + private EventLoopGroup bossGroup; | |
| 179 | + private EventLoopGroup workerGroup; | |
| 180 | + | |
| 181 | + private void start() throws Exception | |
| 182 | + { | |
| 183 | + bossGroup = new NioEventLoopGroup(); | |
| 184 | + workerGroup = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors()); | |
| 185 | + | |
| 186 | + ServerBootstrap bootstrap = new ServerBootstrap(); | |
| 187 | + bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) | |
| 188 | + .childHandler(new ChannelInitializer<SocketChannel>() | |
| 189 | + { | |
| 190 | + @Override | |
| 191 | + public void initChannel(SocketChannel ch) throws Exception | |
| 192 | + { | |
| 193 | + ch.pipeline().addLast( | |
| 194 | + new GeneralResponseWriter(), | |
| 195 | + new HttpResponseEncoder(), | |
| 196 | + new HttpRequestDecoder(), | |
| 197 | + new HttpObjectAggregator(1024 * 64), | |
| 198 | + new NettyHttpServerHandler() | |
| 199 | + ); | |
| 200 | + } | |
| 201 | + }).option(ChannelOption.SO_BACKLOG, 1024) | |
| 202 | + .childOption(ChannelOption.SO_KEEPALIVE, true); | |
| 203 | + try | |
| 204 | + { | |
| 205 | + int port = Configs.getInt("server.http.port", 3333); | |
| 206 | +// int historyPort = Configs.getInt("server.history.http.port", 3334); | |
| 207 | + ChannelFuture f = bootstrap.bind(InetAddress.getByName("0.0.0.0"), port).sync(); | |
| 208 | +// ChannelFuture historyF = bootstrap.bind(InetAddress.getByName("0.0.0.0"), historyPort).sync(); | |
| 209 | + logger.info("HTTP Server started at: {}", port); | |
| 210 | +// logger.info("HTTP Server started at: {}", historyPort); | |
| 211 | + f.channel().closeFuture().sync(); | |
| 212 | +// historyF.channel().closeFuture().sync(); | |
| 213 | + } | |
| 214 | + catch (InterruptedException e) | |
| 215 | + { | |
| 216 | + logger.error("http server error", e); | |
| 217 | + } | |
| 218 | + finally | |
| 219 | + { | |
| 220 | + workerGroup.shutdownGracefully(); | |
| 221 | + bossGroup.shutdownGracefully(); | |
| 222 | + } | |
| 223 | + } | |
| 224 | + | |
| 225 | + private void shutdown() | |
| 226 | + { | |
| 227 | + try | |
| 228 | + { | |
| 229 | + bossGroup.shutdownGracefully(); | |
| 230 | + workerGroup.shutdownGracefully(); | |
| 231 | + } | |
| 232 | + catch(Exception e) | |
| 233 | + { | |
| 234 | + e.printStackTrace(); | |
| 235 | + } | |
| 236 | + } | |
| 237 | + } | |
| 238 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/codec/ADPCMCodec.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/codec/ADPCMCodec.java
| 1 | -package com.genersoft.iot.vmp.jt1078.codec; | |
| 1 | +package com.genersoft.iot.vmp.jtt1078.codec; | |
| 2 | 2 | |
| 3 | -import com.genersoft.iot.vmp.jt1078.server.Jtt1078Decoder; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.util.ByteHolder; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.util.Packet; | |
| 3 | +import com.genersoft.iot.vmp.jtt1078.server.Jtt1078Decoder; | |
| 4 | +import com.genersoft.iot.vmp.jtt1078.util.Packet; | |
| 6 | 5 | |
| 7 | 6 | import java.io.ByteArrayInputStream; |
| 8 | 7 | import java.io.ByteArrayOutputStream; |
| 9 | 8 | import java.io.FileInputStream; |
| 10 | 9 | import java.io.FileOutputStream; |
| 11 | -import java.util.Arrays; | |
| 12 | 10 | |
| 13 | 11 | /** |
| 14 | 12 | * Created by houcheng on 2019-12-05. | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/codec/AudioCodec.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/codec/AudioCodec.java
src/main/java/com/genersoft/iot/vmp/jt1078/codec/G711Codec.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/codec/G711Codec.java
| 1 | -package com.genersoft.iot.vmp.jt1078.codec; | |
| 1 | +package com.genersoft.iot.vmp.jtt1078.codec; | |
| 2 | 2 | |
| 3 | +import com.genersoft.iot.vmp.jtt1078.codec.AudioCodec; | |
| 3 | 4 | |
| 4 | 5 | /** |
| 5 | 6 | * 核心转换,PCM转G711 |
| ... | ... | @@ -154,4 +155,4 @@ public class G711Codec extends AudioCodec |
| 154 | 155 | public byte[] fromPCM(byte[] data) { |
| 155 | 156 | return encode(data); |
| 156 | 157 | } |
| 157 | -} | |
| 158 | 158 | \ No newline at end of file |
| 159 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/codec/G711UCodec.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/codec/G711UCodec.java
src/main/java/com/genersoft/iot/vmp/jt1078/codec/G726Codec.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/codec/G726Codec.java
src/main/java/com/genersoft/iot/vmp/jt1078/codec/MP3Encoder.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/codec/MP3Encoder.java
src/main/java/com/genersoft/iot/vmp/jt1078/codec/SilenceCodec.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/codec/SilenceCodec.java
src/main/java/com/genersoft/iot/vmp/jt1078/codec/g726/G726.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/codec/g726/G726.java
| 1 | 1 | |
| 2 | -package com.genersoft.iot.vmp.jt1078.codec.g726; | |
| 2 | +package com.genersoft.iot.vmp.jtt1078.codec.g726; | |
| 3 | 3 | |
| 4 | 4 | |
| 5 | -import com.genersoft.iot.vmp.jt1078.codec.G711Codec; | |
| 6 | -import com.genersoft.iot.vmp.jt1078.codec.G711UCodec; | |
| 5 | +import com.genersoft.iot.vmp.jtt1078.codec.G711Codec; | |
| 6 | +import com.genersoft.iot.vmp.jtt1078.codec.G711UCodec; | |
| 7 | 7 | |
| 8 | 8 | /** Common routines for G.721 and G.723 conversions. |
| 9 | 9 | * <p> |
| ... | ... | @@ -15,7 +15,7 @@ import com.genersoft.iot.vmp.jt1078.codec.G711UCodec; |
| 15 | 15 | * ANSI-C source code to the public domain. |
| 16 | 16 | */ |
| 17 | 17 | public abstract class G726 { |
| 18 | - | |
| 18 | + | |
| 19 | 19 | // ##### C-to-Java conversion: ##### |
| 20 | 20 | // short becomes int |
| 21 | 21 | // char becomes int |
| ... | ... | @@ -26,10 +26,10 @@ public abstract class G726 { |
| 26 | 26 | |
| 27 | 27 | /** ISDN u-law */ |
| 28 | 28 | public static final int AUDIO_ENCODING_ULAW=1; |
| 29 | - | |
| 29 | + | |
| 30 | 30 | /** ISDN A-law */ |
| 31 | 31 | public static final int AUDIO_ENCODING_ALAW=2; |
| 32 | - | |
| 32 | + | |
| 33 | 33 | /** PCM 2's-complement (0-center) */ |
| 34 | 34 | public static final int AUDIO_ENCODING_LINEAR=3; |
| 35 | 35 | |
| ... | ... | @@ -44,7 +44,7 @@ public abstract class G726 { |
| 44 | 44 | * <p> |
| 45 | 45 | * Using linear search for simple coding. */ |
| 46 | 46 | private static int quan(int val, /*short*/int[] table, int size) { |
| 47 | - | |
| 47 | + | |
| 48 | 48 | int i; |
| 49 | 49 | for (i=0; i<size; i++) if (val<table[i]) break; |
| 50 | 50 | return i; |
| ... | ... | @@ -63,24 +63,24 @@ public abstract class G726 { |
| 63 | 63 | * @param size - Table size of short integers |
| 64 | 64 | */ |
| 65 | 65 | protected static int quantize(int d, int y, /*short*/int[] table, int size) { |
| 66 | - | |
| 66 | + | |
| 67 | 67 | /* LOG |
| 68 | 68 | * Compute base 2 log of 'd', and store in 'dl'. |
| 69 | 69 | */ |
| 70 | 70 | /*short*/int dqm=Math.abs(d); /* Magnitude of 'd' */ |
| 71 | - | |
| 71 | + | |
| 72 | 72 | /*short*/int exp=quan(dqm>>1, power2, 15); /* Integer part of base 2 log of 'd' */ |
| 73 | - | |
| 73 | + | |
| 74 | 74 | /*short*/int mant=((dqm<<7)>>exp)&0x7F; /* Fractional part of base 2 log */ |
| 75 | - | |
| 75 | + | |
| 76 | 76 | /*short*/int dl=(exp<<7)+mant; /* Log of magnitude of 'd' */ |
| 77 | - | |
| 77 | + | |
| 78 | 78 | /* SUBTB |
| 79 | 79 | * "Divide" by step size multiplier. |
| 80 | 80 | */ |
| 81 | 81 | /* Step size scale factor normalized log */ |
| 82 | 82 | /*short*/int dln=dl-(y>>2); |
| 83 | - | |
| 83 | + | |
| 84 | 84 | /* QUAN |
| 85 | 85 | * Obtain codword i for 'd'. |
| 86 | 86 | */ |
| ... | ... | @@ -102,10 +102,10 @@ public abstract class G726 { |
| 102 | 102 | * @param y - Step size multiplier |
| 103 | 103 | */ |
| 104 | 104 | protected static int reconstruct(int sign, int dqln, int y) { |
| 105 | - | |
| 105 | + | |
| 106 | 106 | /* Log of 'dq' magnitude */ |
| 107 | 107 | /*short*/int dql=dqln+(y>>2); /* ADDA */ |
| 108 | - | |
| 108 | + | |
| 109 | 109 | if (dql<0) { |
| 110 | 110 | return ((sign!=0)? -0x8000 : 0); |
| 111 | 111 | } |
| ... | ... | @@ -119,8 +119,8 @@ public abstract class G726 { |
| 119 | 119 | return ((sign!=0)? (dq-0x8000) : dq); |
| 120 | 120 | } |
| 121 | 121 | } |
| 122 | - | |
| 123 | - | |
| 122 | + | |
| 123 | + | |
| 124 | 124 | /** updates the state variables for each output code |
| 125 | 125 | * @param code_size - distinguish 723_40 with others |
| 126 | 126 | * @param y - quantizer step size |
| ... | ... | @@ -132,7 +132,7 @@ public abstract class G726 { |
| 132 | 132 | * @param state - coder state |
| 133 | 133 | */ |
| 134 | 134 | protected static void update(int code_size, int y, int wi, int fi, int dq, int sr, int dqsez, G726State state) { |
| 135 | - | |
| 135 | + | |
| 136 | 136 | int cnt; |
| 137 | 137 | /*short*/int mag, exp, mant; /* Adaptive predictor, FLOAT A */ |
| 138 | 138 | /*short*/int a2p; /* LIMC */ |
| ... | ... | @@ -144,13 +144,13 @@ public abstract class G726 { |
| 144 | 144 | /*short*/int ylint, thr2, dqthr; |
| 145 | 145 | /*short*/int ylfrac, thr1; |
| 146 | 146 | /*short*/int pk0; |
| 147 | - | |
| 147 | + | |
| 148 | 148 | // ##### C-to-Java conversion: ##### |
| 149 | 149 | // init a2p |
| 150 | - a2p=0; | |
| 151 | - | |
| 150 | + a2p=0; | |
| 151 | + | |
| 152 | 152 | pk0=(dqsez<0)? 1 : 0; /* needed in updating predictor poles */ |
| 153 | - | |
| 153 | + | |
| 154 | 154 | mag=dq&0x7FFF; /* prediction difference magnitude */ |
| 155 | 155 | /* TRANS */ |
| 156 | 156 | ylint=state.yl>>15; /* exponent part of yl */ |
| ... | ... | @@ -165,24 +165,24 @@ public abstract class G726 { |
| 165 | 165 | tr=0; /* treated as voice */ |
| 166 | 166 | else /* signal is data (modem) */ |
| 167 | 167 | tr=1; |
| 168 | - | |
| 168 | + | |
| 169 | 169 | /* Quantizer scale factor adaptation. */ |
| 170 | - | |
| 170 | + | |
| 171 | 171 | /* FUNCTW&FILTD&DELAY */ |
| 172 | 172 | /* update non-steady state step size multiplier */ |
| 173 | 173 | state.yu=y+((wi-y)>>5); |
| 174 | - | |
| 174 | + | |
| 175 | 175 | /* LIMB */ |
| 176 | 176 | if (state.yu<544) /* 544<=yu<=5120 */ |
| 177 | 177 | state.yu=544; |
| 178 | 178 | else |
| 179 | 179 | if (state.yu>5120) |
| 180 | 180 | state.yu=5120; |
| 181 | - | |
| 181 | + | |
| 182 | 182 | /* FILTE&DELAY */ |
| 183 | 183 | /* update steady state step size multiplier */ |
| 184 | 184 | state.yl+=state.yu+((-state.yl)>>6); |
| 185 | - | |
| 185 | + | |
| 186 | 186 | /* |
| 187 | 187 | * Adaptive predictor coefficients. |
| 188 | 188 | */ |
| ... | ... | @@ -200,7 +200,7 @@ public abstract class G726 { |
| 200 | 200 | else { |
| 201 | 201 | /* update a's and b's */ |
| 202 | 202 | pks1=pk0^state.pk[0]; /* UPA2 */ |
| 203 | - | |
| 203 | + | |
| 204 | 204 | /* update predictor pole a[1] */ |
| 205 | 205 | a2p=state.a[1]-(state.a[1]>>7); |
| 206 | 206 | if (dqsez != 0) { |
| ... | ... | @@ -212,7 +212,7 @@ public abstract class G726 { |
| 212 | 212 | a2p+=0xFF; |
| 213 | 213 | else |
| 214 | 214 | a2p+=fa1>>5; |
| 215 | - | |
| 215 | + | |
| 216 | 216 | if ((pk0^state.pk[1])!=0) { |
| 217 | 217 | /* LIMC */ |
| 218 | 218 | if (a2p<=-12160) |
| ... | ... | @@ -232,10 +232,10 @@ public abstract class G726 { |
| 232 | 232 | else |
| 233 | 233 | a2p+=0x80; |
| 234 | 234 | } |
| 235 | - | |
| 235 | + | |
| 236 | 236 | /* TRIGB&DELAY */ |
| 237 | 237 | state.a[1]=a2p; |
| 238 | - | |
| 238 | + | |
| 239 | 239 | /* UPA1 */ |
| 240 | 240 | /* update predictor pole a[0] */ |
| 241 | 241 | state.a[0] -= state.a[0]>>8; |
| ... | ... | @@ -244,17 +244,17 @@ public abstract class G726 { |
| 244 | 244 | state.a[0]+=192; |
| 245 | 245 | else |
| 246 | 246 | state.a[0] -= 192; |
| 247 | - | |
| 247 | + | |
| 248 | 248 | /* LIMD */ |
| 249 | 249 | a1ul=15360-a2p; |
| 250 | 250 | if (state.a[0]<-a1ul) |
| 251 | 251 | state.a[0]=-a1ul; |
| 252 | 252 | else if (state.a[0]>a1ul) |
| 253 | 253 | state.a[0]=a1ul; |
| 254 | - | |
| 254 | + | |
| 255 | 255 | /* UPB : update predictor zeros b[6] */ |
| 256 | 256 | for (cnt=0; cnt<6; cnt++) { |
| 257 | - | |
| 257 | + | |
| 258 | 258 | if (code_size==5) /* for 40Kbps G.723 */ |
| 259 | 259 | state.b[cnt]-=state.b[cnt]>>9; |
| 260 | 260 | else /* for G.721 and 24Kbps G.723 */ |
| ... | ... | @@ -268,7 +268,7 @@ public abstract class G726 { |
| 268 | 268 | } |
| 269 | 269 | } |
| 270 | 270 | } |
| 271 | - | |
| 271 | + | |
| 272 | 272 | for (cnt=5; cnt>0; cnt--) state.dq[cnt]=state.dq[cnt-1]; |
| 273 | 273 | /* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */ |
| 274 | 274 | if (mag==0) { |
| ... | ... | @@ -278,7 +278,7 @@ public abstract class G726 { |
| 278 | 278 | exp=quan(mag, power2, 15); |
| 279 | 279 | state.dq[0]=(dq>=0) ? (exp<<6)+((mag<<6)>>exp) : (exp<<6)+((mag<<6)>>exp)-0x400; |
| 280 | 280 | } |
| 281 | - | |
| 281 | + | |
| 282 | 282 | state.sr[1]=state.sr[0]; |
| 283 | 283 | /* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */ |
| 284 | 284 | if (sr==0) { |
| ... | ... | @@ -297,11 +297,11 @@ public abstract class G726 { |
| 297 | 297 | } |
| 298 | 298 | else |
| 299 | 299 | state.sr[0]=0xFC20; |
| 300 | - | |
| 300 | + | |
| 301 | 301 | /* DELAY A */ |
| 302 | 302 | state.pk[1]=state.pk[0]; |
| 303 | 303 | state.pk[0]=pk0; |
| 304 | - | |
| 304 | + | |
| 305 | 305 | /* TONE */ |
| 306 | 306 | if (tr==1) /* this sample has been treated as data */ |
| 307 | 307 | state.td=0; /* next one will be treated as voice */ |
| ... | ... | @@ -310,13 +310,13 @@ public abstract class G726 { |
| 310 | 310 | state.td=1; /* signal may be data */ |
| 311 | 311 | else /* signal is voice */ |
| 312 | 312 | state.td=0; |
| 313 | - | |
| 313 | + | |
| 314 | 314 | /* |
| 315 | 315 | * Adaptation speed control. |
| 316 | 316 | */ |
| 317 | 317 | state.dms+=(fi-state.dms)>>5; /* FILTA */ |
| 318 | 318 | state.dml+=(((fi<<2)-state.dml)>>7); /* FILTB */ |
| 319 | - | |
| 319 | + | |
| 320 | 320 | if (tr==1) |
| 321 | 321 | state.ap=256; |
| 322 | 322 | else |
| ... | ... | @@ -331,7 +331,7 @@ public abstract class G726 { |
| 331 | 331 | else |
| 332 | 332 | state.ap+=(-state.ap)>>4; |
| 333 | 333 | } |
| 334 | - | |
| 334 | + | |
| 335 | 335 | /** At the end of ADPCM decoding, it simulates an encoder which may be receiving |
| 336 | 336 | * the output of this decoder as a tandem process. If the output of the |
| 337 | 337 | * simulated encoder differs from the input to this decoder, the decoder output |
| ... | ... | @@ -346,19 +346,19 @@ public abstract class G726 { |
| 346 | 346 | * @return adjusted A-law or u-law compressed sample. |
| 347 | 347 | */ |
| 348 | 348 | protected static int tandem_adjust_alaw(int sr, int se, int y, int i, int sign, /*short*/int[] qtab) { |
| 349 | - | |
| 349 | + | |
| 350 | 350 | /*unsigned char*/int sp; /* A-law compressed 8-bit code */ |
| 351 | 351 | /*short*/int dx; /* prediction error */ |
| 352 | 352 | /*char*/int id; /* quantized prediction error */ |
| 353 | 353 | int sd; /* adjusted A-law decoded sample value */ |
| 354 | 354 | int im; /* biased magnitude of i */ |
| 355 | 355 | int imx; /* biased magnitude of id */ |
| 356 | - | |
| 356 | + | |
| 357 | 357 | if (sr<=-32768) sr=-1; |
| 358 | 358 | sp= G711Codec.linear2alaw((short)((sr>>1)<<3)); /* short to A-law compression */ |
| 359 | 359 | dx=(G711Codec.alaw2linear((byte)sp)>>2)-se; /* 16-bit prediction error */ |
| 360 | 360 | id=quantize(dx, y, qtab, sign-1); |
| 361 | - | |
| 361 | + | |
| 362 | 362 | if (id==i) { |
| 363 | 363 | /* no adjustment on sp */ |
| 364 | 364 | return (sp); |
| ... | ... | @@ -368,12 +368,12 @@ public abstract class G726 { |
| 368 | 368 | /* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */ |
| 369 | 369 | im=i^sign; /* 2's complement to biased unsigned */ |
| 370 | 370 | imx=id^sign; |
| 371 | - | |
| 371 | + | |
| 372 | 372 | if (imx>im) { |
| 373 | 373 | /* sp adjusted to next lower value */ |
| 374 | 374 | if ((sp&0x80)!=0) { |
| 375 | 375 | sd=(sp==0xD5)? 0x55 : ((sp^0x55)-1)^0x55; |
| 376 | - } | |
| 376 | + } | |
| 377 | 377 | else { |
| 378 | 378 | sd=(sp==0x2A)? 0x2A : ((sp^0x55)+1)^0x55; |
| 379 | 379 | } |
| ... | ... | @@ -388,7 +388,7 @@ public abstract class G726 { |
| 388 | 388 | return (sd); |
| 389 | 389 | } |
| 390 | 390 | } |
| 391 | - | |
| 391 | + | |
| 392 | 392 | /** @param sr - decoder output linear PCM sample |
| 393 | 393 | * @param se - predictor estimate sample |
| 394 | 394 | * @param y - quantizer step size |
| ... | ... | @@ -397,21 +397,21 @@ public abstract class G726 { |
| 397 | 397 | * @param qtab |
| 398 | 398 | */ |
| 399 | 399 | protected static int tandem_adjust_ulaw(int sr, int se, int y, int i, int sign, /*short*/int[] qtab) { |
| 400 | - | |
| 400 | + | |
| 401 | 401 | /*unsigned char*/int sp; /* u-law compressed 8-bit code */ |
| 402 | 402 | /*short*/int dx; /* prediction error */ |
| 403 | 403 | /*char*/int id; /* quantized prediction error */ |
| 404 | 404 | int sd; /* adjusted u-law decoded sample value */ |
| 405 | 405 | int im; /* biased magnitude of i */ |
| 406 | 406 | int imx; /* biased magnitude of id */ |
| 407 | - | |
| 407 | + | |
| 408 | 408 | if (sr<=-32768) sr=0; |
| 409 | 409 | sp= G711UCodec.linear2ulaw((short)(sr<<2)); /* short to u-law compression */ |
| 410 | 410 | dx=(G711UCodec.ulaw2linear((byte)sp)>>2)-se; /* 16-bit prediction error */ |
| 411 | 411 | id=quantize(dx, y, qtab, sign-1); |
| 412 | 412 | if (id==i) { |
| 413 | 413 | return (sp); |
| 414 | - } | |
| 414 | + } | |
| 415 | 415 | else { |
| 416 | 416 | /* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */ |
| 417 | 417 | im=i^sign; /* 2's complement to biased unsigned */ |
| ... | ... | @@ -422,7 +422,7 @@ public abstract class G726 { |
| 422 | 422 | sd=(sp==0xFF)? 0x7E : sp+1; |
| 423 | 423 | else |
| 424 | 424 | sd=(sp==0)? 0 : sp-1; |
| 425 | - | |
| 425 | + | |
| 426 | 426 | } |
| 427 | 427 | else { |
| 428 | 428 | /* sp adjusted to next higher value */ |
| ... | ... | @@ -437,7 +437,7 @@ public abstract class G726 { |
| 437 | 437 | |
| 438 | 438 | |
| 439 | 439 | // ##### C-to-Java conversion: ##### |
| 440 | - | |
| 440 | + | |
| 441 | 441 | /** Converts a byte into an unsigned int. */ |
| 442 | 442 | protected static int unsignedInt(byte b) { |
| 443 | 443 | return ((int)b+0x100)&0xFF; |
| ... | ... | @@ -477,7 +477,7 @@ public abstract class G726 { |
| 477 | 477 | /** Encodes the input vale of linear PCM, A-law or u-law data sl and returns |
| 478 | 478 | * the resulting code. -1 is returned for unknown input coding value. */ |
| 479 | 479 | public abstract int encode(int sl, int in_coding); |
| 480 | - | |
| 480 | + | |
| 481 | 481 | |
| 482 | 482 | /** Encodes the input chunk in_buff of linear PCM, A-law or u-law data and returns |
| 483 | 483 | * the G726 encoded chuck into out_buff. <br> |
| ... | ... | @@ -498,4 +498,4 @@ public abstract class G726 { |
| 498 | 498 | * out_coding value. */ |
| 499 | 499 | public abstract int decode(byte[] in_buff, int in_offset, int in_len, int out_coding, byte[] out_buff, int out_offset); |
| 500 | 500 | |
| 501 | -} | |
| 502 | 501 | \ No newline at end of file |
| 502 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/codec/g726/G726State.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/codec/g726/G726State.java
src/main/java/com/genersoft/iot/vmp/jt1078/codec/g726/G726_16.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/codec/g726/G726_16.java
| 1 | -package com.genersoft.iot.vmp.jt1078.codec.g726; | |
| 1 | +package com.genersoft.iot.vmp.jtt1078.codec.g726; | |
| 2 | 2 | |
| 3 | - | |
| 4 | -import com.genersoft.iot.vmp.jt1078.codec.G711Codec; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.codec.G711UCodec; | |
| 3 | +import com.genersoft.iot.vmp.jtt1078.codec.G711Codec; | |
| 4 | +import com.genersoft.iot.vmp.jtt1078.codec.G711UCodec; | |
| 6 | 5 | |
| 7 | 6 | /** G726_16 encoder and decoder. |
| 8 | 7 | * <p> | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/codec/g726/G726_24.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/codec/g726/G726_24.java
| 1 | -package com.genersoft.iot.vmp.jt1078.codec.g726; | |
| 1 | +package com.genersoft.iot.vmp.jtt1078.codec.g726; | |
| 2 | 2 | |
| 3 | - | |
| 4 | -import com.genersoft.iot.vmp.jt1078.codec.G711Codec; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.codec.G711UCodec; | |
| 3 | +import com.genersoft.iot.vmp.jtt1078.codec.G711Codec; | |
| 4 | +import com.genersoft.iot.vmp.jtt1078.codec.G711UCodec; | |
| 6 | 5 | |
| 7 | 6 | /** G726_24 encoder and decoder. |
| 8 | 7 | * <p> |
| ... | ... | @@ -19,7 +18,7 @@ import com.genersoft.iot.vmp.jt1078.codec.G711UCodec; |
| 19 | 18 | * ANSI-C source code to the public domain. |
| 20 | 19 | */ |
| 21 | 20 | public class G726_24 extends G726 { |
| 22 | - | |
| 21 | + | |
| 23 | 22 | // ##### C-to-Java conversion: ##### |
| 24 | 23 | // short becomes int |
| 25 | 24 | // char becomes int |
| ... | ... | @@ -33,30 +32,30 @@ public class G726_24 extends G726 { |
| 33 | 32 | * magnitude values. |
| 34 | 33 | */ |
| 35 | 34 | static /*short*/int[] _dqlntab={-2048, 135, 273, 373, 373, 273, 135, -2048}; |
| 36 | - | |
| 35 | + | |
| 37 | 36 | /* Maps G726_24 code word to log of scale factor multiplier. */ |
| 38 | 37 | static /*short*/int[] _witab={-128, 960, 4384, 18624, 18624, 4384, 960, -128}; |
| 39 | - | |
| 38 | + | |
| 40 | 39 | /* |
| 41 | 40 | * Maps G726_24 code words to a set of values whose long and short |
| 42 | 41 | * term averages are computed and then compared to give an indication |
| 43 | 42 | * how stationary (steady state) the signal is. |
| 44 | 43 | */ |
| 45 | 44 | static /*short*/int[] _fitab={0, 0x200, 0x400, 0xE00, 0xE00, 0x400, 0x200, 0}; |
| 46 | - | |
| 45 | + | |
| 47 | 46 | static /*short*/int[] qtab_723_24={8, 218, 331}; |
| 48 | - | |
| 47 | + | |
| 49 | 48 | /** Encodes a linear PCM, A-law or u-law input sample and returns its 3-bit code. |
| 50 | 49 | * Returns -1 if invalid input coding value. */ |
| 51 | 50 | public static int encode(int sl, int in_coding, G726State state) { |
| 52 | - | |
| 51 | + | |
| 53 | 52 | /*short*/int sei, sezi, se, sez; /* ACCUM */ |
| 54 | 53 | /*short*/int d; /* SUBTA */ |
| 55 | 54 | /*short*/int y; /* MIX */ |
| 56 | 55 | /*short*/int sr; /* ADDB */ |
| 57 | 56 | /*short*/int dqsez; /* ADDC */ |
| 58 | 57 | /*short*/int dq, i; |
| 59 | - | |
| 58 | + | |
| 60 | 59 | switch (in_coding) { |
| 61 | 60 | /* linearize input sample to 14-bit PCM */ |
| 62 | 61 | case AUDIO_ENCODING_ALAW: |
| ... | ... | @@ -71,57 +70,57 @@ public class G726_24 extends G726 { |
| 71 | 70 | default: |
| 72 | 71 | return (-1); |
| 73 | 72 | } |
| 74 | - | |
| 73 | + | |
| 75 | 74 | sezi=state.predictor_zero(); |
| 76 | 75 | sez=sezi >> 1; |
| 77 | 76 | sei=sezi+state.predictor_pole(); |
| 78 | 77 | se=sei >> 1; /* se=estimated signal */ |
| 79 | - | |
| 78 | + | |
| 80 | 79 | d=sl-se; /* d=estimation diff. */ |
| 81 | - | |
| 80 | + | |
| 82 | 81 | /* quantize prediction difference d */ |
| 83 | 82 | y=state.step_size(); /* quantizer step size */ |
| 84 | 83 | i=quantize(d, y, qtab_723_24, 3); /* i=ADPCM code */ |
| 85 | 84 | dq=reconstruct(i & 4, _dqlntab[i], y); /* quantized diff. */ |
| 86 | - | |
| 85 | + | |
| 87 | 86 | sr=(dq<0)? se-(dq & 0x3FFF) : se+dq; /* reconstructed signal */ |
| 88 | - | |
| 87 | + | |
| 89 | 88 | dqsez=sr+sez-se; /* pole prediction diff. */ |
| 90 | - | |
| 89 | + | |
| 91 | 90 | update(3, y, _witab[i], _fitab[i], dq, sr, dqsez, state); |
| 92 | - | |
| 91 | + | |
| 93 | 92 | return (i); |
| 94 | 93 | } |
| 95 | - | |
| 94 | + | |
| 96 | 95 | |
| 97 | 96 | /** Decodes a 3-bit CCITT G.726 24kbps ADPCM code and returns |
| 98 | 97 | * the resulting 16-bit linear PCM, A-law or u-law sample value. |
| 99 | 98 | * -1 is returned if the output coding is unknown. */ |
| 100 | 99 | public static int decode(int i, int out_coding, G726State state) { |
| 101 | - | |
| 100 | + | |
| 102 | 101 | /*short*/int sezi, sei, sez, se; /* ACCUM */ |
| 103 | 102 | /*short*/int y; /* MIX */ |
| 104 | 103 | /*short*/int sr; /* ADDB */ |
| 105 | 104 | /*short*/int dq; |
| 106 | 105 | /*short*/int dqsez; |
| 107 | - | |
| 106 | + | |
| 108 | 107 | i &= 0x07; /* mask to get proper bits */ |
| 109 | 108 | sezi=state.predictor_zero(); |
| 110 | 109 | sez=sezi >> 1; |
| 111 | 110 | sei=sezi+state.predictor_pole(); |
| 112 | 111 | se=sei >> 1; /* se=estimated signal */ |
| 113 | - | |
| 112 | + | |
| 114 | 113 | y=state.step_size(); /* adaptive quantizer step size */ |
| 115 | 114 | dq=reconstruct(i & 0x04, _dqlntab[i], y); /* unquantize pred diff */ |
| 116 | - | |
| 115 | + | |
| 117 | 116 | sr=(dq<0)? (se-(dq & 0x3FFF)) : (se+dq); /* reconst. signal */ |
| 118 | - | |
| 117 | + | |
| 119 | 118 | dqsez=sr-se+sez; /* pole prediction diff. */ |
| 120 | - | |
| 119 | + | |
| 121 | 120 | update(3, y, _witab[i], _fitab[i], dq, sr, dqsez, state); |
| 122 | - | |
| 121 | + | |
| 123 | 122 | switch (out_coding) { |
| 124 | - | |
| 123 | + | |
| 125 | 124 | case AUDIO_ENCODING_ALAW: |
| 126 | 125 | return (tandem_adjust_alaw(sr, se, y, i, 4, qtab_723_24)); |
| 127 | 126 | case AUDIO_ENCODING_ULAW: |
| ... | ... | @@ -139,9 +138,9 @@ public class G726_24 extends G726 { |
| 139 | 138 | * It returns the actual size of the output data, or -1 in case of unknown |
| 140 | 139 | * in_coding value. */ |
| 141 | 140 | public static int encode(byte[] in_buff, int in_offset, int in_len, int in_coding, byte[] out_buff, int out_offset, G726State state) { |
| 142 | - | |
| 141 | + | |
| 143 | 142 | if (in_coding==AUDIO_ENCODING_ALAW || in_coding==AUDIO_ENCODING_ULAW) { |
| 144 | - | |
| 143 | + | |
| 145 | 144 | int len_div_8=in_len/8; |
| 146 | 145 | for (int i=0; i<len_div_8; i++) { |
| 147 | 146 | int value8=0; |
| ... | ... | @@ -160,7 +159,7 @@ public class G726_24 extends G726 { |
| 160 | 159 | } |
| 161 | 160 | else |
| 162 | 161 | if (in_coding==AUDIO_ENCODING_LINEAR) { |
| 163 | - | |
| 162 | + | |
| 164 | 163 | int len_div_16=in_len/16; |
| 165 | 164 | for (int i=0; i<len_div_16; i++) { |
| 166 | 165 | int value16=0; |
| ... | ... | @@ -188,9 +187,9 @@ public class G726_24 extends G726 { |
| 188 | 187 | * It returns the actual size of the output data, or -1 in case of unknown |
| 189 | 188 | * out_coding value. */ |
| 190 | 189 | public static int decode(byte[] in_buff, int in_offset, int in_len, int out_coding, byte[] out_buff, int out_offset, G726State state) { |
| 191 | - | |
| 190 | + | |
| 192 | 191 | if (out_coding==AUDIO_ENCODING_ALAW || out_coding==AUDIO_ENCODING_ULAW) { |
| 193 | - | |
| 192 | + | |
| 194 | 193 | int len_div_3=in_len/3; |
| 195 | 194 | for (int i=0; i<len_div_3; i++) { |
| 196 | 195 | int value8=0; |
| ... | ... | @@ -209,7 +208,7 @@ public class G726_24 extends G726 { |
| 209 | 208 | } |
| 210 | 209 | else |
| 211 | 210 | if (out_coding==AUDIO_ENCODING_LINEAR) { |
| 212 | - | |
| 211 | + | |
| 213 | 212 | int len_div_3=in_len/3; |
| 214 | 213 | for (int i=0; i<len_div_3; i++) { |
| 215 | 214 | int value16=0; | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/codec/g726/G726_32.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/codec/g726/G726_32.java
| 1 | 1 | |
| 2 | -package com.genersoft.iot.vmp.jt1078.codec.g726; | |
| 2 | +package com.genersoft.iot.vmp.jtt1078.codec.g726; | |
| 3 | 3 | |
| 4 | - | |
| 5 | -import com.genersoft.iot.vmp.jt1078.codec.G711Codec; | |
| 6 | -import com.genersoft.iot.vmp.jt1078.codec.G711UCodec; | |
| 4 | +import com.genersoft.iot.vmp.jtt1078.codec.G711Codec; | |
| 5 | +import com.genersoft.iot.vmp.jtt1078.codec.G711UCodec; | |
| 7 | 6 | |
| 8 | 7 | /** G726_32 encoder and decoder. |
| 9 | 8 | * <p> |
| ... | ... | @@ -31,7 +30,7 @@ import com.genersoft.iot.vmp.jt1078.codec.G711UCodec; |
| 31 | 30 | * ANSI-C source code to the public domain. |
| 32 | 31 | */ |
| 33 | 32 | public class G726_32 extends G726 { |
| 34 | - | |
| 33 | + | |
| 35 | 34 | // ##### C-to-Java conversion: ##### |
| 36 | 35 | // short becomes int |
| 37 | 36 | // char becomes int |
| ... | ... | @@ -46,7 +45,7 @@ public class G726_32 extends G726 { |
| 46 | 45 | * magnitude values. |
| 47 | 46 | */ |
| 48 | 47 | static /*short*/int[] _dqlntab={-2048, 4, 135, 213, 273, 323, 373, 425, 425, 373, 323, 273, 213, 135, 4, -2048}; |
| 49 | - | |
| 48 | + | |
| 50 | 49 | /* Maps G726_32 code word to log of scale factor multiplier. */ |
| 51 | 50 | static /*short*/int[] _witab={-12, 18, 41, 64, 112, 198, 355, 1122, 1122, 355, 198, 112, 64, 41, 18, -12}; |
| 52 | 51 | |
| ... | ... | @@ -56,18 +55,18 @@ public class G726_32 extends G726 { |
| 56 | 55 | * how stationary (steady state) the signal is. |
| 57 | 56 | */ |
| 58 | 57 | static /*short*/int[] _fitab={0, 0, 0, 0x200, 0x200, 0x200, 0x600, 0xE00, 0xE00, 0x600, 0x200, 0x200, 0x200, 0, 0, 0}; |
| 59 | - | |
| 58 | + | |
| 60 | 59 | /** Encodes the input vale of linear PCM, A-law or u-law data sl and returns |
| 61 | 60 | * the resulting code. -1 is returned for unknown input coding value. */ |
| 62 | 61 | public static int encode(int sl, int in_coding, G726State state) { |
| 63 | - | |
| 62 | + | |
| 64 | 63 | /*short*/int sezi, se, sez; /* ACCUM */ |
| 65 | 64 | /*short*/int d; /* SUBTA */ |
| 66 | 65 | /*short*/int sr; /* ADDB */ |
| 67 | 66 | /*short*/int y; /* MIX */ |
| 68 | 67 | /*short*/int dqsez; /* ADDC */ |
| 69 | 68 | /*short*/int dq, i; |
| 70 | - | |
| 69 | + | |
| 71 | 70 | switch (in_coding) { |
| 72 | 71 | /* linearize input sample to 14-bit PCM */ |
| 73 | 72 | case AUDIO_ENCODING_ALAW: |
| ... | ... | @@ -82,57 +81,57 @@ public class G726_32 extends G726 { |
| 82 | 81 | default: |
| 83 | 82 | return -1; |
| 84 | 83 | } |
| 85 | - | |
| 84 | + | |
| 86 | 85 | sezi=state.predictor_zero(); |
| 87 | 86 | sez=sezi >> 1; |
| 88 | 87 | se=(sezi+state.predictor_pole()) >> 1; /* estimated signal */ |
| 89 | - | |
| 88 | + | |
| 90 | 89 | d=sl-se; /* estimation difference */ |
| 91 | - | |
| 90 | + | |
| 92 | 91 | /* quantize the prediction difference */ |
| 93 | 92 | y=state.step_size(); /* quantizer step size */ |
| 94 | 93 | i=quantize(d, y, qtab_721, 7); /* i=ADPCM code */ |
| 95 | - | |
| 94 | + | |
| 96 | 95 | dq=reconstruct(i & 8, _dqlntab[i], y); /* quantized est diff */ |
| 97 | - | |
| 96 | + | |
| 98 | 97 | sr=(dq<0)? se-(dq & 0x3FFF) : se+dq; /* reconst. signal */ |
| 99 | - | |
| 98 | + | |
| 100 | 99 | dqsez=sr+sez-se; /* pole prediction diff. */ |
| 101 | - | |
| 100 | + | |
| 102 | 101 | update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state); |
| 103 | - | |
| 102 | + | |
| 104 | 103 | return i; |
| 105 | 104 | } |
| 106 | - | |
| 105 | + | |
| 107 | 106 | /** Decodes a 4-bit code of G726_32 encoded data of i and |
| 108 | 107 | * returns the resulting linear PCM, A-law or u-law value. |
| 109 | 108 | * return -1 for unknown out_coding value. */ |
| 110 | 109 | public static int decode(int i, int out_coding, G726State state) { |
| 111 | - | |
| 110 | + | |
| 112 | 111 | /*short*/int sezi, sei, sez, se; /* ACCUM */ |
| 113 | 112 | /*short*/int y; /* MIX */ |
| 114 | 113 | /*short*/int sr; /* ADDB */ |
| 115 | 114 | /*short*/int dq; |
| 116 | 115 | /*short*/int dqsez; |
| 117 | - | |
| 116 | + | |
| 118 | 117 | i &= 0x0f; /* mask to get proper bits */ |
| 119 | 118 | sezi=state.predictor_zero(); |
| 120 | 119 | sez=sezi >> 1; |
| 121 | 120 | sei=sezi+state.predictor_pole(); |
| 122 | 121 | se=sei >> 1; /* se=estimated signal */ |
| 123 | - | |
| 122 | + | |
| 124 | 123 | y=state.step_size(); /* dynamic quantizer step size */ |
| 125 | - | |
| 124 | + | |
| 126 | 125 | dq=reconstruct(i & 0x08, _dqlntab[i], y); /* quantized diff. */ |
| 127 | - | |
| 126 | + | |
| 128 | 127 | sr=(dq<0)? (se-(dq & 0x3FFF)) : se+dq; /* reconst. signal */ |
| 129 | - | |
| 128 | + | |
| 130 | 129 | dqsez=sr-se+sez; /* pole prediction diff. */ |
| 131 | - | |
| 130 | + | |
| 132 | 131 | update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state); |
| 133 | - | |
| 132 | + | |
| 134 | 133 | switch (out_coding) { |
| 135 | - | |
| 134 | + | |
| 136 | 135 | case AUDIO_ENCODING_ALAW: |
| 137 | 136 | return (tandem_adjust_alaw(sr, se, y, i, 8, qtab_721)); |
| 138 | 137 | case AUDIO_ENCODING_ULAW: |
| ... | ... | @@ -150,9 +149,9 @@ public class G726_32 extends G726 { |
| 150 | 149 | * It returns the actual size of the output data, or -1 in case of unknown |
| 151 | 150 | * in_coding value. */ |
| 152 | 151 | public static int encode(byte[] in_buff, int in_offset, int in_len, int in_coding, byte[] out_buff, int out_offset, G726State state) { |
| 153 | - | |
| 152 | + | |
| 154 | 153 | if (in_coding==AUDIO_ENCODING_ALAW || in_coding==AUDIO_ENCODING_ULAW) { |
| 155 | - | |
| 154 | + | |
| 156 | 155 | /* |
| 157 | 156 | for (int i=0; i<in_len; i++) { |
| 158 | 157 | int in_value=in_buff[in_offset+i]; |
| ... | ... | @@ -170,25 +169,25 @@ public class G726_32 extends G726 { |
| 170 | 169 | int in_index=in_offset+i*2; |
| 171 | 170 | int in_value1=in_buff[in_index]; |
| 172 | 171 | int in_value2=in_buff[in_index+1]; |
| 173 | - int out_value1=encode(in_value1,in_coding,state); | |
| 174 | - int out_value2=encode(in_value2,in_coding,state); | |
| 172 | + int out_value1=encode(in_value1,in_coding,state); | |
| 173 | + int out_value2=encode(in_value2,in_coding,state); | |
| 175 | 174 | out_buff[out_offset+i]=(byte)((out_value1<<4) + out_value2); |
| 176 | 175 | } |
| 177 | 176 | return len_div_2; |
| 178 | 177 | } |
| 179 | 178 | else |
| 180 | 179 | if (in_coding==AUDIO_ENCODING_LINEAR) { |
| 181 | - | |
| 180 | + | |
| 182 | 181 | int len_div_4=in_len/4; |
| 183 | 182 | for (int i=0; i<len_div_4; i++) { |
| 184 | 183 | int in_index=in_offset+i*4; |
| 185 | 184 | int in_value1=signedIntLittleEndian(in_buff[in_index+1],in_buff[in_index+0]); |
| 186 | 185 | int in_value2=signedIntLittleEndian(in_buff[in_index+3],in_buff[in_index+2]); |
| 187 | 186 | |
| 188 | - //int out_value1=encode(G711.linear2ulaw(in_value1),AUDIO_ENCODING_ULAW,state); | |
| 189 | - //int out_value2=encode(G711.linear2ulaw(in_value2),AUDIO_ENCODING_ULAW,state); | |
| 190 | - int out_value1=encode(in_value1,in_coding,state); | |
| 191 | - int out_value2=encode(in_value2,in_coding,state); | |
| 187 | + //int out_value1=encode(G711.linear2ulaw(in_value1),AUDIO_ENCODING_ULAW,state); | |
| 188 | + //int out_value2=encode(G711.linear2ulaw(in_value2),AUDIO_ENCODING_ULAW,state); | |
| 189 | + int out_value1=encode(in_value1,in_coding,state); | |
| 190 | + int out_value2=encode(in_value2,in_coding,state); | |
| 192 | 191 | out_buff[out_offset+i]=(byte)((out_value1<<4) + out_value2); |
| 193 | 192 | } |
| 194 | 193 | return len_div_4; |
| ... | ... | @@ -202,24 +201,24 @@ public class G726_32 extends G726 { |
| 202 | 201 | * It returns the actual size of the output data, or -1 in case of unknown |
| 203 | 202 | * out_coding value. */ |
| 204 | 203 | public static int decode(byte[] in_buff, int in_offset, int in_len, int out_coding, byte[] out_buff, int out_offset, G726State state) { |
| 205 | - | |
| 204 | + | |
| 206 | 205 | if (out_coding==AUDIO_ENCODING_ALAW || out_coding==AUDIO_ENCODING_ULAW) { |
| 207 | - | |
| 206 | + | |
| 208 | 207 | /* |
| 209 | 208 | for (int i=0; i<in_len*2; i++) { |
| 210 | 209 | int in_value=unsignedInt(in_buff[in_offset+i/2]); |
| 211 | 210 | if ((i/2)*2==i) |
| 212 | 211 | in_value>>=4; |
| 213 | 212 | else |
| 214 | - in_value%=0x10; | |
| 215 | - int out_value=decode(in_value,out_coding,state); | |
| 213 | + in_value%=0x10; | |
| 214 | + int out_value=decode(in_value,out_coding,state); | |
| 216 | 215 | out_buff[out_offset+i]=(byte)out_value; |
| 217 | 216 | } |
| 218 | 217 | return in_len*2; |
| 219 | 218 | */ |
| 220 | 219 | for (int i=0; i<in_len; i++) { |
| 221 | 220 | int in_value=unsignedInt(in_buff[in_offset+i]); |
| 222 | - int out_value1=decode(in_value>>4,out_coding,state); | |
| 221 | + int out_value1=decode(in_value>>4,out_coding,state); | |
| 223 | 222 | int out_value2=decode(in_value&0xF,out_coding,state); |
| 224 | 223 | int out_index=out_offset+i*2; |
| 225 | 224 | out_buff[out_index]=(byte)out_value1; |
| ... | ... | @@ -229,12 +228,12 @@ public class G726_32 extends G726 { |
| 229 | 228 | } |
| 230 | 229 | else |
| 231 | 230 | if (out_coding==AUDIO_ENCODING_LINEAR) { |
| 232 | - | |
| 231 | + | |
| 233 | 232 | for (int i=0; i<in_len; i++) { |
| 234 | 233 | int in_value=unsignedInt(in_buff[in_offset+i]); |
| 235 | - //int out_value1=G711.ulaw2linear(decode(in_value>>4,AUDIO_ENCODING_ULAW,state)); | |
| 234 | + //int out_value1=G711.ulaw2linear(decode(in_value>>4,AUDIO_ENCODING_ULAW,state)); | |
| 236 | 235 | //int out_value2=G711.ulaw2linear(decode(in_value&0xF,AUDIO_ENCODING_ULAW,state)); |
| 237 | - int out_value1=decode(in_value>>4,out_coding,state); | |
| 236 | + int out_value1=decode(in_value>>4,out_coding,state); | |
| 238 | 237 | int out_value2=decode(in_value&0xF,out_coding,state); |
| 239 | 238 | int out_index=out_offset+i*4; |
| 240 | 239 | out_buff[out_index]=(byte)(out_value1&0xFF); | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/codec/g726/G726_40.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/codec/g726/G726_40.java
| 1 | -package com.genersoft.iot.vmp.jt1078.codec.g726; | |
| 1 | +package com.genersoft.iot.vmp.jtt1078.codec.g726; | |
| 2 | 2 | |
| 3 | - | |
| 4 | -import com.genersoft.iot.vmp.jt1078.codec.G711Codec; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.codec.G711UCodec; | |
| 3 | +import com.genersoft.iot.vmp.jtt1078.codec.G711Codec; | |
| 4 | +import com.genersoft.iot.vmp.jtt1078.codec.G711UCodec; | |
| 6 | 5 | |
| 7 | 6 | /** G726_40 encoder and decoder. |
| 8 | 7 | * <p> |
| ... | ... | @@ -27,12 +26,12 @@ import com.genersoft.iot.vmp.jt1078.codec.G711UCodec; |
| 27 | 26 | * ANSI-C source code to the public domain. |
| 28 | 27 | */ |
| 29 | 28 | public class G726_40 extends G726 { |
| 30 | - | |
| 29 | + | |
| 31 | 30 | // ##### C-to-Java conversion: ##### |
| 32 | 31 | // short becomes int |
| 33 | 32 | // char becomes int |
| 34 | 33 | // unsigned char becomes int |
| 35 | - | |
| 34 | + | |
| 36 | 35 | |
| 37 | 36 | // *************************** STATIC *************************** |
| 38 | 37 | |
| ... | ... | @@ -41,31 +40,31 @@ public class G726_40 extends G726 { |
| 41 | 40 | * magnitude values. |
| 42 | 41 | */ |
| 43 | 42 | static /*short*/int[] _dqlntab={-2048, -66, 28, 104, 169, 224, 274, 318, 358, 395, 429, 459, 488, 514, 539, 566, 566, 539, 514, 488, 459, 429, 395, 358, 318, 274, 224, 169, 104, 28, -66, -2048}; |
| 44 | - | |
| 43 | + | |
| 45 | 44 | /* Maps G723_40 code word to log of scale factor multiplier. */ |
| 46 | 45 | static /*short*/int[] _witab={448, 448, 768, 1248, 1280, 1312, 1856, 3200, 4512, 5728, 7008, 8960, 11456, 14080, 16928, 22272, 22272, 16928, 14080, 11456, 8960, 7008, 5728, 4512, 3200, 1856, 1312, 1280, 1248, 768, 448, 448}; |
| 47 | - | |
| 46 | + | |
| 48 | 47 | /* |
| 49 | 48 | * Maps G723_40 code words to a set of values whose long and short |
| 50 | 49 | * term averages are computed and then compared to give an indication |
| 51 | 50 | * how stationary (steady state) the signal is. |
| 52 | 51 | */ |
| 53 | 52 | static /*short*/int[] _fitab={0, 0, 0, 0, 0, 0x200, 0x200, 0x200, 0x200, 0x200, 0x400, 0x600, 0x800, 0xA00, 0xC00, 0xC00, 0xC00, 0xC00, 0xA00, 0x800, 0x600, 0x400, 0x200, 0x200, 0x200, 0x200, 0x200, 0, 0, 0, 0, 0}; |
| 54 | - | |
| 53 | + | |
| 55 | 54 | static /*short*/int[] qtab_723_40={-122, -16, 68, 139, 198, 250, 298, 339, 378, 413, 445, 475, 502, 528, 553}; |
| 56 | - | |
| 55 | + | |
| 57 | 56 | /** Encodes a 16-bit linear PCM, A-law or u-law input sample and retuens |
| 58 | 57 | * the resulting 5-bit CCITT G726 40kbps code. |
| 59 | 58 | * Returns -1 if the input coding value is invalid. */ |
| 60 | 59 | public static int encode(int sl, int in_coding, G726State state) { |
| 61 | - | |
| 60 | + | |
| 62 | 61 | /*short*/int sei, sezi, se, sez; /* ACCUM */ |
| 63 | 62 | /*short*/int d; /* SUBTA */ |
| 64 | 63 | /*short*/int y; /* MIX */ |
| 65 | 64 | /*short*/int sr; /* ADDB */ |
| 66 | 65 | /*short*/int dqsez; /* ADDC */ |
| 67 | 66 | /*short*/int dq, i; |
| 68 | - | |
| 67 | + | |
| 69 | 68 | switch (in_coding) { |
| 70 | 69 | /* linearize input sample to 14-bit PCM */ |
| 71 | 70 | case AUDIO_ENCODING_ALAW: |
| ... | ... | @@ -80,58 +79,58 @@ public class G726_40 extends G726 { |
| 80 | 79 | default: |
| 81 | 80 | return (-1); |
| 82 | 81 | } |
| 83 | - | |
| 82 | + | |
| 84 | 83 | sezi=state.predictor_zero(); |
| 85 | 84 | sez=sezi >> 1; |
| 86 | 85 | sei=sezi+state.predictor_pole(); |
| 87 | 86 | se=sei >> 1; /* se=estimated signal */ |
| 88 | - | |
| 87 | + | |
| 89 | 88 | d=sl-se; /* d=estimation difference */ |
| 90 | - | |
| 89 | + | |
| 91 | 90 | /* quantize prediction difference */ |
| 92 | 91 | y=state.step_size(); /* adaptive quantizer step size */ |
| 93 | 92 | i=quantize(d, y, qtab_723_40, 15); /* i=ADPCM code */ |
| 94 | - | |
| 93 | + | |
| 95 | 94 | dq=reconstruct(i & 0x10, _dqlntab[i], y); /* quantized diff */ |
| 96 | - | |
| 95 | + | |
| 97 | 96 | sr=(dq<0)? se-(dq & 0x7FFF) : se+dq; /* reconstructed signal */ |
| 98 | - | |
| 97 | + | |
| 99 | 98 | dqsez=sr+sez-se; /* dqsez=pole prediction diff. */ |
| 100 | - | |
| 99 | + | |
| 101 | 100 | update(5, y, _witab[i], _fitab[i], dq, sr, dqsez, state); |
| 102 | - | |
| 101 | + | |
| 103 | 102 | return (i); |
| 104 | 103 | } |
| 105 | 104 | |
| 106 | - | |
| 105 | + | |
| 107 | 106 | /** Decodes a 5-bit CCITT G.726 40kbps code and returns |
| 108 | 107 | * the resulting 16-bit linear PCM, A-law or u-law sample value. |
| 109 | 108 | * -1 is returned if the output coding is unknown. */ |
| 110 | 109 | public static int decode(int i, int out_coding, G726State state) { |
| 111 | - | |
| 110 | + | |
| 112 | 111 | /*short*/int sezi, sei, sez, se; /* ACCUM */ |
| 113 | 112 | /*short*/int y, dif; /* MIX */ |
| 114 | 113 | /*short*/int sr; /* ADDB */ |
| 115 | 114 | /*short*/int dq; |
| 116 | 115 | /*short*/int dqsez; |
| 117 | - | |
| 116 | + | |
| 118 | 117 | i &= 0x1f; /* mask to get proper bits */ |
| 119 | 118 | sezi=state.predictor_zero(); |
| 120 | 119 | sez=sezi >> 1; |
| 121 | 120 | sei=sezi+state.predictor_pole(); |
| 122 | 121 | se=sei >> 1; /* se=estimated signal */ |
| 123 | - | |
| 122 | + | |
| 124 | 123 | y=state.step_size(); /* adaptive quantizer step size */ |
| 125 | 124 | dq=reconstruct(i & 0x10, _dqlntab[i], y); /* estimation diff. */ |
| 126 | - | |
| 125 | + | |
| 127 | 126 | sr=(dq<0)? (se-(dq & 0x7FFF)) : (se+dq); /* reconst. signal */ |
| 128 | - | |
| 127 | + | |
| 129 | 128 | dqsez=sr-se+sez; /* pole prediction diff. */ |
| 130 | - | |
| 129 | + | |
| 131 | 130 | update(5, y, _witab[i], _fitab[i], dq, sr, dqsez, state); |
| 132 | - | |
| 131 | + | |
| 133 | 132 | switch (out_coding) { |
| 134 | - | |
| 133 | + | |
| 135 | 134 | case AUDIO_ENCODING_ALAW: |
| 136 | 135 | return (tandem_adjust_alaw(sr, se, y, i, 0x10, qtab_723_40)); |
| 137 | 136 | case AUDIO_ENCODING_ULAW: |
| ... | ... | @@ -149,9 +148,9 @@ public class G726_40 extends G726 { |
| 149 | 148 | * It returns the actual size of the output data, or -1 in case of unknown |
| 150 | 149 | * in_coding value. */ |
| 151 | 150 | public static int encode(byte[] in_buff, int in_offset, int in_len, int in_coding, byte[] out_buff, int out_offset, G726State state) { |
| 152 | - | |
| 151 | + | |
| 153 | 152 | if (in_coding==AUDIO_ENCODING_ALAW || in_coding==AUDIO_ENCODING_ULAW) { |
| 154 | - | |
| 153 | + | |
| 155 | 154 | int len_div_8=in_len/8; |
| 156 | 155 | for (int i=0; i<len_div_8; i++) { |
| 157 | 156 | long value8=0; |
| ... | ... | @@ -170,7 +169,7 @@ public class G726_40 extends G726 { |
| 170 | 169 | } |
| 171 | 170 | else |
| 172 | 171 | if (in_coding==AUDIO_ENCODING_LINEAR) { |
| 173 | - | |
| 172 | + | |
| 174 | 173 | int len_div_16=in_len/16; |
| 175 | 174 | for (int i=0; i<len_div_16; i++) { |
| 176 | 175 | long value16=0; |
| ... | ... | @@ -197,9 +196,9 @@ public class G726_40 extends G726 { |
| 197 | 196 | * It returns the actual size of the output data, or -1 in case of unknown |
| 198 | 197 | * out_coding value. */ |
| 199 | 198 | public static int decode(byte[] in_buff, int in_offset, int in_len, int out_coding, byte[] out_buff, int out_offset, G726State state) { |
| 200 | - | |
| 199 | + | |
| 201 | 200 | if (out_coding==AUDIO_ENCODING_ALAW || out_coding==AUDIO_ENCODING_ULAW) { |
| 202 | - | |
| 201 | + | |
| 203 | 202 | int len_div_5=in_len/5; |
| 204 | 203 | for (int i=0; i<len_div_5; i++) { |
| 205 | 204 | long value8=0; |
| ... | ... | @@ -218,7 +217,7 @@ public class G726_40 extends G726 { |
| 218 | 217 | } |
| 219 | 218 | else |
| 220 | 219 | if (out_coding==AUDIO_ENCODING_LINEAR) { |
| 221 | - | |
| 220 | + | |
| 222 | 221 | int len_div_5=in_len/5; |
| 223 | 222 | for (int i=0; i<len_div_5; i++) { |
| 224 | 223 | long value16=0; | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/entity/Audio.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/entity/Audio.java
src/main/java/com/genersoft/iot/vmp/jt1078/entity/Media.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/entity/Media.java
src/main/java/com/genersoft/iot/vmp/jt1078/entity/MediaEncoding.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/entity/MediaEncoding.java
src/main/java/com/genersoft/iot/vmp/jt1078/entity/Video.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/entity/Video.java
| 1 | -package com.genersoft.iot.vmp.jt1078.entity; | |
| 1 | +package com.genersoft.iot.vmp.jtt1078.entity; | |
| 2 | 2 | |
| 3 | 3 | /** |
| 4 | 4 | * Created by houcheng on 2019-12-11. |
| 5 | 5 | */ |
| 6 | -public class Video extends Media { | |
| 7 | - public Video(long sequence, MediaEncoding.Encoding encoding, byte[] data) { | |
| 6 | +public class Video extends Media | |
| 7 | +{ | |
| 8 | + public Video(long sequence, MediaEncoding.Encoding encoding, byte[] data) | |
| 9 | + { | |
| 8 | 10 | super(sequence, encoding, data); |
| 9 | 11 | } |
| 10 | 12 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/flv/AudioTag.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/flv/AudioTag.java
src/main/java/com/genersoft/iot/vmp/jt1078/flv/FlvAudioTagEncoder.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/flv/FlvAudioTagEncoder.java
src/main/java/com/genersoft/iot/vmp/jt1078/flv/FlvEncoder.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/flv/FlvEncoder.java
| 1 | -package com.genersoft.iot.vmp.jt1078.flv; | |
| 1 | +package com.genersoft.iot.vmp.jtt1078.flv; | |
| 2 | 2 | |
| 3 | -import com.genersoft.iot.vmp.jt1078.util.Packet; | |
| 3 | +import com.genersoft.iot.vmp.jtt1078.util.Packet; | |
| 4 | 4 | |
| 5 | 5 | import java.io.ByteArrayOutputStream; |
| 6 | -import java.io.IOException; | |
| 7 | -import java.io.OutputStream; | |
| 8 | 6 | |
| 9 | 7 | /** |
| 10 | 8 | * Created by matrixy on 2020/1/3. | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/flv/FlvTag.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/flv/FlvTag.java
src/main/java/com/genersoft/iot/vmp/jt1078/http/GeneralResponseWriter.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/http/GeneralResponseWriter.java
src/main/java/com/genersoft/iot/vmp/jtt1078/http/NettyHttpServerHandler.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.jtt1078.http; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.jtt1078.entity.Media; | |
| 4 | +import com.genersoft.iot.vmp.jtt1078.publisher.PublishManager; | |
| 5 | +import com.genersoft.iot.vmp.jtt1078.server.Session; | |
| 6 | +import com.genersoft.iot.vmp.jtt1078.util.*; | |
| 7 | +import io.netty.buffer.ByteBuf; | |
| 8 | +import io.netty.buffer.Unpooled; | |
| 9 | +import io.netty.channel.ChannelHandlerContext; | |
| 10 | +import io.netty.channel.ChannelInboundHandlerAdapter; | |
| 11 | +import io.netty.handler.codec.http.*; | |
| 12 | +import io.netty.util.Attribute; | |
| 13 | +import io.netty.util.AttributeKey; | |
| 14 | +import org.slf4j.Logger; | |
| 15 | +import org.slf4j.LoggerFactory; | |
| 16 | + | |
| 17 | +/** | |
| 18 | + * Created by matrixy on 2019/8/13. | |
| 19 | + */ | |
| 20 | +public class NettyHttpServerHandler extends ChannelInboundHandlerAdapter | |
| 21 | +{ | |
| 22 | + static Logger logger = LoggerFactory.getLogger(NettyHttpServerHandler.class); | |
| 23 | + static final byte[] HTTP_403_DATA = "<h1>403 Forbidden</h1><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding--><!--padding-->".getBytes(); | |
| 24 | + static final String HEADER_ENCODING = "ISO-8859-1"; | |
| 25 | + | |
| 26 | + private static final AttributeKey<Session> SESSION_KEY = AttributeKey.valueOf("session"); | |
| 27 | + | |
| 28 | + @Override | |
| 29 | + public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception | |
| 30 | + { | |
| 31 | + FullHttpRequest fhr = (FullHttpRequest) msg; | |
| 32 | + String uri = fhr.uri(); | |
| 33 | + Packet resp = Packet.create(1024); | |
| 34 | + // uri的第二段,就是通道标签 | |
| 35 | + if (uri.startsWith("/video/")) | |
| 36 | + { | |
| 37 | + String tag = uri.substring("/video/".length()); | |
| 38 | + resp.addBytes("HTTP/1.1 200 OK\r\n".getBytes(HEADER_ENCODING)); | |
| 39 | + resp.addBytes("Connection: keep-alive\r\n".getBytes(HEADER_ENCODING)); | |
| 40 | + resp.addBytes("Content-Type: video/x-flv\r\n".getBytes(HEADER_ENCODING)); | |
| 41 | + resp.addBytes("Transfer-Encoding: chunked\r\n".getBytes(HEADER_ENCODING)); | |
| 42 | + resp.addBytes("Cache-Control: no-cache\r\n".getBytes(HEADER_ENCODING)); | |
| 43 | + resp.addBytes("Access-Control-Allow-Origin: *\r\n".getBytes(HEADER_ENCODING)); | |
| 44 | + resp.addBytes("Access-Control-Allow-Credentials: true\r\n".getBytes(HEADER_ENCODING)); | |
| 45 | + resp.addBytes("\r\n".getBytes(HEADER_ENCODING)); | |
| 46 | + | |
| 47 | + ctx.writeAndFlush(resp.getBytes()).await(); | |
| 48 | + | |
| 49 | + // 订阅视频数据 | |
| 50 | + long wid = PublishManager.getInstance().subscribe(tag, Media.Type.Video, ctx).getId(); | |
| 51 | + setSession(ctx, new Session().set("subscriber-id", wid).set("tag", tag)); | |
| 52 | + | |
| 53 | + } | |
| 54 | + else if (uri.equals("/test/multimedia")) | |
| 55 | + { | |
| 56 | + responseHTMLFile("/multimedia.html", ctx); | |
| 57 | + } | |
| 58 | + else | |
| 59 | + { | |
| 60 | + ByteBuf body = Unpooled.buffer(HTTP_403_DATA.length); | |
| 61 | + body.writeBytes(HTTP_403_DATA); | |
| 62 | + FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(403), body); | |
| 63 | + response.headers().add("Content-Length", HTTP_403_DATA.length); | |
| 64 | + ctx.writeAndFlush(response).await(); | |
| 65 | + ctx.flush(); | |
| 66 | + } | |
| 67 | + } | |
| 68 | + | |
| 69 | + @Override | |
| 70 | + public void channelInactive(ChannelHandlerContext ctx) throws Exception | |
| 71 | + { | |
| 72 | + super.channelInactive(ctx); | |
| 73 | + Session session = getSession(ctx); | |
| 74 | + if (session != null && session.has("subscriber-id") && session.has("tag")) | |
| 75 | + { | |
| 76 | + String tag = session.get("tag"); | |
| 77 | + Long wid = session.get("subscriber-id"); | |
| 78 | + PublishManager.getInstance().unsubscribe(tag, wid); | |
| 79 | + } | |
| 80 | + } | |
| 81 | + | |
| 82 | + // 响应静态文件内容 | |
| 83 | + private void responseHTMLFile(String htmlFilePath, ChannelHandlerContext ctx) | |
| 84 | + { | |
| 85 | + byte[] fileData = FileUtils.read(NettyHttpServerHandler.class.getResourceAsStream(htmlFilePath)); | |
| 86 | + ByteBuf body = Unpooled.buffer(fileData.length); | |
| 87 | + body.writeBytes(fileData); | |
| 88 | + FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(200), body); | |
| 89 | + response.headers().add("Content-Length", fileData.length); | |
| 90 | + ctx.write(response); | |
| 91 | + ctx.flush(); | |
| 92 | + } | |
| 93 | + | |
| 94 | + @Override | |
| 95 | + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception | |
| 96 | + { | |
| 97 | + ctx.flush(); | |
| 98 | + } | |
| 99 | + | |
| 100 | + @Override | |
| 101 | + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception | |
| 102 | + { | |
| 103 | + ctx.close(); | |
| 104 | + cause.printStackTrace(); | |
| 105 | + } | |
| 106 | + | |
| 107 | + public final void setSession(ChannelHandlerContext context, Session session) | |
| 108 | + { | |
| 109 | + context.channel().attr(SESSION_KEY).set(session); | |
| 110 | + } | |
| 111 | + | |
| 112 | + public final Session getSession(ChannelHandlerContext context) | |
| 113 | + { | |
| 114 | + Attribute<Session> attr = context.channel().attr(SESSION_KEY); | |
| 115 | + if (null == attr) return null; | |
| 116 | + else return attr.get(); | |
| 117 | + } | |
| 118 | +} | |
| 119 | + | ... | ... |
src/main/java/com/genersoft/iot/vmp/jtt1078/publisher/Channel.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.jtt1078.publisher; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.jtt1078.app.VideoServerApp; | |
| 4 | +import com.genersoft.iot.vmp.jtt1078.codec.AudioCodec; | |
| 5 | +import com.genersoft.iot.vmp.jtt1078.entity.Media; | |
| 6 | +import com.genersoft.iot.vmp.jtt1078.entity.MediaEncoding; | |
| 7 | +import com.genersoft.iot.vmp.jtt1078.flv.FlvEncoder; | |
| 8 | +import com.genersoft.iot.vmp.jtt1078.subscriber.RTMPPublisher; | |
| 9 | +import com.genersoft.iot.vmp.jtt1078.subscriber.Subscriber; | |
| 10 | +import com.genersoft.iot.vmp.jtt1078.subscriber.VideoSubscriber; | |
| 11 | +import com.genersoft.iot.vmp.jtt1078.util.ByteHolder; | |
| 12 | +import com.genersoft.iot.vmp.jtt1078.util.Configs; | |
| 13 | +import io.netty.channel.ChannelHandlerContext; | |
| 14 | +import org.apache.commons.lang3.StringUtils; | |
| 15 | +import org.slf4j.Logger; | |
| 16 | +import org.slf4j.LoggerFactory; | |
| 17 | + | |
| 18 | +import java.util.Iterator; | |
| 19 | +import java.util.concurrent.ConcurrentLinkedQueue; | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * Created by matrixy on 2020/1/11. | |
| 23 | + */ | |
| 24 | +public class Channel | |
| 25 | +{ | |
| 26 | + static Logger logger = LoggerFactory.getLogger(Channel.class); | |
| 27 | + | |
| 28 | + ConcurrentLinkedQueue<Subscriber> subscribers; | |
| 29 | + RTMPPublisher rtmpPublisher; | |
| 30 | + | |
| 31 | + String tag; | |
| 32 | + boolean publishing; | |
| 33 | + ByteHolder buffer; | |
| 34 | + AudioCodec audioCodec; | |
| 35 | + FlvEncoder flvEncoder; | |
| 36 | + private long firstTimestamp = -1; | |
| 37 | + | |
| 38 | + public Channel(String tag) | |
| 39 | + { | |
| 40 | + this.tag = tag; | |
| 41 | + this.subscribers = new ConcurrentLinkedQueue<Subscriber>(); | |
| 42 | + this.flvEncoder = new FlvEncoder(true, true); | |
| 43 | + this.buffer = new ByteHolder(2048 * 100); | |
| 44 | + | |
| 45 | + if (!StringUtils.isEmpty(Configs.get("rtmp.url"))) | |
| 46 | + { | |
| 47 | + rtmpPublisher = new RTMPPublisher(tag); | |
| 48 | + rtmpPublisher.start(); | |
| 49 | + } | |
| 50 | + } | |
| 51 | + | |
| 52 | + public boolean isPublishing() | |
| 53 | + { | |
| 54 | + return publishing; | |
| 55 | + } | |
| 56 | + | |
| 57 | + public Subscriber subscribe(ChannelHandlerContext ctx) | |
| 58 | + { | |
| 59 | + logger.info("channel: {} -> {}, subscriber: {}", Long.toHexString(hashCode() & 0xffffffffL), tag, ctx.channel().remoteAddress().toString()); | |
| 60 | + | |
| 61 | + Subscriber subscriber = new VideoSubscriber(this.tag, ctx); | |
| 62 | + this.subscribers.add(subscriber); | |
| 63 | + return subscriber; | |
| 64 | + } | |
| 65 | + | |
| 66 | + public void writeAudio(long timestamp, int pt, byte[] data) | |
| 67 | + { | |
| 68 | + if (audioCodec == null) | |
| 69 | + { | |
| 70 | + audioCodec = AudioCodec.getCodec(pt); | |
| 71 | + logger.info("audio codec: {}", MediaEncoding.getEncoding(Media.Type.Audio, pt)); | |
| 72 | + } | |
| 73 | + broadcastAudio(timestamp, audioCodec.toPCM(data)); | |
| 74 | + } | |
| 75 | + | |
| 76 | + public void writeVideo(long sequence, long timeoffset, int payloadType, byte[] h264) | |
| 77 | + { | |
| 78 | + if (firstTimestamp == -1) firstTimestamp = timeoffset; | |
| 79 | + this.publishing = true; | |
| 80 | + this.buffer.write(h264); | |
| 81 | + while (true) | |
| 82 | + { | |
| 83 | + byte[] nalu = readNalu(); | |
| 84 | + if (nalu == null) break; | |
| 85 | + if (nalu.length < 4) continue; | |
| 86 | + | |
| 87 | + byte[] flvTag = this.flvEncoder.write(nalu, (int) (timeoffset - firstTimestamp)); | |
| 88 | + | |
| 89 | + if (flvTag == null) continue; | |
| 90 | + | |
| 91 | + // 广播给所有的观众 | |
| 92 | + broadcastVideo(timeoffset, flvTag); | |
| 93 | + } | |
| 94 | + } | |
| 95 | + | |
| 96 | + public void broadcastVideo(long timeoffset, byte[] flvTag) | |
| 97 | + { | |
| 98 | + for (Subscriber subscriber : subscribers) | |
| 99 | + { | |
| 100 | + subscriber.onVideoData(timeoffset, flvTag, flvEncoder); | |
| 101 | + } | |
| 102 | + } | |
| 103 | + | |
| 104 | + public void broadcastAudio(long timeoffset, byte[] flvTag) | |
| 105 | + { | |
| 106 | + for (Subscriber subscriber : subscribers) | |
| 107 | + { | |
| 108 | + subscriber.onAudioData(timeoffset, flvTag, flvEncoder); | |
| 109 | + } | |
| 110 | + } | |
| 111 | + | |
| 112 | + public void unsubscribe(long watcherId) | |
| 113 | + { | |
| 114 | + for (Iterator<Subscriber> itr = subscribers.iterator(); itr.hasNext(); ) | |
| 115 | + { | |
| 116 | + Subscriber subscriber = itr.next(); | |
| 117 | + if (subscriber.getId() == watcherId) | |
| 118 | + { | |
| 119 | + itr.remove(); | |
| 120 | + subscriber.close(); | |
| 121 | + return; | |
| 122 | + } | |
| 123 | + } | |
| 124 | + } | |
| 125 | + | |
| 126 | + public void close() | |
| 127 | + { | |
| 128 | + for (Iterator<Subscriber> itr = subscribers.iterator(); itr.hasNext(); ) | |
| 129 | + { | |
| 130 | + Subscriber subscriber = itr.next(); | |
| 131 | + subscriber.close(); | |
| 132 | + itr.remove(); | |
| 133 | + } | |
| 134 | + if (rtmpPublisher != null) rtmpPublisher.close(); | |
| 135 | + } | |
| 136 | + | |
| 137 | + private byte[] readNalu() | |
| 138 | + { | |
| 139 | + for (int i = 0; i < buffer.size() - 3; i++) | |
| 140 | + { | |
| 141 | + int a = buffer.get(i + 0) & 0xff; | |
| 142 | + int b = buffer.get(i + 1) & 0xff; | |
| 143 | + int c = buffer.get(i + 2) & 0xff; | |
| 144 | + int d = buffer.get(i + 3) & 0xff; | |
| 145 | + if (a == 0x00 && b == 0x00 && c == 0x00 && d == 0x01) | |
| 146 | + { | |
| 147 | + if (i == 0) continue; | |
| 148 | + byte[] nalu = new byte[i]; | |
| 149 | + buffer.sliceInto(nalu, i); | |
| 150 | + return nalu; | |
| 151 | + } | |
| 152 | + } | |
| 153 | + return null; | |
| 154 | + } | |
| 155 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/jtt1078/publisher/PublishManager.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.jtt1078.publisher; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.jtt1078.entity.Media; | |
| 4 | +import com.genersoft.iot.vmp.jtt1078.subscriber.Subscriber; | |
| 5 | +import io.netty.channel.ChannelHandlerContext; | |
| 6 | +import org.slf4j.Logger; | |
| 7 | +import org.slf4j.LoggerFactory; | |
| 8 | + | |
| 9 | +import java.util.concurrent.ConcurrentHashMap; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * Created by houcheng on 2019-12-11. | |
| 13 | + */ | |
| 14 | +public final class PublishManager | |
| 15 | +{ | |
| 16 | + static Logger logger = LoggerFactory.getLogger(PublishManager.class); | |
| 17 | + ConcurrentHashMap<String, Channel> channels; | |
| 18 | + | |
| 19 | + private PublishManager() | |
| 20 | + { | |
| 21 | + channels = new ConcurrentHashMap<String, Channel>(); | |
| 22 | + } | |
| 23 | + | |
| 24 | + public Subscriber subscribe(String tag, Media.Type type, ChannelHandlerContext ctx) | |
| 25 | + { | |
| 26 | + Channel chl = channels.get(tag); | |
| 27 | + if (chl == null) | |
| 28 | + { | |
| 29 | + chl = new Channel(tag); | |
| 30 | + channels.put(tag, chl); | |
| 31 | + } | |
| 32 | + Subscriber subscriber = null; | |
| 33 | + if (type.equals(Media.Type.Video)) subscriber = chl.subscribe(ctx); | |
| 34 | + else throw new RuntimeException("unknown media type: " + type); | |
| 35 | + | |
| 36 | + subscriber.setName("subscriber-" + tag + "-" + subscriber.getId()); | |
| 37 | + subscriber.start(); | |
| 38 | + | |
| 39 | + return subscriber; | |
| 40 | + } | |
| 41 | + | |
| 42 | + public void publishAudio(String tag, int sequence, long timestamp, int payloadType, byte[] data) | |
| 43 | + { | |
| 44 | + Channel chl = channels.get(tag); | |
| 45 | + if (chl != null) chl.writeAudio(timestamp, payloadType, data); | |
| 46 | + } | |
| 47 | + | |
| 48 | + public void publishVideo(String tag, int sequence, long timestamp, int payloadType, byte[] data) | |
| 49 | + { | |
| 50 | + Channel chl = channels.get(tag); | |
| 51 | + if (chl != null) chl.writeVideo(sequence, timestamp, payloadType, data); | |
| 52 | + } | |
| 53 | + | |
| 54 | + public Channel open(String tag) | |
| 55 | + { | |
| 56 | + Channel chl = channels.get(tag); | |
| 57 | + if (chl == null) | |
| 58 | + { | |
| 59 | + chl = new Channel(tag); | |
| 60 | + channels.put(tag, chl); | |
| 61 | + } | |
| 62 | + if (chl.isPublishing()) throw new RuntimeException("channel already publishing"); | |
| 63 | + return chl; | |
| 64 | + } | |
| 65 | + | |
| 66 | + public void close(String tag) | |
| 67 | + { | |
| 68 | + Channel chl = channels.remove(tag); | |
| 69 | + if (chl != null) chl.close(); | |
| 70 | + } | |
| 71 | + | |
| 72 | + public void unsubscribe(String tag, long watcherId) | |
| 73 | + { | |
| 74 | + Channel chl = channels.get(tag); | |
| 75 | + if (chl != null) chl.unsubscribe(watcherId); | |
| 76 | + logger.info("unsubscribe: {} - {}", tag, watcherId); | |
| 77 | + } | |
| 78 | + static final PublishManager instance = new PublishManager(); | |
| 79 | + public static void init() { } | |
| 80 | + | |
| 81 | + public static PublishManager getInstance() | |
| 82 | + { | |
| 83 | + return instance; | |
| 84 | + } | |
| 85 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/server/Jtt1078Decoder.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/server/Jtt1078Decoder.java
| 1 | -package com.genersoft.iot.vmp.jt1078.server; | |
| 1 | +package com.genersoft.iot.vmp.jtt1078.server; | |
| 2 | 2 | |
| 3 | -import com.genersoft.iot.vmp.jt1078.util.ByteHolder; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.util.ByteUtils; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.util.Packet; | |
| 3 | +import com.genersoft.iot.vmp.jtt1078.util.ByteHolder; | |
| 4 | +import com.genersoft.iot.vmp.jtt1078.util.ByteUtils; | |
| 5 | +import com.genersoft.iot.vmp.jtt1078.util.Packet; | |
| 6 | 6 | |
| 7 | 7 | /** |
| 8 | 8 | * Created by matrixy on 2019/4/9. | ... | ... |
src/main/java/com/genersoft/iot/vmp/jtt1078/server/Jtt1078Handler.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.jtt1078.server; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.jtt1078.publisher.Channel; | |
| 4 | +import com.genersoft.iot.vmp.jtt1078.publisher.PublishManager; | |
| 5 | +import com.genersoft.iot.vmp.jtt1078.util.Packet; | |
| 6 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.Jt1078OfCarController; | |
| 7 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.config.DataBuffer; | |
| 8 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.SimFlow; | |
| 9 | +import io.netty.channel.ChannelHandlerContext; | |
| 10 | +import io.netty.channel.SimpleChannelInboundHandler; | |
| 11 | +import io.netty.handler.timeout.IdleState; | |
| 12 | +import io.netty.handler.timeout.IdleStateEvent; | |
| 13 | +import io.netty.util.AttributeKey; | |
| 14 | +import org.slf4j.Logger; | |
| 15 | +import org.slf4j.LoggerFactory; | |
| 16 | +import org.springframework.context.ApplicationContext; | |
| 17 | +import org.springframework.data.redis.core.StringRedisTemplate; | |
| 18 | + | |
| 19 | +import java.math.BigDecimal; | |
| 20 | +import java.util.Set; | |
| 21 | +import java.util.concurrent.TimeUnit; | |
| 22 | + | |
| 23 | +import static com.genersoft.iot.vmp.VManageBootstrap.getBean; | |
| 24 | + | |
| 25 | +/** | |
| 26 | + * Created by matrixy on 2019/4/9. | |
| 27 | + */ | |
| 28 | +public class Jtt1078Handler extends SimpleChannelInboundHandler<Packet> | |
| 29 | +{ | |
| 30 | + private static ApplicationContext applicationContext; | |
| 31 | + static Logger logger = LoggerFactory.getLogger(Jtt1078Handler.class); | |
| 32 | + private static final AttributeKey<Session> SESSION_KEY = AttributeKey.valueOf("session-key"); | |
| 33 | + private Integer port; | |
| 34 | + | |
| 35 | + public Jtt1078Handler(Integer port) { | |
| 36 | + this.port = port; | |
| 37 | + } | |
| 38 | + | |
| 39 | + public Jtt1078Handler() { | |
| 40 | + } | |
| 41 | + | |
| 42 | + /** | |
| 43 | + * 流来 | |
| 44 | + */ | |
| 45 | + @Override | |
| 46 | + protected void channelRead0(ChannelHandlerContext ctx, Packet packet) throws Exception | |
| 47 | + { | |
| 48 | + io.netty.channel.Channel nettyChannel = ctx.channel(); | |
| 49 | + packet.seek(8); | |
| 50 | + String sim = packet.nextBCD() + packet.nextBCD() + packet.nextBCD() + packet.nextBCD() + packet.nextBCD() + packet.nextBCD(); | |
| 51 | + int channel = packet.nextByte() & 0xff; | |
| 52 | + String tag = sim + "-" + channel; | |
| 53 | + tag = tag.replaceAll("^0+", ""); | |
| 54 | + if (port != null){ | |
| 55 | + Set<String> set = Jt1078OfCarController.map.get(port); | |
| 56 | + String findSet = Jt1078OfCarController.getFindSet(set, tag); | |
| 57 | + if (findSet != null){ | |
| 58 | + tag = findSet + "_" + port; | |
| 59 | + }else { | |
| 60 | + return; | |
| 61 | + } | |
| 62 | + } | |
| 63 | + StringRedisTemplate redisTemplate = getBean(StringRedisTemplate.class); | |
| 64 | + if (redisTemplate.opsForSet().add("tag:" + tag, tag) > 0){ | |
| 65 | + redisTemplate.expire("tag:" + tag, 60, TimeUnit.SECONDS); | |
| 66 | + logger.info("[ {} ] --> 流接收成功 ",tag); | |
| 67 | + }else { | |
| 68 | + redisTemplate.expire("tag:" + tag, 60, TimeUnit.SECONDS); | |
| 69 | + } | |
| 70 | + double num = new BigDecimal(packet.size()).divide(new BigDecimal(1024 * 1024 * 1024), 10, BigDecimal.ROUND_HALF_UP).doubleValue(); | |
| 71 | + DataBuffer simFlowDataBuffer = getBean(DataBuffer.class); | |
| 72 | + if (simFlowDataBuffer != null) { | |
| 73 | + simFlowDataBuffer.setValue(SimFlow.build(sim,String.valueOf(channel),num)); | |
| 74 | + } | |
| 75 | + if (SessionManager.contains(nettyChannel, "tag") == false) | |
| 76 | + { | |
| 77 | + Channel chl = PublishManager.getInstance().open(tag); | |
| 78 | + SessionManager.set(nettyChannel, "tag", tag); | |
| 79 | + logger.info("start publishing: {} -> {}-{}", Long.toHexString(chl.hashCode() & 0xffffffffL), sim, channel); | |
| 80 | + } | |
| 81 | + | |
| 82 | + Integer sequence = SessionManager.get(nettyChannel, "video-sequence"); | |
| 83 | + if (sequence == null) sequence = 0; | |
| 84 | + // 1. 做好序号 | |
| 85 | + // 2. 音频需要转码后提供订阅 | |
| 86 | + int lengthOffset = 28; | |
| 87 | + int dataType = (packet.seek(15).nextByte() >> 4) & 0x0f; | |
| 88 | + int pkType = packet.seek(15).nextByte() & 0x0f; | |
| 89 | + // 透传数据类型:0100,没有后面的时间以及Last I Frame Interval和Last Frame Interval字段 | |
| 90 | + if (dataType == 0x04) lengthOffset = 28 - 8 - 2 - 2; | |
| 91 | + else if (dataType == 0x03) lengthOffset = 28 - 4; | |
| 92 | + | |
| 93 | + int pt = packet.seek(5).nextByte() & 0x7f; | |
| 94 | + | |
| 95 | + if (dataType == 0x00 || dataType == 0x01 || dataType == 0x02) | |
| 96 | + { | |
| 97 | + // 碰到结束标记时,序号+1 | |
| 98 | + if (pkType == 0 || pkType == 2) | |
| 99 | + { | |
| 100 | + sequence += 1; | |
| 101 | + SessionManager.set(nettyChannel, "video-sequence", sequence); | |
| 102 | + } | |
| 103 | + long timestamp = packet.seek(16).nextLong(); | |
| 104 | + PublishManager.getInstance().publishVideo(tag, sequence, timestamp, pt, packet.seek(lengthOffset + 2).nextBytes()); | |
| 105 | + } | |
| 106 | + else if (dataType == 0x03) | |
| 107 | + { | |
| 108 | + long timestamp = packet.seek(16).nextLong(); | |
| 109 | + byte[] data = packet.seek(lengthOffset + 2).nextBytes(); | |
| 110 | + PublishManager.getInstance().publishAudio(tag, sequence, timestamp, pt, data); | |
| 111 | + } | |
| 112 | + } | |
| 113 | + | |
| 114 | + @Override | |
| 115 | + public void channelInactive(ChannelHandlerContext ctx) throws Exception | |
| 116 | + { | |
| 117 | + super.channelInactive(ctx); | |
| 118 | + release(ctx.channel()); | |
| 119 | + } | |
| 120 | + | |
| 121 | + @Override | |
| 122 | + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception | |
| 123 | + { | |
| 124 | + // super.exceptionCaught(ctx, cause); | |
| 125 | + cause.printStackTrace(); | |
| 126 | + release(ctx.channel()); | |
| 127 | + ctx.close(); | |
| 128 | + } | |
| 129 | + | |
| 130 | + @Override | |
| 131 | + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { | |
| 132 | + if (IdleStateEvent.class.isAssignableFrom(evt.getClass())) { | |
| 133 | + IdleStateEvent event = (IdleStateEvent) evt; | |
| 134 | + if (event.state() == IdleState.READER_IDLE) { | |
| 135 | + String tag = SessionManager.get(ctx.channel(), "tag"); | |
| 136 | + logger.info("read timeout: {}",tag); | |
| 137 | + release(ctx.channel()); | |
| 138 | + } | |
| 139 | + } | |
| 140 | + } | |
| 141 | + | |
| 142 | + private void release(io.netty.channel.Channel channel) | |
| 143 | + { | |
| 144 | + String tag = SessionManager.get(channel, "tag"); | |
| 145 | + if (tag != null) | |
| 146 | + { | |
| 147 | + logger.info("close netty channel: {}", tag); | |
| 148 | + PublishManager.getInstance().close(tag); | |
| 149 | + } | |
| 150 | + } | |
| 151 | + | |
| 152 | + | |
| 153 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/server/Jtt1078MessageDecoder.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/server/Jtt1078MessageDecoder.java
| 1 | -package com.genersoft.iot.vmp.jt1078.server; | |
| 1 | +package com.genersoft.iot.vmp.jtt1078.server; | |
| 2 | 2 | |
| 3 | -import com.genersoft.iot.vmp.jt1078.util.ByteUtils; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.util.Packet; | |
| 3 | +import com.genersoft.iot.vmp.jtt1078.util.Packet; | |
| 5 | 4 | import io.netty.buffer.ByteBuf; |
| 6 | 5 | import io.netty.channel.ChannelHandlerContext; |
| 7 | 6 | import io.netty.handler.codec.ByteToMessageDecoder; | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/server/Session.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/server/Session.java
src/main/java/com/genersoft/iot/vmp/jt1078/server/SessionManager.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/server/SessionManager.java
| 1 | -package com.genersoft.iot.vmp.jt1078.server; | |
| 1 | +package com.genersoft.iot.vmp.jtt1078.server; | |
| 2 | 2 | |
| 3 | 3 | import io.netty.channel.Channel; |
| 4 | +import org.apache.commons.collections4.map.HashedMap; | |
| 5 | + | |
| 4 | 6 | |
| 5 | -import java.util.HashMap; | |
| 6 | 7 | import java.util.Map; |
| 7 | 8 | |
| 8 | 9 | public final class SessionManager |
| 9 | 10 | { |
| 10 | - private static final Map<String, Object> mappings = new HashMap<>(); | |
| 11 | + private static final Map<String, Object> mappings = new HashedMap(); | |
| 11 | 12 | |
| 12 | 13 | public static void init() |
| 13 | 14 | { |
| ... | ... | @@ -28,4 +29,4 @@ public final class SessionManager |
| 28 | 29 | { |
| 29 | 30 | return mappings.containsKey(channel.id().asLongText() + key); |
| 30 | 31 | } |
| 31 | -} | |
| 32 | 32 | \ No newline at end of file |
| 33 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/subscriber/RTMPPublisher.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/subscriber/RTMPPublisher.java
| 1 | -// | |
| 2 | -// Source code recreated from a .class file by IntelliJ IDEA | |
| 3 | -// (powered by FernFlower decompiler) | |
| 4 | -// | |
| 1 | +package com.genersoft.iot.vmp.jtt1078.subscriber; | |
| 5 | 2 | |
| 6 | -package com.genersoft.iot.vmp.jt1078.subscriber; | |
| 7 | - | |
| 8 | -import com.genersoft.iot.vmp.jt1078.util.Configs; | |
| 9 | -import java.io.InputStream; | |
| 3 | +import com.genersoft.iot.vmp.jtt1078.util.*; | |
| 10 | 4 | import org.slf4j.Logger; |
| 11 | 5 | import org.slf4j.LoggerFactory; |
| 6 | +import org.springframework.data.redis.core.RedisTemplate; | |
| 7 | + | |
| 8 | +import javax.annotation.Resource; | |
| 9 | +import java.io.InputStream; | |
| 12 | 10 | |
| 13 | -public class RTMPPublisher extends Thread { | |
| 11 | +public class RTMPPublisher extends Thread | |
| 12 | +{ | |
| 14 | 13 | static Logger logger = LoggerFactory.getLogger(RTMPPublisher.class); |
| 14 | + | |
| 15 | 15 | String tag = null; |
| 16 | - private Integer port; | |
| 17 | 16 | Process process = null; |
| 18 | 17 | |
| 19 | - public RTMPPublisher(String tag, Integer port) { | |
| 18 | + public RTMPPublisher(String tag) | |
| 19 | + { | |
| 20 | 20 | this.tag = tag; |
| 21 | - this.port = port; | |
| 22 | 21 | } |
| 23 | 22 | |
| 24 | 23 | @Override |
| ... | ... | @@ -31,14 +30,15 @@ public class RTMPPublisher extends Thread { |
| 31 | 30 | |
| 32 | 31 | try |
| 33 | 32 | { |
| 34 | - String rtmpUrl = Configs.get("rtmp.url").replaceAll("\\{TAG\\}", tag); | |
| 35 | - String cmd = String.format("%s -i http://localhost:%d/video/%s -vcodec copy -acodec aac -f flv %s", | |
| 33 | + String sign = "41db35390ddad33f83944f44b8b75ded"; | |
| 34 | + String rtmpUrl = Configs.get("rtmp.url").replaceAll("\\{TAG\\}", tag).replaceAll("\\{sign\\}",sign); | |
| 35 | + String cmd = String.format("%s -i http://127.0.0.1:%d/video/%s -vcodec copy -acodec aac -f rtsp %s", | |
| 36 | 36 | Configs.get("ffmpeg.path"), |
| 37 | 37 | Configs.getInt("server.http.port", 3333), |
| 38 | 38 | tag, |
| 39 | 39 | rtmpUrl |
| 40 | 40 | ); |
| 41 | - logger.info("Execute: {}", cmd); | |
| 41 | + logger.info("推流命令 Execute: {}", cmd); | |
| 42 | 42 | process = Runtime.getRuntime().exec(cmd); |
| 43 | 43 | stderr = process.getErrorStream(); |
| 44 | 44 | while ((len = stderr.read(buff)) > -1) |
| ... | ... | @@ -57,4 +57,4 @@ public class RTMPPublisher extends Thread { |
| 57 | 57 | { |
| 58 | 58 | try { if (process != null) process.destroyForcibly(); } catch(Exception e) { } |
| 59 | 59 | } |
| 60 | -} | |
| 61 | 60 | \ No newline at end of file |
| 61 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/subscriber/Subscriber.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/subscriber/Subscriber.java
| 1 | -package com.genersoft.iot.vmp.jt1078.subscriber; | |
| 1 | +package com.genersoft.iot.vmp.jtt1078.subscriber; | |
| 2 | 2 | |
| 3 | -import com.genersoft.iot.vmp.jt1078.flv.FlvEncoder; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.util.Packet; | |
| 3 | +import com.genersoft.iot.vmp.jtt1078.flv.FlvEncoder; | |
| 5 | 4 | import io.netty.channel.ChannelFuture; |
| 6 | 5 | import io.netty.channel.ChannelHandlerContext; |
| 7 | 6 | import org.slf4j.Logger; | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/subscriber/VideoSubscriber.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/subscriber/VideoSubscriber.java
| 1 | -package com.genersoft.iot.vmp.jt1078.subscriber; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.jt1078.codec.MP3Encoder; | |
| 4 | -import com.genersoft.iot.vmp.jt1078.flv.AudioTag; | |
| 5 | -import com.genersoft.iot.vmp.jt1078.flv.FlvAudioTagEncoder; | |
| 6 | -import com.genersoft.iot.vmp.jt1078.flv.FlvEncoder; | |
| 7 | -import com.genersoft.iot.vmp.jt1078.util.ByteBufUtils; | |
| 8 | -import com.genersoft.iot.vmp.jt1078.util.FLVUtils; | |
| 9 | -import com.genersoft.iot.vmp.jt1078.util.HttpChunk; | |
| 1 | +package com.genersoft.iot.vmp.jtt1078.subscriber; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.jtt1078.codec.MP3Encoder; | |
| 4 | +import com.genersoft.iot.vmp.jtt1078.flv.AudioTag; | |
| 5 | +import com.genersoft.iot.vmp.jtt1078.flv.FlvAudioTagEncoder; | |
| 6 | +import com.genersoft.iot.vmp.jtt1078.flv.FlvEncoder; | |
| 7 | +import com.genersoft.iot.vmp.jtt1078.util.ByteBufUtils; | |
| 8 | +import com.genersoft.iot.vmp.jtt1078.util.FLVUtils; | |
| 9 | +import com.genersoft.iot.vmp.jtt1078.util.HttpChunk; | |
| 10 | 10 | import io.netty.buffer.ByteBuf; |
| 11 | 11 | import io.netty.channel.ChannelHandlerContext; |
| 12 | 12 | |
| ... | ... | @@ -30,7 +30,6 @@ public class VideoSubscriber extends Subscriber |
| 30 | 30 | public void onVideoData(long timeoffset, byte[] data, FlvEncoder flvEncoder) |
| 31 | 31 | { |
| 32 | 32 | if (lastVideoFrameTimeOffset == 0) lastVideoFrameTimeOffset = timeoffset; |
| 33 | - | |
| 34 | 33 | // 之前是不是已经发送过了?没有的话,需要补发FLV HEADER的。。。 |
| 35 | 34 | if (videoHeaderSent == false && flvEncoder.videoReady()) |
| 36 | 35 | { |
| ... | ... | @@ -47,9 +46,7 @@ public class VideoSubscriber extends Subscriber |
| 47 | 46 | |
| 48 | 47 | videoHeaderSent = true; |
| 49 | 48 | } |
| 50 | - | |
| 51 | 49 | if (data == null) return; |
| 52 | - | |
| 53 | 50 | // 修改时间戳 |
| 54 | 51 | // System.out.println("Time: " + videoTimestamp + ", current: " + timeoffset); |
| 55 | 52 | FLVUtils.resetTimestamp(data, (int) videoTimestamp); | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/util/Bin.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/util/Bin.java
src/main/java/com/genersoft/iot/vmp/jt1078/util/ByteBufUtils.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/util/ByteBufUtils.java
src/main/java/com/genersoft/iot/vmp/jt1078/util/ByteHolder.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/util/ByteHolder.java
| 1 | -package com.genersoft.iot.vmp.jt1078.util; | |
| 1 | +package com.genersoft.iot.vmp.jtt1078.util; | |
| 2 | 2 | |
| 3 | 3 | import java.util.Arrays; |
| 4 | 4 | |
| ... | ... | @@ -93,4 +93,4 @@ public class ByteHolder |
| 93 | 93 | int l = this.buffer[position + 1] & 0xff; |
| 94 | 94 | return ((h << 8) | l) & 0xffff; |
| 95 | 95 | } |
| 96 | -} | |
| 97 | 96 | \ No newline at end of file |
| 97 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/jt1078/util/ByteUtils.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/util/ByteUtils.java
src/main/java/com/genersoft/iot/vmp/jt1078/util/Configs.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/util/Configs.java
src/main/java/com/genersoft/iot/vmp/jt1078/util/FLVUtils.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/util/FLVUtils.java
src/main/java/com/genersoft/iot/vmp/jt1078/util/FileUtils.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/util/FileUtils.java
src/main/java/com/genersoft/iot/vmp/jt1078/util/HttpChunk.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/util/HttpChunk.java
src/main/java/com/genersoft/iot/vmp/jt1078/util/Packet.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/util/Packet.java
src/main/java/com/genersoft/iot/vmp/jt1078/util/WAVUtils.java renamed to src/main/java/com/genersoft/iot/vmp/jtt1078/util/WAVUtils.java
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
| ... | ... | @@ -29,10 +29,7 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| 29 | 29 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 30 | 30 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 31 | 31 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 32 | -import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; | |
| 33 | -import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo; | |
| 34 | -import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo; | |
| 35 | -import com.genersoft.iot.vmp.vmanager.bean.StreamContent; | |
| 32 | +import com.genersoft.iot.vmp.vmanager.bean.*; | |
| 36 | 33 | import com.genersoft.iot.vmp.vmanager.jt1078.platform.Jt1078OfCarController; |
| 37 | 34 | import org.apache.commons.lang3.StringUtils; |
| 38 | 35 | import org.slf4j.Logger; |
| ... | ... | @@ -40,6 +37,7 @@ import org.slf4j.LoggerFactory; |
| 40 | 37 | import org.springframework.beans.factory.annotation.Autowired; |
| 41 | 38 | import org.springframework.beans.factory.annotation.Qualifier; |
| 42 | 39 | import org.springframework.data.redis.core.RedisTemplate; |
| 40 | +import org.springframework.scheduling.annotation.Scheduled; | |
| 43 | 41 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
| 44 | 42 | import org.springframework.util.ObjectUtils; |
| 45 | 43 | import org.springframework.web.bind.annotation.*; |
| ... | ... | @@ -50,6 +48,7 @@ import javax.sip.InvalidArgumentException; |
| 50 | 48 | import javax.sip.SipException; |
| 51 | 49 | import java.text.ParseException; |
| 52 | 50 | import java.util.*; |
| 51 | +import java.util.concurrent.TimeUnit; | |
| 53 | 52 | |
| 54 | 53 | /** |
| 55 | 54 | * @description:针对 ZLMediaServer的hook事件监听 |
| ... | ... | @@ -187,7 +186,6 @@ public class ZLMHttpHookListener { |
| 187 | 186 | return new HookResult(401, "Unauthorized"); |
| 188 | 187 | } |
| 189 | 188 | } |
| 190 | - | |
| 191 | 189 | return HookResult.SUCCESS(); |
| 192 | 190 | } |
| 193 | 191 | |
| ... | ... | @@ -679,8 +677,16 @@ public class ZLMHttpHookListener { |
| 679 | 677 | // StreamPushItem streamPushItem = streamPushService.getPush(app, streamId); |
| 680 | 678 | // if (streamPushItem != null) { |
| 681 | 679 | // // TODO 发送停止 |
| 682 | -// | |
| 683 | 680 | // } |
| 681 | + //推流需要更新缓存数据以防止端口占用 | |
| 682 | + logger.info("无人观看流 ---> {}", JSONObject.toJSONString(param)); | |
| 683 | + Object object = redisTemplate.opsForValue().get("patrol:stream:" + param.getStream()); | |
| 684 | + if (object == null) { | |
| 685 | + String[] split = param.getStream().split("_"); | |
| 686 | + if (split != null && split.length == 2) { | |
| 687 | + jt1078OfCarController.clearMap(split[1],split[0]); | |
| 688 | + } | |
| 689 | + } | |
| 684 | 690 | } |
| 685 | 691 | return ret; |
| 686 | 692 | } |
| ... | ... | @@ -700,7 +706,6 @@ public class ZLMHttpHookListener { |
| 700 | 706 | defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); |
| 701 | 707 | return defaultResult; |
| 702 | 708 | } |
| 703 | - | |
| 704 | 709 | if ("rtp".equals(param.getApp())) { |
| 705 | 710 | String[] s = param.getStream().split("_"); |
| 706 | 711 | if ((s.length != 2 && s.length != 4)) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java
| ... | ... | @@ -114,6 +114,10 @@ public interface IStreamProxyService { |
| 114 | 114 | * 更新代理流 |
| 115 | 115 | */ |
| 116 | 116 | boolean updateStreamProxy(StreamProxyItem streamProxyItem); |
| 117 | + /** | |
| 118 | + * 更新代理流 | |
| 119 | + */ | |
| 120 | + boolean updateStreamProxy(StreamProxyItem streamProxyItem, GeneralCallback<StreamInfo> callback); | |
| 117 | 121 | |
| 118 | 122 | /** |
| 119 | 123 | * 获取统计信息 | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
| ... | ... | @@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; |
| 7 | 7 | import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis; |
| 8 | 8 | import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; |
| 9 | 9 | import com.github.pagehelper.PageInfo; |
| 10 | +import org.springframework.scheduling.annotation.Scheduled; | |
| 10 | 11 | |
| 11 | 12 | import java.util.List; |
| 12 | 13 | import java.util.Map; | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
| ... | ... | @@ -193,6 +193,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 193 | 193 | callback.run(ErrorCode.ERROR100.getCode(), "超时", null); |
| 194 | 194 | } |
| 195 | 195 | }, 7000); |
| 196 | + //TODO | |
| 196 | 197 | JSONObject jsonObject = addStreamProxyToZlm(param); |
| 197 | 198 | if (jsonObject != null && jsonObject.getInteger("code") == 0) { |
| 198 | 199 | hookSubscribe.removeSubscribe(hookSubscribeForStreamChange); |
| ... | ... | @@ -273,8 +274,6 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 273 | 274 | logger.error("向数据库添加流代理失败:", e); |
| 274 | 275 | dataSourceTransactionManager.rollback(transactionStatus); |
| 275 | 276 | } |
| 276 | - | |
| 277 | - | |
| 278 | 277 | return result; |
| 279 | 278 | } |
| 280 | 279 | |
| ... | ... | @@ -312,6 +311,42 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 312 | 311 | } |
| 313 | 312 | return result; |
| 314 | 313 | } |
| 314 | + /** | |
| 315 | + * 更新代理流 | |
| 316 | + * | |
| 317 | + * @param streamProxyItem | |
| 318 | + * @return | |
| 319 | + */ | |
| 320 | + @Override | |
| 321 | + public boolean updateStreamProxy(StreamProxyItem streamProxyItem, GeneralCallback<StreamInfo> callback) { | |
| 322 | + TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); | |
| 323 | + boolean result = false; | |
| 324 | + streamProxyItem.setStreamType("proxy"); | |
| 325 | + try { | |
| 326 | + if (streamProxyMapper.update(streamProxyItem) > 0) { | |
| 327 | + if (!ObjectUtils.isEmpty(streamProxyItem.getGbId())) { | |
| 328 | + if (gbStreamMapper.updateByAppAndStream(streamProxyItem) == 0) { | |
| 329 | + //事务回滚 | |
| 330 | + dataSourceTransactionManager.rollback(transactionStatus); | |
| 331 | + callback.run(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg(), null); | |
| 332 | + return false; | |
| 333 | + } | |
| 334 | + } | |
| 335 | + } else { | |
| 336 | + //事务回滚 | |
| 337 | + dataSourceTransactionManager.rollback(transactionStatus); | |
| 338 | + callback.run(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg(), null); | |
| 339 | + return false; | |
| 340 | + } | |
| 341 | + callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), null); | |
| 342 | + dataSourceTransactionManager.commit(transactionStatus); //手动提交 | |
| 343 | + result = true; | |
| 344 | + } catch (Exception e) { | |
| 345 | + logger.error("未处理的异常 ", e); | |
| 346 | + dataSourceTransactionManager.rollback(transactionStatus); | |
| 347 | + } | |
| 348 | + return result; | |
| 349 | + } | |
| 315 | 350 | |
| 316 | 351 | @Override |
| 317 | 352 | public JSONObject addStreamProxyToZlm(StreamProxyItem param) { |
| ... | ... | @@ -491,8 +526,10 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 491 | 526 | @Override |
| 492 | 527 | public void zlmServerOnline(String mediaServerId) { |
| 493 | 528 | // 移除开启了无人观看自动移除的流 |
| 529 | + choose1078HistoryLister(); | |
| 494 | 530 | |
| 495 | 531 | choose1078Lister(); |
| 532 | + | |
| 496 | 533 | List<StreamProxyItem> streamProxyItemList = streamProxyMapper.selectAutoRemoveItemByMediaServerId(mediaServerId); |
| 497 | 534 | if (streamProxyItemList.size() > 0) { |
| 498 | 535 | gbStreamMapper.batchDel(streamProxyItemList); |
| ... | ... | @@ -647,7 +684,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 647 | 684 | } |
| 648 | 685 | |
| 649 | 686 | |
| 650 | - public void choose1078Lister() { | |
| 687 | + public void choose1078HistoryLister() { | |
| 651 | 688 | Set<String> keys = redisTemplate.keys("tag:history:port:*"); |
| 652 | 689 | if (org.apache.commons.collections4.CollectionUtils.isEmpty(keys)) { |
| 653 | 690 | return; |
| ... | ... | @@ -680,10 +717,45 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 680 | 717 | logger.error("[{}]停流失败", stream, e); |
| 681 | 718 | } |
| 682 | 719 | } |
| 683 | - | |
| 684 | 720 | // task execution logic |
| 685 | 721 | } |
| 686 | 722 | |
| 723 | + | |
| 724 | + public void choose1078Lister() { | |
| 725 | + Set<String> keys = redisTemplate.keys("tag:history:port:*"); | |
| 726 | + if (org.apache.commons.collections4.CollectionUtils.isEmpty(keys)) { | |
| 727 | + return; | |
| 728 | + } | |
| 729 | + Long nowDate = new Date().getTime(); | |
| 730 | + for (String key : keys) { | |
| 731 | + String stream = StringUtils.substringAfter(key, "tag:history:port:"); | |
| 732 | + if (StringUtils.isEmpty(stream)) { | |
| 733 | + continue; | |
| 734 | + } | |
| 735 | + | |
| 736 | + Object value = redisTemplate.opsForValue().get("tag:history:httpPort:time:" + stream); | |
| 737 | + if (Objects.isNull(value)) { | |
| 738 | + sendIORequestStop(stream); | |
| 739 | + continue; | |
| 740 | + } | |
| 741 | + try { | |
| 742 | + Long val = (Long) value; | |
| 743 | + if (val == 0L) { | |
| 744 | + sendIORequestStop(stream); | |
| 745 | + continue; | |
| 746 | + } | |
| 747 | + | |
| 748 | + Long val1 = (nowDate - val) / 1000; | |
| 749 | + if (val1 > StreamProxyTask.TIME_OUT) { | |
| 750 | + sendIORequestStop(stream); | |
| 751 | + } | |
| 752 | + | |
| 753 | + } catch (Exception e) { | |
| 754 | + logger.error("[{}]停流失败", stream, e); | |
| 755 | + } | |
| 756 | + } | |
| 757 | + } | |
| 758 | + | |
| 687 | 759 | private void sendIORequestStop(String stream) { |
| 688 | 760 | try { |
| 689 | 761 | String sim = StringUtils.substringBeforeLast(stream, "-"); | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/StremProxyService1078Impl.java
| 1 | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.VManageBootstrap; |
| 4 | -import com.genersoft.iot.vmp.jt1078.app.VideoServerApp; | |
| 5 | 4 | import com.genersoft.iot.vmp.service.IStreamProxyService; |
| 6 | 5 | import com.genersoft.iot.vmp.service.StremProxyService1078; |
| 7 | 6 | import com.genersoft.iot.vmp.vmanager.jt1078.platform.ben.HttpClientPostEntity; |
| 8 | 7 | import com.genersoft.iot.vmp.vmanager.jt1078.platform.config.Jt1078ConfigBean; |
| 9 | 8 | import com.genersoft.iot.vmp.vmanager.jt1078.platform.handler.HttpClientUtil; |
| 10 | -import org.apache.commons.collections4.CollectionUtils; | |
| 11 | 9 | import org.apache.commons.lang3.StringUtils; |
| 12 | 10 | import org.slf4j.Logger; |
| 13 | 11 | import org.slf4j.LoggerFactory; |
| 14 | 12 | import org.springframework.beans.factory.annotation.Autowired; |
| 15 | 13 | import org.springframework.data.redis.core.RedisTemplate; |
| 16 | 14 | import org.springframework.stereotype.Service; |
| 17 | -import org.springframework.web.bind.annotation.PathVariable; | |
| 18 | 15 | |
| 19 | 16 | import java.io.IOException; |
| 20 | 17 | import java.net.URISyntaxException; |
| 21 | 18 | import java.util.HashMap; |
| 22 | -import java.util.List; | |
| 23 | 19 | import java.util.Map; |
| 24 | 20 | import java.util.Objects; |
| 25 | 21 | import java.util.concurrent.TimeUnit; |
| ... | ... | @@ -35,10 +31,8 @@ public class StremProxyService1078Impl implements StremProxyService1078 { |
| 35 | 31 | @Autowired |
| 36 | 32 | private RedisTemplate<Object, Object> redisTemplate; |
| 37 | 33 | |
| 38 | - | |
| 39 | 34 | private static final Logger log = LoggerFactory.getLogger(StremProxyService1078Impl.class); |
| 40 | 35 | |
| 41 | - | |
| 42 | 36 | @Override |
| 43 | 37 | public Map<String, Object> sendIORequestStop(String sim, String channel, String stream, Integer port, Integer httpPort) { |
| 44 | 38 | Map<String, Object> resultMap = new HashMap<>(); |
| ... | ... | @@ -70,7 +64,7 @@ public class StremProxyService1078Impl implements StremProxyService1078 { |
| 70 | 64 | } |
| 71 | 65 | log.info("port:[{}]",port); |
| 72 | 66 | if(Objects.nonNull(port)){ |
| 73 | - VideoServerApp.stopServer(port,httpPort); | |
| 67 | +// VideoServerApp.stopServer(port,httpPort); | |
| 74 | 68 | } |
| 75 | 69 | |
| 76 | 70 | ... | ... |
src/main/java/com/genersoft/iot/vmp/utils/JsonUtil.java
| ... | ... | @@ -31,4 +31,13 @@ public final class JsonUtil { |
| 31 | 31 | } |
| 32 | 32 | return clazz.cast(jsonObject); |
| 33 | 33 | } |
| 34 | -} | |
| 35 | 34 | \ No newline at end of file |
| 35 | + | |
| 36 | + /** | |
| 37 | + * 存入redis | |
| 38 | + * @param key redis key | |
| 39 | + * @param object redis value | |
| 40 | + */ | |
| 41 | + public static void redisJsonToObject(RedisTemplate<Object, Object> redisTemplate, String key, Object object) { | |
| 42 | + redisTemplate.opsForValue().set(key, object); | |
| 43 | + } | |
| 44 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/bean/ErrorCode.java
| ... | ... | @@ -10,7 +10,11 @@ public enum ErrorCode { |
| 10 | 10 | ERROR404(404, "资源未找到"), |
| 11 | 11 | ERROR403(403, "无权限操作"), |
| 12 | 12 | ERROR401(401, "请登录后重新请求"), |
| 13 | - ERROR500(500, "系统异常"); | |
| 13 | + ERROR500(500, "系统异常"), | |
| 14 | + ERROR450(450, "新建链接错误,请稍后再试"), | |
| 15 | + ERROR420(420, "发送推流指令异常"), | |
| 16 | + ERROR301(301, "下发指令异常"), | |
| 17 | + ERROR304(304, "离线的客户端(请检查设备是否注册或者鉴权"); | |
| 14 | 18 | |
| 15 | 19 | private final int code; |
| 16 | 20 | private final String msg; | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java
| ... | ... | @@ -4,96 +4,202 @@ import com.genersoft.iot.vmp.common.StreamInfo; |
| 4 | 4 | import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; |
| 5 | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 6 | |
| 7 | +/** | |
| 8 | + * 流信息 | |
| 9 | + */ | |
| 7 | 10 | @Schema(description = "流信息") |
| 8 | 11 | public class StreamContent { |
| 9 | 12 | |
| 13 | + /** | |
| 14 | + * 应用名 | |
| 15 | + */ | |
| 10 | 16 | @Schema(description = "应用名") |
| 11 | 17 | private String app; |
| 12 | 18 | |
| 19 | + | |
| 20 | + /** | |
| 21 | + * http端口 | |
| 22 | + */ | |
| 23 | + @Schema(description = "http端口") | |
| 24 | + private Integer httpPort; | |
| 25 | + | |
| 26 | + /** | |
| 27 | + * 接受流端口 | |
| 28 | + */ | |
| 29 | + @Schema(description = "接受流端口") | |
| 30 | + private Integer port; | |
| 31 | + | |
| 32 | + /** | |
| 33 | + * 流ID | |
| 34 | + */ | |
| 13 | 35 | @Schema(description = "流ID") |
| 14 | 36 | private String stream; |
| 15 | 37 | |
| 38 | + /** | |
| 39 | + * IP | |
| 40 | + */ | |
| 16 | 41 | @Schema(description = "IP") |
| 17 | 42 | private String ip; |
| 18 | 43 | |
| 44 | + /** | |
| 45 | + * HTTP-FLV流地址 | |
| 46 | + */ | |
| 19 | 47 | @Schema(description = "HTTP-FLV流地址") |
| 20 | 48 | private String flv; |
| 21 | 49 | |
| 50 | + /** | |
| 51 | + * HTTPS-FLV流地址 | |
| 52 | + */ | |
| 22 | 53 | @Schema(description = "HTTPS-FLV流地址") |
| 23 | 54 | private String https_flv; |
| 24 | 55 | |
| 56 | + /** | |
| 57 | + * Websocket-FLV流地址 | |
| 58 | + */ | |
| 25 | 59 | @Schema(description = "Websocket-FLV流地址") |
| 26 | 60 | private String ws_flv; |
| 27 | 61 | |
| 62 | + /** | |
| 63 | + * Websockets-FLV流地址 | |
| 64 | + */ | |
| 28 | 65 | @Schema(description = "Websockets-FLV流地址") |
| 29 | 66 | private String wss_flv; |
| 30 | 67 | |
| 68 | + /** | |
| 69 | + * HTTP-FMP4流地址 | |
| 70 | + */ | |
| 31 | 71 | @Schema(description = "HTTP-FMP4流地址") |
| 32 | 72 | private String fmp4; |
| 33 | 73 | |
| 74 | + /** | |
| 75 | + * HTTPS-FMP4流地址 | |
| 76 | + */ | |
| 34 | 77 | @Schema(description = "HTTPS-FMP4流地址") |
| 35 | 78 | private String https_fmp4; |
| 36 | 79 | |
| 80 | + /** | |
| 81 | + * Websocket-FMP4流地址 | |
| 82 | + */ | |
| 37 | 83 | @Schema(description = "Websocket-FMP4流地址") |
| 38 | 84 | private String ws_fmp4; |
| 39 | 85 | |
| 86 | + /** | |
| 87 | + * Websockets-FMP4流地址 | |
| 88 | + */ | |
| 40 | 89 | @Schema(description = "Websockets-FMP4流地址") |
| 41 | 90 | private String wss_fmp4; |
| 42 | 91 | |
| 92 | + /** | |
| 93 | + * HLS流地址 | |
| 94 | + */ | |
| 43 | 95 | @Schema(description = "HLS流地址") |
| 44 | 96 | private String hls; |
| 45 | 97 | |
| 98 | + /** | |
| 99 | + * HTTPS-HLS流地址 | |
| 100 | + */ | |
| 46 | 101 | @Schema(description = "HTTPS-HLS流地址") |
| 47 | 102 | private String https_hls; |
| 48 | 103 | |
| 104 | + /** | |
| 105 | + * Websocket-HLS流地址 | |
| 106 | + */ | |
| 49 | 107 | @Schema(description = "Websocket-HLS流地址") |
| 50 | 108 | private String ws_hls; |
| 51 | 109 | |
| 110 | + /** | |
| 111 | + * Websockets-HLS流地址 | |
| 112 | + */ | |
| 52 | 113 | @Schema(description = "Websockets-HLS流地址") |
| 53 | 114 | private String wss_hls; |
| 54 | 115 | |
| 116 | + /** | |
| 117 | + * HTTP-TS流地址 | |
| 118 | + */ | |
| 55 | 119 | @Schema(description = "HTTP-TS流地址") |
| 56 | 120 | private String ts; |
| 57 | 121 | |
| 122 | + /** | |
| 123 | + * HTTPS-TS流地址 | |
| 124 | + */ | |
| 58 | 125 | @Schema(description = "HTTPS-TS流地址") |
| 59 | 126 | private String https_ts; |
| 60 | 127 | |
| 128 | + /** | |
| 129 | + * Websocket-TS流地址 | |
| 130 | + */ | |
| 61 | 131 | @Schema(description = "Websocket-TS流地址") |
| 62 | 132 | private String ws_ts; |
| 63 | 133 | |
| 134 | + /** | |
| 135 | + * Websockets-TS流地址 | |
| 136 | + */ | |
| 64 | 137 | @Schema(description = "Websockets-TS流地址") |
| 65 | 138 | private String wss_ts; |
| 66 | 139 | |
| 140 | + /** | |
| 141 | + * RTMP流地址 | |
| 142 | + */ | |
| 67 | 143 | @Schema(description = "RTMP流地址") |
| 68 | 144 | private String rtmp; |
| 69 | 145 | |
| 146 | + /** | |
| 147 | + * RTMPS流地址 | |
| 148 | + */ | |
| 70 | 149 | @Schema(description = "RTMPS流地址") |
| 71 | 150 | private String rtmps; |
| 72 | 151 | |
| 152 | + /** | |
| 153 | + * RTSP流地址 | |
| 154 | + */ | |
| 73 | 155 | @Schema(description = "RTSP流地址") |
| 74 | 156 | private String rtsp; |
| 75 | 157 | |
| 158 | + /** | |
| 159 | + * RTSPS流地址 | |
| 160 | + */ | |
| 76 | 161 | @Schema(description = "RTSPS流地址") |
| 77 | 162 | private String rtsps; |
| 78 | 163 | |
| 164 | + /** | |
| 165 | + * RTC流地址 | |
| 166 | + */ | |
| 79 | 167 | @Schema(description = "RTC流地址") |
| 80 | 168 | private String rtc; |
| 81 | 169 | |
| 170 | + /** | |
| 171 | + * RTCS流地址 | |
| 172 | + */ | |
| 82 | 173 | @Schema(description = "RTCS流地址") |
| 83 | 174 | private String rtcs; |
| 84 | 175 | |
| 176 | + /** | |
| 177 | + * 流媒体ID | |
| 178 | + */ | |
| 85 | 179 | @Schema(description = "流媒体ID") |
| 86 | 180 | private String mediaServerId; |
| 87 | 181 | |
| 182 | + /** | |
| 183 | + * 流编码信息 | |
| 184 | + */ | |
| 88 | 185 | @Schema(description = "流编码信息") |
| 89 | 186 | private Object tracks; |
| 90 | 187 | |
| 188 | + /** | |
| 189 | + * 开始时间 | |
| 190 | + */ | |
| 91 | 191 | @Schema(description = "开始时间") |
| 92 | 192 | private String startTime; |
| 93 | 193 | |
| 194 | + /** | |
| 195 | + * 结束时间 | |
| 196 | + */ | |
| 94 | 197 | @Schema(description = "结束时间") |
| 95 | 198 | private String endTime; |
| 96 | 199 | |
| 200 | + /** | |
| 201 | + * 文件下载地址 | |
| 202 | + */ | |
| 97 | 203 | @Schema(description = "文件下载地址(录像下载使用)") |
| 98 | 204 | private DownloadFileInfo downLoadFilePath; |
| 99 | 205 | |
| ... | ... | @@ -102,6 +208,23 @@ public class StreamContent { |
| 102 | 208 | public StreamContent(){ |
| 103 | 209 | |
| 104 | 210 | } |
| 211 | + | |
| 212 | + public Integer getHttpPort() { | |
| 213 | + return httpPort; | |
| 214 | + } | |
| 215 | + | |
| 216 | + public void setHttpPort(Integer httpPort) { | |
| 217 | + this.httpPort = httpPort; | |
| 218 | + } | |
| 219 | + | |
| 220 | + public Integer getPort() { | |
| 221 | + return port; | |
| 222 | + } | |
| 223 | + | |
| 224 | + public void setPort(Integer port) { | |
| 225 | + this.port = port; | |
| 226 | + } | |
| 227 | + | |
| 105 | 228 | public StreamContent(StreamInfo streamInfo) { |
| 106 | 229 | if (streamInfo == null) { |
| 107 | 230 | return; | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamPlayPath.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.bean; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * 视频流播放地址对象 | |
| 7 | + * | |
| 8 | + * @Author WangXin | |
| 9 | + * @Data 2025/1/14 | |
| 10 | + * @Version 1.0.0 | |
| 11 | + */ | |
| 12 | +@Schema(description = "视频流播放地址对象") | |
| 13 | +public class StreamPlayPath { | |
| 14 | + /** | |
| 15 | + * 应用名 | |
| 16 | + */ | |
| 17 | + @Schema(description = "应用名") | |
| 18 | + private String app; | |
| 19 | + | |
| 20 | + /** | |
| 21 | + * 流ID | |
| 22 | + */ | |
| 23 | + @Schema(description = "流ID") | |
| 24 | + private String stream; | |
| 25 | + | |
| 26 | + /** | |
| 27 | + * IP | |
| 28 | + */ | |
| 29 | + @Schema(description = "IP") | |
| 30 | + private String ip; | |
| 31 | + | |
| 32 | + /** | |
| 33 | + * HTTP-FLV流地址 | |
| 34 | + */ | |
| 35 | + @Schema(description = "HTTP-FLV流地址") | |
| 36 | + private String flv; | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * HTTPS-FLV流地址 | |
| 40 | + */ | |
| 41 | + @Schema(description = "HTTPS-FLV流地址") | |
| 42 | + private String https_flv; | |
| 43 | + | |
| 44 | + /** | |
| 45 | + * Websocket-FLV流地址 | |
| 46 | + */ | |
| 47 | + @Schema(description = "Websocket-FLV流地址") | |
| 48 | + private String ws_flv; | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * Websockets-FLV流地址 | |
| 52 | + */ | |
| 53 | + @Schema(description = "Websockets-FLV流地址") | |
| 54 | + private String wss_flv; | |
| 55 | + | |
| 56 | + /** | |
| 57 | + * HTTP-FMP4流地址 | |
| 58 | + */ | |
| 59 | + @Schema(description = "HTTP-FMP4流地址") | |
| 60 | + private String fmp4; | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * HTTPS-FMP4流地址 | |
| 64 | + */ | |
| 65 | + @Schema(description = "HTTPS-FMP4流地址") | |
| 66 | + private String https_fmp4; | |
| 67 | + | |
| 68 | + /** | |
| 69 | + * Websocket-FMP4流地址 | |
| 70 | + */ | |
| 71 | + @Schema(description = "Websocket-FMP4流地址") | |
| 72 | + private String ws_fmp4; | |
| 73 | + | |
| 74 | + /** | |
| 75 | + * Websockets-FMP4流地址 | |
| 76 | + */ | |
| 77 | + @Schema(description = "Websockets-FMP4流地址") | |
| 78 | + private String wss_fmp4; | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * HLS流地址 | |
| 82 | + */ | |
| 83 | + @Schema(description = "HLS流地址") | |
| 84 | + private String hls; | |
| 85 | + | |
| 86 | + /** | |
| 87 | + * HTTPS-HLS流地址 | |
| 88 | + */ | |
| 89 | + @Schema(description = "HTTPS-HLS流地址") | |
| 90 | + private String https_hls; | |
| 91 | + | |
| 92 | + /** | |
| 93 | + * Websocket-HLS流地址 | |
| 94 | + */ | |
| 95 | + @Schema(description = "Websocket-HLS流地址") | |
| 96 | + private String ws_hls; | |
| 97 | + | |
| 98 | + /** | |
| 99 | + * Websockets-HLS流地址 | |
| 100 | + */ | |
| 101 | + @Schema(description = "Websockets-HLS流地址") | |
| 102 | + private String wss_hls; | |
| 103 | + | |
| 104 | + /** | |
| 105 | + * HTTP-TS流地址 | |
| 106 | + */ | |
| 107 | + @Schema(description = "HTTP-TS流地址") | |
| 108 | + private String ts; | |
| 109 | + | |
| 110 | + /** | |
| 111 | + * HTTPS-TS流地址 | |
| 112 | + */ | |
| 113 | + @Schema(description = "HTTPS-TS流地址") | |
| 114 | + private String https_ts; | |
| 115 | + | |
| 116 | + /** | |
| 117 | + * Websocket-TS流地址 | |
| 118 | + */ | |
| 119 | + @Schema(description = "Websocket-TS流地址") | |
| 120 | + private String ws_ts; | |
| 121 | + | |
| 122 | + /** | |
| 123 | + * Websockets-TS流地址 | |
| 124 | + */ | |
| 125 | + @Schema(description = "Websockets-TS流地址") | |
| 126 | + private String wss_ts; | |
| 127 | + | |
| 128 | + /** | |
| 129 | + * RTMP流地址 | |
| 130 | + */ | |
| 131 | + @Schema(description = "RTMP流地址") | |
| 132 | + private String rtmp; | |
| 133 | + | |
| 134 | + /** | |
| 135 | + * RTMPS流地址 | |
| 136 | + */ | |
| 137 | + @Schema(description = "RTMPS流地址") | |
| 138 | + private String rtmps; | |
| 139 | + | |
| 140 | + /** | |
| 141 | + * RTSP流地址 | |
| 142 | + */ | |
| 143 | + @Schema(description = "RTSP流地址") | |
| 144 | + private String rtsp; | |
| 145 | + | |
| 146 | + /** | |
| 147 | + * RTSPS流地址 | |
| 148 | + */ | |
| 149 | + @Schema(description = "RTSPS流地址") | |
| 150 | + private String rtsps; | |
| 151 | + | |
| 152 | + /** | |
| 153 | + * RTC流地址 | |
| 154 | + */ | |
| 155 | + @Schema(description = "RTC流地址") | |
| 156 | + private String rtc; | |
| 157 | + | |
| 158 | + /** | |
| 159 | + * RTCS流地址 | |
| 160 | + */ | |
| 161 | + @Schema(description = "RTCS流地址") | |
| 162 | + private String rtcs; | |
| 163 | + | |
| 164 | + public String getApp() { | |
| 165 | + return app; | |
| 166 | + } | |
| 167 | + | |
| 168 | + public void setApp(String app) { | |
| 169 | + this.app = app; | |
| 170 | + } | |
| 171 | + | |
| 172 | + public String getStream() { | |
| 173 | + return stream; | |
| 174 | + } | |
| 175 | + | |
| 176 | + public void setStream(String stream) { | |
| 177 | + this.stream = stream; | |
| 178 | + } | |
| 179 | + | |
| 180 | + public String getIp() { | |
| 181 | + return ip; | |
| 182 | + } | |
| 183 | + | |
| 184 | + public void setIp(String ip) { | |
| 185 | + this.ip = ip; | |
| 186 | + } | |
| 187 | + | |
| 188 | + public String getFlv() { | |
| 189 | + return flv; | |
| 190 | + } | |
| 191 | + | |
| 192 | + public void setFlv(String flv) { | |
| 193 | + this.flv = flv; | |
| 194 | + } | |
| 195 | + | |
| 196 | + public String getHttps_flv() { | |
| 197 | + return https_flv; | |
| 198 | + } | |
| 199 | + | |
| 200 | + public void setHttps_flv(String https_flv) { | |
| 201 | + this.https_flv = https_flv; | |
| 202 | + } | |
| 203 | + | |
| 204 | + public String getWs_flv() { | |
| 205 | + return ws_flv; | |
| 206 | + } | |
| 207 | + | |
| 208 | + public void setWs_flv(String ws_flv) { | |
| 209 | + this.ws_flv = ws_flv; | |
| 210 | + } | |
| 211 | + | |
| 212 | + public String getWss_flv() { | |
| 213 | + return wss_flv; | |
| 214 | + } | |
| 215 | + | |
| 216 | + public void setWss_flv(String wss_flv) { | |
| 217 | + this.wss_flv = wss_flv; | |
| 218 | + } | |
| 219 | + | |
| 220 | + public String getFmp4() { | |
| 221 | + return fmp4; | |
| 222 | + } | |
| 223 | + | |
| 224 | + public void setFmp4(String fmp4) { | |
| 225 | + this.fmp4 = fmp4; | |
| 226 | + } | |
| 227 | + | |
| 228 | + public String getHttps_fmp4() { | |
| 229 | + return https_fmp4; | |
| 230 | + } | |
| 231 | + | |
| 232 | + public void setHttps_fmp4(String https_fmp4) { | |
| 233 | + this.https_fmp4 = https_fmp4; | |
| 234 | + } | |
| 235 | + | |
| 236 | + public String getWs_fmp4() { | |
| 237 | + return ws_fmp4; | |
| 238 | + } | |
| 239 | + | |
| 240 | + public void setWs_fmp4(String ws_fmp4) { | |
| 241 | + this.ws_fmp4 = ws_fmp4; | |
| 242 | + } | |
| 243 | + | |
| 244 | + public String getWss_fmp4() { | |
| 245 | + return wss_fmp4; | |
| 246 | + } | |
| 247 | + | |
| 248 | + public void setWss_fmp4(String wss_fmp4) { | |
| 249 | + this.wss_fmp4 = wss_fmp4; | |
| 250 | + } | |
| 251 | + | |
| 252 | + public String getHls() { | |
| 253 | + return hls; | |
| 254 | + } | |
| 255 | + | |
| 256 | + public void setHls(String hls) { | |
| 257 | + this.hls = hls; | |
| 258 | + } | |
| 259 | + | |
| 260 | + public String getHttps_hls() { | |
| 261 | + return https_hls; | |
| 262 | + } | |
| 263 | + | |
| 264 | + public void setHttps_hls(String https_hls) { | |
| 265 | + this.https_hls = https_hls; | |
| 266 | + } | |
| 267 | + | |
| 268 | + public String getWs_hls() { | |
| 269 | + return ws_hls; | |
| 270 | + } | |
| 271 | + | |
| 272 | + public void setWs_hls(String ws_hls) { | |
| 273 | + this.ws_hls = ws_hls; | |
| 274 | + } | |
| 275 | + | |
| 276 | + public String getWss_hls() { | |
| 277 | + return wss_hls; | |
| 278 | + } | |
| 279 | + | |
| 280 | + public void setWss_hls(String wss_hls) { | |
| 281 | + this.wss_hls = wss_hls; | |
| 282 | + } | |
| 283 | + | |
| 284 | + public String getTs() { | |
| 285 | + return ts; | |
| 286 | + } | |
| 287 | + | |
| 288 | + public void setTs(String ts) { | |
| 289 | + this.ts = ts; | |
| 290 | + } | |
| 291 | + | |
| 292 | + public String getHttps_ts() { | |
| 293 | + return https_ts; | |
| 294 | + } | |
| 295 | + | |
| 296 | + public void setHttps_ts(String https_ts) { | |
| 297 | + this.https_ts = https_ts; | |
| 298 | + } | |
| 299 | + | |
| 300 | + public String getWs_ts() { | |
| 301 | + return ws_ts; | |
| 302 | + } | |
| 303 | + | |
| 304 | + public void setWs_ts(String ws_ts) { | |
| 305 | + this.ws_ts = ws_ts; | |
| 306 | + } | |
| 307 | + | |
| 308 | + public String getWss_ts() { | |
| 309 | + return wss_ts; | |
| 310 | + } | |
| 311 | + | |
| 312 | + public void setWss_ts(String wss_ts) { | |
| 313 | + this.wss_ts = wss_ts; | |
| 314 | + } | |
| 315 | + | |
| 316 | + public String getRtmp() { | |
| 317 | + return rtmp; | |
| 318 | + } | |
| 319 | + | |
| 320 | + public void setRtmp(String rtmp) { | |
| 321 | + this.rtmp = rtmp; | |
| 322 | + } | |
| 323 | + | |
| 324 | + public String getRtmps() { | |
| 325 | + return rtmps; | |
| 326 | + } | |
| 327 | + | |
| 328 | + public void setRtmps(String rtmps) { | |
| 329 | + this.rtmps = rtmps; | |
| 330 | + } | |
| 331 | + | |
| 332 | + public String getRtsp() { | |
| 333 | + return rtsp; | |
| 334 | + } | |
| 335 | + | |
| 336 | + public void setRtsp(String rtsp) { | |
| 337 | + this.rtsp = rtsp; | |
| 338 | + } | |
| 339 | + | |
| 340 | + public String getRtsps() { | |
| 341 | + return rtsps; | |
| 342 | + } | |
| 343 | + | |
| 344 | + public void setRtsps(String rtsps) { | |
| 345 | + this.rtsps = rtsps; | |
| 346 | + } | |
| 347 | + | |
| 348 | + public String getRtc() { | |
| 349 | + return rtc; | |
| 350 | + } | |
| 351 | + | |
| 352 | + public void setRtc(String rtc) { | |
| 353 | + this.rtc = rtc; | |
| 354 | + } | |
| 355 | + | |
| 356 | + public String getRtcs() { | |
| 357 | + return rtcs; | |
| 358 | + } | |
| 359 | + | |
| 360 | + public void setRtcs(String rtcs) { | |
| 361 | + this.rtcs = rtcs; | |
| 362 | + } | |
| 363 | + | |
| 364 | + @Override | |
| 365 | + public String toString() { | |
| 366 | + final StringBuilder sb = new StringBuilder("StreamPlayPath{"); | |
| 367 | + sb.append("app='").append(app).append('\''); | |
| 368 | + sb.append(", stream='").append(stream).append('\''); | |
| 369 | + sb.append(", ip='").append(ip).append('\''); | |
| 370 | + sb.append(", flv='").append(flv).append('\''); | |
| 371 | + sb.append(", https_flv='").append(https_flv).append('\''); | |
| 372 | + sb.append(", ws_flv='").append(ws_flv).append('\''); | |
| 373 | + sb.append(", wss_flv='").append(wss_flv).append('\''); | |
| 374 | + sb.append(", fmp4='").append(fmp4).append('\''); | |
| 375 | + sb.append(", https_fmp4='").append(https_fmp4).append('\''); | |
| 376 | + sb.append(", ws_fmp4='").append(ws_fmp4).append('\''); | |
| 377 | + sb.append(", wss_fmp4='").append(wss_fmp4).append('\''); | |
| 378 | + sb.append(", hls='").append(hls).append('\''); | |
| 379 | + sb.append(", https_hls='").append(https_hls).append('\''); | |
| 380 | + sb.append(", ws_hls='").append(ws_hls).append('\''); | |
| 381 | + sb.append(", wss_hls='").append(wss_hls).append('\''); | |
| 382 | + sb.append(", ts='").append(ts).append('\''); | |
| 383 | + sb.append(", https_ts='").append(https_ts).append('\''); | |
| 384 | + sb.append(", ws_ts='").append(ws_ts).append('\''); | |
| 385 | + sb.append(", wss_ts='").append(wss_ts).append('\''); | |
| 386 | + sb.append(", rtmp='").append(rtmp).append('\''); | |
| 387 | + sb.append(", rtmps='").append(rtmps).append('\''); | |
| 388 | + sb.append(", rtsp='").append(rtsp).append('\''); | |
| 389 | + sb.append(", rtsps='").append(rtsps).append('\''); | |
| 390 | + sb.append(", rtc='").append(rtc).append('\''); | |
| 391 | + sb.append(", rtcs='").append(rtcs).append('\''); | |
| 392 | + sb.append('}'); | |
| 393 | + return sb.toString(); | |
| 394 | + } | |
| 395 | + | |
| 396 | + public static StreamPlayPath build(StreamContent streamContent,String stream){ | |
| 397 | + StreamPlayPath streamPlayPath = new StreamPlayPath(); | |
| 398 | + streamPlayPath.setApp(streamContent.getApp()); | |
| 399 | + streamPlayPath.setStream(streamContent.getStream()==null?stream:streamContent.getStream()); | |
| 400 | + streamPlayPath.setIp(streamContent.getIp()); | |
| 401 | + streamPlayPath.setFlv(streamContent.getFlv()); | |
| 402 | + streamPlayPath.setHttps_flv(streamContent.getHttps_flv()); | |
| 403 | + streamPlayPath.setWs_flv(streamContent.getWs_flv()); | |
| 404 | + streamPlayPath.setWss_flv(streamContent.getWss_flv()); | |
| 405 | + streamPlayPath.setFmp4(streamContent.getFmp4()); | |
| 406 | + streamPlayPath.setHttps_fmp4(streamContent.getHttps_fmp4()); | |
| 407 | + streamPlayPath.setWs_fmp4(streamContent.getWs_fmp4()); | |
| 408 | + streamPlayPath.setWss_fmp4(streamContent.getWss_fmp4()); | |
| 409 | + streamPlayPath.setHls(streamContent.getHls()); | |
| 410 | + streamPlayPath.setHttps_hls(streamContent.getHttps_hls()); | |
| 411 | + streamPlayPath.setWs_hls(streamContent.getWs_hls()); | |
| 412 | + streamPlayPath.setWss_hls(streamContent.getWss_hls()); | |
| 413 | + streamPlayPath.setTs(streamContent.getTs()); | |
| 414 | + streamPlayPath.setHttps_ts(streamContent.getHttps_ts()); | |
| 415 | + streamPlayPath.setWs_ts(streamContent.getWs_ts()); | |
| 416 | + streamPlayPath.setWss_ts(streamContent.getWss_ts()); | |
| 417 | + streamPlayPath.setRtmp(streamContent.getRtmp()); | |
| 418 | + streamPlayPath.setRtmps(streamContent.getRtmps()); | |
| 419 | + streamPlayPath.setRtsp(streamContent.getRtsp()); | |
| 420 | + streamPlayPath.setRtsps(streamContent.getRtsps()); | |
| 421 | + streamPlayPath.setRtc(streamContent.getRtc()); | |
| 422 | + streamPlayPath.setRtcs(streamContent.getRtcs()); | |
| 423 | + return streamPlayPath; | |
| 424 | + } | |
| 425 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/Jt1078OfCarController.java
| ... | ... | @@ -9,45 +9,29 @@ import com.alibaba.fastjson2.JSON; |
| 9 | 9 | import com.alibaba.fastjson2.JSONArray; |
| 10 | 10 | import com.alibaba.fastjson2.JSONException; |
| 11 | 11 | import com.alibaba.fastjson2.JSONObject; |
| 12 | -import com.genersoft.iot.vmp.VManageBootstrap; | |
| 13 | 12 | import com.genersoft.iot.vmp.conf.MediaConfig; |
| 14 | 13 | import com.genersoft.iot.vmp.conf.StreamProxyTask; |
| 15 | 14 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 16 | -import com.genersoft.iot.vmp.jt1078.app.VideoServerApp; | |
| 17 | -import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; | |
| 18 | -import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; | |
| 15 | +import com.genersoft.iot.vmp.jtt1078.app.VideoServerApp; | |
| 16 | +import com.genersoft.iot.vmp.jtt1078.publisher.PublishManager; | |
| 19 | 17 | import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; |
| 20 | 18 | import com.genersoft.iot.vmp.service.IStreamProxyService; |
| 21 | 19 | import com.genersoft.iot.vmp.service.IStreamPushService; |
| 22 | 20 | import com.genersoft.iot.vmp.service.StremProxyService1078; |
| 21 | +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; | |
| 23 | 22 | import com.genersoft.iot.vmp.vmanager.bean.StreamContent; |
| 23 | +import com.genersoft.iot.vmp.vmanager.bean.StreamPlayPath; | |
| 24 | 24 | import com.genersoft.iot.vmp.vmanager.jt1078.platform.ben.HttpClientPostEntity; |
| 25 | -import com.genersoft.iot.vmp.vmanager.jt1078.platform.ben.TestEntity; | |
| 26 | 25 | import com.genersoft.iot.vmp.vmanager.jt1078.platform.config.Jt1078ConfigBean; |
| 27 | 26 | import com.genersoft.iot.vmp.vmanager.jt1078.platform.config.RtspConfigBean; |
| 28 | 27 | import com.genersoft.iot.vmp.vmanager.jt1078.platform.config.TuohuaConfigBean; |
| 28 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.PatrolDataReq; | |
| 29 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.SimFlow; | |
| 29 | 30 | import com.genersoft.iot.vmp.vmanager.jt1078.platform.handler.HttpClientUtil; |
| 31 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.service.FlowService; | |
| 32 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.service.Jt1078OfService; | |
| 30 | 33 | import com.genersoft.iot.vmp.vmanager.streamProxy.StreamProxyController; |
| 31 | 34 | import com.genersoft.iot.vmp.vmanager.streamPush.StreamPushController; |
| 32 | - | |
| 33 | -import java.io.ByteArrayOutputStream; | |
| 34 | -import java.io.IOException; | |
| 35 | -import java.net.URISyntaxException; | |
| 36 | -import java.security.Key; | |
| 37 | -import java.security.KeyFactory; | |
| 38 | -import java.security.spec.X509EncodedKeySpec; | |
| 39 | -import java.text.MessageFormat; | |
| 40 | -import java.util.ArrayList; | |
| 41 | -import java.util.Date; | |
| 42 | -import java.util.HashMap; | |
| 43 | -import java.util.Iterator; | |
| 44 | -import java.util.List; | |
| 45 | -import java.util.Map; | |
| 46 | -import java.util.Objects; | |
| 47 | -import java.util.concurrent.TimeUnit; | |
| 48 | -import javax.crypto.Cipher; | |
| 49 | -import javax.servlet.http.HttpServletRequest; | |
| 50 | - | |
| 51 | 35 | import org.apache.commons.collections4.CollectionUtils; |
| 52 | 36 | import org.apache.commons.collections4.MapUtils; |
| 53 | 37 | import org.apache.commons.lang3.RandomUtils; |
| ... | ... | @@ -59,14 +43,35 @@ import org.slf4j.Logger; |
| 59 | 43 | import org.slf4j.LoggerFactory; |
| 60 | 44 | import org.springframework.beans.factory.annotation.Autowired; |
| 61 | 45 | import org.springframework.beans.factory.annotation.Value; |
| 46 | +import org.springframework.data.redis.core.Cursor; | |
| 47 | +import org.springframework.data.redis.core.RedisCallback; | |
| 62 | 48 | import org.springframework.data.redis.core.RedisTemplate; |
| 49 | +import org.springframework.data.redis.core.ScanOptions; | |
| 63 | 50 | import org.springframework.util.Base64Utils; |
| 64 | -import org.springframework.web.bind.annotation.GetMapping; | |
| 65 | -import org.springframework.web.bind.annotation.PathVariable; | |
| 66 | -import org.springframework.web.bind.annotation.PostMapping; | |
| 67 | -import org.springframework.web.bind.annotation.RequestBody; | |
| 68 | -import org.springframework.web.bind.annotation.RequestMapping; | |
| 69 | -import org.springframework.web.bind.annotation.RestController; | |
| 51 | +import org.springframework.web.bind.annotation.*; | |
| 52 | +import sun.misc.Signal; | |
| 53 | +import sun.misc.SignalHandler; | |
| 54 | + | |
| 55 | +import javax.annotation.Resource; | |
| 56 | +import javax.crypto.Cipher; | |
| 57 | +import javax.validation.constraints.NotBlank; | |
| 58 | +import java.io.ByteArrayOutputStream; | |
| 59 | +import java.io.IOException; | |
| 60 | +import java.net.URISyntaxException; | |
| 61 | +import java.security.Key; | |
| 62 | +import java.security.KeyFactory; | |
| 63 | +import java.security.spec.X509EncodedKeySpec; | |
| 64 | +import java.text.MessageFormat; | |
| 65 | +import java.text.SimpleDateFormat; | |
| 66 | +import java.time.LocalDateTime; | |
| 67 | +import java.util.*; | |
| 68 | +import java.util.concurrent.ArrayBlockingQueue; | |
| 69 | +import java.util.concurrent.ConcurrentHashMap; | |
| 70 | +import java.util.concurrent.ThreadPoolExecutor; | |
| 71 | +import java.util.concurrent.TimeUnit; | |
| 72 | +import java.util.stream.Collectors; | |
| 73 | + | |
| 74 | +import static com.genersoft.iot.vmp.utils.DateUtil.formatter; | |
| 70 | 75 | |
| 71 | 76 | @RestController |
| 72 | 77 | @RequestMapping({"/api/jt1078/query"}) |
| ... | ... | @@ -97,6 +102,14 @@ public class Jt1078OfCarController { |
| 97 | 102 | private Date tokenDate; |
| 98 | 103 | @Autowired |
| 99 | 104 | private IStreamProxyService streamProxyService; |
| 105 | + @Resource | |
| 106 | + private FlowService flowService; | |
| 107 | + @Resource | |
| 108 | + private Jt1078OfService jt1078OfService; | |
| 109 | + //存储历史端口 key -->端口 value ---> sim-channel-startTime-endTime-port | |
| 110 | + public static final ConcurrentHashMap<Integer, Set<String>> map = new ConcurrentHashMap<>(); | |
| 111 | + | |
| 112 | + private static final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,20,40,TimeUnit.SECONDS,new ArrayBlockingQueue<>(10)); | |
| 100 | 113 | |
| 101 | 114 | @Value("${spring.profiles.active}") |
| 102 | 115 | private String profilesActive; |
| ... | ... | @@ -105,10 +118,14 @@ public class Jt1078OfCarController { |
| 105 | 118 | public Jt1078OfCarController() { |
| 106 | 119 | } |
| 107 | 120 | |
| 121 | + @GetMapping("/flow/countList/{timeType}/{statisticsType}/{time}") | |
| 122 | + public Map<String, SimFlow> flowCountList(@PathVariable String statisticsType, @PathVariable String time, @PathVariable String timeType) { | |
| 123 | + return flowService.getList(timeType, statisticsType, time); | |
| 124 | + } | |
| 125 | + | |
| 108 | 126 | @GetMapping({"/company/tree"}) |
| 109 | 127 | public Map<String, Object> requestTreeOfCompany() { |
| 110 | 128 | Map<String, Object> resultMap = new HashMap(); |
| 111 | - | |
| 112 | 129 | try { |
| 113 | 130 | resultMap.put("code", "1"); |
| 114 | 131 | List<HashMap<String, Object>> compList = new ArrayList(); |
| ... | ... | @@ -119,14 +136,13 @@ public class Jt1078OfCarController { |
| 119 | 136 | resultMap.put("code", "-100"); |
| 120 | 137 | resultMap.put("msg", "请求错误,请联系管理员"); |
| 121 | 138 | } |
| 122 | - | |
| 123 | 139 | return resultMap; |
| 124 | 140 | } |
| 125 | 141 | |
| 126 | 142 | @GetMapping({"/car/tree/{companyId}"}) |
| 127 | 143 | public Map<String, Object> requestTreeOfCarByCompanyId(@PathVariable String companyId) { |
| 144 | + clearRedisTree(); | |
| 128 | 145 | Map<String, Object> resultMap = new HashMap(); |
| 129 | - | |
| 130 | 146 | try { |
| 131 | 147 | List<HashMap<String, Object>> linesCars = this.tuohuaConfigBean.requestOfLineAndCarAndCombationTree(this.httpClientUtil, companyId); |
| 132 | 148 | resultMap.put("result", linesCars); |
| ... | ... | @@ -135,19 +151,45 @@ public class Jt1078OfCarController { |
| 135 | 151 | resultMap.put("code", "-100"); |
| 136 | 152 | resultMap.put("msg", "请求错误,请联系管理员"); |
| 137 | 153 | } |
| 138 | - | |
| 139 | 154 | return resultMap; |
| 140 | 155 | } |
| 141 | 156 | |
| 157 | + /** | |
| 158 | + * redis清除在线车辆 | |
| 159 | + */ | |
| 160 | + public void clearRedisTree() { | |
| 161 | + Set<Object> carId = redisTemplate.keys("carId"); | |
| 162 | + if (carId != null) { | |
| 163 | + redisTemplate.delete(carId); | |
| 164 | + } | |
| 165 | + } | |
| 166 | + /** | |
| 167 | + * redis存储在线车辆 | |
| 168 | + * @param linesCars | |
| 169 | + */ | |
| 170 | + public HashMap<String, Object> storageRedisTree(List<HashMap<String, Object>> linesCars) { | |
| 171 | + HashMap<String, Object> map = new HashMap<>(); | |
| 172 | + for (HashMap<String, Object> linesCar : linesCars) { | |
| 173 | + if (null == linesCar.get("children") && linesCar.get("abnormalStatus").equals(1)) { | |
| 174 | + map.put(linesCar.get("id").toString(), linesCar); | |
| 175 | + } | |
| 176 | + if (null == linesCar.get("abnormalStatus")) { | |
| 177 | + List<HashMap<String, Object>> listMap = (List<HashMap<String, Object>>) linesCar.get("children"); | |
| 178 | + if (!listMap.isEmpty()) { | |
| 179 | + storageRedisTree(listMap); | |
| 180 | + } | |
| 181 | + } | |
| 182 | + } | |
| 183 | + return map; | |
| 184 | + } | |
| 185 | + | |
| 142 | 186 | @GetMapping({"/car/sim/{zbh}"}) |
| 143 | 187 | public Map<String, Object> requestSimple(@PathVariable String zbh) { |
| 144 | 188 | Map<String, Object> resultMap = new HashMap(); |
| 145 | - | |
| 146 | 189 | try { |
| 147 | 190 | if (this.cookieTimeOut()) { |
| 148 | 191 | this.requestToken(); |
| 149 | 192 | } |
| 150 | - | |
| 151 | 193 | String url = MessageFormat.format(this.tuohuaConfigBean.getSimURL(), zbh); |
| 152 | 194 | HttpClientPostEntity clientPostEntity = this.httpClientUtil.doGet(url, this.jsessionid); |
| 153 | 195 | if (Objects.isNull(clientPostEntity)) { |
| ... | ... | @@ -170,83 +212,184 @@ public class Jt1078OfCarController { |
| 170 | 212 | } |
| 171 | 213 | } |
| 172 | 214 | |
| 215 | + /** | |
| 216 | + * 请求设备推送流 | |
| 217 | + * @param sim sim号 | |
| 218 | + * @param channel 通道号 | |
| 219 | + * @return | |
| 220 | + */ | |
| 173 | 221 | @GetMapping({"/send/request/io/{sim}/{channel}"}) |
| 174 | - public Map<String, Object> sendIORequest(@PathVariable String sim, @PathVariable String channel) { | |
| 175 | - Map<String, Object> resultMap = new HashMap(); | |
| 222 | + public StreamContent sendIORequest(@PathVariable String sim, @PathVariable String channel) { | |
| 176 | 223 | if (StringUtils.isBlank(sim)) { |
| 177 | - resultMap.put("code", "-100"); | |
| 178 | - resultMap.put("msg", "sim 不能为空"); | |
| 179 | - return resultMap; | |
| 180 | - } else if (StringUtils.isBlank(channel)) { | |
| 181 | - resultMap.put("code", "-100"); | |
| 182 | - resultMap.put("msg", "channel 不能为空"); | |
| 183 | - return resultMap; | |
| 184 | - } else { | |
| 185 | - String msg = null; | |
| 186 | - String stream = StringUtils.join(new String[]{sim, "-", channel}); | |
| 187 | - String url = StringUtils.replace(this.jt1078ConfigBean.getJt1078Url(), "{0}", this.jt1078ConfigBean.getJt1078SendPort()); | |
| 224 | + throw new ControllerException(-100,"sim 不能为空"); | |
| 225 | + } | |
| 226 | + if (StringUtils.isBlank(channel)) { | |
| 227 | + throw new ControllerException(-100, "channel 不能为空"); | |
| 228 | + } | |
| 229 | + String stream = StringUtils.join(new String[]{sim, "-", channel}); | |
| 230 | + StreamContent streamContent = getStreamContentPlayURL(stream); | |
| 231 | + if (Objects.isNull(streamContent) || StringUtils.isBlank(streamContent.getWs_flv())){ | |
| 232 | + sendIORequest(stream); | |
| 233 | + } | |
| 234 | + streamContent = getStreamContent(stream); | |
| 235 | + streamContent.setPort(jt1078ConfigBean.getPort()); | |
| 236 | + streamContent.setHttpPort(jt1078ConfigBean.getHttpPort()); | |
| 237 | + return streamContent; | |
| 238 | + } | |
| 188 | 239 | |
| 189 | - try { | |
| 190 | - StreamContent streamContent = this.getStreamContentPlayURL(StringUtils.join(new String[]{stream})); | |
| 191 | - if (Objects.isNull(streamContent) || StringUtils.isBlank(streamContent.getWs_flv())) { | |
| 192 | - HttpClientPostEntity entity = this.createServerLister(stream); | |
| 193 | - if (Objects.isNull(entity)) { | |
| 194 | - resultMap.put("code", "-20"); | |
| 195 | - resultMap.put("msg", "新建链接错误,请稍后再试"); | |
| 196 | - | |
| 197 | - return resultMap; | |
| 198 | - } | |
| 240 | + /** | |
| 241 | + * 批量请求设备推送流 | |
| 242 | + * @param streamList 流唯一值集合 {sim-channel} | |
| 243 | + */ | |
| 244 | + @PostMapping({"/beachSend/request/io"}) | |
| 245 | + public List<StreamContent> beachSendIORequest(@RequestBody List<String> streamList) { | |
| 246 | + if (CollectionUtils.isEmpty(streamList)) { | |
| 247 | + throw new ControllerException(ErrorCode.ERROR400); | |
| 248 | + } | |
| 249 | + List<StreamContent> list = new ArrayList<>(); | |
| 250 | + for (String stream : streamList) { | |
| 251 | + sendIORequest(stream); | |
| 252 | + list.add(getStreamContent(stream)); | |
| 253 | + } | |
| 254 | + return list; | |
| 255 | + } | |
| 199 | 256 | |
| 200 | - resultMap.put("port", entity.getPort()); | |
| 201 | - resultMap.put("httpPort", entity.getHttpPort()); | |
| 202 | - resultMap.put("stream", stream); | |
| 203 | - this.redisTemplate.opsForValue().set("tag:history:port:" + stream, entity.getPort(), 2L, TimeUnit.DAYS); | |
| 204 | - this.redisTemplate.opsForValue().set("tag:history:httpPort:" + stream, entity.getHttpPort(), 2L, TimeUnit.DAYS); | |
| 205 | - this.redisTemplate.opsForValue().set("tag:history:httpPort:time:" + stream, (new Date()).getTime(), StreamProxyTask.TIME_OUT, TimeUnit.SECONDS); | |
| 206 | - redisTemplate.delete("jt1078:count:" + stream); | |
| 207 | - | |
| 208 | - msg = this.jt1078ConfigBean.formatMessageId(sim, channel, this.rtspConfigBean, entity.getPort()); | |
| 209 | - VManageBootstrap.getBean(VideoServerApp.class).newVideoServer(stream, entity.getPort(), entity.getHttpPort()); | |
| 210 | - | |
| 211 | - HttpClientPostEntity entity1 = httpClientUtil.doPost(url, msg, null); | |
| 212 | - Map<String, Object> resultMap1 = this.chooseEntity(entity1, url, false); | |
| 213 | - if (Objects.nonNull(resultMap1)) { | |
| 214 | - return resultMap1; | |
| 215 | - } | |
| 257 | + /** | |
| 258 | + * 视频巡查功能开启 | |
| 259 | + * @param PatrolDataReqList 视频巡查请求对象 | |
| 260 | + */ | |
| 261 | + @PostMapping({"/startPatrol/request/io"}) | |
| 262 | + public List<StreamContent> startPatrol(@RequestBody List<PatrolDataReq> PatrolDataReqList) { | |
| 263 | + if (CollectionUtils.isEmpty(PatrolDataReqList)) { | |
| 264 | + throw new ControllerException(ErrorCode.ERROR400); | |
| 265 | + } | |
| 266 | + List<String> simList = PatrolDataReqList.stream().map(patrolDataReq -> { | |
| 267 | + String id = patrolDataReq.getId(); | |
| 268 | + String[] split = id.split("_"); | |
| 269 | + String stream = split[1] + "-" + split[2]; | |
| 270 | + patrolDataReq.setId(stream); | |
| 271 | + redisTemplate.opsForValue().set("patrol:stream:" + stream, patrolDataReq); | |
| 272 | + return stream; | |
| 273 | + }).distinct().collect(Collectors.toList()); | |
| 274 | + return beachSendIORequest(simList); | |
| 275 | + } | |
| 216 | 276 | |
| 217 | - createStreamProxy(stream, entity.getPort()); | |
| 218 | - Map<String, Object> resultMap2 = this.getStreamContent(stream, entity.getHttpPort()); | |
| 219 | - if (Objects.nonNull(resultMap2) && Objects.nonNull(resultMap2.get("code")) && !StringUtils.equals(resultMap2.get("code").toString(), "1")) { | |
| 220 | - return resultMap2; | |
| 221 | - } | |
| 277 | + /** | |
| 278 | + * 关闭视频巡查 (必须在关闭按钮后关闭,否则流量在一直消耗) | |
| 279 | + */ | |
| 280 | + @GetMapping("/stopPatrol/request/io") | |
| 281 | + public void stopPatrol(){ | |
| 282 | + Set<Object> keys = redisTemplate.keys("patrol:stream:*"); | |
| 283 | + redisTemplate.delete(keys); | |
| 284 | + } | |
| 222 | 285 | |
| 223 | - streamContent = (StreamContent) resultMap2.get("streamContent"); | |
| 224 | - } else { | |
| 225 | - resultMap.put("port", redisTemplate.opsForValue().get("tag:history:port:" + stream)); | |
| 226 | - resultMap.put("httpPort", redisTemplate.opsForValue().get("tag:history:httpPort:" + stream)); | |
| 227 | - resultMap.put("stream", stream); | |
| 286 | + /** | |
| 287 | + * 获取播放地址对外接口 | |
| 288 | + * @param sim | |
| 289 | + * @param channel | |
| 290 | + * @return | |
| 291 | + */ | |
| 292 | + @PostMapping("/send/request/getPlay") | |
| 293 | + public Object sendGetPlay(@RequestParam String sim, @RequestParam String channel) { | |
| 294 | + if (StringUtils.isBlank(sim)) { | |
| 295 | + throw new ControllerException(-100,"sim 不能为空"); | |
| 296 | + } | |
| 297 | + if (StringUtils.isBlank(channel)) { | |
| 298 | + throw new ControllerException(-100, "channel 不能为空"); | |
| 299 | + } | |
| 300 | + String stream = sim + "-" + channel; | |
| 301 | + | |
| 302 | + StreamPushItem streamPushItem = streamPushController.getStreamPushItem(sim, channel); | |
| 303 | + StreamContent playUrl = null; | |
| 304 | + if (null != streamPushItem) { | |
| 305 | + playUrl = streamPushController.getPlayUrl(streamPushItem.getApp(), stream, streamPushItem.getMediaServerId()); | |
| 306 | + if (playUrl != null){ | |
| 307 | + return StreamPlayPath.build(playUrl,stream); | |
| 308 | + } | |
| 309 | + } | |
| 310 | + HashMap<String, Object> resultMap = new HashMap<>(); | |
| 311 | + sendIORequest(stream); | |
| 312 | + try { | |
| 313 | + Thread.sleep(4000); | |
| 314 | + } catch (InterruptedException e) { | |
| 315 | + throw new RuntimeException(e); | |
| 316 | + } | |
| 317 | + if (map.get("code").equals("1")){ | |
| 318 | + | |
| 319 | + while (true){ | |
| 320 | + streamPushItem = streamPushController.getStreamPushItem(sim, channel); | |
| 321 | + if (null == streamPushItem) { | |
| 322 | + try { | |
| 323 | + Thread.sleep(1000); | |
| 324 | + } catch (InterruptedException e) { | |
| 325 | + throw new RuntimeException(e); | |
| 326 | + } | |
| 327 | + continue; | |
| 328 | + } | |
| 329 | + playUrl = streamPushController.getPlayUrl(streamPushItem.getApp(), stream, streamPushItem.getMediaServerId()); | |
| 330 | + if (playUrl == null){ | |
| 331 | + try { | |
| 332 | + Thread.sleep(1000); | |
| 333 | + } catch (InterruptedException e) { | |
| 334 | + throw new RuntimeException(e); | |
| 335 | + } | |
| 336 | + continue; | |
| 228 | 337 | } |
| 338 | + return StreamPlayPath.build(playUrl,stream); | |
| 339 | + } | |
| 340 | + } | |
| 341 | + throw new RuntimeException("获取视频失败"); | |
| 342 | + } | |
| 229 | 343 | |
| 230 | 344 | |
| 231 | - resultMap.put("code", "1"); | |
| 232 | - resultMap.put("message", "OK"); | |
| 233 | - resultMap.put("data", streamContent); | |
| 234 | - return resultMap; | |
| 235 | - } catch (IOException | InterruptedException | URISyntaxException var11) { | |
| 236 | - Exception e = var11; | |
| 237 | - log.error("发送推流指令异常;[{}],[{}]", new Object[]{url, msg, e}); | |
| 238 | - resultMap.put("code", "-20"); | |
| 239 | - resultMap.put("msg", "发送推流指令异常"); | |
| 240 | - return resultMap; | |
| 241 | - } catch (Exception e) { | |
| 242 | - log.error("发送推流指令异常;[{}],[{}]", new Object[]{url, msg, e}); | |
| 243 | - resultMap.put("code", "-20"); | |
| 244 | - resultMap.put("msg", "发送推流指令异常"); | |
| 245 | - return resultMap; | |
| 345 | + /** | |
| 346 | + * 请求设备开始推流 | |
| 347 | + * @param stream 流唯一标识 | |
| 348 | + */ | |
| 349 | + public void sendIORequest(String stream) { | |
| 350 | + | |
| 351 | + threadPoolExecutor.execute(() -> { | |
| 352 | + String msg = null; | |
| 353 | + // http://192.168.168.241:8100/device/{0} 指令下发地址 | |
| 354 | + String url = StringUtils.replace(jt1078ConfigBean.getJt1078Url(), "{0}", jt1078ConfigBean.getJt1078SendPort()); | |
| 355 | + try { | |
| 356 | + // http://192.169.1.88:3333/new/server/{pushKey}/{port}/{httpPort} | |
| 357 | + // 根据 开始和结束1078的端口号生成 | |
| 358 | + Integer port = jt1078ConfigBean.getPort(); | |
| 359 | + Integer httpPort = jt1078ConfigBean.getHttpPort(); | |
| 360 | + HttpClientPostEntity entity = createServerLister(stream, port, httpPort); | |
| 361 | + if (Objects.isNull(entity)) { | |
| 362 | + throw new ControllerException(ErrorCode.ERROR450); | |
| 363 | + } | |
| 364 | + //port 推流端口 | |
| 365 | + //httpPort 拉流端口 | |
| 366 | + //stream 流名称 | |
| 367 | + redisTemplate.opsForValue().set("tag:history:port:" + stream, entity.getPort(), 2L, TimeUnit.DAYS); | |
| 368 | + redisTemplate.opsForValue().set("tag:history:httpPort:" + stream, entity.getHttpPort(), 2L, TimeUnit.DAYS); | |
| 369 | + redisTemplate.opsForValue().set("tag:history:httpPort:time:" + stream, (new Date()).getTime(), StreamProxyTask.TIME_OUT, TimeUnit.SECONDS); | |
| 370 | + redisTemplate.delete("jt1078:count:" + stream); | |
| 371 | + String[] split = stream.split("-"); | |
| 372 | + msg = jt1078ConfigBean.formatMessageId(split[0], split[1], rtspConfigBean, entity.getPort()); | |
| 373 | + HttpClientPostEntity entity1 = httpClientUtil.doPost(url, msg, jsessionid); | |
| 374 | + chooseEntity(entity1, url, false); | |
| 375 | + log.info("发送[ {} ]推流指令成功 ===》 {}", stream, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); | |
| 376 | + } catch (Exception e) { | |
| 377 | + log.error("发送推流指令异常;[{}], [{}], [{}]", url, msg, e.getMessage()); | |
| 378 | + throw new ControllerException(ErrorCode.ERROR420); | |
| 246 | 379 | } |
| 247 | - } | |
| 380 | + }); | |
| 248 | 381 | } |
| 249 | 382 | |
| 383 | + /** | |
| 384 | + * 停止推送 | |
| 385 | + * | |
| 386 | + * @param sim | |
| 387 | + * @param channel | |
| 388 | + * @param stream | |
| 389 | + * @param port | |
| 390 | + * @param httpPort | |
| 391 | + * @return | |
| 392 | + */ | |
| 250 | 393 | @GetMapping({"/send/stop/io/{sim}/{channel}/{stream}/{port}/{httpPort}"}) |
| 251 | 394 | public Map<String, Object> sendIORequestStop(@PathVariable String sim, @PathVariable String channel, @PathVariable String stream, @PathVariable Integer port, @PathVariable Integer httpPort) { |
| 252 | 395 | Map<String, Object> resultMap = new HashMap(); |
| ... | ... | @@ -292,6 +435,13 @@ public class Jt1078OfCarController { |
| 292 | 435 | } |
| 293 | 436 | } |
| 294 | 437 | |
| 438 | + /** | |
| 439 | + * 停止推送 | |
| 440 | + * | |
| 441 | + * @param sim | |
| 442 | + * @param channel | |
| 443 | + * @return | |
| 444 | + */ | |
| 295 | 445 | @GetMapping({"/send/stop/io/{sim}/{channel}"}) |
| 296 | 446 | public Map<String, Object> sendIORequestStop(@PathVariable String sim, @PathVariable String channel) { |
| 297 | 447 | Map<String, Object> resultMap = new HashMap(); |
| ... | ... | @@ -323,7 +473,6 @@ public class Jt1078OfCarController { |
| 323 | 473 | |
| 324 | 474 | for (int i = 0; i < count; ++i) { |
| 325 | 475 | StreamPushItem item = streamPushItems.get(i); |
| 326 | - | |
| 327 | 476 | try { |
| 328 | 477 | this.streamProxyController.del(item.getApp(), item.getStream()); |
| 329 | 478 | this.streamPushService.stop(item.getApp(), item.getStream()); |
| ... | ... | @@ -332,7 +481,6 @@ public class Jt1078OfCarController { |
| 332 | 481 | log.error("推流停止失败,[{}]", item, e); |
| 333 | 482 | } |
| 334 | 483 | } |
| 335 | - | |
| 336 | 484 | resultMap.put("code", "1"); |
| 337 | 485 | resultMap.put("message", "OK"); |
| 338 | 486 | return resultMap; |
| ... | ... | @@ -345,6 +493,15 @@ public class Jt1078OfCarController { |
| 345 | 493 | } |
| 346 | 494 | } |
| 347 | 495 | |
| 496 | + /** | |
| 497 | + * 历史数据列表 | |
| 498 | + * | |
| 499 | + * @param sim | |
| 500 | + * @param channel | |
| 501 | + * @param startTime | |
| 502 | + * @param endTime | |
| 503 | + * @return | |
| 504 | + */ | |
| 348 | 505 | @GetMapping({"/history/list/{sim}/{channel}/{startTime}/{endTime}"}) |
| 349 | 506 | public Map<String, Object> historyListOfSim(@PathVariable String sim, @PathVariable String channel, @PathVariable String startTime, @PathVariable String endTime) { |
| 350 | 507 | Map<String, Object> resultMap = new HashMap(); |
| ... | ... | @@ -366,10 +523,9 @@ public class Jt1078OfCarController { |
| 366 | 523 | return resultMap; |
| 367 | 524 | } else { |
| 368 | 525 | String url = StringUtils.replace(this.jt1078ConfigBean.getJt1078Url(), "{0}", this.jt1078ConfigBean.getHistoryListPort()); |
| 369 | - startTime = this.formatTime(startTime); | |
| 370 | - endTime = this.formatTime(endTime); | |
| 526 | + startTime = this.formatTime(startTime).substring(2); | |
| 527 | + endTime = this.formatTime(endTime).substring(2); | |
| 371 | 528 | String msg = this.jt1078ConfigBean.formatMessageHistoryListRTSP(sim, channel, startTime, endTime); |
| 372 | - | |
| 373 | 529 | try { |
| 374 | 530 | HttpClientPostEntity entity = this.httpClientUtil.doPost(url, msg, (String) null); |
| 375 | 531 | if (Objects.isNull(entity)) { |
| ... | ... | @@ -377,263 +533,353 @@ public class Jt1078OfCarController { |
| 377 | 533 | resultMap.put("msg", "请求历史视频列表错误,请联系管理员"); |
| 378 | 534 | return resultMap; |
| 379 | 535 | } else { |
| 380 | - Map<String, Object> resultMap1 = this.chooseEntity(entity, url, true); | |
| 381 | - if (Objects.nonNull(resultMap1)) { | |
| 382 | - return resultMap1; | |
| 383 | - } else { | |
| 384 | - HashMap<String, Object> hashMap = (HashMap) JSON.parseObject(entity.getResultStr(), HashMap.class); | |
| 385 | - if (MapUtils.isNotEmpty(hashMap) && Objects.nonNull(hashMap.get("data"))) { | |
| 386 | - JSONObject dataJO = (JSONObject) hashMap.get("data"); | |
| 387 | - if (Objects.nonNull(dataJO.get("items"))) { | |
| 388 | - JSONArray jsonArray = (JSONArray) dataJO.get("items"); | |
| 389 | - for (Object o : jsonArray) { | |
| 390 | - JSONObject jo = (JSONObject) o; | |
| 391 | - String startTimeStr = jo.getString("startTime"); | |
| 392 | - if (StringUtils.isEmpty(startTimeStr)) { | |
| 393 | - startTimeStr = StringUtils.join(String.valueOf(System.currentTimeMillis()), "-", String.valueOf(RandomUtils.nextInt(1, 1000))); | |
| 394 | - } else { | |
| 395 | - startTimeStr = StringUtils.replace(startTimeStr, "-", ""); | |
| 396 | - startTimeStr = StringUtils.replace(startTimeStr, ":", ""); | |
| 397 | - startTimeStr = StringUtils.replace(startTimeStr, " ", ""); | |
| 398 | - } | |
| 399 | - String channelMapping = StringUtils.join(new String[]{sim, "-", startTimeStr, "-", channel}); | |
| 400 | - jo.put("channelMapping", channelMapping); | |
| 401 | - } | |
| 536 | + chooseEntity(entity, url, true); | |
| 537 | + HashMap<String, Object> hashMap = (HashMap) JSON.parseObject(entity.getResultStr(), HashMap.class); | |
| 538 | + if (MapUtils.isNotEmpty(hashMap) && Objects.nonNull(hashMap.get("data"))) { | |
| 539 | + JSONObject dataJO = (JSONObject) hashMap.get("data"); | |
| 540 | + HashSet<String> set = new HashSet<>(); | |
| 541 | + if (Objects.nonNull(dataJO.get("items"))) { | |
| 542 | + JSONArray jsonArray = (JSONArray) dataJO.get("items"); | |
| 543 | + jsonArray = | |
| 544 | + new JSONArray( | |
| 545 | + jsonArray.stream() | |
| 546 | + .map(json -> dateCon((JSONObject) json, sim, channel)) | |
| 547 | + .filter(jsonObject -> { | |
| 548 | + // 获取channelMapping并转换为List以便于比较 | |
| 549 | + String channelMapping = jsonObject.getString("channelMapping"); | |
| 550 | + return set.add(channelMapping); | |
| 551 | + }) | |
| 552 | + .collect(Collectors.toList()) | |
| 553 | + ); | |
| 554 | + if (jsonArray.size() > 1) { | |
| 555 | + jsonArray = filterContainedRanges(jsonArray); | |
| 402 | 556 | } |
| 557 | + dataJO.put("items", jsonArray); | |
| 403 | 558 | } |
| 404 | - resultMap.put("code", "1"); | |
| 405 | - | |
| 406 | - resultMap.put("obj", hashMap); | |
| 407 | - return resultMap; | |
| 408 | 559 | } |
| 560 | + resultMap.put("code", "1"); | |
| 561 | + resultMap.put("obj", hashMap); | |
| 562 | + return resultMap; | |
| 409 | 563 | } |
| 410 | - } catch (URISyntaxException var11) { | |
| 411 | - URISyntaxException e = var11; | |
| 412 | - log.error("发送获取历史视频指令异常;[{}],[{}]", new Object[]{url, msg, e}); | |
| 413 | - resultMap.put("code", "-20"); | |
| 414 | - resultMap.put("msg", "发送获取历史视频指令异常"); | |
| 415 | - return resultMap; | |
| 416 | - } catch (IOException var12) { | |
| 417 | - IOException e = var12; | |
| 564 | + } catch (Exception e) { | |
| 418 | 565 | log.error("发送获取历史视频指令异常;[{}],[{}]", new Object[]{url, msg, e}); |
| 419 | - resultMap.put("code", "-20"); | |
| 420 | - resultMap.put("msg", "发送获取历史视频指令异常"); | |
| 421 | - return resultMap; | |
| 566 | + throw new ControllerException(-20, "发送获取历史视频指令异常"); | |
| 422 | 567 | } |
| 423 | 568 | } |
| 424 | 569 | } |
| 425 | 570 | |
| 426 | - @GetMapping({"/send/request/io/history/{sim}/{channel}/{startTime}/{endTime}/{channelMapping}"}) | |
| 427 | - public Map<String, Object> sendIORequestOfHistory(@PathVariable String sim, @PathVariable String channel, @PathVariable String startTime, @PathVariable String endTime, @PathVariable String channelMapping) { | |
| 571 | + public static JSONArray filterContainedRanges(JSONArray jsonArray) { | |
| 572 | + List<JSONObject> list = new ArrayList<>(); | |
| 573 | + for (int i = 0; i < jsonArray.size(); i++) { | |
| 574 | + list.add(jsonArray.getJSONObject(i)); | |
| 575 | + } | |
| 576 | + | |
| 577 | + // 过滤逻辑 | |
| 578 | + List<JSONObject> filteredList = list.stream() | |
| 579 | + .filter(timeRange -> !isAnyOtherRangeContainingThis(list, timeRange)) | |
| 580 | + .collect(Collectors.toList()); | |
| 581 | + | |
| 582 | + // 将过滤后的列表转换回 JSONArray | |
| 583 | + return new JSONArray(filteredList); | |
| 584 | + } | |
| 585 | + | |
| 586 | + private static boolean isAnyOtherRangeContainingThis(List<JSONObject> jsonArray, JSONObject timeRange) { | |
| 587 | + LocalDateTime startTimeInner = LocalDateTime.parse(timeRange.getString("startTime"), formatter); | |
| 588 | + LocalDateTime endTimeInner = LocalDateTime.parse(timeRange.getString("endTime"), formatter); | |
| 589 | + | |
| 590 | + return jsonArray.stream() | |
| 591 | + .anyMatch(other -> !other.equals(timeRange) && | |
| 592 | + isContainedIn(startTimeInner, endTimeInner, other)); | |
| 593 | + } | |
| 594 | + | |
| 595 | + private static boolean isContainedIn(LocalDateTime startTimeInner, LocalDateTime endTimeInner, JSONObject outer) { | |
| 596 | + LocalDateTime startTimeOuter = LocalDateTime.parse(outer.getString("startTime"), formatter); | |
| 597 | + LocalDateTime endTimeOuter = LocalDateTime.parse(outer.getString("endTime"), formatter); | |
| 598 | + | |
| 599 | + return !startTimeInner.isBefore(startTimeOuter) && !endTimeInner.isAfter(endTimeOuter); | |
| 600 | + } | |
| 601 | + | |
| 602 | + /** | |
| 603 | + * json对象时间转换 | |
| 604 | + * | |
| 605 | + * @param jsonObject | |
| 606 | + * @param sim | |
| 607 | + * @param channel | |
| 608 | + */ | |
| 609 | + public JSONObject dateCon(JSONObject jsonObject, String sim, String channel) { | |
| 610 | + String startTimeStr = jsonObject.getString("startTime"); | |
| 611 | + if (StringUtils.isEmpty(startTimeStr)) { | |
| 612 | + startTimeStr = StringUtils.join(String.valueOf(System.currentTimeMillis()), "-", String.valueOf(RandomUtils.nextInt(1, 1000))); | |
| 613 | + } else { | |
| 614 | + startTimeStr = StringUtils | |
| 615 | + .replace(startTimeStr, "-", "") | |
| 616 | + .replace(":", "") | |
| 617 | + .replace(" ", ""); | |
| 618 | + } | |
| 619 | + String channelMapping = StringUtils.join(new String[]{sim, "-", startTimeStr, "-", channel}); | |
| 620 | + jsonObject.put("channelMapping", channelMapping); | |
| 621 | + return jsonObject; | |
| 622 | + } | |
| 623 | + | |
| 624 | + /** | |
| 625 | + * 停止历史视频回放 | |
| 626 | + * | |
| 627 | + * @param channel | |
| 628 | + * @param sim | |
| 629 | + * @return | |
| 630 | + */ | |
| 631 | + @PostMapping("/send/request/stop/history/{sim}/{channel}") | |
| 632 | + public Map<String, Object> stopHistory(@PathVariable String channel, @PathVariable String sim) { | |
| 428 | 633 | Map<String, Object> resultMap = new HashMap(); |
| 429 | 634 | if (StringUtils.isBlank(sim)) { |
| 430 | 635 | resultMap.put("code", "-100"); |
| 431 | 636 | resultMap.put("msg", "sim 不能为空"); |
| 432 | 637 | return resultMap; |
| 433 | - } else if (StringUtils.isBlank(channel)) { | |
| 638 | + } | |
| 639 | + if (StringUtils.isBlank(channel)) { | |
| 434 | 640 | resultMap.put("code", "-100"); |
| 435 | 641 | resultMap.put("msg", "channel 不能为空"); |
| 436 | 642 | return resultMap; |
| 437 | - } else if (StringUtils.isBlank(startTime)) { | |
| 438 | - resultMap.put("code", "-100"); | |
| 439 | - resultMap.put("msg", "开始时间不能为空"); | |
| 440 | - return resultMap; | |
| 441 | - } else if (StringUtils.isBlank(endTime)) { | |
| 442 | - resultMap.put("code", "-100"); | |
| 443 | - resultMap.put("msg", "结束时间不能为空"); | |
| 643 | + } | |
| 644 | + String url = StringUtils.replace(this.jt1078ConfigBean.getJt1078Url(), "{0}", "9202"); | |
| 645 | + String msg = this.jt1078ConfigBean.formatMessageHistoryStopRTSP(sim, channel, this.rtspConfigBean); | |
| 646 | + try { | |
| 647 | + HttpClientPostEntity entity1 = this.httpClientUtil.doPost(url, msg, (String) null); | |
| 648 | + resultMap.put("code", "1"); | |
| 649 | + resultMap.put("obj", entity1); | |
| 444 | 650 | return resultMap; |
| 445 | - } else { | |
| 651 | + } catch (Exception e) { | |
| 652 | + throw new RuntimeException(e); | |
| 653 | + } | |
| 654 | + } | |
| 446 | 655 | |
| 447 | - StreamContent streamContent = this.getStreamContentPlayURL(StringUtils.join(new String[]{channelMapping})); | |
| 448 | - if (Objects.nonNull(streamContent) && StringUtils.isNotEmpty(streamContent.getWs_flv())) { | |
| 656 | + /** | |
| 657 | + * 历史视频回放 | |
| 658 | + * | |
| 659 | + * @param sim sim号 | |
| 660 | + * @param channel 通道号 | |
| 661 | + * @param startTime 开始时间 | |
| 662 | + * @param endTime 结束时间 | |
| 663 | + * @param channelMapping 通道唯一值 | |
| 664 | + */ | |
| 665 | + @GetMapping({"/send/request/io/history/{sim}/{channel}/{startTime}/{endTime}/{channelMapping}"}) | |
| 666 | + public Map<String, Object> sendIORequestOfHistory(@PathVariable @NotBlank(message = "sim 不能为空") String sim, | |
| 667 | + @PathVariable @NotBlank(message = "channel 不能为空") String channel, | |
| 668 | + @PathVariable @NotBlank(message = "开始时间不能为空") String startTime, | |
| 669 | + @PathVariable @NotBlank(message = "结束时间不能为空") String endTime, | |
| 670 | + String channelMapping) { | |
| 671 | + Map<String, Object> resultMap = new HashMap(); | |
| 672 | + startTime = this.formatTime(startTime); | |
| 673 | + endTime = this.formatTime(endTime); | |
| 674 | + String key = StringUtils.join(new String[]{sim, "-", channel}); | |
| 675 | + channelMapping = StringUtils.join(new String[]{sim, "-", channel,"-",startTime,"-",endTime}); | |
| 676 | + Integer historyPort = createHistoryPort(channelMapping); | |
| 677 | + channelMapping = StringUtils.join(new String[]{channelMapping,"_", String.valueOf(historyPort)}); | |
| 678 | + this.redisTemplate.opsForValue().set(key, channelMapping, 1L, TimeUnit.HOURS); | |
| 679 | +// PublishManager.getInstance().open(channelMapping); | |
| 680 | + StreamContent streamContent = this.getStreamContentPlayURL(StringUtils.join(new String[]{channelMapping})); | |
| 681 | + if (Objects.nonNull(streamContent) && StringUtils.isNotEmpty(streamContent.getWs_flv())) { | |
| 682 | + resultMap.put("code", "1"); | |
| 683 | + resultMap.put("data", streamContent); | |
| 684 | + resultMap.put("port", redisTemplate.opsForValue().get("tag:history:port:" + channelMapping)); | |
| 685 | + resultMap.put("httpPort", redisTemplate.opsForValue().get("tag:history:httpPort:" + channelMapping)); | |
| 686 | + resultMap.put("stream", channelMapping); | |
| 687 | + return resultMap; | |
| 688 | + } | |
| 689 | + String msg = null; | |
| 690 | + String url = StringUtils.replace(this.jt1078ConfigBean.getJt1078Url(), "{0}", this.jt1078ConfigBean.getPlayHistoryPort()); | |
| 691 | + try { | |
| 692 | + Integer httpPort = this.jt1078ConfigBean.getHttpPort(); | |
| 693 | + HttpClientPostEntity entity = this.createServerLister(channelMapping, historyPort, httpPort); | |
| 694 | + if (Objects.isNull(entity)) { | |
| 695 | + resultMap.put("code", "-20"); | |
| 696 | + resultMap.put("msg", "新建链接错误,请稍后再试"); | |
| 697 | + return resultMap; | |
| 698 | + } else { | |
| 699 | + resultMap.put("stream", channelMapping); | |
| 700 | + resultMap.put("port", entity.getPort()); | |
| 701 | + resultMap.put("httpPort", entity.getHttpPort()); | |
| 702 | + this.redisTemplate.opsForValue().set("tag:history:port:" + channelMapping, entity.getPort(), 2L, TimeUnit.DAYS); | |
| 703 | + this.redisTemplate.opsForValue().set("tag:history:httpPort:" + channelMapping, entity.getHttpPort(), 2L, TimeUnit.DAYS); | |
| 704 | + this.redisTemplate.opsForValue().set("tag:history:httpPort:time:" + channelMapping, (new Date()).getTime(), StreamProxyTask.TIME_OUT, TimeUnit.SECONDS); | |
| 705 | + msg = this.jt1078ConfigBean.formatMessageHistoryPlayRTSP(sim, channel, startTime, endTime, this.rtspConfigBean, entity.getPort()); | |
| 706 | + | |
| 707 | + HttpClientPostEntity entity1 = this.httpClientUtil.doPost(url, msg, (String) null); | |
| 708 | + chooseEntity(entity1, url, true); | |
| 449 | 709 | resultMap.put("code", "1"); |
| 710 | + streamContent = this.getStreamContent(channelMapping); | |
| 450 | 711 | log.info("StreamContent:[{}]", streamContent); |
| 451 | 712 | resultMap.put("data", streamContent); |
| 452 | - | |
| 453 | - resultMap.put("port", redisTemplate.opsForValue().get("tag:history:port:" + channelMapping)); | |
| 454 | - resultMap.put("httpPort", redisTemplate.opsForValue().get("tag:history:httpPort:" + channelMapping)); | |
| 455 | - resultMap.put("stream", channelMapping); | |
| 456 | 713 | return resultMap; |
| 457 | 714 | } |
| 458 | - redisTemplate.delete("jt1078:count:" + channelMapping); | |
| 715 | + }catch (Exception e) { | |
| 716 | + log.error("发送推流指令异常;[{}], [{}], [{}]", url, msg, e.getMessage()); | |
| 717 | + throw new ControllerException(-20, "发送推流指令异常"); | |
| 718 | + } | |
| 719 | + } | |
| 459 | 720 | |
| 460 | - startTime = this.formatTime(startTime); | |
| 461 | - endTime = this.formatTime(endTime); | |
| 721 | + /** | |
| 722 | + * 从set<String>中找到对应唯一的sim-channel值 | |
| 723 | + */ | |
| 724 | + public static String getFindSet(Set<String> set,String targetString) { | |
| 725 | + for (String str : set) { | |
| 726 | + if (str.startsWith(targetString)) { | |
| 727 | + return str; // 找到匹配项后立即返回 | |
| 728 | + } | |
| 729 | + } | |
| 730 | + return null; | |
| 731 | + } | |
| 732 | + /** | |
| 733 | + * 从形如"sim-channel-start-end"的字符串中提取第二个'-'之前的值。 | |
| 734 | + */ | |
| 735 | + private static String getSecondDashValue(String str) { | |
| 736 | + if (str == null || !str.contains("-")) { | |
| 737 | + return null; // 如果输入为空或没有'-',则返回null | |
| 738 | + } | |
| 462 | 739 | |
| 463 | - String key = StringUtils.join(new String[]{sim, "-", channel}); | |
| 464 | - this.redisTemplate.opsForValue().set(key, channelMapping, 1L, TimeUnit.HOURS); | |
| 465 | - String msg = null; | |
| 466 | - log.info("msg:{}", msg); | |
| 467 | - String url = StringUtils.replace(this.jt1078ConfigBean.getJt1078Url(), "{0}", this.jt1078ConfigBean.getPlayHistoryPort()); | |
| 740 | + // 找到第一个和第二个'-'的位置 | |
| 741 | + int firstDashIndex = str.indexOf('-'); | |
| 742 | + int secondDashIndex = str.indexOf('-', firstDashIndex + 1); | |
| 468 | 743 | |
| 469 | - try { | |
| 470 | - HttpClientPostEntity entity = this.createServerLister(channelMapping); | |
| 471 | - if (Objects.isNull(entity)) { | |
| 472 | - resultMap.put("code", "-20"); | |
| 473 | - resultMap.put("msg", "新建链接错误,请稍后再试"); | |
| 474 | - return resultMap; | |
| 475 | - } else { | |
| 476 | - this.chooseEntity(entity, url, false); | |
| 477 | - resultMap.put("stream", channelMapping); | |
| 478 | - resultMap.put("port", entity.getPort()); | |
| 479 | - resultMap.put("httpPort", entity.getHttpPort()); | |
| 480 | - this.redisTemplate.opsForValue().set("tag:history:port:" + channelMapping, entity.getPort(), 2L, TimeUnit.DAYS); | |
| 481 | - this.redisTemplate.opsForValue().set("tag:history:httpPort:" + channelMapping, entity.getHttpPort(), 2L, TimeUnit.DAYS); | |
| 482 | - this.redisTemplate.opsForValue().set("tag:history:httpPort:time:" + channelMapping, (new Date()).getTime(), StreamProxyTask.TIME_OUT, TimeUnit.SECONDS); | |
| 483 | - msg = this.jt1078ConfigBean.formatMessageHistoryPlayRTSP(sim, channel, startTime, endTime, this.rtspConfigBean, entity.getPort()); | |
| 484 | - VManageBootstrap.getBean(VideoServerApp.class).newVideoServer(channelMapping, entity.getPort(), entity.getHttpPort()); | |
| 485 | - | |
| 486 | - this.createStreamProxy(sim + "-" + channel, entity.getHttpPort()); | |
| 487 | - HttpClientPostEntity entity1 = this.httpClientUtil.doPost(url, msg, (String) null); | |
| 488 | - createStreamProxy(channelMapping, entity.getHttpPort()); | |
| 489 | - | |
| 490 | - Map<String, Object> resultMap2 = this.chooseEntity(entity1, url, true); | |
| 491 | - if (Objects.nonNull(resultMap2)) { | |
| 492 | - return resultMap2; | |
| 493 | - } else { | |
| 494 | - resultMap.put("code", "1"); | |
| 495 | - Map<String, Object> resultMap3 = this.getStreamContent(channelMapping, entity.getHttpPort()); | |
| 496 | - if (Objects.nonNull(resultMap3) && Objects.nonNull(resultMap3.get("code")) && !StringUtils.equals(resultMap3.get("code").toString(), "1")) { | |
| 497 | - return resultMap3; | |
| 498 | - } else { | |
| 499 | - streamContent = (StreamContent) resultMap3.get("streamContent"); | |
| 500 | - if (Objects.isNull(streamContent)) { | |
| 501 | - resultMap.put("code", "-20"); | |
| 502 | - resultMap.put("msg", "新建链接错误,请稍后再试"); | |
| 503 | - return resultMap; | |
| 504 | - } else { | |
| 505 | - log.info("StreamContent:[{}]", streamContent); | |
| 506 | - resultMap.put("data", streamContent); | |
| 507 | - return resultMap; | |
| 508 | - } | |
| 509 | - } | |
| 510 | - } | |
| 511 | - } | |
| 512 | - } catch (IOException | URISyntaxException e) { | |
| 513 | - log.error("发送推流指令异常;[{}],[{}]", new Object[]{url, msg, e}); | |
| 514 | - resultMap.put("code", "-20"); | |
| 515 | - resultMap.put("msg", "发送推流指令异常"); | |
| 516 | - return resultMap; | |
| 517 | - } catch (InterruptedException e) { | |
| 518 | - log.error("发送推流指令异常;[{}],[{}]", new Object[]{url, msg, e}); | |
| 519 | - resultMap.put("code", "-20"); | |
| 520 | - resultMap.put("msg", "发送推流指令异常"); | |
| 521 | - return resultMap; | |
| 522 | - } catch (Exception e) { | |
| 523 | - log.error("发送推流指令异常;[{}],[{}]", new Object[]{url, msg, e}); | |
| 524 | - resultMap.put("code", "-20"); | |
| 525 | - resultMap.put("msg", "发送推流指令异常"); | |
| 526 | - return resultMap; | |
| 744 | + // 确保字符串中有至少两个'-' | |
| 745 | + if (firstDashIndex != -1 && secondDashIndex != -1) { | |
| 746 | + // 提取并返回第一个'-'之后、第二个'-'之前的部分 | |
| 747 | + return str.substring(0, secondDashIndex); | |
| 748 | + } else { | |
| 749 | + return null; // 如果少于两个'-',则返回null | |
| 750 | + } | |
| 751 | + } | |
| 752 | + /** | |
| 753 | + * 遍历Map,寻找第一个不包含指定string的Set<String>, | |
| 754 | + * 将该string添加到Set中并返回对应的key,如果没有找到则返回null。 | |
| 755 | + */ | |
| 756 | + private Integer addStringToFirstNonContainingSet(String targetString) { | |
| 757 | + // 使用entrySet()方法直接获取键值对进行迭代,效率更高 | |
| 758 | + for (Map.Entry<Integer, Set<String>> entry : map.entrySet()) { | |
| 759 | + Set<String> set = entry.getValue(); | |
| 760 | + if (set.contains(targetString)){ | |
| 761 | + return entry.getKey(); | |
| 762 | + } | |
| 763 | + // 如果当前Set不包含目标字符串,则添加并返回key | |
| 764 | + String secondDashValue = getSecondDashValue(targetString); | |
| 765 | + String findSet = getFindSet(set, secondDashValue); | |
| 766 | + set.add(targetString); | |
| 767 | + if (secondDashValue != null && findSet == null) { | |
| 768 | + return entry.getKey(); // 立即返回对应的key,不再继续查找 | |
| 769 | + }else { | |
| 770 | + clearMap(String.valueOf(entry.getKey()),findSet); | |
| 527 | 771 | } |
| 528 | 772 | } |
| 773 | + return null; // 如果所有Set都包含目标字符串,则返回null | |
| 529 | 774 | } |
| 530 | 775 | |
| 776 | + /** | |
| 777 | + * 清理map中的值 | |
| 778 | + */ | |
| 779 | + public void clearMap(String key,String value) { | |
| 780 | + if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) { | |
| 781 | + Set<String> strings = map.get(Integer.valueOf(key)); | |
| 782 | + if (strings == null) { | |
| 783 | + return; | |
| 784 | + } | |
| 785 | + if (strings.contains(value)) { | |
| 786 | + PublishManager.getInstance().close(value + "_" + key); | |
| 787 | + try { | |
| 788 | + Thread.sleep(200); | |
| 789 | + } catch (InterruptedException e) { | |
| 790 | + throw new RuntimeException(e); | |
| 791 | + } | |
| 792 | + String[] split = value.split("-"); | |
| 793 | + stopHistory(split[1],split[0]); | |
| 794 | + strings.remove(value); | |
| 795 | + } | |
| 796 | + }else { | |
| 797 | + log.error("清理端口缓存错误 !!!"); | |
| 798 | + } | |
| 799 | + } | |
| 531 | 800 | |
| 532 | - @PostMapping({"/test"}) | |
| 533 | - public String test(@RequestBody TestEntity test) { | |
| 534 | - return "OK"; | |
| 801 | + /** | |
| 802 | + * 创建历史端口 | |
| 803 | + * @param key 通道唯一值 | |
| 804 | + */ | |
| 805 | + public Integer createHistoryPort(String key){ | |
| 806 | + Integer port = addStringToFirstNonContainingSet(key); | |
| 807 | + if (port == null) { | |
| 808 | + throw new RuntimeException(String.format("[ %s ]通道观看人数太多,请等待 !!!",key)); | |
| 809 | + } | |
| 810 | + try { | |
| 811 | + if (redisTemplate.opsForValue().get("history:port:"+port) == null) { | |
| 812 | + startPost(port); | |
| 813 | + redisTemplate.opsForValue().set("history:port:"+port, port); | |
| 814 | + } | |
| 815 | + return port; | |
| 816 | + } catch (Exception e) { | |
| 817 | + log.error("{}",e.getMessage(),e); | |
| 818 | + throw new RuntimeException(String.format("[ %s ]端口启动异常", port)); | |
| 819 | + } | |
| 535 | 820 | } |
| 536 | 821 | |
| 537 | - @GetMapping({"/test1"}) | |
| 538 | - public String test1(HttpServletRequest request) throws URISyntaxException, IOException { | |
| 539 | - this.jsessionid = StringUtils.join(new String[]{"JSESSIONID=", request.getParameter("jsessionid")}); | |
| 540 | - return "OK"; | |
| 822 | + /** | |
| 823 | + * 启动历史端口监听 | |
| 824 | + * @param port 端口 | |
| 825 | + */ | |
| 826 | + private void startPost(Integer port) throws Exception { | |
| 827 | + VideoServerApp videoServerApp = new VideoServerApp(); | |
| 828 | + | |
| 829 | + VideoServerApp.VideoServer videoServer = videoServerApp.getVideoServer(port); | |
| 830 | + Signal.handle(new Signal("TERM"), new SignalHandler() | |
| 831 | + { | |
| 832 | + @Override | |
| 833 | + public void handle(Signal signal) | |
| 834 | + { | |
| 835 | + videoServer.shutdown(); | |
| 836 | + } | |
| 837 | + }); | |
| 838 | + videoServer.historyStart(); | |
| 541 | 839 | } |
| 542 | 840 | |
| 543 | - @Nullable | |
| 544 | - private Map<String, Object> getStreamContent(String stream, int httpPort) throws InterruptedException { | |
| 545 | 841 | |
| 546 | - Map<String, Object> datas = new HashMap(); | |
| 547 | - StreamContent streamContent = requestStreamContent(1, stream, httpPort); | |
| 842 | + @Nullable | |
| 843 | + private StreamContent getStreamContent(String stream){ | |
| 548 | 844 | |
| 845 | + StreamContent streamContent = this.getStreamContentPlayURL(stream); | |
| 549 | 846 | if (Objects.isNull(streamContent) || StringUtils.isEmpty(streamContent.getWs_flv())) { |
| 550 | 847 | streamContent = new StreamContent(); |
| 551 | - streamContent.setWs_flv(StringUtils.replace(this.jt1078ConfigBean.getWs(), "{stream}", stream)); | |
| 552 | - streamContent.setWss_flv(StringUtils.replace(this.jt1078ConfigBean.getWss(), "{stream}", stream)); | |
| 553 | - streamContent.setFlv(StringUtils.replace(this.jt1078ConfigBean.getDownloadFlv(), "{stream}", stream)); | |
| 554 | - | |
| 555 | - | |
| 556 | - new Thread(new Runnable() { | |
| 557 | - @Override | |
| 558 | - public void run() { | |
| 559 | - requestStreamContent(100, stream, httpPort); | |
| 560 | - } | |
| 561 | - }).start(); | |
| 848 | + String authKey = this.jt1078ConfigBean.getPushKey(); | |
| 849 | + streamContent.setWs_flv(StringUtils.replace(this.jt1078ConfigBean.getWs() + authKey, "{stream}", stream)); | |
| 850 | + streamContent.setWss_flv(StringUtils.replace(this.jt1078ConfigBean.getWss() + authKey, "{stream}", stream)); | |
| 851 | + streamContent.setFlv(StringUtils.replace(this.jt1078ConfigBean.getDownloadFlv() + authKey, "{stream}", stream)); | |
| 562 | 852 | } |
| 563 | 853 | |
| 564 | - log.info("StreamContent:[{}]", streamContent); | |
| 565 | - datas.put("code", "1"); | |
| 566 | - datas.put("streamContent", streamContent); | |
| 567 | - return datas; | |
| 854 | + return streamContent; | |
| 568 | 855 | } |
| 569 | 856 | |
| 857 | + /** | |
| 858 | + * 请求获取流 | |
| 859 | + * | |
| 860 | + * @param count | |
| 861 | + * @param stream | |
| 862 | + * @param httpPort | |
| 863 | + * @return | |
| 864 | + */ | |
| 570 | 865 | private StreamContent requestStreamContent(int count, String stream, int httpPort) { |
| 571 | - int index = 0; | |
| 572 | - StreamContent streamContent = null; | |
| 573 | - try { | |
| 574 | - do { | |
| 575 | - ++index; | |
| 576 | - streamContent = this.getStreamContentPlayURL(stream); | |
| 577 | - if (Objects.nonNull(streamContent) && StringUtils.isNotEmpty(streamContent.getWs_flv())) { | |
| 578 | - break; | |
| 579 | - } | |
| 580 | - | |
| 581 | - Object valObj = redisTemplate.opsForValue().get("jt1078:stream:status:" + stream); | |
| 582 | - if (Objects.nonNull(valObj) && StringUtils.equals(valObj.toString(), "1")) { | |
| 583 | - StreamProxyItem streamProxyItem = streamProxyController.one("schedule", stream); | |
| 584 | - if (Objects.nonNull(streamProxyItem) && StringUtils.isNotEmpty(streamProxyItem.getApp())) { | |
| 585 | - try { | |
| 586 | - streamProxyController.start("schedule", stream); | |
| 587 | - } catch (Exception e) { | |
| 588 | - log.error(e.getMessage()); | |
| 589 | - } | |
| 590 | - } else { | |
| 591 | - createStreamProxy(stream, httpPort); | |
| 592 | - } | |
| 593 | - | |
| 594 | - | |
| 595 | - } else if (Objects.nonNull(valObj) && StringUtils.equals(valObj.toString(), "2")) { | |
| 596 | -// streamProxyService.del("schedule", stream); | |
| 597 | -// redisTemplate.delete("jt1078:stream:status:" + stream); | |
| 598 | -// createStreamProxy(stream,httpPort); | |
| 599 | - streamProxyService.stop1("schedule", stream); | |
| 600 | - | |
| 601 | - } else { | |
| 602 | - Object val = this.redisTemplate.opsForValue().get("timeout:" + stream); | |
| 603 | - if (Objects.nonNull(val) && StringUtils.equals(val.toString(), "1")) { | |
| 604 | - try { | |
| 605 | - streamProxyController.start("schedule", stream); | |
| 606 | - } catch (Exception e) { | |
| 607 | - log.error(e.getMessage()); | |
| 608 | - } | |
| 609 | - } | |
| 610 | - } | |
| 611 | - | |
| 612 | - Integer countVal = stremProxyService1078.stopCount(stream); | |
| 613 | - if (Objects.nonNull(countVal)) { | |
| 614 | - index = countVal; | |
| 615 | - } | |
| 616 | - if (index >= count) { | |
| 617 | - | |
| 618 | - break; | |
| 619 | - } | |
| 620 | 866 | |
| 621 | - try { | |
| 622 | - Thread.sleep(1000L); | |
| 623 | - } catch (InterruptedException e) { | |
| 624 | - log.info(e.getMessage()); | |
| 625 | - } | |
| 626 | - } while (index < count); | |
| 627 | 867 | |
| 628 | - } catch (Exception e) { | |
| 629 | - log.error(e.getMessage()); | |
| 630 | - } | |
| 868 | + StreamContent streamContent = this.getStreamContentPlayURL(stream); | |
| 631 | 869 | return streamContent; |
| 632 | 870 | } |
| 633 | 871 | |
| 872 | + /** | |
| 873 | + * 获取视频播放地址 | |
| 874 | + * | |
| 875 | + * @param stream 流名称 | |
| 876 | + * @return 流信息 | |
| 877 | + */ | |
| 634 | 878 | private StreamContent getStreamContentPlayURL(String stream) { |
| 635 | 879 | try { |
| 636 | - return this.streamPushController.getPlayUrl("schedule", stream, this.mediaConfig.getId()); | |
| 880 | + StreamContent streamContent = this.streamPushController.getPlayUrl("schedule", stream, this.mediaConfig.getId()); | |
| 881 | + streamContent.setStream(stream); | |
| 882 | + return streamContent; | |
| 637 | 883 | } catch (ControllerException var3) { |
| 638 | 884 | log.debug("获取播放地址失败:[{}],[{}]", stream, this.mediaConfig.getId()); |
| 639 | 885 | return null; |
| ... | ... | @@ -728,69 +974,80 @@ public class Jt1078OfCarController { |
| 728 | 974 | return StringUtils.replace(time, ":", ""); |
| 729 | 975 | } |
| 730 | 976 | |
| 731 | - private HttpClientPostEntity createServerLister(String channelMapping) throws URISyntaxException, IOException { | |
| 732 | - | |
| 733 | - Integer port = RandomUtils.nextInt(this.jt1078ConfigBean.getStart1078Port(), this.jt1078ConfigBean.getEnd1078Port()); | |
| 734 | - while (true) { | |
| 735 | - port = RandomUtils.nextInt(this.jt1078ConfigBean.getStart1078Port(), this.jt1078ConfigBean.getEnd1078Port()); | |
| 736 | - | |
| 737 | - String key = "jt1078:server:port:" + port; | |
| 738 | - if (!this.redisTemplate.hasKey(key)) { | |
| 739 | - redisTemplate.opsForValue().set("jt1078:server:port:" + port, port, 3, TimeUnit.HOURS); | |
| 740 | - break; | |
| 977 | + /** | |
| 978 | + * 获取所有匹配模式 jt1078:server:port:* 的键,并找到其中剩余时间最短的键。 | |
| 979 | + */ | |
| 980 | + public String findKeyWithShortestTTL(String keyMatch) { | |
| 981 | + String shortestTTLKey = null; | |
| 982 | + long shortestTTL = Long.MAX_VALUE; | |
| 983 | + // 使用 SCAN 命令遍历键空间 | |
| 984 | + Cursor<byte[]> cursor = redisTemplate.execute( | |
| 985 | + (RedisCallback<Cursor<byte[]>>) connection -> { | |
| 986 | + ScanOptions options = ScanOptions.scanOptions().match(keyMatch).count(100).build(); | |
| 987 | + return connection.scan(options); | |
| 988 | + }); | |
| 989 | + | |
| 990 | + if (cursor != null) { | |
| 991 | + while (cursor.hasNext()) { | |
| 992 | + byte[] keyBytes = cursor.next(); | |
| 993 | + String key = new String(keyBytes); | |
| 994 | + | |
| 995 | + // 获取当前键的 TTL | |
| 996 | + Long ttl = redisTemplate.getExpire(key, TimeUnit.SECONDS); | |
| 997 | + if (ttl != null && ttl >= 0 && ttl < shortestTTL) { | |
| 998 | + shortestTTL = ttl; | |
| 999 | + shortestTTLKey = key; | |
| 1000 | + } | |
| 741 | 1001 | } |
| 742 | - | |
| 743 | 1002 | } |
| 1003 | + return shortestTTLKey; | |
| 1004 | + } | |
| 1005 | + | |
| 1006 | + /** | |
| 1007 | + * 创建监听者 | |
| 1008 | + * | |
| 1009 | + * @param channelMapping | |
| 1010 | + * @return | |
| 1011 | + */ | |
| 1012 | + private HttpClientPostEntity createServerLister(String channelMapping, Integer port, Integer httPort) throws URISyntaxException, IOException { | |
| 1013 | + | |
| 1014 | + //不存在存入redis | |
| 1015 | + redisTemplate.opsForValue().set("jt1078:server:port:" + port, port, 3, TimeUnit.HOURS); | |
| 744 | 1016 | // Integer port = 11078; |
| 745 | - Integer httPort = 3333; | |
| 746 | 1017 | |
| 747 | 1018 | String url = this.jt1078ConfigBean.formatPushURL(channelMapping, port, httPort); |
| 748 | - | |
| 749 | 1019 | try { |
| 750 | 1020 | HttpClientPostEntity httpClientPostEntity = new HttpClientPostEntity(); |
| 751 | - | |
| 752 | 1021 | httpClientPostEntity.setHttpPort(httPort); |
| 753 | 1022 | httpClientPostEntity.setPort(port); |
| 754 | 1023 | return httpClientPostEntity; |
| 755 | - | |
| 756 | 1024 | } catch (Exception e) { |
| 757 | 1025 | log.error("url:[{}]", url, e); |
| 758 | 1026 | return null; |
| 759 | 1027 | } |
| 760 | 1028 | } |
| 761 | 1029 | |
| 762 | - private Map<String, Object> chooseEntity(HttpClientPostEntity entity, String url, boolean flag) { | |
| 1030 | + private void chooseEntity(HttpClientPostEntity entity, String url, boolean flag) { | |
| 763 | 1031 | Map<String, Object> result = new HashMap(); |
| 764 | 1032 | if (Objects.isNull(entity)) { |
| 765 | - result.put("code", "301"); | |
| 766 | - result.put("msg", "下发指令异常"); | |
| 767 | - return result; | |
| 1033 | + throw new ControllerException(ErrorCode.ERROR301); | |
| 768 | 1034 | } else { |
| 769 | 1035 | try { |
| 770 | 1036 | Map<String, Object> rsultMap = (Map) JSON.parseObject(entity.getResultStr(), HashMap.class); |
| 771 | 1037 | if (Objects.equals(rsultMap.get("code"), "4000") || Objects.equals(rsultMap.get("code"), 4000)) { |
| 772 | - result.put("code", "304"); | |
| 773 | - result.put("msg", "离线的客户端(请检查设备是否注册或者鉴权"); | |
| 774 | - return result; | |
| 1038 | + throw new ControllerException(ErrorCode.ERROR304); | |
| 775 | 1039 | } |
| 776 | 1040 | |
| 777 | 1041 | if (flag) { |
| 778 | - if (Objects.nonNull(rsultMap.get("success")) && StringUtils.equalsAnyIgnoreCase(String.valueOf(rsultMap.get("success")), new CharSequence[]{"true"})) { | |
| 779 | - return null; | |
| 780 | - } | |
| 781 | - | |
| 782 | 1042 | if (StringUtils.isNoneBlank(new CharSequence[]{rsultMap.get("msg") + ""})) { |
| 783 | - result.put("code", "304"); | |
| 784 | - result.put("msg", rsultMap.get("msg")); | |
| 785 | - return result; | |
| 1043 | + throw new ControllerException(304, String.valueOf(rsultMap.get("msg"))); | |
| 786 | 1044 | } |
| 787 | 1045 | } |
| 788 | 1046 | } catch (Exception var6) { |
| 789 | 1047 | Exception e = var6; |
| 790 | - log.error("entity.getResultStr():{{}}", entity.getResultStr(), e.getMessage()); | |
| 1048 | + log.error("entity.getResultStr():{{}}", entity.getResultStr(), e.getMessage(), e); | |
| 1049 | + throw new ControllerException(500,e.getMessage()); | |
| 791 | 1050 | } |
| 792 | - | |
| 793 | - return null; | |
| 794 | 1051 | } |
| 795 | 1052 | } |
| 796 | 1053 | |
| ... | ... | @@ -841,27 +1098,5 @@ public class Jt1078OfCarController { |
| 841 | 1098 | } |
| 842 | 1099 | } |
| 843 | 1100 | }).start(); |
| 844 | - | |
| 845 | - | |
| 846 | -// String url = StringUtils.replace(jt1078ConfigBean.getGetURL(), "{stream}", stream); | |
| 847 | -// url = StringUtils.replace(url, "{port}", port + ""); | |
| 848 | -// StreamProxyItem item = new StreamProxyItem(); | |
| 849 | -// item.setApp("schedule"); | |
| 850 | -// item.setEnable(true); | |
| 851 | -// item.setEnableAudio(true); | |
| 852 | -// item.setRtpType("default"); | |
| 853 | -// item.setStream(stream); | |
| 854 | -// item.setMediaServerId(mediaConfig.getId()); | |
| 855 | -// item.setUrl(url); | |
| 856 | -// item.setFfmpegCmdKey("ffmpeg.cmd"); | |
| 857 | -// item.setEnable(true); | |
| 858 | -// item.setEnableAudio(true); | |
| 859 | -// item.setEnableMp4(false); | |
| 860 | -// item.setEnableRemoveNoneReader(false); | |
| 861 | -// item.setEnableDisableNoneReader(false); | |
| 862 | -// item.setName(stream); | |
| 863 | -// streamProxyController.save(item); | |
| 864 | - | |
| 865 | - | |
| 866 | 1101 | } |
| 867 | 1102 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/config/DataBuffer.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.jt1078.platform.config; | |
| 2 | + | |
| 3 | +import java.util.ArrayList; | |
| 4 | +import java.util.List; | |
| 5 | +import java.util.concurrent.LinkedBlockingDeque; | |
| 6 | +import java.util.concurrent.atomic.AtomicBoolean; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 数据缓存区 | |
| 10 | + * @Author WangXin | |
| 11 | + * @Data 2024/11/26 | |
| 12 | + * @Version 1.0.0 | |
| 13 | + */ | |
| 14 | +public class DataBuffer<T> { | |
| 15 | + | |
| 16 | + private LinkedBlockingDeque<T> trueQueue = new LinkedBlockingDeque<>(); | |
| 17 | + | |
| 18 | + private LinkedBlockingDeque<T> falseQueue = new LinkedBlockingDeque<>(); | |
| 19 | + | |
| 20 | + private final AtomicBoolean booleanValue = new AtomicBoolean(false); | |
| 21 | + | |
| 22 | + public void setValue(T dataValue){ | |
| 23 | + if (booleanValue.get()){ | |
| 24 | + trueQueue.add(dataValue); | |
| 25 | + }else { | |
| 26 | + falseQueue.add(dataValue); | |
| 27 | + } | |
| 28 | + } | |
| 29 | + | |
| 30 | + public List<T> getDataList(){ | |
| 31 | + if (booleanValue.getAndSet(!booleanValue.get())){ | |
| 32 | + return new ArrayList<>(trueQueue); | |
| 33 | + } | |
| 34 | + return new ArrayList<>(falseQueue); | |
| 35 | + } | |
| 36 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/config/DataBufferConfig.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.jt1078.platform.config; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.SimFlow; | |
| 4 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.service.FlowService; | |
| 5 | +import org.apache.commons.collections4.CollectionUtils; | |
| 6 | +import org.slf4j.Logger; | |
| 7 | +import org.slf4j.LoggerFactory; | |
| 8 | +import org.springframework.context.annotation.Bean; | |
| 9 | +import org.springframework.context.annotation.Configuration; | |
| 10 | + | |
| 11 | +import javax.annotation.Resource; | |
| 12 | +import java.text.SimpleDateFormat; | |
| 13 | +import java.util.Date; | |
| 14 | +import java.util.List; | |
| 15 | +import java.util.Map; | |
| 16 | +import java.util.Set; | |
| 17 | +import java.util.concurrent.ScheduledExecutorService; | |
| 18 | +import java.util.concurrent.TimeUnit; | |
| 19 | +import java.util.stream.Collectors; | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * 数据缓存配置类 | |
| 23 | + * @Author WangXin | |
| 24 | + * @Data 2024/11/26 | |
| 25 | + * @Version 1.0.0 | |
| 26 | + */ | |
| 27 | +@Configuration | |
| 28 | +public class DataBufferConfig { | |
| 29 | + | |
| 30 | + private static final Logger log = LoggerFactory.getLogger(DataBufferConfig.class); | |
| 31 | + | |
| 32 | + @Resource | |
| 33 | + private FlowService flowService; | |
| 34 | + | |
| 35 | + | |
| 36 | + /** | |
| 37 | + * 储存原始数据 | |
| 38 | + * @return | |
| 39 | + */ | |
| 40 | + @Bean("simFlowDataBuffer") | |
| 41 | + public DataBuffer<SimFlow> storeCarOriginalDataDataBuffer(ScheduledExecutorService scheduledExecutor) { | |
| 42 | + DataBuffer<SimFlow> carOriginalDataDataBuffer = new DataBuffer<>(); | |
| 43 | + scheduledExecutor.scheduleAtFixedRate(() -> { | |
| 44 | + try { | |
| 45 | + List<SimFlow> dataList = carOriginalDataDataBuffer.getDataList(); | |
| 46 | + if (CollectionUtils.isNotEmpty(dataList)) { | |
| 47 | + Map<String, SimFlow> map = dataList.stream() | |
| 48 | + .collect(Collectors.toMap( | |
| 49 | + // 创建唯一键:simId_channel_timestamp | |
| 50 | + record -> record.getSim() + "_" + record.getChannel() + "_" + record.getTime(), | |
| 51 | + // 选择要放入map中的值 | |
| 52 | + record -> record, | |
| 53 | + // 解决键冲突问题(如果有相同的键,则保留第一个) | |
| 54 | + (existing, replacement) -> { | |
| 55 | + existing.setFlow(existing.getFlow() + replacement.getFlow()); | |
| 56 | + return existing; | |
| 57 | + } | |
| 58 | + )); | |
| 59 | + //批量落库 | |
| 60 | + Set<Map.Entry<String, SimFlow>> entries = map.entrySet(); | |
| 61 | + entries.forEach(entry -> { | |
| 62 | + SimFlow value = entry.getValue(); | |
| 63 | + SimFlow simFlow = flowService.selectOne(value); | |
| 64 | + if (simFlow == null) { | |
| 65 | + boolean b = flowService.addFlow(value); | |
| 66 | + log.info("流量信息添加 {} ",b?"成功":"失败"); | |
| 67 | + }else { | |
| 68 | + boolean b = flowService.updateFlow(value); | |
| 69 | + log.info("修改库中流量信息 {} ",b?"成功":"失败"); | |
| 70 | + } | |
| 71 | + }); | |
| 72 | + } | |
| 73 | + } catch (Exception e) { | |
| 74 | + log.error("流量统计落库异常 ===》 {}",e.getMessage(), e); | |
| 75 | + } | |
| 76 | + }, 30, 30, TimeUnit.SECONDS); | |
| 77 | + return carOriginalDataDataBuffer; | |
| 78 | + } | |
| 79 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/config/Jt1078ConfigBean.java
| 1 | -package com.genersoft.iot.vmp.vmanager.jt1078.platform.config; import com.genersoft.iot.vmp.vmanager.jt1078.platform.config.RtspConfigBean; import java.util.Objects; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class Jt1078ConfigBean { @Value("${tuohua.bsth.jt1078.url}") private String jt1078Url; @Value("${tuohua.bsth.jt1078.sendPort}") private String jt1078SendPort; @Value("${tuohua.bsth.jt1078.stopSendPort}") private String stopSendPort; @Value("${tuohua.bsth.jt1078.historyListPort}") private String historyListPort; @Value("${tuohua.bsth.jt1078.playHistoryPort}") private String playHistoryPort; @Value("${tuohua.bsth.jt1078.ports}") private String portsOf1078; @Value("${tuohua.bsth.jt1078.pushURL}") private String pushURL; @Value("${tuohua.bsth.jt1078.stopPushURL}") private String stopPUshURL; private Integer start1078Port; private Integer end1078Port; @Value("${tuohua.bsth.jt1078.get.url}") private String getURL; @Value("${tuohua.bsth.jt1078.addPortVal}") private Integer addPort; @Value("${tuohua.bsth.jt1078.ws}") private String ws; @Value("${tuohua.bsth.jt1078.wss}") private String wss; @Value("${tuohua.bsth.jt1078.downloadFLV}") private String downloadFlv; private static final String SEND_IO_MESSAGE_RTSP = "{ \"messageId\": 37121, \"properties\": 0, \"clientId\": \"{clientId}\", \"serialNo\": \"1\", \"ip\": \"{ip}\", \"tcpPort\": \"{tcpPort}\", \"udpPort\": \"{udpPort}\", \"channelNo\": \"{channelNo}\", \"mediaType\": \"1\", \"streamType\": \"1\"}"; private static final String SEND_IO_MESSAGE_RTSP_STOP = "{\"messageId\": 37122,\"properties\": 0,\"clientId\": \"{clientId}\",\"serialNo\": \"1\",\"channelNo\": \"{channelNo}\",\"command\": \"0\",\"closeType\": \"0\",\"streamType\": \"1\"}"; private static final String SEND_IO_HISTORY_RTSP = "{\"msgid\":37381,\"clientId\":\"{clientId}\",\"startTime\":\"{startTime}\",\"endTime\":\"{endTime}\",\"mediaType\":0,\"streamType\":0,\"storageType\":0,\"channelId\":{channelNo}}"; private static final String SEND_IO_PLAY_RTSP = "{\"ip\":\"{ip}\",\"tcpPort\":{tcpPort},\"udpPort\":{udpPort},\"channelNo\":\"{channelNo}\",\"mediaType\":0,\"streamType\":0,\"storageType\":0,\"playbackType\":0,\"playbackSpeed\":1,\"startTime\":\"{startTime}\",\"endTime\":\"{endTime}\",\"clientId\":\"{sim}\",\"messageId\":37377}"; public String formatMessageId(String sim, String channel, RtspConfigBean configBean, Integer port) { String msg = StringUtils.replace("{ \"messageId\": 37121, \"properties\": 0, \"clientId\": \"{clientId}\", \"serialNo\": \"1\", \"ip\": \"{ip}\", \"tcpPort\": \"{tcpPort}\", \"udpPort\": \"{udpPort}\", \"channelNo\": \"{channelNo}\", \"mediaType\": \"1\", \"streamType\": \"1\"}", "{clientId}", sim); msg = StringUtils.replace(msg, "{tcpPort}", (port.intValue() +getAddPort()) + ""); msg = StringUtils.replace(msg, "{udpPort}", (port.intValue() +getAddPort()) + ""); msg = StringUtils.replace(msg, "{channelNo}", channel); return StringUtils.replace(msg, "{ip}", configBean.getRtspIp()); } public String formatMessageStop(String sim, String channel) { String msg = StringUtils.replace("{\"messageId\": 37122,\"properties\": 0,\"clientId\": \"{clientId}\",\"serialNo\": \"1\",\"channelNo\": \"{channelNo}\",\"command\": \"0\",\"closeType\": \"0\",\"streamType\": \"1\"}", "{clientId}", sim); return StringUtils.replace(msg, "{channelNo}", channel); } public String formatMessageHistoryListRTSP(String sim, String channel, String startTime, String endTime) { String msg = StringUtils.replace("{\"msgid\":37381,\"clientId\":\"{clientId}\",\"startTime\":\"{startTime}\",\"endTime\":\"{endTime}\",\"mediaType\":0,\"streamType\":0,\"storageType\":0,\"channelId\":{channelNo}}", "{clientId}", sim); msg = StringUtils.replace(msg, "{startTime}", startTime); msg = StringUtils.replace(msg, "{endTime}", endTime); return StringUtils.replace(msg, "{channelNo}", channel); } public String formatMessageHistoryPlayRTSP(String sim, String channel, String startTime, String endTime, RtspConfigBean configBean, Integer port) { String msg = StringUtils.replace("{\"ip\":\"{ip}\",\"tcpPort\":{tcpPort},\"udpPort\":{udpPort},\"channelNo\":\"{channelNo}\",\"mediaType\":0,\"streamType\":0,\"storageType\":0,\"playbackType\":0,\"playbackSpeed\":1,\"startTime\":\"{startTime}\",\"endTime\":\"{endTime}\",\"clientId\":\"{sim}\",\"messageId\":37377}", "{clientId}", sim); msg = StringUtils.replace(msg, "{startTime}", startTime); msg = StringUtils.replace(msg, "{endTime}", endTime); msg = StringUtils.replace(msg, "{channelNo}", channel); msg = StringUtils.replace(msg, "{tcpPort}", (port.intValue() +getAddPort()) + ""); msg = StringUtils.replace(msg, "{udpPort}", (port.intValue() +getAddPort()) + ""); msg = StringUtils.replace(msg, "{sim}", sim); return StringUtils.replace(msg, "{ip}", configBean.getRtspIp()); } public String formatPushURL(String pushKey, int port, int httpPort) { String msg = StringUtils.replace(this.pushURL, "{pushKey}", pushKey); msg = StringUtils.replace(msg, "{port}", String.valueOf(port)); return StringUtils.replace(msg, "{httpPort}", String.valueOf(httpPort)); } public String formatStopPushURL(String pushKey, int port, int httpPort) { String msg = StringUtils.replace(this.stopPUshURL, "{pushKey}", pushKey); msg = StringUtils.replace(msg, "{port}", String.valueOf(port)); return StringUtils.replace(msg, "{httpPort}", String.valueOf(httpPort)); } public String formatVideoURL(String stream){ String url = StringUtils.replace(getGetURL(),"{stream}",stream); if(!StringUtils.endsWith(url,".flv")){ url = url+".flv"; } return url; } public String getJt1078Url() { return this.jt1078Url; } public String getJt1078SendPort() { return this.jt1078SendPort; } public String getStopSendPort() { return this.stopSendPort; } public String getHistoryListPort() { return this.historyListPort; } public String getPlayHistoryPort() { return this.playHistoryPort; } public String getPushURL() { return this.pushURL; } public Integer getStart1078Port() { if (Objects.isNull(this.start1078Port)) this.start1078Port = Integer.valueOf(Integer.parseInt(StringUtils.substringBefore(this.portsOf1078, ","))); return this.start1078Port; } public Integer getEnd1078Port() { if (Objects.isNull(this.end1078Port)) this.end1078Port = Integer.valueOf(Integer.parseInt(StringUtils.substringAfter(this.portsOf1078, ","))); return this.end1078Port; } public String getStopPUshURL() { return this.stopPUshURL; } public String getGetURL() { return this.getURL; } public Integer getAddPort() { return this.addPort; } public String getWs() { return this.ws; } public String getWss() { return this.wss; } public String getDownloadFlv() { return downloadFlv; } public String getPortsOf1078() { return portsOf1078; } } | |
| 2 | 1 | \ No newline at end of file |
| 2 | +package com.genersoft.iot.vmp.vmanager.jt1078.platform.config; import com.genersoft.iot.vmp.vmanager.jt1078.platform.Jt1078OfCarController; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.util.*; @Component public class Jt1078ConfigBean { @Value("${tuohua.bsth.jt1078.url}") private String jt1078Url; @Value("${tuohua.bsth.jt1078.sendPort}") private String jt1078SendPort; @Value("${tuohua.bsth.jt1078.stopSendPort}") private String stopSendPort; @Value("${tuohua.bsth.jt1078.historyListPort}") private String historyListPort; @Value("${tuohua.bsth.jt1078.playHistoryPort}") private String playHistoryPort; @Value("${tuohua.bsth.jt1078.ports}") private String portsOf1078; @Value("${tuohua.bsth.jt1078.pushURL}") private String pushURL; @Value("${tuohua.bsth.jt1078.stopPushURL}") private String stopPUshURL; private Integer start1078Port; private Integer end1078Port; @Value("${tuohua.bsth.jt1078.get.url}") private String getURL; @Value("${tuohua.bsth.jt1078.addPortVal}") private Integer addPort; @Value("${tuohua.bsth.jt1078.ws}") private String ws; @Value("${tuohua.bsth.jt1078.wss}") private String wss; @Value("${tuohua.bsth.jt1078.downloadFLV}") private String downloadFlv; @Value("${tuohua.bsth.jt1078.port}") private Integer port; @Value("${tuohua.bsth.jt1078.httpPort}") private Integer httpPort; @Value("${spring.profiles.active}") private String profilesActive; @Value("${media.pushKey}") private String pushKey; @Resource private RedisTemplate<String, Integer> redisTemplate; public Integer getPort() { if (port == null) { return 30000; } return port; } public Integer getHttpPort() { if (httpPort == null) { return 30000; } return httpPort; } private Integer getIntPort() { return profilesActive.equals("wx-local") ? 10000 : 0; } @PostConstruct public void initMap() { Set<String> historyPortKeys = redisTemplate.keys("history:port:*"); Set<String> keys = redisTemplate.keys("tag:*"); Set<String> patrolKeys = redisTemplate.keys("patrol:stream:*"); if (!historyPortKeys.isEmpty()) { keys.addAll(historyPortKeys); } if (!patrolKeys.isEmpty()) { keys.addAll(patrolKeys); } if (keys != null) { redisTemplate.delete(keys); } Map<Integer, Set<String>> hashMap = new HashMap<>(); for (int number = getStart1078Port(); number <= getEnd1078Port(); number++) { hashMap.put(number, new HashSet<>()); } Jt1078OfCarController.map.putAll(hashMap); } private static final String SEND_IO_MESSAGE_RTSP = "{ \"messageId\": 37121, \"properties\": 0, \"clientId\": \"{clientId}\", \"serialNo\": \"1\", \"ip\": \"{ip}\", \"tcpPort\": \"{tcpPort}\", \"udpPort\": \"{udpPort}\", \"channelNo\": \"{channelNo}\", \"mediaType\": \"1\", \"streamType\": \"1\"}"; private static final String SEND_IO_MESSAGE_RTSP_STOP = "{\"messageId\": 37122,\"properties\": 0,\"clientId\": \"{clientId}\",\"serialNo\": \"1\",\"channelNo\": \"{channelNo}\",\"command\": \"0\",\"closeType\": \"0\",\"streamType\": \"1\"}"; private static final String SEND_IO_HISTORY_RTSP = "{\"msgid\":37381,\"clientId\":\"{clientId}\",\"startTime\":\"{startTime}\",\"endTime\":\"{endTime}\",\"mediaType\":0,\"streamType\":0,\"storageType\":0,\"channelId\":{channelNo}}"; private static final String SEND_IO_PLAY_RTSP = "{\"ip\":\"{ip}\",\"tcpPort\":{tcpPort},\"udpPort\":{udpPort},\"channelNo\":\"{channelNo}\",\"mediaType\":0,\"streamType\":0,\"storageType\":0,\"playbackType\":0,\"playbackSpeed\":1,\"startTime\":\"{startTime}\",\"endTime\":\"{endTime}\",\"clientId\":\"{sim}\",\"messageId\":37377}"; public String formatMessageId(String sim, String channel, RtspConfigBean configBean, Integer port) { String msg = StringUtils.replace("{ \"messageId\": 37121, \"properties\": 0, \"clientId\": \"{clientId}\", \"serialNo\": \"1\", \"ip\": \"{ip}\", \"tcpPort\": \"{tcpPort}\", \"udpPort\": \"{udpPort}\", \"channelNo\": \"{channelNo}\", \"mediaType\": \"1\", \"streamType\": \"1\"}", "{clientId}", sim); msg = StringUtils.replace(msg, "{tcpPort}", (port.intValue() + getIntPort() + getAddPort()) + ""); msg = StringUtils.replace(msg, "{udpPort}", (port.intValue() + getIntPort() + getAddPort()) + ""); msg = StringUtils.replace(msg, "{channelNo}", channel); return StringUtils.replace(msg, "{ip}", configBean.getRtspIp()); } public String formatMessageStop(String sim, String channel) { String msg = StringUtils.replace("{\"messageId\": 37122,\"properties\": 0,\"clientId\": \"{clientId}\",\"serialNo\": \"1\",\"channelNo\": \"{channelNo}\",\"command\": \"0\",\"closeType\": \"0\",\"streamType\": \"1\"}", "{clientId}", sim); return StringUtils.replace(msg, "{channelNo}", channel); } public String formatMessageHistoryListRTSP(String sim, String channel, String startTime, String endTime) { String msg = StringUtils.replace("{\"msgid\":37381,\"clientId\":\"{clientId}\",\"startTime\":\"{startTime}\",\"endTime\":\"{endTime}\",\"mediaType\":0,\"streamType\":0,\"storageType\":0,\"channelId\":{channelNo}}", "{clientId}", sim); msg = StringUtils.replace(msg, "{startTime}", startTime); msg = StringUtils.replace(msg, "{endTime}", endTime); return StringUtils.replace(msg, "{channelNo}", channel); } public String formatMessageHistoryPlayRTSP(String sim, String channel, String startTime, String endTime, RtspConfigBean configBean, Integer port) { String msg = StringUtils.replace("{\"ip\":\"{ip}\",\"tcpPort\":{tcpPort},\"udpPort\":{udpPort},\"channelNo\":\"{channelNo}\",\"mediaType\":0,\"streamType\":0,\"storageType\":0,\"playbackType\":0,\"playbackSpeed\":1,\"startTime\":\"{startTime}\",\"endTime\":\"{endTime}\",\"clientId\":\"{sim}\",\"messageId\":37377}", "{clientId}", sim); msg = StringUtils.replace(msg, "{startTime}", startTime); msg = StringUtils.replace(msg, "{endTime}", endTime); msg = StringUtils.replace(msg, "{channelNo}", channel); msg = StringUtils.replace(msg, "{tcpPort}", (port.intValue() + getIntPort() +getAddPort()) + ""); msg = StringUtils.replace(msg, "{udpPort}", (port.intValue() + getIntPort() + getAddPort()) + ""); msg = StringUtils.replace(msg, "{sim}", sim); return StringUtils.replace(msg, "{ip}", configBean.getRtspIp()); } public String formatMessageHistoryStopRTSP(String sim, String channel, RtspConfigBean configBean) { String msg = StringUtils.replace("{\"playbackMode\":2,\"channelNo\":{channelNo},\"playbackSpeed\":0,\"clientId\":\"{sim}\"}", "{sim}", sim); return StringUtils.replace(msg, "{channelNo}", channel); } public String formatPushURL(String pushKey, int port, int httpPort) { String msg = StringUtils.replace(this.pushURL, "{pushKey}", pushKey); msg = StringUtils.replace(msg, "{port}", String.valueOf(port)); return StringUtils.replace(msg, "{httpPort}", String.valueOf(httpPort)); } public String formatStopPushURL(String pushKey, int port, int httpPort) { String msg = StringUtils.replace(this.stopPUshURL, "{pushKey}", pushKey); msg = StringUtils.replace(msg, "{port}", String.valueOf(port)); return StringUtils.replace(msg, "{httpPort}", String.valueOf(httpPort)); } public String formatVideoURL(String stream) { String url = StringUtils.replace(getGetURL(), "{stream}", stream); if (!StringUtils.endsWith(url, ".flv")) { url = url + ".flv"; } return url; } public String getJt1078Url() { return this.jt1078Url; } public String getJt1078SendPort() { return this.jt1078SendPort; } public String getStopSendPort() { return this.stopSendPort; } public String getHistoryListPort() { return this.historyListPort; } public String getPlayHistoryPort() { return this.playHistoryPort; } public String getPushURL() { return this.pushURL; } public Integer getStart1078Port() { if (Objects.isNull(this.start1078Port)) this.start1078Port = Integer.valueOf(Integer.parseInt(StringUtils.substringBefore(this.portsOf1078, ","))); return this.start1078Port; } public Integer getEnd1078Port() { if (Objects.isNull(this.end1078Port)) this.end1078Port = Integer.valueOf(Integer.parseInt(StringUtils.substringAfter(this.portsOf1078, ","))); return this.end1078Port; } public String getPushKey(){ if (Objects.isNull(this.pushKey)){ this.pushKey = "?callId=41db35390ddad33f83944f44b8b75ded"; } return "?callId="+this.pushKey; } public String getStopPUshURL() { return this.stopPUshURL; } public String getGetURL() { return this.getURL; } public Integer getAddPort() { return this.addPort; } public String getWs() { return this.ws; } public String getWss() { return this.wss; } public String getDownloadFlv() { return downloadFlv; } public String getPortsOf1078() { return portsOf1078; } } | |
| 3 | 3 | \ No newline at end of file | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/config/ThreadConfig.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.jt1078.platform.config; | |
| 2 | + | |
| 3 | +import org.springframework.context.annotation.Bean; | |
| 4 | +import org.springframework.context.annotation.Configuration; | |
| 5 | + | |
| 6 | +import java.util.concurrent.ScheduledExecutorService; | |
| 7 | +import java.util.concurrent.ScheduledThreadPoolExecutor; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * 周期性线程池配置 | |
| 11 | + * | |
| 12 | + * @Author WangXin | |
| 13 | + * @Data 2024/11/26 | |
| 14 | + * @Version 1.0.0 | |
| 15 | + */ | |
| 16 | +@Configuration | |
| 17 | +public class ThreadConfig { | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 周期性线程池 | |
| 21 | + * @return | |
| 22 | + */ | |
| 23 | + @Bean("scheduledExecutor") | |
| 24 | + public ScheduledExecutorService scheduledExecutor() { | |
| 25 | + return new ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors()); | |
| 26 | + } | |
| 27 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/config/TuohuaConfigBean.java
| ... | ... | @@ -43,7 +43,7 @@ public class TuohuaConfigBean { |
| 43 | 43 | private String simURL; |
| 44 | 44 | |
| 45 | 45 | @Value("${tuohua.bsth.login.rest.baseURL}") |
| 46 | - public String baseURL; | |
| 46 | + public String baseURL; | |
| 47 | 47 | @Value("${tuohua.bsth.login.rest.password}") |
| 48 | 48 | private String restPassword; |
| 49 | 49 | |
| ... | ... | @@ -138,15 +138,12 @@ public class TuohuaConfigBean { |
| 138 | 138 | return null; |
| 139 | 139 | } |
| 140 | 140 | return (List<HashMap>) JSON.parseArray(postEntity.getResultStr(), HashMap.class); |
| 141 | - | |
| 142 | 141 | } |
| 143 | 142 | |
| 144 | 143 | public List<HashMap<String, Object>> requestOfLineAndCarAndCombationTree(HttpClientUtil httpClientUtil, String companyId) throws Exception { |
| 145 | 144 | String lineJson = requestLine(httpClientUtil, companyId); |
| 146 | 145 | String carJson = requestCars(httpClientUtil, companyId); |
| 147 | 146 | // String carJson = redisTemplate.opsForValue().get("test:car").toString(); |
| 148 | - | |
| 149 | - | |
| 150 | 147 | List<HashMap> linesJsonList = null; |
| 151 | 148 | int linesSize = 0; |
| 152 | 149 | if (StringUtils.isNoneBlank(lineJson)) { |
| ... | ... | @@ -179,15 +176,12 @@ public class TuohuaConfigBean { |
| 179 | 176 | ch.put("used", "1"); |
| 180 | 177 | return combatioinCarTree(ch,gpsList); |
| 181 | 178 | }).collect(Collectors.toList()); |
| 182 | - | |
| 183 | 179 | map.put("children", carList); |
| 184 | 180 | } |
| 185 | - | |
| 186 | 181 | return map; |
| 187 | 182 | }).collect(Collectors.toList()); |
| 188 | 183 | returnData.addAll(lines); |
| 189 | 184 | } |
| 190 | - | |
| 191 | 185 | if (carsSize > 0) { |
| 192 | 186 | List<HashMap<String, Object>> cars = carJsonList.stream().filter(c -> !Objects.equals(convertStr(c.get("used")), "1")).map(c -> combatioinCarTree(c,gpsList)).collect(Collectors.toList()); |
| 193 | 187 | returnData.addAll(cars); |
| ... | ... | @@ -242,7 +236,12 @@ public class TuohuaConfigBean { |
| 242 | 236 | return result; |
| 243 | 237 | } |
| 244 | 238 | |
| 245 | - | |
| 239 | + /** | |
| 240 | + * 修改测试号 | |
| 241 | + * @param ch | |
| 242 | + * @param gpsList | |
| 243 | + * @return | |
| 244 | + */ | |
| 246 | 245 | private HashMap<String, Object> combatioinCarTree(HashMap ch, List<HashMap> gpsList) { |
| 247 | 246 | String code = convertStr(ch.get("nbbm")); |
| 248 | 247 | String sim = convertStr(ch.get("sim")); |
| ... | ... | @@ -268,9 +267,9 @@ public class TuohuaConfigBean { |
| 268 | 267 | hashMap.put("sim", formatSim(convertStr(ch.get("sim")))); |
| 269 | 268 | hashMap.put("abnormalStatus",abnormalStatus); |
| 270 | 269 | |
| 271 | - if (StringUtils.equals(profileActive, "local")) { | |
| 272 | -// hashMap.put("sim","123456789011"); | |
| 273 | - hashMap.put("sim", "122223333444"); | |
| 270 | + if (StringUtils.equals(profileActive, "wx-local")) { | |
| 271 | + hashMap.put("sim","123456789011"); | |
| 272 | +// hashMap.put("sim", "122223333444"); | |
| 274 | 273 | } |
| 275 | 274 | // |
| 276 | 275 | return hashMap; | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/domain/CarData.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.jt1078.platform.domain; | |
| 2 | + | |
| 3 | +import lombok.AllArgsConstructor; | |
| 4 | +import lombok.Data; | |
| 5 | +import lombok.NoArgsConstructor; | |
| 6 | +import lombok.experimental.SuperBuilder; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 大邑车辆对象 | |
| 10 | + * | |
| 11 | + * @Author WangXin | |
| 12 | + * @Data 2025/1/17 | |
| 13 | + * @Version 1.0.0 | |
| 14 | + */ | |
| 15 | +@Data | |
| 16 | +@SuperBuilder | |
| 17 | +@AllArgsConstructor | |
| 18 | +@NoArgsConstructor | |
| 19 | +public class CarData { | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * 车辆自编号 | |
| 23 | + */ | |
| 24 | + private String nbbm; | |
| 25 | + /** | |
| 26 | + * 公司编码 | |
| 27 | + */ | |
| 28 | + private String companyCode; | |
| 29 | + /** | |
| 30 | + * 子公司编码 | |
| 31 | + */ | |
| 32 | + private String brancheCompanyCode; | |
| 33 | + /** | |
| 34 | + * 车牌号 | |
| 35 | + */ | |
| 36 | + private String carPlate; | |
| 37 | + /** | |
| 38 | + * 车辆编码 | |
| 39 | + */ | |
| 40 | + private String equipmentCode; | |
| 41 | + /** | |
| 42 | + * 车型 | |
| 43 | + */ | |
| 44 | + private Object carType; | |
| 45 | + /** | |
| 46 | + * 车辆状态 | |
| 47 | + */ | |
| 48 | + private Object vehicleStats; | |
| 49 | + /** | |
| 50 | + * "sfdc" : false | |
| 51 | + */ | |
| 52 | + private Boolean sfdc; | |
| 53 | + /** | |
| 54 | + * "scrapState" : false, | |
| 55 | + */ | |
| 56 | + private Boolean scrapState; | |
| 57 | + /** | |
| 58 | + * "idRfid" : null, | |
| 59 | + */ | |
| 60 | + private Object idRfid; | |
| 61 | + /** | |
| 62 | + * "tagRfid" : null | |
| 63 | + */ | |
| 64 | + private Object tagRfid; | |
| 65 | + /** | |
| 66 | + * 线路编号 | |
| 67 | + */ | |
| 68 | + private String lineCode; | |
| 69 | + /** | |
| 70 | + * 线路名称 | |
| 71 | + */ | |
| 72 | + private String lineName; | |
| 73 | + /** | |
| 74 | + * 备注 | |
| 75 | + */ | |
| 76 | + private Object remark; | |
| 77 | + /** | |
| 78 | + * 修改时间 | |
| 79 | + */ | |
| 80 | + private Long updateDate; | |
| 81 | + /** | |
| 82 | + * sim号 | |
| 83 | + */ | |
| 84 | + private String sim; | |
| 85 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/domain/CarGPSData.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.jt1078.platform.domain; | |
| 2 | + | |
| 3 | +import lombok.AllArgsConstructor; | |
| 4 | +import lombok.Data; | |
| 5 | +import lombok.NoArgsConstructor; | |
| 6 | +import lombok.experimental.SuperBuilder; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 车辆GPS数据 | |
| 10 | + * | |
| 11 | + * @Author WangXin | |
| 12 | + * @Data 2025/1/17 | |
| 13 | + * @Version 1.0.0 | |
| 14 | + */ | |
| 15 | +@Data | |
| 16 | +@SuperBuilder | |
| 17 | +@AllArgsConstructor | |
| 18 | +@NoArgsConstructor | |
| 19 | +public class CarGPSData { | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * 公司编码 | |
| 23 | + */ | |
| 24 | + private Integer companyCode; | |
| 25 | + /** | |
| 26 | + * 线路编码 | |
| 27 | + */ | |
| 28 | + private String lineId; | |
| 29 | + /** | |
| 30 | + * 车辆编码 | |
| 31 | + */ | |
| 32 | + private String deviceId; | |
| 33 | + /** | |
| 34 | + * "carparkNo" : "", | |
| 35 | + */ | |
| 36 | + private String carparkNo; | |
| 37 | + /** | |
| 38 | + * "stopNo" : "144664", | |
| 39 | + */ | |
| 40 | + private String stopNo; | |
| 41 | + /** | |
| 42 | + * "stationName" : null, | |
| 43 | + */ | |
| 44 | + private Object stationName; | |
| 45 | + /** | |
| 46 | + * 经度 | |
| 47 | + */ | |
| 48 | + private Double lon; | |
| 49 | + /** | |
| 50 | + * 纬度 | |
| 51 | + */ | |
| 52 | + private Double lat; | |
| 53 | + /** | |
| 54 | + * 时间 | |
| 55 | + */ | |
| 56 | + private Long timestamp; | |
| 57 | + /** | |
| 58 | + * 车速 | |
| 59 | + */ | |
| 60 | + private Integer speed; | |
| 61 | + /** | |
| 62 | + * 方向 "direction" : 236.0, | |
| 63 | + */ | |
| 64 | + private Integer direction; | |
| 65 | + /** | |
| 66 | + * 车辆状态 0 正常 -1 | |
| 67 | + */ | |
| 68 | + private Integer state; | |
| 69 | + /** | |
| 70 | + * "upDown" : 0, | |
| 71 | + */ | |
| 72 | + private Integer upDown; | |
| 73 | + /** | |
| 74 | + * 自编号 "nbbm" : null, | |
| 75 | + */ | |
| 76 | + private String nbbm; | |
| 77 | + /** | |
| 78 | + * "expectStopTime" : null, | |
| 79 | + */ | |
| 80 | + private Object expectStopTime; | |
| 81 | + /** | |
| 82 | + * "version" : 0, | |
| 83 | + */ | |
| 84 | + private Integer version; | |
| 85 | + /** | |
| 86 | + * "abnormalStatus" : null, | |
| 87 | + */ | |
| 88 | + private Object abnormalStatus; | |
| 89 | + /** | |
| 90 | + * "outOfBoundDistance" : 0.0, | |
| 91 | + */ | |
| 92 | + private Integer outOfBoundDistance; | |
| 93 | + /** | |
| 94 | + * "valid" : 0, | |
| 95 | + */ | |
| 96 | + private Integer valid; | |
| 97 | + /** | |
| 98 | + * "inOrOutStation" : -1, | |
| 99 | + */ | |
| 100 | + private Integer inOrOutStation; | |
| 101 | + /** | |
| 102 | + * "sectionCode" : "209599" | |
| 103 | + */ | |
| 104 | + private String sectionCode; | |
| 105 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/domain/CarTreeData.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.jt1078.platform.domain; | |
| 2 | + | |
| 3 | +import lombok.AllArgsConstructor; | |
| 4 | +import lombok.Data; | |
| 5 | +import lombok.NoArgsConstructor; | |
| 6 | +import lombok.experimental.SuperBuilder; | |
| 7 | + | |
| 8 | +import java.util.List; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * 大邑车辆树对象 | |
| 12 | + * | |
| 13 | + * @Author WangXin | |
| 14 | + * @Data 2025/1/17 | |
| 15 | + * @Version 1.0.0 | |
| 16 | + */ | |
| 17 | +@Data | |
| 18 | +@SuperBuilder | |
| 19 | +@AllArgsConstructor | |
| 20 | +@NoArgsConstructor | |
| 21 | +public class CarTreeData { | |
| 22 | + /** | |
| 23 | + * 唯一Id | |
| 24 | + */ | |
| 25 | + private Integer id; | |
| 26 | + /** | |
| 27 | + * 名称 | |
| 28 | + */ | |
| 29 | + private String name; | |
| 30 | + /** | |
| 31 | + * 状态 | |
| 32 | + */ | |
| 33 | + private Integer state; | |
| 34 | + /** | |
| 35 | + * 父级Id | |
| 36 | + */ | |
| 37 | + private Integer pid; | |
| 38 | + /** | |
| 39 | + * sim号 | |
| 40 | + */ | |
| 41 | + private String sim; | |
| 42 | + /** | |
| 43 | + * 子集 | |
| 44 | + */ | |
| 45 | + private List<CarTreeData> children; | |
| 46 | + | |
| 47 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/domain/LineData.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.jt1078.platform.domain; | |
| 2 | + | |
| 3 | +import lombok.AllArgsConstructor; | |
| 4 | +import lombok.Data; | |
| 5 | +import lombok.NoArgsConstructor; | |
| 6 | +import lombok.experimental.SuperBuilder; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 大邑线路对象 | |
| 10 | + * | |
| 11 | + * @Author WangXin | |
| 12 | + * @Data 2025/1/17 | |
| 13 | + * @Version 1.0.0 | |
| 14 | + */ | |
| 15 | +@Data | |
| 16 | +@SuperBuilder | |
| 17 | +@AllArgsConstructor | |
| 18 | +@NoArgsConstructor | |
| 19 | +public class LineData { | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * 线路名称 | |
| 23 | + */ | |
| 24 | + private String name; | |
| 25 | + /** | |
| 26 | + * 线路编码 | |
| 27 | + */ | |
| 28 | + private String lineCode; | |
| 29 | + /** | |
| 30 | + * 始发站 | |
| 31 | + */ | |
| 32 | + private String startStationName; | |
| 33 | + /** | |
| 34 | + * 终点站 | |
| 35 | + */ | |
| 36 | + private String endStationName; | |
| 37 | + /** | |
| 38 | + * 始发站发车时间 | |
| 39 | + */ | |
| 40 | + private String startStationFirstTime; | |
| 41 | + /** | |
| 42 | + * 始发站末班车时间 | |
| 43 | + */ | |
| 44 | + private String startStationEndTime; | |
| 45 | + /** | |
| 46 | + * 终点站发车时间 | |
| 47 | + */ | |
| 48 | + private String endStationFirstTime; | |
| 49 | + /** | |
| 50 | + * 终点站末班车时间 | |
| 51 | + */ | |
| 52 | + private String endStationEndTime; | |
| 53 | + /** | |
| 54 | + * 公司编号 | |
| 55 | + */ | |
| 56 | + private String company; | |
| 57 | + /** | |
| 58 | + * 公司名称 | |
| 59 | + */ | |
| 60 | + private String companyName; | |
| 61 | + /** | |
| 62 | + * 子公司编号 | |
| 63 | + */ | |
| 64 | + private String brancheCompany; | |
| 65 | + | |
| 66 | + private String nature; | |
| 67 | + /** | |
| 68 | + * 等级 | |
| 69 | + */ | |
| 70 | + private String level; | |
| 71 | + | |
| 72 | + private Integer destroy; | |
| 73 | + | |
| 74 | + private Integer supperLine; | |
| 75 | + | |
| 76 | + private String eqLinecode; | |
| 77 | + /** | |
| 78 | + * 创建时间 | |
| 79 | + */ | |
| 80 | + private Long createDate; | |
| 81 | + | |
| 82 | + private Integer totalMileage; | |
| 83 | + | |
| 84 | + private Object earlyIntervalLg; | |
| 85 | + | |
| 86 | + private Object lateIntervalLg; | |
| 87 | + | |
| 88 | + private Object intervalLg; | |
| 89 | + | |
| 90 | + private Integer speedLimit; | |
| 91 | + | |
| 92 | + private Object lagStation; | |
| 93 | + | |
| 94 | + private Object skip; | |
| 95 | + | |
| 96 | + private Integer speeding; | |
| 97 | + | |
| 98 | + private Object crossedLine; | |
| 99 | + | |
| 100 | + private Object overflights; | |
| 101 | + | |
| 102 | + private String shanghaiLinecode; | |
| 103 | + | |
| 104 | + private Integer linePlayType; | |
| 105 | + | |
| 106 | + private Integer region; | |
| 107 | + | |
| 108 | + private Object ticketSellType; | |
| 109 | + /** | |
| 110 | + * 修改时间 | |
| 111 | + */ | |
| 112 | + private Long updateDate; | |
| 113 | + /** | |
| 114 | + * 使用状态 | |
| 115 | + */ | |
| 116 | + private Integer inUse; | |
| 117 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/domain/PatrolDataReq.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.jt1078.platform.domain; | |
| 2 | + | |
| 3 | +import lombok.AllArgsConstructor; | |
| 4 | +import lombok.Data; | |
| 5 | +import lombok.NoArgsConstructor; | |
| 6 | +import lombok.experimental.SuperBuilder; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 巡查请求对象 | |
| 10 | + * | |
| 11 | + * @Author WangXin | |
| 12 | + * @Data 2025/1/20 | |
| 13 | + * @Version 1.0.0 | |
| 14 | + */ | |
| 15 | +@Data | |
| 16 | +@SuperBuilder | |
| 17 | +@AllArgsConstructor | |
| 18 | +@NoArgsConstructor | |
| 19 | +public class PatrolDataReq { | |
| 20 | + /** | |
| 21 | + * nbbm_sim_channel | |
| 22 | + */ | |
| 23 | + private String id; | |
| 24 | + /** | |
| 25 | + * 通道名称 | |
| 26 | + */ | |
| 27 | + private String name; | |
| 28 | + /** | |
| 29 | + * nbbm | |
| 30 | + */ | |
| 31 | + private String pid; | |
| 32 | + /** | |
| 33 | + * 在线情况 true 离线 null 在线 | |
| 34 | + */ | |
| 35 | + private Boolean disabled; | |
| 36 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/domain/SimFlow.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.jt1078.platform.domain; | |
| 2 | + | |
| 3 | +import com.fasterxml.jackson.annotation.JsonFormat; | |
| 4 | +import org.springframework.format.annotation.DateTimeFormat; | |
| 5 | + | |
| 6 | +import java.text.SimpleDateFormat; | |
| 7 | +import java.util.Date; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * 流量统计 | |
| 11 | + * | |
| 12 | + * @Author WangXin | |
| 13 | + * @Data 2025/1/7 | |
| 14 | + * @Version 1.0.0 | |
| 15 | + */ | |
| 16 | +public class SimFlow { | |
| 17 | + | |
| 18 | + private String id; | |
| 19 | + private String sim; | |
| 20 | + private String channel; | |
| 21 | + private Double flow; | |
| 22 | + private String time; | |
| 23 | + | |
| 24 | + public String getId() { | |
| 25 | + return id; | |
| 26 | + } | |
| 27 | + | |
| 28 | + public void setId(String id) { | |
| 29 | + this.id = id; | |
| 30 | + } | |
| 31 | + | |
| 32 | + public String getSim() { | |
| 33 | + return sim; | |
| 34 | + } | |
| 35 | + | |
| 36 | + public void setSim(String sim) { | |
| 37 | + this.sim = sim; | |
| 38 | + } | |
| 39 | + | |
| 40 | + public String getChannel() { | |
| 41 | + return channel; | |
| 42 | + } | |
| 43 | + | |
| 44 | + public void setChannel(String channel) { | |
| 45 | + this.channel = channel; | |
| 46 | + } | |
| 47 | + | |
| 48 | + public Double getFlow() { | |
| 49 | + return flow; | |
| 50 | + } | |
| 51 | + | |
| 52 | + public void setFlow(Double flow) { | |
| 53 | + this.flow = flow; | |
| 54 | + } | |
| 55 | + | |
| 56 | + public String getTime() { | |
| 57 | + return time; | |
| 58 | + } | |
| 59 | + | |
| 60 | + public void setTime(String time) { | |
| 61 | + this.time = time; | |
| 62 | + } | |
| 63 | + | |
| 64 | + @Override | |
| 65 | + public String toString() { | |
| 66 | + final StringBuilder sb = new StringBuilder("SimFlow{"); | |
| 67 | + sb.append("id='").append(id).append('\''); | |
| 68 | + sb.append(", sim='").append(sim).append('\''); | |
| 69 | + sb.append(", channel='").append(channel).append('\''); | |
| 70 | + sb.append(", flow=").append(flow); | |
| 71 | + sb.append(", time=").append(time); | |
| 72 | + sb.append('}'); | |
| 73 | + return sb.toString(); | |
| 74 | + } | |
| 75 | + | |
| 76 | + public static SimFlow build(String sim, String channel, Double flow) { | |
| 77 | + SimFlow simFlow = new SimFlow(); | |
| 78 | + simFlow.setSim(sim); | |
| 79 | + simFlow.setChannel(channel); | |
| 80 | + simFlow.setFlow(flow); | |
| 81 | + simFlow.setTime(new SimpleDateFormat("yyyy-MM-dd").format(new Date())); | |
| 82 | + return simFlow; | |
| 83 | + } | |
| 84 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/handler/HttpClientUtil.java
| ... | ... | @@ -86,7 +86,7 @@ public class HttpClientUtil { |
| 86 | 86 | URIBuilder uriBuilder = new URIBuilder(url); |
| 87 | 87 | URI uri = uriBuilder.build(); |
| 88 | 88 | |
| 89 | - // 创建http GET请求 | |
| 89 | + // 创建http POST请求 | |
| 90 | 90 | HttpPost httpPost = new HttpPost(uri); |
| 91 | 91 | StringEntity stringEntity = new StringEntity(requestBody, "UTF-8"); |
| 92 | 92 | stringEntity.setContentType("application/json"); |
| ... | ... | @@ -194,7 +194,15 @@ public class HttpClientUtil { |
| 194 | 194 | return false; |
| 195 | 195 | } |
| 196 | 196 | |
| 197 | - | |
| 197 | + /** | |
| 198 | + * 检查设备是否注册 | |
| 199 | + * @param response | |
| 200 | + * @param httpclient | |
| 201 | + * @param url | |
| 202 | + * @param requestBody | |
| 203 | + * @return | |
| 204 | + * @throws IOException | |
| 205 | + */ | |
| 198 | 206 | @NotNull |
| 199 | 207 | private static HttpClientPostEntity combationReturnObj(CloseableHttpResponse response, DefaultHttpClient httpclient,String url,String requestBody) throws IOException { |
| 200 | 208 | HttpEntity httpEntity = response.getEntity(); |
| ... | ... | @@ -205,7 +213,7 @@ public class HttpClientUtil { |
| 205 | 213 | HttpClientPostEntity postEntity = new HttpClientPostEntity(); |
| 206 | 214 | postEntity.setCookieStore(cookieStore); |
| 207 | 215 | postEntity.setResultStr(result); |
| 208 | - log.info("url:{};requestBody:{};response data:{}",url,requestBody,result); | |
| 216 | + log.info("url:{};requestBody:{};response :{}",url,requestBody,"请求成功"); | |
| 209 | 217 | return postEntity; |
| 210 | 218 | } |
| 211 | 219 | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/handler/RtspHandler.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.vmanager.jt1078.platform.handler; | |
| 2 | - | |
| 3 | -import org.springframework.beans.factory.annotation.Value; | |
| 4 | -import org.springframework.stereotype.Component; | |
| 5 | - | |
| 6 | -/** | |
| 7 | - * @author liujun | |
| 8 | - * @date 2024年10月23日 13:24 | |
| 9 | - */ | |
| 10 | -@Component | |
| 11 | -public class RtspHandler { | |
| 12 | - | |
| 13 | -} |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/mapper/FlowMapper.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.jt1078.platform.mapper; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.SimFlow; | |
| 4 | +import org.apache.ibatis.annotations.*; | |
| 5 | +import org.apache.ibatis.annotations.Param; | |
| 6 | + | |
| 7 | +import java.util.List; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * @Author WangXin | |
| 11 | + * @Data 2025/1/7 | |
| 12 | + * @Version 1.0.0 | |
| 13 | + */ | |
| 14 | +@Mapper | |
| 15 | +public interface FlowMapper { | |
| 16 | + | |
| 17 | + @Select(value = {" <script>" + | |
| 18 | + "SELECT " + | |
| 19 | + " <if test=\"time != null and time == 'day'\" >" + | |
| 20 | + " `time`," + | |
| 21 | + " </if>" + | |
| 22 | + " <if test=\"time != null and time == 'year'\" >" + | |
| 23 | + " YEAR(`time`) `time`," + | |
| 24 | + " </if>" + | |
| 25 | + " <if test=\"time != null and time == 'month'\" >" + | |
| 26 | + " CONCAT(YEAR(`time`),'-',MONTH(`time`)) `time`," + | |
| 27 | + " </if>" + | |
| 28 | + " `sim`, `channel`, SUM(flow) flow" + | |
| 29 | + " FROM `wvp_sim_flow`" + | |
| 30 | + " <where> " + | |
| 31 | + " <if test=\"time != null and time != '' and statisticsType = 'day'\">" + | |
| 32 | + " AND time = #{time}" + | |
| 33 | + " </if>" + | |
| 34 | + " <if test=\"time != null and time != '' and statisticsType = 'month'\">" + | |
| 35 | + " AND CONCAT(YEAR(`time`),'-',MONTH(`time`)) = #{time}" + | |
| 36 | + " </if>" + | |
| 37 | + " <if test=\"time != null and time != '' and statisticsType = 'year'\">" + | |
| 38 | + " AND YEAR(`time`) = #{time}" + | |
| 39 | + " </if>" + | |
| 40 | + " </where>" + | |
| 41 | + " GROUP BY sim " + | |
| 42 | + " <if test=\"statisticsType!=null and statisticsType !='' and statisticsType = 'channel' \">" + | |
| 43 | + " ,`channel` " + | |
| 44 | + " </if>" + | |
| 45 | + " <if test=\"timeType == 'day'\">" + | |
| 46 | + " ,`time`" + | |
| 47 | + " </if>" + | |
| 48 | + " <if test=\"timeType == 'year'\" >" + | |
| 49 | + " ,YEAR(`time`)" + | |
| 50 | + " </if>" + | |
| 51 | + " <if test=\"timeType == 'month'\" >" + | |
| 52 | + " ,CONCAT(YEAR(`time`),'-',MONTH(`time`))" + | |
| 53 | + " </if>" + | |
| 54 | + " ORDER BY `time` DESC " + | |
| 55 | + " </script>"} | |
| 56 | + ) | |
| 57 | + List<SimFlow> getList(@Param("timeType") String timeType, @Param("statisticsType") String statisticsType, @Param("time") String time); | |
| 58 | + | |
| 59 | + @Insert( | |
| 60 | + "INSERT INTO " + | |
| 61 | + "`wvp_sim_flow`" + | |
| 62 | + " (`id`,`sim`, `channel`, `flow`, `time`)" + | |
| 63 | + " VALUES " + | |
| 64 | + " (#{id}, #{sim}, #{channel}, #{flow}, #{time})" | |
| 65 | + ) | |
| 66 | + int addFlow(SimFlow flowList); | |
| 67 | + | |
| 68 | + @Update( | |
| 69 | + "UPDATE `wvp_sim_flow` SET `flow` = `flow` + #{flow} " + | |
| 70 | + "WHERE `sim`=#{sim} " + | |
| 71 | + "AND `channel`=#{channel} " + | |
| 72 | + "AND CONCAT(YEAR(`time`),'-',MONTH(`time`),'-',DAY(`time`)) " + | |
| 73 | + "= CONCAT(YEAR(#{time}),'-',MONTH(#{time}),'-',DAY(#{time}))" | |
| 74 | + ) | |
| 75 | + int updateFlow(SimFlow simFlow); | |
| 76 | + | |
| 77 | + @Select("SELECT * from `wvp_sim_flow` where `sim`=#{sim}" + | |
| 78 | + " AND `channel`=#{channel} " + | |
| 79 | + " AND CONCAT(YEAR(`time`),'-',MONTH(`time`),'-',DAY(`time`))" + | |
| 80 | + " = CONCAT(YEAR(#{time}),'-',MONTH(#{time}),'-',DAY(#{time}))") | |
| 81 | + SimFlow selectOne(SimFlow simFlow); | |
| 82 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/remote/DaYiApi.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.jt1078.platform.remote; | |
| 2 | + | |
| 3 | +import com.dtflys.forest.annotation.Address; | |
| 4 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.remote.cnofig.DaYiAddressSourceConfig; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * 大邑API | |
| 8 | + * @Author WangXin | |
| 9 | + * @Data 2025/1/17 | |
| 10 | + * @Version 1.0.0 | |
| 11 | +*/ | |
| 12 | +@Address(source = DaYiAddressSourceConfig.class) | |
| 13 | +public interface DaYiApi { | |
| 14 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/remote/cnofig/DaYiAddressSourceConfig.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.jt1078.platform.remote.cnofig; | |
| 2 | + | |
| 3 | +import com.dtflys.forest.callback.AddressSource; | |
| 4 | +import com.dtflys.forest.http.ForestAddress; | |
| 5 | +import com.dtflys.forest.http.ForestRequest; | |
| 6 | +import org.springframework.beans.factory.annotation.Value; | |
| 7 | +import org.springframework.context.annotation.Configuration; | |
| 8 | + | |
| 9 | +import java.net.MalformedURLException; | |
| 10 | +import java.util.Map; | |
| 11 | + | |
| 12 | +import static com.genersoft.iot.vmp.vmanager.util.URLParser.parseURL; | |
| 13 | + | |
| 14 | +/** | |
| 15 | + * 大邑地址配置 | |
| 16 | + */ | |
| 17 | +@Configuration | |
| 18 | +public class DaYiAddressSourceConfig implements AddressSource { | |
| 19 | + | |
| 20 | + @Value("${tuohua.bsth.login.rest.baseURL}") | |
| 21 | + public String baseURL; | |
| 22 | + @Value("${tuohua.bsth.login.rest.password}") | |
| 23 | + private String restPassword; | |
| 24 | + | |
| 25 | + @Override | |
| 26 | + public ForestAddress getAddress(ForestRequest request) { | |
| 27 | + try { | |
| 28 | + Map<String, String> map = parseURL(baseURL); | |
| 29 | + return new ForestAddress(map.get("scheme"),map.get("host"),Integer.valueOf(map.get("port")),map.get("path")); | |
| 30 | + } catch (MalformedURLException e) { | |
| 31 | + throw new RuntimeException(e); | |
| 32 | + } | |
| 33 | + } | |
| 34 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/service/FlowService.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.jt1078.platform.service; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.SimFlow; | |
| 4 | + | |
| 5 | +import java.util.List; | |
| 6 | +import java.util.Map; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * @Author WangXin | |
| 10 | + * @Data 2025/1/7 | |
| 11 | + * @Version 1.0.0 | |
| 12 | + */ | |
| 13 | +public interface FlowService { | |
| 14 | + /** | |
| 15 | + * 流量列表 | |
| 16 | + * @param timeType 时间类型 | |
| 17 | + * @param statisticsType 统计类型 | |
| 18 | + */ | |
| 19 | + Map<String, SimFlow> getList(String timeType, String statisticsType, String time); | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * 批量添加流量记录 | |
| 23 | + * @param simFlow 流量记录集合 | |
| 24 | + */ | |
| 25 | + boolean addFlow(SimFlow simFlow); | |
| 26 | + | |
| 27 | + /** | |
| 28 | + * 修改 | |
| 29 | + * @param simFlow 流量统计对象 | |
| 30 | + */ | |
| 31 | + boolean updateFlow(SimFlow simFlow); | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 搜索流量统计是否存在 | |
| 35 | + * @param simFlow 流量统计对象 | |
| 36 | + */ | |
| 37 | + SimFlow selectOne(SimFlow simFlow); | |
| 38 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/service/Jt1078OfService.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.jt1078.platform.service; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.CarTreeData; | |
| 4 | + | |
| 5 | +import java.util.List; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * Jtt1078业务层 | |
| 9 | + * | |
| 10 | + * @Author WangXin | |
| 11 | + * @Data 2025/1/17 | |
| 12 | + * @Version 1.0.0 | |
| 13 | + */ | |
| 14 | +public interface Jt1078OfService { | |
| 15 | + | |
| 16 | + /** | |
| 17 | + * 获取车辆列表数据 | |
| 18 | + * @return 车辆列表数据 | |
| 19 | + */ | |
| 20 | + List<CarTreeData> getCarTreeData(); | |
| 21 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/service/impl/FlowServiceImpl.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.jt1078.platform.service.impl; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.SimFlow; | |
| 4 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.mapper.FlowMapper; | |
| 5 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.service.FlowService; | |
| 6 | +import org.springframework.stereotype.Service; | |
| 7 | + | |
| 8 | +import javax.annotation.Resource; | |
| 9 | +import java.util.*; | |
| 10 | +import java.util.stream.Collectors; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * @Author WangXin | |
| 14 | + * @Data 2025/1/7 | |
| 15 | + * @Version 1.0.0 | |
| 16 | + */ | |
| 17 | +@Service | |
| 18 | +public class FlowServiceImpl implements FlowService { | |
| 19 | + | |
| 20 | + @Resource | |
| 21 | + private FlowMapper flowMapper; | |
| 22 | + | |
| 23 | + @Override | |
| 24 | + public Map<String, SimFlow> getList(String timeType, String statisticsType, String time) { | |
| 25 | + List<SimFlow> list = flowMapper.getList(timeType, statisticsType, time); | |
| 26 | + | |
| 27 | + | |
| 28 | + return null; | |
| 29 | + } | |
| 30 | + | |
| 31 | + @Override | |
| 32 | + public boolean addFlow(SimFlow flowList) { | |
| 33 | + String id = UUID.randomUUID().toString().replaceAll("-", ""); | |
| 34 | + flowList.setId(id); | |
| 35 | + int i = flowMapper.addFlow(flowList); | |
| 36 | + if (i > 0) { | |
| 37 | + return true; | |
| 38 | + } | |
| 39 | + return false; | |
| 40 | + } | |
| 41 | + | |
| 42 | + @Override | |
| 43 | + public boolean updateFlow(SimFlow simFlow) { | |
| 44 | + int i = flowMapper.updateFlow(simFlow); | |
| 45 | + if (i > 0) { | |
| 46 | + return true; | |
| 47 | + } | |
| 48 | + return false; | |
| 49 | + } | |
| 50 | + | |
| 51 | + @Override | |
| 52 | + public SimFlow selectOne(SimFlow simFlow) { | |
| 53 | + return flowMapper.selectOne(simFlow); | |
| 54 | + } | |
| 55 | + | |
| 56 | + | |
| 57 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/jt1078/platform/service/impl/Jt1078OfServiceImpl.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.jt1078.platform.service.impl; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.config.TuohuaConfigBean; | |
| 4 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.domain.CarTreeData; | |
| 5 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.handler.HttpClientUtil; | |
| 6 | +import com.genersoft.iot.vmp.vmanager.jt1078.platform.service.Jt1078OfService; | |
| 7 | +import org.springframework.stereotype.Service; | |
| 8 | + | |
| 9 | +import javax.annotation.Resource; | |
| 10 | +import java.util.Collections; | |
| 11 | +import java.util.List; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * Jtt078实现层 | |
| 15 | + * | |
| 16 | + * @Author WangXin | |
| 17 | + * @Data 2025/1/17 | |
| 18 | + * @Version 1.0.0 | |
| 19 | + */ | |
| 20 | +@Service | |
| 21 | +public class Jt1078OfServiceImpl implements Jt1078OfService { | |
| 22 | + | |
| 23 | + @Resource | |
| 24 | + private TuohuaConfigBean tohuaConfigBean; | |
| 25 | + @Resource | |
| 26 | + private HttpClientUtil httpClientUtil; | |
| 27 | + | |
| 28 | + /** | |
| 29 | + * 获取车辆列表数据 | |
| 30 | + * @return 车辆列表数据 | |
| 31 | + */ | |
| 32 | + @Override | |
| 33 | + public List<CarTreeData> getCarTreeData() { | |
| 34 | + try { | |
| 35 | + String lineJson = tohuaConfigBean.requestLine(httpClientUtil, String.valueOf(100)); | |
| 36 | + String carJson = tohuaConfigBean.requestCars(httpClientUtil, String.valueOf(100)); | |
| 37 | + } catch (Exception e) { | |
| 38 | + throw new RuntimeException(e); | |
| 39 | + } | |
| 40 | + return Collections.emptyList(); | |
| 41 | + } | |
| 42 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
| 1 | 1 | package com.genersoft.iot.vmp.vmanager.streamProxy; |
| 2 | 2 | |
| 3 | 3 | import com.alibaba.fastjson2.JSONObject; |
| 4 | +import com.genersoft.iot.vmp.common.GeneralCallback; | |
| 4 | 5 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 5 | 6 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 6 | 7 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| ... | ... | @@ -104,19 +105,17 @@ public class StreamProxyController { |
| 104 | 105 | if (ObjectUtils.isEmpty(param.getGbId())) { |
| 105 | 106 | param.setGbId(null); |
| 106 | 107 | } |
| 107 | - StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream()); | |
| 108 | - if (streamProxyItem != null) { | |
| 109 | - streamProxyService.del(param.getApp(), param.getStream()); | |
| 110 | - } | |
| 108 | + DeferredResult<Object> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); | |
| 111 | 109 | |
| 112 | 110 | RequestMessage requestMessage = new RequestMessage(); |
| 113 | 111 | String key = DeferredResultHolder.CALLBACK_CMD_PROXY + param.getApp() + param.getStream(); |
| 114 | 112 | requestMessage.setKey(key); |
| 115 | 113 | String uuid = UUID.randomUUID().toString(); |
| 116 | 114 | requestMessage.setId(uuid); |
| 117 | - DeferredResult<Object> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); | |
| 115 | + | |
| 118 | 116 | // 录像查询以channelId作为deviceId查询 |
| 119 | 117 | resultHolder.put(key, uuid, result); |
| 118 | + | |
| 120 | 119 | result.onTimeout(()->{ |
| 121 | 120 | WVPResult<StreamInfo> wvpResult = new WVPResult<>(); |
| 122 | 121 | wvpResult.setCode(ErrorCode.ERROR100.getCode()); |
| ... | ... | @@ -127,21 +126,22 @@ public class StreamProxyController { |
| 127 | 126 | |
| 128 | 127 | streamProxyService.save(param, (code, msg, streamInfo) -> { |
| 129 | 128 | String stream = null; |
| 130 | - if(Objects.nonNull(streamInfo)){ | |
| 129 | + if (Objects.nonNull(streamInfo)) { | |
| 131 | 130 | stream = streamInfo.getStream(); |
| 132 | 131 | } |
| 133 | - logger.info("[拉流代理] {}[{}]", code == ErrorCode.SUCCESS.getCode()? "成功":"失败: " + msg,stream); | |
| 132 | + logger.info("[拉流代理] {}[{}]", code == ErrorCode.SUCCESS.getCode() ? "成功" : "失败: " + msg, stream); | |
| 134 | 133 | if (code == ErrorCode.SUCCESS.getCode()) { |
| 135 | 134 | requestMessage.setData(new StreamContent(streamInfo)); |
| 136 | - }else { | |
| 135 | + } else { | |
| 137 | 136 | requestMessage.setData(WVPResult.fail(code, msg)); |
| 138 | 137 | } |
| 139 | 138 | resultHolder.invokeAllResult(requestMessage); |
| 140 | - if(StringUtils.equals(msg,"This stream already exists")){ | |
| 141 | - redisTemplate.opsForValue().set("timeout:"+param.getStream(),2,30, TimeUnit.SECONDS); | |
| 142 | - | |
| 143 | - }else { | |
| 144 | - redisTemplate.opsForValue().set("timeout:" + param.getStream(), 1, 30, TimeUnit.SECONDS); | |
| 139 | + if (StringUtils.equals(msg, "This stream already exists")) { | |
| 140 | + redisTemplate.opsForValue() | |
| 141 | + .set("timeout:" + param.getStream(), 2, 30, TimeUnit.SECONDS); | |
| 142 | + } else { | |
| 143 | + redisTemplate.opsForValue() | |
| 144 | + .set("timeout:" + param.getStream(), 1, 30, TimeUnit.SECONDS); | |
| 145 | 145 | } |
| 146 | 146 | }); |
| 147 | 147 | return result; | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
| ... | ... | @@ -30,10 +30,14 @@ import org.springframework.http.HttpStatus; |
| 30 | 30 | import org.springframework.http.ResponseEntity; |
| 31 | 31 | import org.springframework.stereotype.Controller; |
| 32 | 32 | import org.springframework.util.ObjectUtils; |
| 33 | +import org.springframework.util.StringUtils; | |
| 33 | 34 | import org.springframework.web.bind.annotation.*; |
| 34 | 35 | import org.springframework.web.context.request.async.DeferredResult; |
| 35 | 36 | import org.springframework.web.multipart.MultipartFile; |
| 36 | 37 | |
| 38 | +import javax.annotation.Resource; | |
| 39 | +import javax.servlet.ServletException; | |
| 40 | +import javax.servlet.http.HttpServletRequest; | |
| 37 | 41 | import java.io.IOException; |
| 38 | 42 | import java.io.InputStream; |
| 39 | 43 | import java.util.HashMap; |
| ... | ... | @@ -41,9 +45,10 @@ import java.util.List; |
| 41 | 45 | import java.util.Map; |
| 42 | 46 | import java.util.UUID; |
| 43 | 47 | |
| 48 | +import static com.genersoft.iot.vmp.conf.security.IpWhitelistFilter.verifyIpAndPath; | |
| 49 | + | |
| 44 | 50 | @Tag(name = "推流信息管理") |
| 45 | 51 | @Controller |
| 46 | - | |
| 47 | 52 | @RequestMapping(value = "/api/push") |
| 48 | 53 | public class StreamPushController { |
| 49 | 54 | |
| ... | ... | @@ -64,6 +69,9 @@ public class StreamPushController { |
| 64 | 69 | @Autowired |
| 65 | 70 | private UserSetting userSetting; |
| 66 | 71 | |
| 72 | + @Resource | |
| 73 | + private HttpServletRequest request; | |
| 74 | + | |
| 67 | 75 | @GetMapping(value = "/list") |
| 68 | 76 | @ResponseBody |
| 69 | 77 | @Operation(summary = "推流列表查询", security = @SecurityRequirement(name = JwtUtils.HEADER)) |
| ... | ... | @@ -88,6 +96,18 @@ public class StreamPushController { |
| 88 | 96 | return pushList; |
| 89 | 97 | } |
| 90 | 98 | |
| 99 | + @GetMapping(value = "/getStreamPushItem") | |
| 100 | + public StreamPushItem getStreamPushItem(@RequestParam(required = false)String sim, @RequestParam(required = false)String channel){ | |
| 101 | + if (ObjectUtils.isEmpty(sim)) { | |
| 102 | + sim = null; | |
| 103 | + } | |
| 104 | + if (ObjectUtils.isEmpty(channel)) { | |
| 105 | + channel = null; | |
| 106 | + } | |
| 107 | + return streamPushService.getPush("schedule", sim+ "-"+ channel); | |
| 108 | + } | |
| 109 | + | |
| 110 | + | |
| 91 | 111 | @PostMapping(value = "/save_to_gb") |
| 92 | 112 | @ResponseBody |
| 93 | 113 | @Operation(summary = "将推流添加到国标", security = @SecurityRequirement(name = JwtUtils.HEADER)) |
| ... | ... | @@ -241,9 +261,17 @@ public class StreamPushController { |
| 241 | 261 | @RequestParam(required = false) String mediaServerId){ |
| 242 | 262 | boolean authority = false; |
| 243 | 263 | // 是否登陆用户, 登陆用户返回完整信息 |
| 244 | - LoginUser userInfo = SecurityUtils.getUserInfo(); | |
| 245 | - if (userInfo!= null) { | |
| 246 | - authority = true; | |
| 264 | + try { | |
| 265 | + if (!verifyIpAndPath(request)){ | |
| 266 | + LoginUser userInfo = SecurityUtils.getUserInfo(); | |
| 267 | + if (userInfo!= null) { | |
| 268 | + authority = true; | |
| 269 | + } | |
| 270 | + }else { | |
| 271 | + authority = true; | |
| 272 | + } | |
| 273 | + } catch (Exception e) { | |
| 274 | + throw new RuntimeException(e); | |
| 247 | 275 | } |
| 248 | 276 | StreamPushItem push = streamPushService.getPush(app, stream); |
| 249 | 277 | if (push != null && !push.isSelf()) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/util/MD5Util.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.util; | |
| 2 | + | |
| 3 | +import java.security.MessageDigest; | |
| 4 | +import java.security.NoSuchAlgorithmException; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * MD5工具 | |
| 8 | + * | |
| 9 | + * @Author WangXin | |
| 10 | + * @Data 2025/1/6 | |
| 11 | + * @Version 1.0.0 | |
| 12 | + */ | |
| 13 | +public class MD5Util { | |
| 14 | + | |
| 15 | + public static String encrypt(String input) { | |
| 16 | + try { | |
| 17 | + MessageDigest md = MessageDigest.getInstance("MD5"); | |
| 18 | + byte[] messageDigest = md.digest(input.getBytes()); | |
| 19 | + StringBuilder hexString = new StringBuilder(); | |
| 20 | + | |
| 21 | + for (byte b : messageDigest) { | |
| 22 | + String hex = Integer.toHexString(0xff & b); | |
| 23 | + if (hex.length() == 1) hexString.append('0'); | |
| 24 | + hexString.append(hex); | |
| 25 | + } | |
| 26 | + return hexString.toString(); | |
| 27 | + } catch (NoSuchAlgorithmException e) { | |
| 28 | + throw new RuntimeException(e); | |
| 29 | + } | |
| 30 | + } | |
| 31 | +} | |
| 32 | + | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/util/URLParser.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.util; | |
| 2 | + | |
| 3 | +import java.net.MalformedURLException; | |
| 4 | +import java.net.URL; | |
| 5 | +import java.util.HashMap; | |
| 6 | +import java.util.Map; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * url验证工具 | |
| 10 | + */ | |
| 11 | +public class URLParser { | |
| 12 | + | |
| 13 | + public static void main(String[] args) { | |
| 14 | + String urlString = "http://127.0.0.1:8080/data/rest"; // 示例URL,实际使用时可以替换为任何URL字符串 | |
| 15 | + | |
| 16 | + try { | |
| 17 | + Map<String, String> urlParts = parseURL(urlString); | |
| 18 | + System.out.println("URL分割结果:" + urlParts); | |
| 19 | + } catch (MalformedURLException e) { | |
| 20 | + System.out.println(e.getMessage()); | |
| 21 | + } | |
| 22 | + } | |
| 23 | + | |
| 24 | + public static Map<String, String> parseURL(String urlString) throws MalformedURLException { | |
| 25 | + Map<String, String> result = new HashMap<>(); | |
| 26 | + | |
| 27 | + // 尝试创建URL对象以验证格式是否正确 | |
| 28 | + URL url = new URL(urlString); | |
| 29 | + | |
| 30 | + // 验证协议是否为http | |
| 31 | + if (!"http".equalsIgnoreCase(url.getProtocol())) { | |
| 32 | + throw new MalformedURLException("协议必须是http"); | |
| 33 | + } | |
| 34 | + | |
| 35 | + // 确认主机名(域名或IP)存在 | |
| 36 | + if (url.getHost() == null || url.getHost().isEmpty()) { | |
| 37 | + throw new MalformedURLException("必须有域名或IP地址"); | |
| 38 | + } | |
| 39 | + | |
| 40 | + // 设置端口,如果未指定则默认为80 | |
| 41 | + int port = url.getPort(); | |
| 42 | + if (port == -1) { | |
| 43 | + port = 80; // 默认HTTP端口 | |
| 44 | + } | |
| 45 | + | |
| 46 | + // 构建最终的路径,包括查询参数(如果有) | |
| 47 | + String path = url.getPath(); | |
| 48 | + if (url.getQuery() != null && !url.getQuery().isEmpty()) { | |
| 49 | + path += "?" + url.getQuery(); | |
| 50 | + } | |
| 51 | + | |
| 52 | + // 将分割的结果放入集合中 | |
| 53 | + result.put("scheme", url.getProtocol()); | |
| 54 | + result.put("hostname", url.getHost()); | |
| 55 | + result.put("port", String.valueOf(port)); | |
| 56 | + result.put("path", path.isEmpty() ? "/" : path); // 如果没有路径,默认为根路径 | |
| 57 | + | |
| 58 | + return result; | |
| 59 | + } | |
| 60 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiController.java
| ... | ... | @@ -91,7 +91,6 @@ public class ApiController { |
| 91 | 91 | logger.debug(String.format("模拟接口> 登录 API调用,username:%s ,password:%s ", |
| 92 | 92 | username, password)); |
| 93 | 93 | } |
| 94 | - | |
| 95 | 94 | JSONObject result = new JSONObject(); |
| 96 | 95 | result.put("CookieToken","ynBDDiKMg"); |
| 97 | 96 | result.put("URLToken","MOBkORkqnrnoVGcKIAHXppgfkNWRdV7utZSkDrI448Q.oxNjAxNTM4NDk3LCJwIjoiZGJjODg5NzliNzVj" + | ... | ... |
src/main/resources/app-dev100.properties
0 → 100644
| 1 | +server.port = 9100 | |
| 2 | +server.http.port = 3333 | |
| 3 | +server.history.port = 9101 | |
| 4 | +server.backlog = 1024 | |
| 5 | + | |
| 6 | +# ffmpegå¯æÂ§è¡ÂæÂÂä»¶è·¯å¾Âï¼Âå¯以çÂÂ空 | |
| 7 | +ffmpeg.path = ffmpeg | |
| 8 | + | |
| 9 | +# é Âç½®rtmpå°åÂÂå°Âå¨ç»Â端åÂÂéÂÂRTPæ¶ÂæÂ¯å æÂ¶ï¼Âé¢Âå¤ÂçÂÂÃ¥ÂÂRTMPæÂÂå¡å¨æÂ¨æµ | |
| 10 | +# TAGçÂÂå½¢å¼Âå°±æÂ¯SIM-CHANNELï¼Âå¦Â13800138999-2 | |
| 11 | +# å¦ÂæÂÂçÂÂ空å°Âä¸ÂÃ¥ÂÂRTMPæÂÂå¡å¨æÂ¨æµ | |
| 12 | +#rtmp.url = rtsp://192.168.169.100:9555/schedule/{TAG}?sign={sign} | |
| 13 | +rtmp.url = rtsp://192.168.169.100:19555/schedule/{TAG}?sign={sign} | |
| 14 | + | |
| 15 | +#rtmp.url = rtsp://192.168.169.100:19555/schedule/{TAG}?sign={sign} | |
| 16 | +# 设置为onæÂ¶ï¼ÂæÂ§å¶å°å°Âè¾ÂåºffmpegçÂÂè¾Âåº | |
| 17 | +debug.mode = off | ... | ... |
src/main/resources/app-dev103.properties
0 → 100644
| 1 | +server.port = 9100 | |
| 2 | +server.http.port = 3333 | |
| 3 | +server.history.port = 9101 | |
| 4 | +server.backlog = 1024 | |
| 5 | + | |
| 6 | +# ffmpegå¯æÂ§è¡ÂæÂÂä»¶è·¯å¾Âï¼Âå¯以çÂÂ空 | |
| 7 | +ffmpeg.path = ffmpeg | |
| 8 | + | |
| 9 | +# é Âç½®rtmpå°åÂÂå°Âå¨ç»Â端åÂÂéÂÂRTPæ¶ÂæÂ¯å æÂ¶ï¼Âé¢Âå¤ÂçÂÂÃ¥ÂÂRTMPæÂÂå¡å¨æÂ¨æµ | |
| 10 | +# TAGçÂÂå½¢å¼Âå°±æÂ¯SIM-CHANNELï¼Âå¦Â13800138999-2 | |
| 11 | +# å¦ÂæÂÂçÂÂ空å°Âä¸ÂÃ¥ÂÂRTMPæÂÂå¡å¨æÂ¨æµ | |
| 12 | +#rtmp.url = rtsp://192.168.169.100:9555/schedule/{TAG}?sign={sign} | |
| 13 | +rtmp.url = rtsp://10.10.2.22:9654/schedule/{TAG}?sign={sign} | |
| 14 | + | |
| 15 | +#rtmp.url = rtsp://192.168.169.100:19555/schedule/{TAG}?sign={sign} | |
| 16 | +# 设置为onæÂ¶ï¼ÂæÂ§å¶å°å°Âè¾ÂåºffmpegçÂÂè¾Âåº | |
| 17 | +debug.mode = off | ... | ... |
src/main/resources/app.properties
| 1 | -server.port = 1078 | |
| 1 | +server.port = 30000 | |
| 2 | 2 | server.http.port = 3333 |
| 3 | +server.history.port = 30001 | |
| 3 | 4 | server.backlog = 1024 |
| 4 | 5 | |
| 5 | -# ffmpeg可执行文件路径,可以留空 | |
| 6 | -ffmpeg.path = D:/Tools/ffmpeg-4.2.2-win64-static/bin/ffmpeg.exe | |
| 6 | +# ffmpeg坿§è¡æä»¶è·¯å¾ï¼å¯ä»¥ç空 | |
| 7 | +ffmpeg.path = F:/ffmpeg/ffmpeg-7.0.2-essentials_build/bin/ffmpeg.exe | |
| 7 | 8 | |
| 8 | -# 配置rtmp地址将在终端发送RTP消息包时,额外的向RTMP服务器推流 | |
| 9 | -# TAG的形式就是SIM-CHANNEL,如13800138999-2 | |
| 10 | -# 如果留空将不向RTMP服务器推流 | |
| 11 | -# rtmp.url = rtmp://192.168.0.2/live/{TAG} | |
| 9 | +# é ç½®rtmpå°åå°å¨ç»ç«¯åéRTPæ¶æ¯å æ¶ï¼é¢å¤çåRTMPæå¡å¨æ¨æµ | |
| 10 | +# TAGçå½¢å¼å°±æ¯SIM-CHANNELï¼å¦13800138999-2 | |
| 11 | +# 妿ç空å°ä¸åRTMPæå¡å¨æ¨æµ | |
| 12 | +#rtmp.url = rtsp://192.168.169.100:9555/schedule/{TAG}?sign={sign} | |
| 13 | +rtmp.url = rtsp://127.0.0.1:554/schedule/{TAG}?sign={sign} | |
| 12 | 14 | |
| 13 | -# 设置为on时,控制台将输出ffmpeg的输出 | |
| 14 | -debug.mode = off | |
| 15 | 15 | \ No newline at end of file |
| 16 | +#rtmp.url = rtsp://192.168.169.100:19555/schedule/{TAG}?sign={sign} | |
| 17 | +# 设置为onæ¶ï¼æ§å¶å°å°è¾åºffmpegçè¾åº | |
| 18 | +debug.mode = off | ... | ... |
src/main/resources/application-dev100.yml
| ... | ... | @@ -16,11 +16,11 @@ spring: |
| 16 | 16 | # [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1 |
| 17 | 17 | host: 192.168.169.100 |
| 18 | 18 | # [必须修改] 端口号 |
| 19 | - port: 6379 | |
| 19 | + port: 6879 | |
| 20 | 20 | # [可选] 数据库 DB |
| 21 | 21 | database: 7 |
| 22 | 22 | # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接 |
| 23 | -# password: luna | |
| 23 | + password: wvp4@444 | |
| 24 | 24 | # [可选] 超时时间 |
| 25 | 25 | timeout: 10000 |
| 26 | 26 | # mysql数据源 |
| ... | ... | @@ -31,7 +31,7 @@ spring: |
| 31 | 31 | master: |
| 32 | 32 | type: com.zaxxer.hikari.HikariDataSource |
| 33 | 33 | driver-class-name: com.mysql.cj.jdbc.Driver |
| 34 | - url: jdbc:mysql://192.168.169.100:3306/latest_wvp2?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true | |
| 34 | + url: jdbc:mysql://192.168.169.100:3306/wvp4?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=TRUE&serverTimezone=PRC&useSSL=false&allowMultiQueries=true | |
| 35 | 35 | username: root |
| 36 | 36 | password: guzijian |
| 37 | 37 | hikari: |
| ... | ... | @@ -43,7 +43,7 @@ spring: |
| 43 | 43 | max-lifetime: 1200000 # 是池中连接关闭后的最长生命周期(以毫秒为单位) |
| 44 | 44 | #[可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口 |
| 45 | 45 | server: |
| 46 | - port: 18089 | |
| 46 | + port: 18989 | |
| 47 | 47 | # [可选] HTTPS配置, 默认不开启 |
| 48 | 48 | ssl: |
| 49 | 49 | # [可选] 是否开启HTTPS访问 |
| ... | ... | @@ -63,7 +63,7 @@ sip: |
| 63 | 63 | # 请不要使用127.0.0.1,任何包括localhost在内的域名都是不可以的。 |
| 64 | 64 | ip: 192.168.169.100 |
| 65 | 65 | # [可选] 28181服务监听的端口 |
| 66 | - port: 6060 | |
| 66 | + port: 28083 | |
| 67 | 67 | # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007) |
| 68 | 68 | # 后两位为行业编码,定义参照附录D.3 |
| 69 | 69 | # 3701020049标识山东济南历下区 信息行业接入 |
| ... | ... | @@ -78,11 +78,11 @@ sip: |
| 78 | 78 | |
| 79 | 79 | #zlm 默认服务器配置 |
| 80 | 80 | media: |
| 81 | - id: guzijian | |
| 81 | + id: guzijian1 | |
| 82 | 82 | # [必须修改] zlm服务器的内网IP |
| 83 | 83 | ip: 192.168.169.100 |
| 84 | 84 | # [必须修改] zlm服务器的http.port |
| 85 | - http-port: 1090 | |
| 85 | + http-port: 1909 | |
| 86 | 86 | # [可选] 返回流地址时的ip,置空使用 media.ip 1 |
| 87 | 87 | stream-ip: 61.169.120.202 |
| 88 | 88 | # [可选] wvp在国标信令中使用的ip,此ip为摄像机可以访问到的ip, 置空使用 media.ip 1 |
| ... | ... | @@ -90,17 +90,18 @@ media: |
| 90 | 90 | # [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip |
| 91 | 91 | hook-ip: 192.168.169.100 |
| 92 | 92 | # [可选] zlm服务器的http.sslport, 置空使用zlm配置文件配置 |
| 93 | - http-ssl-port: 8443 | |
| 93 | + http-ssl-port: 2939 | |
| 94 | 94 | # [可选] zlm服务器的hook.admin_params=secret |
| 95 | - secret: RPorcBlIw26uHGnEHYGesIYyFDXpgjkP | |
| 95 | + secret: 8KMYsD5ItKkHN1CIcPI9VeLa6u4S8deU | |
| 96 | + pushKey: 41db35390ddad33f83944f44b8b75ded | |
| 96 | 97 | # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试 |
| 97 | 98 | rtp: |
| 98 | 99 | # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输 |
| 99 | 100 | enable: true |
| 100 | 101 | # [可选] 在此范围内选择端口用于媒体流传输, 必须提前在zlm上配置该属性,不然自动配置此属性可能不成功 |
| 101 | - port-range: 50000,50500 # 端口范围 | |
| 102 | + port-range: 52000,52500 # 端口范围 | |
| 102 | 103 | # [可选] 国标级联在此范围内选择端口发送媒体流, |
| 103 | - send-port-range: 50000,50500 # 端口范围 | |
| 104 | + send-port-range: 52000,52500 # 端口范围 | |
| 104 | 105 | # 录像辅助服务, 部署此服务可以实现zlm录像的管理与下载, 0 表示不使用 |
| 105 | 106 | record-assist-port: 18081 |
| 106 | 107 | # [根据业务需求配置] |
| ... | ... | @@ -112,7 +113,49 @@ user-settings: |
| 112 | 113 | # 设备/通道状态变化时发送消息 |
| 113 | 114 | device-status-notify: true |
| 114 | 115 | # [可选] 日志配置, 一般不需要改 |
| 115 | - | |
| 116 | +jt1078: | |
| 117 | + enable: true | |
| 118 | + port: 1079 | |
| 116 | 119 | logging: |
| 117 | 120 | config: classpath:logback-spring.xml |
| 121 | +tuohua: | |
| 122 | + bsth: | |
| 123 | + login: | |
| 124 | + pageURL: http://192.168.168.152:9088/user/login/jCryptionKey | |
| 125 | + url: http://192.168.168.152:9088/user/login | |
| 126 | + userName: yuanxiaohu | |
| 127 | + password: Yxiaohu1.0 | |
| 128 | + rest: | |
| 129 | + baseURL: http://192.168.168.152:9089/webservice/rest | |
| 130 | + password: bafb2b44a07a02e5e9912f42cd197423884116a8 | |
| 131 | + tree: | |
| 132 | + url: | |
| 133 | + company: http://192.168.168.152:9088/video/tree | |
| 134 | + car: http://192.168.168.152:9088/video/tree/carNo/{0} | |
| 135 | + sim: http://192.168.168.152:9088/video//tree/caNO/sim/{0} | |
| 136 | + wvp28181: | |
| 137 | + rtsp: | |
| 138 | + tcpPort: 1078 | |
| 139 | + udpPort: 1078 | |
| 140 | + historyTcpPort: 9999 | |
| 141 | + historyUdpPort: 9999 | |
| 142 | + ip : 61.169.120.202 | |
| 143 | + jt1078: | |
| 144 | + ports: 9101,9600 | |
| 145 | + port: 9100 | |
| 146 | + httpPort: 3333 | |
| 147 | + addPortVal: 0 | |
| 148 | + pushURL: http://127.0.0.1:3333/new/server/{pushKey}/{port}/{httpPort} | |
| 149 | + stopPushURL: http://127.0.0.1:3333/stop/channel/{pushKey}/{port}/{httpPort} | |
| 150 | + url: http://192.168.168.152:8100/device/{0} | |
| 151 | + historyListPort: 9205 | |
| 152 | + playHistoryPort: 9201 | |
| 153 | + sendPort: 9101 | |
| 154 | + stopSendPort: 9102 | |
| 155 | + ws: ws://61.169.120.202:1909/schedule/{stream}.live.flv | |
| 156 | + wss: wss://61.169.120.202:2930/schedule/{stream}.live.flv | |
| 157 | + downloadFLV: http://118.113.164.50:1909/schedule/{stream}.live.flv | |
| 158 | + get: | |
| 159 | + url: http://192.168.169.100:3333/video/{stream}.flv | |
| 160 | + playURL: /play/wasm/ws%3A%2F%2F{ip}%3A{port}%2Fschedule%2F{sim}-{channel}.live.flv%3FcallId%{publickey} | |
| 118 | 161 | ... | ... |
src/main/resources/application-local.yml
| ... | ... | @@ -15,11 +15,11 @@ spring: |
| 15 | 15 | # [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1 |
| 16 | 16 | host: 127.0.0.1 |
| 17 | 17 | # [必须修改] 端口号 |
| 18 | - port: 6379 | |
| 18 | + port: 6879 | |
| 19 | 19 | # [可选] 数据库 DB |
| 20 | 20 | database: 8 |
| 21 | 21 | # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接 |
| 22 | - # password: guzijian | |
| 22 | + password: wvp4@444 | |
| 23 | 23 | # [可选] 超时时间 |
| 24 | 24 | timeout: 10000 |
| 25 | 25 | # mysql数据源 |
| ... | ... | @@ -30,7 +30,7 @@ spring: |
| 30 | 30 | master: |
| 31 | 31 | type: com.zaxxer.hikari.HikariDataSource |
| 32 | 32 | driver-class-name: com.mysql.cj.jdbc.Driver |
| 33 | - url: jdbc:mysql://192.168.169.100:3306/wvp2?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true | |
| 33 | + url: jdbc:mysql://192.168.169.100:3306/wvp4?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true | |
| 34 | 34 | username: root |
| 35 | 35 | password: guzijian |
| 36 | 36 | hikari: |
| ... | ... | @@ -42,7 +42,7 @@ spring: |
| 42 | 42 | max-lifetime: 1200000 # 是池中连接关闭后的最长生命周期(以毫秒为单位) |
| 43 | 43 | #[可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口 |
| 44 | 44 | server: |
| 45 | - port: 28080 | |
| 45 | + port: 16030 | |
| 46 | 46 | # [可选] HTTPS配置, 默认不开启 |
| 47 | 47 | ssl: |
| 48 | 48 | # [可选] 是否开启HTTPS访问 |
| ... | ... | @@ -60,9 +60,9 @@ sip: |
| 60 | 60 | # 如果要监听多张网卡,可以使用逗号分隔多个IP, 例如: 192.168.1.4,10.0.0.4 |
| 61 | 61 | # 如果不明白,就使用0.0.0.0,大部分情况都是可以的 |
| 62 | 62 | # 请不要使用127.0.0.1,任何包括localhost在内的域名都是不可以的。 |
| 63 | - ip: 0.0.0.0 | |
| 63 | + ip: 192.168.169.100 | |
| 64 | 64 | # [可选] 28181服务监听的端口 |
| 65 | - port: 5060 | |
| 65 | + port: 16030 | |
| 66 | 66 | |
| 67 | 67 | # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007) |
| 68 | 68 | # 后两位为行业编码,定义参照附录D.3 |
| ... | ... | @@ -82,7 +82,7 @@ media: |
| 82 | 82 | # [必须修改] zlm服务器的内网IP |
| 83 | 83 | ip: 192.168.169.100 |
| 84 | 84 | # [必须修改] zlm服务器的http.port |
| 85 | - http-port: 1091 | |
| 85 | + http-port: 1909 | |
| 86 | 86 | # [可选] 返回流地址时的ip,置空使用 media.ip |
| 87 | 87 | stream-ip: 192.168.169.100 |
| 88 | 88 | # [可选] wvp在国标信令中使用的ip,此ip为摄像机可以访问到的ip, 置空使用 media.ip |
| ... | ... | @@ -90,17 +90,17 @@ media: |
| 90 | 90 | # [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip |
| 91 | 91 | hook-ip: 192.168.169.100 |
| 92 | 92 | # [可选] zlm服务器的http.sslport, 置空使用zlm配置文件配置 |
| 93 | - http-ssl-port: 443 | |
| 93 | + http-ssl-port: 8444 | |
| 94 | 94 | # [可选] zlm服务器的hook.admin_params=secret |
| 95 | - secret: RPorcBlIw26uHGnEHYGesIYyFDXpgjkP1 | |
| 95 | + secret: 8KMYsD5ItKkHN1CIcPI9VeLa6u4S8deU | |
| 96 | 96 | # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试 |
| 97 | 97 | rtp: |
| 98 | 98 | # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输 |
| 99 | 99 | enable: true |
| 100 | 100 | # [可选] 在此范围内选择端口用于媒体流传输, 必须提前在zlm上配置该属性,不然自动配置此属性可能不成功 |
| 101 | - port-range: 60000,60300 # 端口范围 | |
| 101 | + port-range: 52000,52500 # 端口范围 | |
| 102 | 102 | # [可选] 国标级联在此范围内选择端口发送媒体流, |
| 103 | - send-port-range: 60000,60300 # 端口范围 | |
| 103 | + send-port-range: 52000,52500 # 端口范围 | |
| 104 | 104 | # 录像辅助服务, 部署此服务可以实现zlm录像的管理与下载, 0 表示不使用 |
| 105 | 105 | record-assist-port: 18081 |
| 106 | 106 | # [根据业务需求配置] |
| ... | ... | @@ -154,19 +154,19 @@ tuohua: |
| 154 | 154 | jt1078: |
| 155 | 155 | ports: 9000,9500 |
| 156 | 156 | addPortVal: 30000 |
| 157 | - pushURL: http://192.169.1.92:3333/new/server/{pushKey}/{port}/{httpPort} | |
| 158 | - stopPushURL: http://192.169.1.92:3333/stop/channel/{pushKey}/{port}/{httpPort} | |
| 157 | + pushURL: http://192.168.169.100:3333/new/server/{pushKey}/{port}/{httpPort} | |
| 158 | + stopPushURL: http://192.168.169.100:3333/stop/channel/{pushKey}/{port}/{httpPort} | |
| 159 | 159 | url: http://192.168.168.241:8100/device/{0} |
| 160 | 160 | historyListPort: 9205 |
| 161 | 161 | playHistoryPort: 9201 |
| 162 | 162 | sendPort: 9101 |
| 163 | 163 | stopSendPort: 9102 |
| 164 | - ws: ws://192.168.169.100:1091/schedule/{stream}.live.flv | |
| 165 | - wss: wss://192.168.169.100:443/schedule/{stream}.live.flv | |
| 166 | - downloadFLV: http://192.168.169.100:1091/schedule/{stream}.live.flv | |
| 164 | + ws: ws://192.168.169.100:1909/schedule/{stream}.live.flv | |
| 165 | + wss: wss://192.168.169.100:8444/schedule/{stream}.live.flv | |
| 166 | + downloadFLV: http://192.168.169.100:1909/schedule/{stream}.live.flv | |
| 167 | 167 | get: |
| 168 | 168 | #url: http://192.169.1.92:{port}/video/{stream}.flv |
| 169 | - url: http://192.169.1.92:3333/video/{stream} | |
| 169 | + url: http://192.168.169.100:3333/video/{stream} | |
| 170 | 170 | playURL: /play/wasm/ws%3A%2F%2F{ip}%3A{port}%2Fschedule%2F{sim}-{channel}.live.flv%3FcallId%{publickey} |
| 171 | 171 | |
| 172 | 172 | ... | ... |
src/main/resources/application-localDev.yml
| ... | ... | @@ -134,7 +134,7 @@ tuohua: |
| 134 | 134 | userName: yuanxiaohu |
| 135 | 135 | password: Yxiaohu1.0 |
| 136 | 136 | rest: |
| 137 | - baseURL: http://10.10.2.20:9089/webservice/rest | |
| 137 | + baseURL: http://192.168.168.152:9089/webservice/rest | |
| 138 | 138 | password: bafb2b44a07a02e5e9912f42cd197423884116a8 |
| 139 | 139 | tree: |
| 140 | 140 | url: | ... | ... |