[*] 修复通道删除

This commit is contained in:
acgist
2023-06-02 09:20:40 +08:00
parent becc68b05f
commit d49444ba60
9 changed files with 96 additions and 74 deletions

View File

@@ -363,9 +363,8 @@ 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) {
while (!this.close && this.connect && (length = this.input.read(bytes)) >= 0) {
buffer.put(bytes, 0, length);
while (buffer.position() > 0) {
if (messageLength <= 0) {
@@ -405,8 +404,7 @@ public final class Taoyao implements ITaoyao {
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();
}
}

View File

@@ -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;
@@ -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);
@@ -851,6 +854,7 @@ class Taoyao {
paused: true
});
videoConsumerId = videoConsumer.id;
videoRtpParameters = videoConsumer.rtpParameters;
await videoConsumer.resume();
videoConsumer.clientId = clientId;
videoConsumer.streamId = videoStreamId;
@@ -859,7 +863,7 @@ 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,
@@ -867,6 +871,8 @@ class Taoyao {
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);

View File

@@ -10,8 +10,8 @@
<el-button @click="taoyao.mediaProducerResume(videoProducer.id)" v-show="videoProducer && videoProducer.paused" type="danger" title="打开摄像头" :icon="VideoPlay" circle />
<el-button @click="taoyao.mediaProducerPause(videoProducer.id)" v-show="videoProducer && !videoProducer.paused" type="primary" title="关闭摄像头" :icon="VideoPause" circle />
<el-button @click="exchangeVideoSource" :icon="Refresh" circle title="交换媒体" />
<el-button @onclick="localPhotograph" :icon="Camera" circle title="拍照" />
<el-button @onclick="localClientRecord" :icon="VideoCamera" circle title="录像" :type="clientRecord ? 'danger' : ''" />
<el-button @click="localPhotograph" :icon="Camera" circle title="拍照" />
<el-button @click="localClientRecord" :icon="VideoCamera" circle title="录像" :type="clientRecord ? 'danger' : ''" />
<el-button @click="taoyao.controlServerRecord(client.clientId, (serverRecord = !serverRecord))" :icon="MostlyCloudy" circle title="录像" :type="serverRecord ? 'danger' : ''" />
<el-button @click="taoyao.mediaProducerStatus()" :icon="InfoFilled" circle title="媒体信息" />
<el-popover placement="top" :width="240" trigger="hover">

View File

@@ -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();

View File

@@ -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 = "录像最小端口")

View File

@@ -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

View File

@@ -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
// """);

View File

@@ -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()) {

View File

@@ -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();
}