声纹模块开发
This commit is contained in:
parent
d8002fae52
commit
3f9fe4d0d4
@ -2,6 +2,7 @@ package com.yfd.platform.component.mqtt;
|
|||||||
|
|
||||||
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.integration.channel.ExecutorChannel;
|
import org.springframework.integration.channel.ExecutorChannel;
|
||||||
@ -21,7 +22,13 @@ import java.util.concurrent.ThreadPoolExecutor;
|
|||||||
*
|
*
|
||||||
* @date 2022/8/24
|
* @date 2022/8/24
|
||||||
*/
|
*/
|
||||||
//@Configuration
|
@Configuration
|
||||||
|
@ConditionalOnProperty(
|
||||||
|
// 配置属性名
|
||||||
|
name = "mqttserver.enable",
|
||||||
|
// 属性值为 true 时生效
|
||||||
|
havingValue = "true"
|
||||||
|
)
|
||||||
public class MqttConfig {
|
public class MqttConfig {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
package com.yfd.platform.component.voiceserver;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.HexUtil;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AudioDataDecoder extends ByteToMessageDecoder {
|
||||||
|
|
||||||
|
private static final int HEAD_LENGTH = 4;
|
||||||
|
private static final int VERSION_LENGTH = 1;
|
||||||
|
private static final int SIZE_LENGTH = 4;
|
||||||
|
private static final int TIMESTAMP_LENGTH = 8;
|
||||||
|
private static final int BASICINFO_LENGTH = 6;
|
||||||
|
private static final int ID_LENGTH = 6;
|
||||||
|
private static final int FIRMWARE_LENGTH = 3;
|
||||||
|
private static final int HARDWARE_LENGTH = 1;
|
||||||
|
private static final int PROTOCOL_LENGTH = 2;
|
||||||
|
private static final int FLAG_LENGTH = 3;
|
||||||
|
private static final int CRC_LENGTH = 2;
|
||||||
|
private static final int END_LENGTH = 1;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||||
|
if (in.readableBytes() < HEAD_LENGTH + VERSION_LENGTH + SIZE_LENGTH) {
|
||||||
|
// 等待更多的数据
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 读取头标志、版本和包大小
|
||||||
|
in.markReaderIndex(); // 标记当前读取位置
|
||||||
|
byte[] headBytes = new byte[HEAD_LENGTH];
|
||||||
|
in.readBytes(headBytes);
|
||||||
|
String head = new String(HexUtil.encodeHex(headBytes, false));
|
||||||
|
byte version = in.readByte(); // 读取版本
|
||||||
|
int size = in.readInt(); // 读取包大小
|
||||||
|
|
||||||
|
// 检查是否有足够的数据来读取整个包
|
||||||
|
if (in.readableBytes() < size) {
|
||||||
|
in.resetReaderIndex(); // 重置读取位置
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 读取整个数据包
|
||||||
|
ByteBuf buf = in.readBytes(size);
|
||||||
|
byte lastByte = buf.getByte(buf.readerIndex() + buf.readableBytes() - 1);
|
||||||
|
int decimalValue = lastByte & 0xFF;
|
||||||
|
if (253 != decimalValue) {
|
||||||
|
// 重置读取位置
|
||||||
|
in.resetReaderIndex();
|
||||||
|
}
|
||||||
|
// 解析数据包(这里只展示如何读取头部信息,实际使用时需要解析整个数据包)
|
||||||
|
VoicePacket packet = new VoicePacket();
|
||||||
|
packet.setHead(head);
|
||||||
|
packet.setSize(size);
|
||||||
|
packet.setVersion(version);
|
||||||
|
packet.setTimestamp(buf.readLong());
|
||||||
|
packet.setBasicInfo(readBytes(buf, BASICINFO_LENGTH));
|
||||||
|
packet.setId(readBytes(buf, ID_LENGTH));
|
||||||
|
packet.setFirmware(readBytes(buf, FIRMWARE_LENGTH));
|
||||||
|
packet.setHardware(buf.readByte());
|
||||||
|
packet.setProtocol(buf.readShort());
|
||||||
|
packet.setFlag(readBytes(buf, FLAG_LENGTH));
|
||||||
|
|
||||||
|
DataGroup dataGroup = new DataGroup();
|
||||||
|
dataGroup.setSType(buf.readByte());
|
||||||
|
dataGroup.setSampleRate(buf.readShort());
|
||||||
|
dataGroup.setBits(buf.readByte());
|
||||||
|
dataGroup.setChannel(buf.readByte());
|
||||||
|
// 减去CRC和End
|
||||||
|
dataGroup.setData(readBytes(buf, buf.readableBytes() - 3));
|
||||||
|
packet.setDataGroup(dataGroup);
|
||||||
|
|
||||||
|
packet.setCrc(buf.readShort());
|
||||||
|
packet.setEnd(buf.readByte());
|
||||||
|
|
||||||
|
// 将解析后的数据添加到输出列表中
|
||||||
|
// 假设我们只需要数据部分
|
||||||
|
out.add(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] readBytes(ByteBuf buf, int length) {
|
||||||
|
byte[] bytes = new byte[length];
|
||||||
|
buf.readBytes(bytes);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.yfd.platform.component.voiceserver;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class DataGroup {
|
||||||
|
private byte sType; // 1 byte
|
||||||
|
private short sampleRate; // 2 bytes
|
||||||
|
private byte bits; // 1 byte
|
||||||
|
private byte channel; // 1 byte
|
||||||
|
private byte[] data; // n bytes
|
||||||
|
|
||||||
|
// Getters and Setters
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.yfd.platform.component.voiceserver;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class VoicePacket {
|
||||||
|
private String head; // 4 bytes
|
||||||
|
private byte version; // 1 byte
|
||||||
|
private int size; // 4 bytes
|
||||||
|
private long timestamp; // 8 bytes
|
||||||
|
private byte[] basicInfo; // 6 bytes
|
||||||
|
private byte[] id; // 6 bytes
|
||||||
|
private byte[] firmware; // 3 bytes
|
||||||
|
private byte hardware; // 1 byte
|
||||||
|
private short protocol; // 2 bytes
|
||||||
|
private byte[] flag; // 3 bytes
|
||||||
|
private DataGroup dataGroup; // n bytes
|
||||||
|
private short crc; // 2 bytes
|
||||||
|
private byte end; // 1 byte
|
||||||
|
|
||||||
|
// Getters and Setters
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,134 @@
|
|||||||
|
package com.yfd.platform.component.voiceserver;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.HexUtil;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
|
|
||||||
|
import javax.sound.sampled.AudioFormat;
|
||||||
|
import javax.sound.sampled.AudioInputStream;
|
||||||
|
import javax.sound.sampled.AudioSystem;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class VoicePacketHandler extends SimpleChannelInboundHandler<VoicePacket> {
|
||||||
|
public static List<DataGroup> dataGroups = new ArrayList<>();
|
||||||
|
boolean flag = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void channelRead0(ChannelHandlerContext ctx, VoicePacket voicePacket) throws Exception {
|
||||||
|
// 处理接收到的数据包
|
||||||
|
dataGroups.add(voicePacket.getDataGroup());
|
||||||
|
}
|
||||||
|
|
||||||
|
private VoicePacket parseVoicePacket(ByteBuf buf) throws Exception {
|
||||||
|
if (buf == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
System.out.println("字节长度" + buf.readableBytes());
|
||||||
|
VoicePacket packet = new VoicePacket();
|
||||||
|
byte[] headBytes = new byte[4];
|
||||||
|
buf.readBytes(headBytes);
|
||||||
|
String head = new String(HexUtil.encodeHex(headBytes, false));
|
||||||
|
if (!"FCFCFCFC".equals(head)) {
|
||||||
|
System.out.println("不符合声纹和巡视主机的通讯协议!");
|
||||||
|
}
|
||||||
|
packet.setHead(head);
|
||||||
|
packet.setVersion(buf.readByte());
|
||||||
|
packet.setSize(buf.readInt());
|
||||||
|
System.out.println("size" + packet.getSize());
|
||||||
|
packet.setTimestamp(buf.readLong());
|
||||||
|
packet.setBasicInfo(readBytes(buf, 6));
|
||||||
|
packet.setId(readBytes(buf, 6));
|
||||||
|
packet.setFirmware(readBytes(buf, 3));
|
||||||
|
packet.setHardware(buf.readByte());
|
||||||
|
packet.setProtocol(buf.readShort());
|
||||||
|
packet.setFlag(readBytes(buf, 3));
|
||||||
|
|
||||||
|
DataGroup dataGroup = new DataGroup();
|
||||||
|
dataGroup.setSType(buf.readByte());
|
||||||
|
dataGroup.setSampleRate(buf.readShort());
|
||||||
|
dataGroup.setBits(buf.readByte());
|
||||||
|
dataGroup.setChannel(buf.readByte());
|
||||||
|
dataGroup.setData(readBytes(buf, buf.readableBytes() - 3)); // 减去CRC和End
|
||||||
|
packet.setDataGroup(dataGroup);
|
||||||
|
|
||||||
|
packet.setCrc(buf.readShort());
|
||||||
|
packet.setEnd(buf.readByte());
|
||||||
|
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] readBytes(ByteBuf buf, int length) {
|
||||||
|
byte[] bytes = new byte[length];
|
||||||
|
buf.readBytes(bytes);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processVoicePacket(VoicePacket packet) throws IOException {
|
||||||
|
|
||||||
|
// byte bits = dataGroup.getBits();
|
||||||
|
// byte channel = dataGroup.getChannel();
|
||||||
|
// short sampleRate = dataGroup.getSampleRate();
|
||||||
|
// // 保存为 WAV 文件
|
||||||
|
// saveAsWav(dataGroup.getData(), sampleRate, channel, bits, "D:\\output.wav");
|
||||||
|
// System.out.println("WAV 文件生成成功");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成模拟音频数据(PCM 格式)
|
||||||
|
*
|
||||||
|
* @param sampleRate 采样率
|
||||||
|
* @param channels 声道数
|
||||||
|
* @param bitsPerSample 位深
|
||||||
|
* @return 模拟的音频数据
|
||||||
|
*/
|
||||||
|
public static byte[] generateAudioData(int sampleRate, int channels, int bitsPerSample) {
|
||||||
|
int duration = 2; // 音频时长(秒)
|
||||||
|
int frameSize = channels * (bitsPerSample / 8); // 每帧的字节数
|
||||||
|
int dataSize = sampleRate * duration * frameSize; // 总数据大小
|
||||||
|
|
||||||
|
byte[] audioData = new byte[dataSize];
|
||||||
|
for (int i = 0; i < dataSize; i++) {
|
||||||
|
audioData[i] = (byte) (Math.random() * 256 - 128); // 随机生成 PCM 数据
|
||||||
|
}
|
||||||
|
return audioData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析声纹数据并保存为 WAV 文件
|
||||||
|
*
|
||||||
|
* @param audioData 音频数据(PCM 格式)
|
||||||
|
* @param sampleRate 采样率(如 48000)
|
||||||
|
* @param channels 声道数(如 2 表示双声道)
|
||||||
|
* @param bitsPerSample 位深(如 16)
|
||||||
|
* @param outputFile 输出文件路径(如 "output.wav")
|
||||||
|
*/
|
||||||
|
public static void saveAsWav(byte[] audioData, int sampleRate, int channels, int bitsPerSample, String outputFile) {
|
||||||
|
try {
|
||||||
|
// 创建音频格式
|
||||||
|
AudioFormat format = new AudioFormat(sampleRate, bitsPerSample, channels, true, false);
|
||||||
|
|
||||||
|
// 将字节数组转换为音频输入流
|
||||||
|
ByteArrayInputStream bais = new ByteArrayInputStream(audioData);
|
||||||
|
AudioInputStream audioInputStream = new AudioInputStream(bais, format,
|
||||||
|
audioData.length / format.getFrameSize());
|
||||||
|
|
||||||
|
// 保存为 WAV 文件
|
||||||
|
AudioSystem.write(audioInputStream, javax.sound.sampled.AudioFileFormat.Type.WAVE, new File(outputFile));
|
||||||
|
System.out.println("Saved audio data to: " + outputFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||||
|
cause.printStackTrace();
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
package com.yfd.platform.component.voiceserver;
|
||||||
|
|
||||||
|
import com.yfd.platform.component.nettyserver.*;
|
||||||
|
import io.netty.bootstrap.ServerBootstrap;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.channel.*;
|
||||||
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class VoiceServer {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(VoiceServer.class);
|
||||||
|
private final int port;
|
||||||
|
|
||||||
|
public VoiceServer(int port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
public void run() throws Exception {
|
||||||
|
//创建两个线程组
|
||||||
|
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
|
||||||
|
EventLoopGroup workerGroup = new NioEventLoopGroup(); //8个NioEventLoop
|
||||||
|
|
||||||
|
try {
|
||||||
|
ServerBootstrap b = new ServerBootstrap();
|
||||||
|
|
||||||
|
b.group(bossGroup, workerGroup)
|
||||||
|
.channel(NioServerSocketChannel.class)
|
||||||
|
.option(ChannelOption.SO_BACKLOG, 128)
|
||||||
|
.childOption(ChannelOption.SO_KEEPALIVE, true)
|
||||||
|
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||||
|
@Override
|
||||||
|
protected void initChannel(SocketChannel ch) throws Exception {
|
||||||
|
//获取到pipeline
|
||||||
|
ChannelPipeline pipeline = ch.pipeline();
|
||||||
|
pipeline.addLast(new AudioDataDecoder());
|
||||||
|
//加入自己的业务处理handler
|
||||||
|
pipeline.addLast(new VoicePacketHandler());
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
logger.info("Voice TCP server is started!(port:" + port + ")");
|
||||||
|
ChannelFuture channelFuture = b.bind(port).sync();
|
||||||
|
//监听关闭
|
||||||
|
channelFuture.channel().closeFuture().sync();
|
||||||
|
} finally {
|
||||||
|
bossGroup.shutdownGracefully();
|
||||||
|
workerGroup.shutdownGracefully();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// public VoiceServer(int port) {
|
||||||
|
// this.port = port;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void run() throws Exception {
|
||||||
|
// EventLoopGroup bossGroup = new NioEventLoopGroup();
|
||||||
|
// EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||||
|
// try {
|
||||||
|
// ServerBootstrap b = new ServerBootstrap();
|
||||||
|
// b.group(bossGroup, workerGroup)
|
||||||
|
// .channel(NioServerSocketChannel.class)
|
||||||
|
// .childHandler(new ChannelInitializer<SocketChannel>() {
|
||||||
|
// @Override
|
||||||
|
// public void initChannel(SocketChannel ch) {
|
||||||
|
// //获取到pipeline
|
||||||
|
// ChannelPipeline pipeline = ch.pipeline();
|
||||||
|
// pipeline.addLast(new AudioDataDecoder());
|
||||||
|
// pipeline.addLast(new VoicePacketHandler());
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// ChannelFuture f = b.bind(port).sync();
|
||||||
|
// f.channel().closeFuture().sync();
|
||||||
|
// } finally {
|
||||||
|
// workerGroup.shutdownGracefully();
|
||||||
|
// bossGroup.shutdownGracefully();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.yfd.platform.component.voiceserver;
|
||||||
|
|
||||||
|
import com.yfd.platform.component.nettyserver.NettyServer;
|
||||||
|
import com.yfd.platform.config.HttpServerConfig;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.boot.CommandLineRunner;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Order(value=21)
|
||||||
|
public class VoiceServerRunner implements CommandLineRunner {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(VoiceServerRunner.class);
|
||||||
|
@Override
|
||||||
|
public void run(String... args) throws Exception {
|
||||||
|
new Thread(()->{
|
||||||
|
try {
|
||||||
|
//项目启动时已经加载好了
|
||||||
|
new VoiceServer(8972).run();
|
||||||
|
logger.info("Netty TCP server is started!");
|
||||||
|
} catch (Exception e){
|
||||||
|
logger.error("发生错误", e);
|
||||||
|
throw new RuntimeException("Netty TCP server start failed!", e);
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.yfd.platform.component.voiceserver;
|
||||||
|
|
||||||
|
import com.yfd.platform.modules.basedata.domain.SubstationPatroldevice;
|
||||||
|
import com.yfd.platform.modules.basedata.domain.VoicePatrolLog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author pcj
|
||||||
|
* @Date 2025/3/6 18:28
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
public interface VoiceServerService {
|
||||||
|
|
||||||
|
boolean sendVoiceServerControl(String ID, String actionPower,String fileName);
|
||||||
|
boolean createAudioFile(String fileName);
|
||||||
|
void executeVoiceTaskAsync(SubstationPatroldevice substationPatroldevice, String duration, VoicePatrolLog log);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,243 @@
|
|||||||
|
package com.yfd.platform.component.voiceserver.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import cn.hutool.log.LogFactory;
|
||||||
|
import com.yfd.platform.component.mqtt.MqttGateway;
|
||||||
|
import com.yfd.platform.component.voiceserver.DataGroup;
|
||||||
|
import com.yfd.platform.component.voiceserver.VoicePacketHandler;
|
||||||
|
import com.yfd.platform.component.voiceserver.VoiceServerService;
|
||||||
|
import com.yfd.platform.config.HttpServerConfig;
|
||||||
|
import com.yfd.platform.config.thread.ThreadPoolExecutorUtil;
|
||||||
|
import com.yfd.platform.modules.basedata.domain.SubstationPatroldevice;
|
||||||
|
import com.yfd.platform.modules.basedata.domain.VoicePatrolLog;
|
||||||
|
import com.yfd.platform.modules.basedata.mapper.VoicePatrolLogMapper;
|
||||||
|
import com.yfd.platform.utils.ExecutionJob;
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Date: 2025/3/6 18:28
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class VoiceServerServiceImpl implements VoiceServerService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MqttGateway mqttGateway;
|
||||||
|
@Resource
|
||||||
|
private HttpServerConfig httpServerConfig;
|
||||||
|
@Resource
|
||||||
|
private VoicePatrolLogMapper voicePatrolLogMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean sendVoiceServerControl(String ID, String actionPower, String fileName) {
|
||||||
|
if ("ON".equals(actionPower)) {
|
||||||
|
VoicePacketHandler.dataGroups.clear();
|
||||||
|
}
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
data.putOpt("GLOBAL_MODE", "ACTION");
|
||||||
|
data.putOpt("GLOBAL_CLIENTID", ID);
|
||||||
|
data.putOpt("GLOBAL_GROUPID", "admin");
|
||||||
|
data.putOpt("ACTION_POWER", actionPower);
|
||||||
|
try {
|
||||||
|
mqttGateway.sendToMqtt("CONTROL/" + ID, 1, JSONUtil.toJsonStr(data));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if ("OFF".equals(actionPower)) {
|
||||||
|
this.createAudioFile(fileName);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean createAudioFile(String fileName) {
|
||||||
|
List<DataGroup> voicePackets = VoicePacketHandler.dataGroups;
|
||||||
|
if (voicePackets.size() <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DataGroup dataGroup = voicePackets.get(0);
|
||||||
|
byte sampleSizeInBits = dataGroup.getBits();
|
||||||
|
byte numChannels = dataGroup.getChannel();
|
||||||
|
short sampleRate = dataGroup.getSampleRate();
|
||||||
|
List<byte[]> pcmDataList = voicePackets.stream().map(DataGroup::getData).collect(Collectors.toList());
|
||||||
|
try {
|
||||||
|
FileUtil.touch(httpServerConfig.getSnapFilePath() + fileName);
|
||||||
|
generateWavFile(httpServerConfig.getSnapFilePath() + fileName, pcmDataList, sampleRate, numChannels,
|
||||||
|
sampleSizeInBits);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************
|
||||||
|
* 用途说明: 线程执行声纹任务
|
||||||
|
* 参数说明 device 设备
|
||||||
|
* 参数说明 duration 录制时间
|
||||||
|
* 参数说明 log 声音日志
|
||||||
|
* 返回值说明: void
|
||||||
|
***********************************/
|
||||||
|
@Override
|
||||||
|
public void executeVoiceTaskAsync(SubstationPatroldevice device, String duration, VoicePatrolLog log) {
|
||||||
|
try {
|
||||||
|
ExecutionJob.EXECUTOR.submit(() -> {
|
||||||
|
// 生成文件路径(异步线程内操作)
|
||||||
|
String fullPath = buildFilePath(device);
|
||||||
|
log.setFileName(fullPath);
|
||||||
|
log.setFilePath(httpServerConfig.getSnapFilePath() + fullPath);
|
||||||
|
|
||||||
|
// 控制音频采集
|
||||||
|
this.sendVoiceServerControl(
|
||||||
|
device.getPatroldeviceCode(), "ON", fullPath
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
TimeUnit.SECONDS.sleep(Integer.parseInt(duration));
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
this.sendVoiceServerControl(
|
||||||
|
device.getPatroldeviceCode(), "OFF", fullPath
|
||||||
|
);
|
||||||
|
// 保存日志
|
||||||
|
voicePatrolLogMapper.insert(log);
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 异常处理:记录详细日志
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildFilePath(SubstationPatroldevice device) {
|
||||||
|
return String.format("%s/%s/%s/%s/%s/%s/%s-%s.wav",
|
||||||
|
device.getStationCode(),
|
||||||
|
DateUtil.format(new Date(), "yyyy"),
|
||||||
|
DateUtil.format(new Date(), "MM"),
|
||||||
|
DateUtil.format(new Date(), "dd"),
|
||||||
|
device.getPatroldeviceCode(),
|
||||||
|
"Audio",
|
||||||
|
device.getPatroldeviceCode(),
|
||||||
|
DateUtil.format(new Date(), "yyyyMMddHHmmss")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] mergePcmData(List<byte[]> pcmDataList) {
|
||||||
|
int totalLength = pcmDataList.stream().mapToInt(data -> data.length).sum();
|
||||||
|
byte[] fullPcmData = new byte[totalLength];
|
||||||
|
int offset = 0;
|
||||||
|
for (byte[] data : pcmDataList) {
|
||||||
|
System.arraycopy(data, 0, fullPcmData, offset, data.length);
|
||||||
|
offset += data.length;
|
||||||
|
}
|
||||||
|
return fullPcmData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateWavFile(String savePath, List<byte[]> pcmDataList, int sampleRate, int numChannels,
|
||||||
|
int bitsPerSample) throws IOException {
|
||||||
|
// 合并 PCM 数据
|
||||||
|
byte[] fullPcmData = mergePcmData(pcmDataList);
|
||||||
|
|
||||||
|
// 构建 WAV 文件头
|
||||||
|
byte[] header = buildWavHeader(sampleRate, numChannels, bitsPerSample, fullPcmData.length);
|
||||||
|
|
||||||
|
// 写入文件
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(savePath)) {
|
||||||
|
fos.write(header);
|
||||||
|
fos.write(fullPcmData);
|
||||||
|
}
|
||||||
|
System.out.println("音频数据已保存为 " + savePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] buildWavHeader(int sampleRate, int numChannels, int bitsPerSample, int dataSize) throws IOException {
|
||||||
|
ByteArrayOutputStream headerStream = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
// ChunkID: "RIFF" (4 bytes)
|
||||||
|
headerStream.write("RIFF".getBytes());
|
||||||
|
|
||||||
|
// ChunkSize: File size - 8 (4 bytes, little-endian)
|
||||||
|
int fileSize = 36 + dataSize; // 36 = 44 - 8 (header size)
|
||||||
|
headerStream.write(ByteBuffer.allocate(4)
|
||||||
|
.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
|
.putInt(fileSize)
|
||||||
|
.array());
|
||||||
|
|
||||||
|
// Format: "WAVE" (4 bytes)
|
||||||
|
headerStream.write("WAVE".getBytes());
|
||||||
|
|
||||||
|
// Subchunk1ID: "fmt " (4 bytes)
|
||||||
|
headerStream.write("fmt ".getBytes());
|
||||||
|
|
||||||
|
// Subchunk1Size: 16 (4 bytes, little-endian)
|
||||||
|
headerStream.write(ByteBuffer.allocate(4)
|
||||||
|
.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
|
.putInt(16)
|
||||||
|
.array());
|
||||||
|
|
||||||
|
// AudioFormat: 1 (PCM, 2 bytes, little-endian)
|
||||||
|
headerStream.write(ByteBuffer.allocate(2)
|
||||||
|
.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
|
.putShort((short) 1)
|
||||||
|
.array());
|
||||||
|
|
||||||
|
// NumChannels (2 bytes, little-endian)
|
||||||
|
headerStream.write(ByteBuffer.allocate(2)
|
||||||
|
.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
|
.putShort((short) numChannels)
|
||||||
|
.array());
|
||||||
|
|
||||||
|
// SampleRate (4 bytes, little-endian)
|
||||||
|
headerStream.write(ByteBuffer.allocate(4)
|
||||||
|
.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
|
.putInt(sampleRate)
|
||||||
|
.array());
|
||||||
|
|
||||||
|
// ByteRate: SampleRate * NumChannels * BitsPerSample/8 (4 bytes, little-endian)
|
||||||
|
int byteRate = sampleRate * numChannels * (bitsPerSample / 8);
|
||||||
|
headerStream.write(ByteBuffer.allocate(4)
|
||||||
|
.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
|
.putInt(byteRate)
|
||||||
|
.array());
|
||||||
|
|
||||||
|
// BlockAlign: NumChannels * BitsPerSample/8 (2 bytes, little-endian)
|
||||||
|
short blockAlign = (short) (numChannels * (bitsPerSample / 8));
|
||||||
|
headerStream.write(ByteBuffer.allocate(2)
|
||||||
|
.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
|
.putShort(blockAlign)
|
||||||
|
.array());
|
||||||
|
|
||||||
|
// BitsPerSample (2 bytes, little-endian)
|
||||||
|
headerStream.write(ByteBuffer.allocate(2)
|
||||||
|
.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
|
.putShort((short) bitsPerSample)
|
||||||
|
.array());
|
||||||
|
|
||||||
|
// Subchunk2ID: "data" (4 bytes)
|
||||||
|
headerStream.write("data".getBytes());
|
||||||
|
|
||||||
|
// Subchunk2Size: data size (4 bytes, little-endian)
|
||||||
|
headerStream.write(ByteBuffer.allocate(4)
|
||||||
|
.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
|
.putInt(dataSize)
|
||||||
|
.array());
|
||||||
|
|
||||||
|
return headerStream.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,119 @@
|
|||||||
|
package com.yfd.platform.modules.basedata.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.yfd.platform.annotation.Log;
|
||||||
|
import com.yfd.platform.component.voiceserver.VoiceServerService;
|
||||||
|
import com.yfd.platform.config.ResponseResult;
|
||||||
|
import com.yfd.platform.modules.basedata.domain.SubstationPatroldevice;
|
||||||
|
import com.yfd.platform.modules.basedata.domain.VoicePatrolLog;
|
||||||
|
import com.yfd.platform.modules.basedata.service.ISubstationPatroldeviceService;
|
||||||
|
import com.yfd.platform.modules.basedata.service.IVoicePatrolLogService;
|
||||||
|
import com.yfd.platform.utils.HttpRESTfulUtils;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 前端控制器
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author zhengsl
|
||||||
|
* @since 2025-04-25
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/basedata/voice-patrol-log")
|
||||||
|
public class VoicePatrolLogController {
|
||||||
|
@Resource
|
||||||
|
private IVoicePatrolLogService voicePatrolLogService;
|
||||||
|
@Resource
|
||||||
|
private ISubstationPatroldeviceService substationPatroldeviceService;
|
||||||
|
@Resource
|
||||||
|
private HttpRESTfulUtils httpRESTfulUtils;
|
||||||
|
@Resource
|
||||||
|
private VoiceServerService voiceServerService;
|
||||||
|
|
||||||
|
@GetMapping("/getVoicePatrolPage")
|
||||||
|
@ApiOperation("分页查看声纹检测数据")
|
||||||
|
public ResponseResult getVoicePatrolPage(Page<Map<String, Object>> page, String stationId, String patroldeviceId,
|
||||||
|
String patroldeviceName
|
||||||
|
, String startDate, String endDate) {
|
||||||
|
if (StrUtil.isBlank(stationId)) {
|
||||||
|
return ResponseResult.error("未传变电站信息");
|
||||||
|
}
|
||||||
|
String startFormat = "";
|
||||||
|
if (StrUtil.isNotBlank(startDate)) {
|
||||||
|
Date parseStart = DateUtil.parse(startDate);
|
||||||
|
//一天的开始
|
||||||
|
Date beginOfDay = DateUtil.beginOfDay(parseStart);
|
||||||
|
startFormat = DateUtil.format(beginOfDay, "yyyy-MM-dd HH:mm:ss");
|
||||||
|
}
|
||||||
|
String endFormat = "";
|
||||||
|
if (StrUtil.isNotBlank(startDate)) {
|
||||||
|
Date parseEnd = DateUtil.parse(endDate);
|
||||||
|
//一天的结束
|
||||||
|
Date endOfDay = DateUtil.endOfDay(parseEnd);
|
||||||
|
endFormat = DateUtil.format(endOfDay, "yyyy-MM-dd HH:mm:ss");
|
||||||
|
}
|
||||||
|
LambdaQueryWrapper<VoicePatrolLog> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
if (StrUtil.isNotBlank(stationId)) {
|
||||||
|
queryWrapper.eq(VoicePatrolLog::getStationId, stationId);
|
||||||
|
}
|
||||||
|
if (StrUtil.isNotBlank(patroldeviceId)) {
|
||||||
|
queryWrapper.eq(VoicePatrolLog::getPatroldeviceId, patroldeviceId);
|
||||||
|
}
|
||||||
|
if (StrUtil.isNotBlank(patroldeviceName)) {
|
||||||
|
queryWrapper.like(VoicePatrolLog::getPatroldeviceName, patroldeviceName);
|
||||||
|
}
|
||||||
|
if (StrUtil.isNotBlank(startFormat) && StrUtil.isNotBlank(endFormat)) {
|
||||||
|
queryWrapper.le(VoicePatrolLog::getDate, endFormat);
|
||||||
|
queryWrapper.ge(VoicePatrolLog::getDate, startFormat);
|
||||||
|
}
|
||||||
|
queryWrapper.orderByDesc(VoicePatrolLog::getDate);
|
||||||
|
Page<Map<String, Object>> mapPage = voicePatrolLogService.pageMaps(page, queryWrapper);
|
||||||
|
return ResponseResult.successData(mapPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Log(module = "声纹检测", value = "执行声纹任务", type = "1")
|
||||||
|
@PostMapping("/executeVoicePatrolTask")
|
||||||
|
@ApiOperation("执行声纹任务")
|
||||||
|
public ResponseResult executeVoicePatrolTask(String id, String duration) {
|
||||||
|
SubstationPatroldevice substationPatroldevice = substationPatroldeviceService.getById(id);
|
||||||
|
if (substationPatroldevice == null) {
|
||||||
|
return ResponseResult.error("当前设备不存在");
|
||||||
|
}
|
||||||
|
// 生成日志对象基础信息(同步执行)
|
||||||
|
VoicePatrolLog log = buildBaseLog(substationPatroldevice, duration);
|
||||||
|
// 提交异步任务
|
||||||
|
voiceServerService.executeVoiceTaskAsync(substationPatroldevice, duration, log);
|
||||||
|
// 立即返回响应
|
||||||
|
return ResponseResult.success("任务已提交");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 基础日志对象构建方法
|
||||||
|
private VoicePatrolLog buildBaseLog(SubstationPatroldevice device, String duration) {
|
||||||
|
VoicePatrolLog log = new VoicePatrolLog();
|
||||||
|
log.setId(IdUtil.fastSimpleUUID());
|
||||||
|
log.setPatroldeviceId(device.getPatroldeviceId());
|
||||||
|
log.setPatroldeviceCode(device.getPatroldeviceCode());
|
||||||
|
log.setPatroldeviceName(device.getPatroldeviceName());
|
||||||
|
log.setStationId(device.getStationId());
|
||||||
|
log.setStationCode(device.getStationCode());
|
||||||
|
log.setStationName(device.getStationName());
|
||||||
|
log.setDate(DateUtil.now());
|
||||||
|
log.setDuration(duration);
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
package com.yfd.platform.modules.basedata.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author zhengsl
|
||||||
|
* @since 2025-04-25
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@TableName("iis_voice_patrol_log")
|
||||||
|
public class VoicePatrolLog implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID
|
||||||
|
*/
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变电站id
|
||||||
|
*/
|
||||||
|
private String stationId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变电站名称
|
||||||
|
*/
|
||||||
|
private String stationName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变电站编码
|
||||||
|
*/
|
||||||
|
private String stationCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡视设备编号
|
||||||
|
*/
|
||||||
|
private String patroldeviceCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡视设备名称
|
||||||
|
*/
|
||||||
|
private String patroldeviceName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡视设备id
|
||||||
|
*/
|
||||||
|
private String patroldeviceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡视点位id
|
||||||
|
*/
|
||||||
|
private String deviceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件名称
|
||||||
|
*/
|
||||||
|
private String fileName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件完整路径
|
||||||
|
*/
|
||||||
|
private String filePath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 采集时长,单位:秒
|
||||||
|
*/
|
||||||
|
private String duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 录制时长
|
||||||
|
*/
|
||||||
|
private String date;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.yfd.platform.modules.basedata.mapper;
|
||||||
|
|
||||||
|
import com.yfd.platform.modules.basedata.domain.VoicePatrolLog;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author zhengsl
|
||||||
|
* @since 2025-04-25
|
||||||
|
*/
|
||||||
|
public interface VoicePatrolLogMapper extends BaseMapper<VoicePatrolLog> {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.yfd.platform.modules.basedata.service;
|
||||||
|
|
||||||
|
import com.yfd.platform.modules.basedata.domain.VoicePatrolLog;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author zhengsl
|
||||||
|
* @since 2025-04-25
|
||||||
|
*/
|
||||||
|
public interface IVoicePatrolLogService extends IService<VoicePatrolLog> {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.yfd.platform.modules.basedata.service.impl;
|
||||||
|
|
||||||
|
import com.yfd.platform.modules.basedata.domain.VoicePatrolLog;
|
||||||
|
import com.yfd.platform.modules.basedata.mapper.VoicePatrolLogMapper;
|
||||||
|
import com.yfd.platform.modules.basedata.service.IVoicePatrolLogService;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author zhengsl
|
||||||
|
* @since 2025-04-25
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class VoicePatrolLogServiceImpl extends ServiceImpl<VoicePatrolLogMapper, VoicePatrolLog> implements IVoicePatrolLogService {
|
||||||
|
|
||||||
|
}
|
@ -18,10 +18,7 @@ package com.yfd.platform.modules.patroltask.service.impl;
|
|||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.util.IdUtil;
|
import cn.hutool.core.util.*;
|
||||||
import cn.hutool.core.util.ObjUtil;
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.json.JSONArray;
|
import cn.hutool.json.JSONArray;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
@ -29,6 +26,7 @@ import com.alibaba.fastjson.JSONObject;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.yfd.platform.component.WebSocketServer;
|
import com.yfd.platform.component.WebSocketServer;
|
||||||
|
import com.yfd.platform.component.voiceserver.VoiceServerService;
|
||||||
import com.yfd.platform.config.HttpServerConfig;
|
import com.yfd.platform.config.HttpServerConfig;
|
||||||
import com.yfd.platform.constant.SystemCode;
|
import com.yfd.platform.constant.SystemCode;
|
||||||
import com.yfd.platform.modules.basedata.domain.LinkageSignal;
|
import com.yfd.platform.modules.basedata.domain.LinkageSignal;
|
||||||
@ -101,6 +99,7 @@ public class TodoTaskJob extends QuartzJobBean implements InterruptableJob {
|
|||||||
ISysDictionaryItemsService sysDictionaryItemsService =
|
ISysDictionaryItemsService sysDictionaryItemsService =
|
||||||
SpringContextHolder.getBean(ISysDictionaryItemsService.class);
|
SpringContextHolder.getBean(ISysDictionaryItemsService.class);
|
||||||
TaskResultMapper taskResultMapper = SpringContextHolder.getBean(TaskResultMapper.class);
|
TaskResultMapper taskResultMapper = SpringContextHolder.getBean(TaskResultMapper.class);
|
||||||
|
VoiceServerService voiceServerService = SpringContextHolder.getBean(VoiceServerService.class);
|
||||||
// QuartzMultiTaskManage quartzMultiTaskManage = SpringContextHolder.getBean(QuartzMultiTaskManage.class);
|
// QuartzMultiTaskManage quartzMultiTaskManage = SpringContextHolder.getBean(QuartzMultiTaskManage.class);
|
||||||
|
|
||||||
if ("false".equals(config.getDoTask())) {
|
if ("false".equals(config.getDoTask())) {
|
||||||
@ -377,7 +376,6 @@ public class TodoTaskJob extends QuartzJobBean implements InterruptableJob {
|
|||||||
JSONObject callresult = null;
|
JSONObject callresult = null;
|
||||||
if ("sound".equals(typelist.get(0).toString())) {
|
if ("sound".equals(typelist.get(0).toString())) {
|
||||||
//声音检测
|
//声音检测
|
||||||
// rtspurl = map.get("rtspDeviceUrl").toString();
|
|
||||||
filename = String.format("%s_%s_%s_%s_%s.wav",
|
filename = String.format("%s_%s_%s_%s_%s.wav",
|
||||||
DateUtil.format(DateUtil.date(), "yyyyMMdd"),
|
DateUtil.format(DateUtil.date(), "yyyyMMdd"),
|
||||||
DateUtil.format(DateUtil.date(), "HHmmss"),
|
DateUtil.format(DateUtil.date(), "HHmmss"),
|
||||||
@ -386,17 +384,40 @@ public class TodoTaskJob extends QuartzJobBean implements InterruptableJob {
|
|||||||
map.get("deviceName").toString()
|
map.get("deviceName").toString()
|
||||||
);
|
);
|
||||||
fullfilename = filepath + filename;
|
fullfilename = filepath + filename;
|
||||||
httpUtil.getMonitorAudioSnap(config.getffmpegPath(), rtspurl, fullfilename);
|
String encodefilename = fullfilename;
|
||||||
|
int duration = 10;
|
||||||
|
if (ObjUtil.isNotEmpty(map.get("duration"))) {
|
||||||
|
duration = NumberUtil.parseInt(map.get("duration").toString());
|
||||||
|
}
|
||||||
|
if (ObjectUtil.isNotEmpty(map.get("outsideAngle"))) {
|
||||||
|
if (JSONUtil.isTypeJSONArray(map.get("outsideAngle").toString())) {
|
||||||
|
JSONArray jsonArray = JSONUtil.parseArray(map.get("outsideAngle").toString());
|
||||||
|
customParams.put("SoundAlarmThresholdList", jsonArray);
|
||||||
|
}
|
||||||
|
if (JSONUtil.isTypeJSONObject(map.get("outsideAngle").toString())) {
|
||||||
|
cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(map.get(
|
||||||
|
"outsideAngle").toString());
|
||||||
|
customParams.put("SoundAlarmThreshold", jsonObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String patroldeviceCode = map.get("patroldeviceCode").toString();
|
||||||
|
voiceServerService.sendVoiceServerControl(patroldeviceCode, "ON", fullfilename);
|
||||||
|
Thread.sleep(duration * 1000);
|
||||||
|
voiceServerService.sendVoiceServerControl(patroldeviceCode, "OFF", fullfilename);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
//更新当前记录状态,修改为 1:已巡视(声音已采集)
|
//更新当前记录状态,修改为 1:已巡视(声音已采集)
|
||||||
fullfilename = URLEncoder.encode(fullfilename, "utf-8");//转码存储
|
fullfilename = URLEncoder.encode(fullfilename, "utf-8");//转码存储
|
||||||
todoTaskService.updateTaskResultStatus(quartzJob.getTaskTodoId(),
|
todoTaskService.updateTaskResultStatus(quartzJob.getTaskTodoId(),
|
||||||
map.get("resultId").toString(),
|
map.get("resultId").toString(),
|
||||||
fullfilename, "2");
|
fullfilename, "2");
|
||||||
|
|
||||||
log.info("customParams:" + JSONUtil.toJsonStr(customParams));
|
System.out.println("customParams:" + JSONUtil.toJsonStr(customParams));
|
||||||
callresult = httpUtil.callPicAnalyse(map.get("taskTodoId").toString(),
|
callresult = httpUtil.callPicAnalyse(map.get("resultId").toString(),
|
||||||
map.get("resultId").toString(), JSONUtil.toJsonStr(typelist),
|
map.get("deviceId").toString(), JSONUtil.toJsonStr(typelist),
|
||||||
JSONUtil.toJsonStr(customParams), fullfilename);
|
JSONUtil.toJsonStr(customParams), encodefilename, analysePort);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (!"3".equals(finalLinkageType)) {
|
if (!"3".equals(finalLinkageType)) {
|
||||||
|
@ -171,7 +171,7 @@ public class CodeGenerator {
|
|||||||
//rca_project,rca_projectanalysisrd,rca_projectinvestigaterd,rca_projectreport,rca_projectsummary,rca_projecttarget,rca_projecttrackrd,rca_analysisguide,rca_eventeffect,rca_failurecase,rca_failurecause,rca_failureclass,rca_failuremode
|
//rca_project,rca_projectanalysisrd,rca_projectinvestigaterd,rca_projectreport,rca_projectsummary,rca_projecttarget,rca_projecttrackrd,rca_analysisguide,rca_eventeffect,rca_failurecase,rca_failurecause,rca_failureclass,rca_failuremode
|
||||||
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
|
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
|
||||||
strategy.setControllerMappingHyphenStyle(true);
|
strategy.setControllerMappingHyphenStyle(true);
|
||||||
strategy.setTablePrefix("fk_");
|
strategy.setTablePrefix("iis_");
|
||||||
mpg.setStrategy(strategy);
|
mpg.setStrategy(strategy);
|
||||||
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
|
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
|
||||||
mpg.execute();
|
mpg.execute();
|
||||||
|
@ -191,6 +191,7 @@ algorithmserver:
|
|||||||
password: 123456
|
password: 123456
|
||||||
|
|
||||||
mqttserver:
|
mqttserver:
|
||||||
|
enable: false
|
||||||
username: admin # 账号
|
username: admin # 账号
|
||||||
password: public # 密码
|
password: public # 密码
|
||||||
host-url: tcp://82.156.18.154:1883 # mqtt连接tcp地址
|
host-url: tcp://82.156.18.154:1883 # mqtt连接tcp地址
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.yfd.platform.modules.basedata.mapper.VoicePatrolLogMapper">
|
||||||
|
|
||||||
|
</mapper>
|
@ -87,7 +87,7 @@
|
|||||||
AND (t.valid1= #{valid}
|
AND (t.valid1= #{valid}
|
||||||
OR ( t.flag = '4' OR t.flag = '6' ))
|
OR ( t.flag = '4' OR t.flag = '6' ))
|
||||||
</if>
|
</if>
|
||||||
ORDER BY t.order_num
|
ORDER BY sd.device_code
|
||||||
</select>
|
</select>
|
||||||
<select id="getHistoricalCurve" resultType="java.util.Map">
|
<select id="getHistoricalCurve" resultType="java.util.Map">
|
||||||
SELECT
|
SELECT
|
||||||
|
Loading…
Reference in New Issue
Block a user