From d49444ba60c5725211eefbd5a57406a624367377 Mon Sep 17 00:00:00 2001
From: acgist <289547414@qq.com>
Date: Fri, 2 Jun 2023 09:20:40 +0800
Subject: [PATCH] =?UTF-8?q?[*]=20=E4=BF=AE=E5=A4=8D=E9=80=9A=E9=81=93?=
=?UTF-8?q?=E5=88=A0=E9=99=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../acgist/taoyao/client/signal/Taoyao.java | 79 ++++++++++---------
taoyao-client-media/src/Taoyao.js | 41 ++++++----
.../src/components/LocalClient.vue | 4 +-
taoyao-client-web/src/components/Taoyao.js | 6 +-
.../taoyao/boot/config/FfmpegProperties.java | 4 +
.../src/main/resources/application.yml | 11 ++-
.../java/com/acgist/taoyao/RecorderTest.java | 13 ++-
.../taoyao/signal/party/media/Recorder.java | 11 +--
.../control/ControlServerRecordProtocol.java | 1 +
9 files changed, 96 insertions(+), 74 deletions(-)
diff --git a/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/signal/Taoyao.java b/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/signal/Taoyao.java
index 4f33a4a..035d9fa 100644
--- a/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/signal/Taoyao.java
+++ b/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/signal/Taoyao.java
@@ -363,50 +363,48 @@ public final class Taoyao implements ITaoyao {
short messageLength = 0;
final byte[] bytes = new byte[1024];
final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
- while (!this.close && this.connect) {
- try {
- while (!this.close && (length = this.input.read(bytes)) >= 0) {
- buffer.put(bytes, 0, length);
- while (buffer.position() > 0) {
- if (messageLength <= 0) {
- if (buffer.position() < Short.BYTES) {
- // 不够消息长度
- break;
- } else {
- buffer.flip();
- messageLength = buffer.getShort();
- buffer.compact();
- if (messageLength > 16 * 1024) {
- throw new RuntimeException("超过最大数据大小:" + messageLength);
- }
- }
+ try {
+ while (!this.close && this.connect && (length = this.input.read(bytes)) >= 0) {
+ buffer.put(bytes, 0, length);
+ while (buffer.position() > 0) {
+ if (messageLength <= 0) {
+ if (buffer.position() < Short.BYTES) {
+ // 不够消息长度
+ break;
} else {
- if (buffer.position() < messageLength) {
- // 不够消息长度
- break;
- } else {
- final byte[] message = new byte[messageLength];
- messageLength = 0;
- buffer.flip();
- buffer.get(message);
- buffer.compact();
- final String content = new String(this.decrypt.doFinal(message));
- try {
- this.on(content);
- } catch (Exception e) {
- Log.e(Taoyao.class.getSimpleName(), "处理信令异常:" + content, e);
- this.taoyaoListener.onError(e);
- }
+ buffer.flip();
+ messageLength = buffer.getShort();
+ buffer.compact();
+ if (messageLength > 16 * 1024) {
+ throw new RuntimeException("超过最大数据大小:" + messageLength);
+ }
+ }
+ } else {
+ if (buffer.position() < messageLength) {
+ // 不够消息长度
+ break;
+ } else {
+ final byte[] message = new byte[messageLength];
+ messageLength = 0;
+ buffer.flip();
+ buffer.get(message);
+ buffer.compact();
+ final String content = new String(this.decrypt.doFinal(message));
+ try {
+ this.on(content);
+ } catch (Exception e) {
+ Log.e(Taoyao.class.getSimpleName(), "处理信令异常:" + content, e);
+ this.taoyaoListener.onError(e);
}
}
}
}
- } catch (Exception e) {
- Log.e(Taoyao.class.getSimpleName(), "接收信令异常", e);
- this.disconnect();
}
+ } catch (Exception e) {
+ Log.e(Taoyao.class.getSimpleName(), "接收信令异常", e);
+ this.disconnect();
}
- if (!this.close && !this.connect) {
+ if (!this.close) {
this.messageHandler.post(this::connect);
}
}
@@ -439,7 +437,11 @@ public final class Taoyao implements ITaoyao {
*/
@Override
public void push(Message message) {
- if (this.output == null) {
+ if (this.close) {
+ Log.w(Taoyao.class.getSimpleName(), "通道已经关闭:" + message);
+ return;
+ }
+ if (!this.connect) {
Log.w(Taoyao.class.getSimpleName(), "通道没有打开:" + message);
return;
}
@@ -448,6 +450,7 @@ public final class Taoyao implements ITaoyao {
this.output.write(this.encrypt(message));
} catch (Exception e) {
Log.e(Taoyao.class.getSimpleName(), "请求信令异常:" + message, e);
+ this.disconnect();
}
}
diff --git a/taoyao-client-media/src/Taoyao.js b/taoyao-client-media/src/Taoyao.js
index 291c0a3..c88be1a 100644
--- a/taoyao-client-media/src/Taoyao.js
+++ b/taoyao-client-media/src/Taoyao.js
@@ -792,13 +792,15 @@ class Taoyao {
const { roomId, clientId, host, audioPort, videoPort, rtpCapabilities, audioStreamId, videoStreamId, audioProducerId, videoProducerId } = body;
const plainTransportOptions = {
...config.mediasoup.plainTransportOptions,
- rtcpMux : true,
- comedia : true
+ rtcpMux: false,
+ comedia: false
};
let videoConsumerId;
let audioConsumerId;
let audioTransportId;
let videoTransportId;
+ let audioRtpParameters;
+ let videoRtpParameters;
if(audioProducerId) {
const audioTransport = await room.mediasoupRouter.createPlainTransport(plainTransportOptions);
audioTransportId = audioTransport.id;
@@ -810,9 +812,9 @@ class Taoyao {
room.transports.delete(audioTransport.id)
});
await audioTransport.connect({
- ip : host,
- port : audioPort,
- rtcpPort : audioPort
+ ip : host,
+ port : audioPort,
+ rtcpPort: audioPort
});
const audioConsumer = await audioTransport.consume({
producerId: audioProducerId,
@@ -820,6 +822,7 @@ class Taoyao {
paused: true
});
audioConsumerId = audioConsumer.id;
+ audioRtpParameters = audioConsumer.rtpParameters;
await audioConsumer.resume();
audioConsumer.clientId = clientId;
audioConsumer.streamId = audioStreamId;
@@ -828,7 +831,7 @@ class Taoyao {
console.log("controlServerRecord audioConsumer close:", audioConsumer.id);
room.consumers.delete(audioConsumer.id);
});
- console.log("controlServerRecord audio", audioTransportId, audioConsumerId, audioTransport.tuple);
+ console.log("controlServerRecord audio", audioTransportId, audioConsumerId, audioTransport.tuple, audioRtpParameters);
}
if(videoProducerId) {
const videoTransport = await room.mediasoupRouter.createPlainTransport(plainTransportOptions);
@@ -841,9 +844,9 @@ class Taoyao {
room.transports.delete(videoTransport.id)
});
await videoTransport.connect({
- ip : host,
- port : videoPort,
- rtcpPort : videoPort
+ ip : host,
+ port : videoPort,
+ rtcpPort: videoPort
});
const videoConsumer = await videoTransport.consume({
producerId: videoProducerId,
@@ -851,6 +854,7 @@ class Taoyao {
paused: true
});
videoConsumerId = videoConsumer.id;
+ videoRtpParameters = videoConsumer.rtpParameters;
await videoConsumer.resume();
videoConsumer.clientId = clientId;
videoConsumer.streamId = videoStreamId;
@@ -859,14 +863,16 @@ class Taoyao {
console.log("controlServerRecord videoConsumer close:", videoConsumer.id);
room.consumers.delete(videoConsumer.id);
});
- console.log("controlServerRecord video:", videoTransportId, videoConsumerId, videoTransport.tuple);
+ console.log("controlServerRecord video:", videoTransportId, videoConsumerId, videoTransport.tuple, videoRtpParameters);
}
message.body = {
- roomId : roomId,
- audioConsumerId : audioConsumerId,
- videoConsumerId : videoConsumerId,
- audioTransportId : audioTransportId,
- videoTransportId : videoTransportId,
+ roomId : roomId,
+ audioConsumerId : audioConsumerId,
+ videoConsumerId : videoConsumerId,
+ audioTransportId : audioTransportId,
+ videoTransportId : videoTransportId,
+ audioRtpParameters: audioRtpParameters,
+ videoRtpParameters: videoRtpParameters,
};
me.push(message);
}
@@ -1528,6 +1534,11 @@ class Taoyao {
*/
transportEvent(type, roomId, transport) {
const self = this;
+ const room = self.rooms.get(roomId);
+ if(!room) {
+ // TODO:提示
+ return;
+ }
/********************* 通用通道事件 *********************/
transport.on("routerclose", () => {
console.info("transport routerclose:", transport.id);
diff --git a/taoyao-client-web/src/components/LocalClient.vue b/taoyao-client-web/src/components/LocalClient.vue
index 73e98bf..df82d12 100644
--- a/taoyao-client-web/src/components/LocalClient.vue
+++ b/taoyao-client-web/src/components/LocalClient.vue
@@ -10,8 +10,8 @@
-
-
+
+
diff --git a/taoyao-client-web/src/components/Taoyao.js b/taoyao-client-web/src/components/Taoyao.js
index fdbac5b..8839f9c 100644
--- a/taoyao-client-web/src/components/Taoyao.js
+++ b/taoyao-client-web/src/components/Taoyao.js
@@ -1958,7 +1958,7 @@ class Taoyao extends RemoteClient {
let track;
try {
console.debug("打开麦克风");
- let track = self.getAudioTrack();
+ let track = await self.getAudioTrack();
this.audioProducer = await this.sendTransport.produce({
track,
codecOptions: {
@@ -2528,7 +2528,7 @@ class Taoyao extends RemoteClient {
videoBitsPerSecond: 2400 * 1000,
mimeType: 'video/webm;codecs=opus,h264',
});
- mediaRecorder.onstop = function (e) {
+ me.mediaRecorder.onstop = function (e) {
const blob = new Blob(me.mediaRecorderChunks);
const objectURL = URL.createObjectURL(blob);
const download = document.createElement('a');
@@ -2541,7 +2541,7 @@ class Taoyao extends RemoteClient {
URL.revokeObjectURL(objectURL);
me.mediaRecorderChunks = [];
};
- mediaRecorder.ondataavailable = (e) => {
+ me.mediaRecorder.ondataavailable = (e) => {
me.mediaRecorderChunks.push(e.data);
};
me.mediaRecorder.start();
diff --git a/taoyao-signal-server/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/FfmpegProperties.java b/taoyao-signal-server/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/FfmpegProperties.java
index cce65af..0d06e1c 100644
--- a/taoyao-signal-server/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/FfmpegProperties.java
+++ b/taoyao-signal-server/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/FfmpegProperties.java
@@ -31,6 +31,10 @@ public class FfmpegProperties {
private String storageImagePath;
@Schema(title = "视频存储目录", description = "视频存储目录")
private String storageVideoPath;
+ @Schema(title = "预览截图时间", description = "预览截图时间")
+ private Integer previewTime;
+ @Schema(title = "预览截图时间", description = "预览截图时间")
+ private String durationRegex;
@Schema(title = "录像录像地址", description = "录像录像地址")
private String host;
@Schema(title = "录像最小端口", description = "录像最小端口")
diff --git a/taoyao-signal-server/taoyao-server/src/main/resources/application.yml b/taoyao-signal-server/taoyao-server/src/main/resources/application.yml
index 814ec71..69548fd 100644
--- a/taoyao-signal-server/taoyao-server/src/main/resources/application.yml
+++ b/taoyao-signal-server/taoyao-server/src/main/resources/application.yml
@@ -235,13 +235,12 @@ taoyao:
c=IN IP4 127.0.0.1
a=rtpmap:100 OPUS/48000/2
a=fmtp:100 sprop-stereo=1
- m=video %d RTP/AVP 107
+ m=video %d RTP/AVP 101
c=IN IP4 127.0.0.1
- a=rtpmap:107 H264/90000
- a=fmtp:107 packetization-mode=1
+ a=rtpmap:101 VP8/90000
# 录像命令
record: ffmpeg -protocol_whitelist "file,rtp,udp" -y -i %s %s
- # 截图命令
+ # 预览命令
preview: ffmpeg -y -i %s -ss %d -vframes 1 -f image2 %s
# 时长命令
duration: ffprobe -i %s -show_entries format=duration
@@ -251,6 +250,10 @@ taoyao:
storage-image-path: /data/taoyao/storage/image
# 视频存储目录
storage-video-path: /data/taoyao/storage/video
+ # 预览时间
+ preview-time: 4
+ # 时长提取
+ duration-regex: .*duration\=([0-9\.]+).*
# 录像地址
#host: 127.0.0.1
host: 192.168.8.40
diff --git a/taoyao-signal-server/taoyao-server/src/test/java/com/acgist/taoyao/RecorderTest.java b/taoyao-signal-server/taoyao-server/src/test/java/com/acgist/taoyao/RecorderTest.java
index 2e0c00c..bbd847a 100644
--- a/taoyao-signal-server/taoyao-server/src/test/java/com/acgist/taoyao/RecorderTest.java
+++ b/taoyao-signal-server/taoyao-server/src/test/java/com/acgist/taoyao/RecorderTest.java
@@ -16,29 +16,28 @@ public class RecorderTest {
ffmpegProperties.setHost("127.0.0.1");
ffmpegProperties.setSdp("""
v=0
- o=- 0 0 IN IP4 %s
+ o=- 0 0 IN IP4 127.0.0.1
s=TaoyaoRecord
t=0 0
m=audio %d RTP/AVP 97
- c=IN IP4 %s
+ c=IN IP4 127.0.0.1
a=rtpmap:97 OPUS/48000/2
a=fmtp:97 sprop-stereo=1
m=video %d RTP/AVP 96
- c=IN IP4 %s
+ c=IN IP4 127.0.0.1
a=rtpmap:96 VP8/90000
- a=fmtp:96 packetization-mode=1
""");
// ffmpegProperties.setSdp("""
// v=0
-// o=- 0 0 IN IP4 %s
+// o=- 0 0 IN IP4 127.0.0.1
// s=TaoyaoRecord
// t=0 0
// m=audio %d RTP/AVP 97
-// c=IN IP4 %s
+// c=IN IP4 127.0.0.1
// a=rtpmap:97 OPUS/48000/2
// a=fmtp:97 sprop-stereo=1
// m=video %d RTP/AVP 96
-// c=IN IP4 %s
+// c=IN IP4 127.0.0.1
// a=rtpmap:96 H264/90000
// a=fmtp:96 packetization-mode=1
// """);
diff --git a/taoyao-signal-server/taoyao-signal/src/main/java/com/acgist/taoyao/signal/party/media/Recorder.java b/taoyao-signal-server/taoyao-signal/src/main/java/com/acgist/taoyao/signal/party/media/Recorder.java
index 4d90f31..4fae2a3 100644
--- a/taoyao-signal-server/taoyao-signal/src/main/java/com/acgist/taoyao/signal/party/media/Recorder.java
+++ b/taoyao-signal-server/taoyao-signal/src/main/java/com/acgist/taoyao/signal/party/media/Recorder.java
@@ -159,6 +159,7 @@ public class Recorder {
this.thread.setDaemon(true);
this.thread.setName("TaoyaoRecord");
this.thread.start();
+ log.info("开始录像:{}", this.folder);
}
/**
@@ -210,14 +211,14 @@ public class Recorder {
* 视频预览截图
*/
private void preview() {
- int time = 2;
+ int time = this.ffmpegProperties.getPreviewTime();
final File file = Paths.get(this.preview).toFile();
- while(time > 0 && !(file.exists() && file.length() > 0L)) {
- log.debug("视频预览截图:{}", this.preview);
+ do {
+ log.debug("视频预览:{}", this.preview);
final String previewScript = String.format(this.ffmpegProperties.getPreview(), this.filepath, time, this.preview);
ScriptUtils.execute(previewScript);
time /= 2;
- }
+ } while (time > 0 && !(file.exists() && file.length() > 0L));
}
/**
@@ -227,7 +228,7 @@ public class Recorder {
log.debug("视频时长:{}", this.filepath);
final String durationScript = String.format(this.ffmpegProperties.getDuration(), this.filepath);
final ScriptExecutor executor = ScriptUtils.execute(durationScript);
- final Pattern pattern = Pattern.compile(".*duration\\=([0-9\\.]+).*");
+ final Pattern pattern = Pattern.compile(this.ffmpegProperties.getDurationRegex());
final Matcher matcher = pattern.matcher(executor.getResult());
String duration = null;
if(matcher.find()) {
diff --git a/taoyao-signal-server/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/control/ControlServerRecordProtocol.java b/taoyao-signal-server/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/control/ControlServerRecordProtocol.java
index 2ddc3fa..8311404 100644
--- a/taoyao-signal-server/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/control/ControlServerRecordProtocol.java
+++ b/taoyao-signal-server/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/control/ControlServerRecordProtocol.java
@@ -148,6 +148,7 @@ public class ControlServerRecordProtocol extends ProtocolControlAdapter implemen
message.setBody(body);
final Client mediaClient = room.getMediaClient();
mediaClient.request(message);
+ // TODO:回写ID,格式自动判断
return recorder.getFilepath();
}