[*] 去掉rtp功能
This commit is contained in:
13
README.md
13
README.md
@@ -33,17 +33,16 @@
|
|||||||
|功能|是否支持|是否实现|描述|
|
|功能|是否支持|是否实现|描述|
|
||||||
|:--|:--|:--|:--|
|
|:--|:--|:--|:--|
|
||||||
|P2P|支持|完成|P2P监控模式|
|
|P2P|支持|完成|P2P监控模式|
|
||||||
|WebRTC|支持|完成|Web终端不能同时进入多个房间|
|
|WebRTC|支持|完成|视频房间|
|
||||||
|控制|支持|完成|实现所有控制信令|
|
|控制|支持|完成|完整控制信令|
|
||||||
|
|
||||||
### 安卓终端功能
|
### 安卓终端功能
|
||||||
|
|
||||||
|功能|是否支持|是否实现|描述|
|
|功能|是否支持|是否实现|描述|
|
||||||
|:--|:--|:--|:--|
|
|:--|:--|:--|:--|
|
||||||
|P2P|支持|实现|P2P监控模式|
|
|P2P|支持|完成|P2P监控模式|
|
||||||
|WebRTC|支持|暂未实现|安卓终端支持同时进入多个房间|
|
|WebRTC|支持|完成|视频房间|
|
||||||
|RTP|支持|暂未实现|支持房间RTP推流(不会拉流)|
|
|控制|支持|完成|部分控制信令|
|
||||||
|控制|支持|完成|实现部分控制信令|
|
|
||||||
|拍照|支持|完成|拍照|
|
|拍照|支持|完成|拍照|
|
||||||
|录像|支持|完成|录制|
|
|录像|支持|完成|录制|
|
||||||
|变声|支持|暂未实现|变声器|
|
|变声|支持|暂未实现|变声器|
|
||||||
@@ -51,6 +50,8 @@
|
|||||||
|美颜|支持|暂未实现|视频美颜|
|
|美颜|支持|暂未实现|视频美颜|
|
||||||
|AI识别|支持|暂未实现|视频AI识别|
|
|AI识别|支持|暂未实现|视频AI识别|
|
||||||
|
|
||||||
|
> 注意:Web不支持同时进入多个视频房间,安卓终端支持同时进入多个视频房间。
|
||||||
|
|
||||||
## 证书
|
## 证书
|
||||||
|
|
||||||
本地开发测试安装`docs/certs`中的`ca.crt`证书到`受信任的根证书颁发机构`
|
本地开发测试安装`docs/certs`中的`ca.crt`证书到`受信任的根证书颁发机构`
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import androidx.core.app.ActivityCompat;
|
|||||||
import com.acgist.taoyao.client.databinding.ActivityMainBinding;
|
import com.acgist.taoyao.client.databinding.ActivityMainBinding;
|
||||||
import com.acgist.taoyao.client.signal.Taoyao;
|
import com.acgist.taoyao.client.signal.Taoyao;
|
||||||
import com.acgist.taoyao.media.MediaManager;
|
import com.acgist.taoyao.media.MediaManager;
|
||||||
import com.acgist.taoyao.media.TransportType;
|
|
||||||
import com.acgist.taoyao.media.VideoSourceType;
|
import com.acgist.taoyao.media.VideoSourceType;
|
||||||
import com.acgist.taoyao.media.config.Config;
|
import com.acgist.taoyao.media.config.Config;
|
||||||
|
|
||||||
@@ -128,7 +127,6 @@ public class MainActivity extends AppCompatActivity implements Serializable {
|
|||||||
resources.getInteger(R.integer.iFrameInterval),
|
resources.getInteger(R.integer.iFrameInterval),
|
||||||
resources.getString(R.string.storagePathImage),
|
resources.getString(R.string.storagePathImage),
|
||||||
resources.getString(R.string.storagePathVideo),
|
resources.getString(R.string.storagePathVideo),
|
||||||
TransportType.valueOf(resources.getString(R.string.transportType)),
|
|
||||||
VideoSourceType.valueOf(resources.getString(R.string.videoSourceType))
|
VideoSourceType.valueOf(resources.getString(R.string.videoSourceType))
|
||||||
);
|
);
|
||||||
final Display display = this.getWindow().getContext().getDisplay();
|
final Display display = this.getWindow().getContext().getDisplay();
|
||||||
|
|||||||
@@ -16,11 +16,10 @@
|
|||||||
<string name="encrypt">DES</string>
|
<string name="encrypt">DES</string>
|
||||||
<!-- 信令加密密钥 -->
|
<!-- 信令加密密钥 -->
|
||||||
<string name="encryptSecret">2SPWy+TF1zM=</string>
|
<string name="encryptSecret">2SPWy+TF1zM=</string>
|
||||||
<!-- 文件存储目录 -->
|
<!-- 图片存储目录 -->
|
||||||
<string name="storagePathImage">/taoyao/image</string>
|
<string name="storagePathImage">/taoyao/image</string>
|
||||||
|
<!-- 视频存储目录 -->
|
||||||
<string name="storagePathVideo">/taoyao/video</string>
|
<string name="storagePathVideo">/taoyao/video</string>
|
||||||
<!-- 传输类型:RTP|WEBRTC -->
|
|
||||||
<string name="transportType">WEBRTC</string>
|
|
||||||
<!-- 视频来源:FILE|BACK|FRONT|SCREEN -->
|
<!-- 视频来源:FILE|BACK|FRONT|SCREEN -->
|
||||||
<string name="videoSourceType">BACK</string>
|
<string name="videoSourceType">BACK</string>
|
||||||
<!-- 媒体配置:是否消费数据 -->
|
<!-- 媒体配置:是否消费数据 -->
|
||||||
@@ -35,9 +34,14 @@
|
|||||||
<bool name="audioProduce">true</bool>
|
<bool name="audioProduce">true</bool>
|
||||||
<!-- 媒体配置:是否生产视频 -->
|
<!-- 媒体配置:是否生产视频 -->
|
||||||
<bool name="videoProduce">true</bool>
|
<bool name="videoProduce">true</bool>
|
||||||
|
<!-- 图片质量 -->
|
||||||
<integer name="imageQuantity">100</integer>
|
<integer name="imageQuantity">100</integer>
|
||||||
|
<!-- 音频质量 -->
|
||||||
<string name="audioQuantity">fd-audio</string>
|
<string name="audioQuantity">fd-audio</string>
|
||||||
|
<!-- 视频质量 -->
|
||||||
<string name="videoQuantity">fd-video</string>
|
<string name="videoQuantity">fd-video</string>
|
||||||
|
<!-- 音频通道数量 -->
|
||||||
<integer name="channelCount">1</integer>
|
<integer name="channelCount">1</integer>
|
||||||
|
<!-- 视频关键帧频率 -->
|
||||||
<integer name="iFrameInterval">1</integer>
|
<integer name="iFrameInterval">1</integer>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -29,12 +29,6 @@ set(
|
|||||||
${SOURCE_DIR}/include/MediaManager.hpp
|
${SOURCE_DIR}/include/MediaManager.hpp
|
||||||
${SOURCE_DIR}/include/Room.hpp
|
${SOURCE_DIR}/include/Room.hpp
|
||||||
${SOURCE_DIR}/include/RouterCallback.hpp
|
${SOURCE_DIR}/include/RouterCallback.hpp
|
||||||
${SOURCE_DIR}/include/RtpAudioPublisher.hpp
|
|
||||||
${SOURCE_DIR}/include/RtpClient.hpp
|
|
||||||
${SOURCE_DIR}/include/RtpVideoPublisher.hpp
|
|
||||||
${SOURCE_DIR}/rtp/RtpAudioPublisher.cpp
|
|
||||||
${SOURCE_DIR}/rtp/RtpClient.cpp
|
|
||||||
${SOURCE_DIR}/rtp/RtpVideoPublisher.cpp
|
|
||||||
${SOURCE_DIR}/webrtc/MediaManager.cpp
|
${SOURCE_DIR}/webrtc/MediaManager.cpp
|
||||||
${SOURCE_DIR}/webrtc/Room.cpp
|
${SOURCE_DIR}/webrtc/Room.cpp
|
||||||
${SOURCE_DIR}/webrtc/RouterCallback.cpp
|
${SOURCE_DIR}/webrtc/RouterCallback.cpp
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
namespace acgist {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
namespace acgist {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
namespace acgist {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#include "RtpAudioPublisher.hpp"
|
|
||||||
|
|
||||||
namespace acgist {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#include "RtpClient.hpp"
|
|
||||||
|
|
||||||
namespace acgist {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#include "RtpVideoPublisher.hpp"
|
|
||||||
|
|
||||||
namespace acgist {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -32,7 +32,6 @@ namespace acgist {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OnConnectionStateChange(mediasoupclient::Transport* transport, const std::string& connectionState) override {
|
void OnConnectionStateChange(mediasoupclient::Transport* transport, const std::string& connectionState) override {
|
||||||
// TODO:restartIce?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::future<std::string> OnProduce(mediasoupclient::SendTransport* transport, const std::string& kind, nlohmann::json rtpParameters, const nlohmann::json& appData) override {
|
std::future<std::string> OnProduce(mediasoupclient::SendTransport* transport, const std::string& kind, nlohmann::json rtpParameters, const nlohmann::json& appData) override {
|
||||||
@@ -401,7 +400,6 @@ namespace acgist {
|
|||||||
// webrtc::PeerConnectionInterface::RTCConfiguration rtcConfiguration(webrtc::PeerConnectionInterface::RTCConfigurationType::kSafe);
|
// webrtc::PeerConnectionInterface::RTCConfiguration rtcConfiguration(webrtc::PeerConnectionInterface::RTCConfigurationType::kSafe);
|
||||||
webrtc::PeerConnectionInterface::RTCConfiguration rtcConfiguration(webrtc::PeerConnectionInterface::RTCConfigurationType::kAggressive);
|
webrtc::PeerConnectionInterface::RTCConfiguration rtcConfiguration(webrtc::PeerConnectionInterface::RTCConfigurationType::kAggressive);
|
||||||
webrtc::JavaParamRef<jobject> jRtcConfigurationRef(env, jRtcConfiguration);
|
webrtc::JavaParamRef<jobject> jRtcConfigurationRef(env, jRtcConfiguration);
|
||||||
// 注意
|
|
||||||
webrtc::jni::JavaToNativeRTCConfiguration(env, jRtcConfigurationRef, &rtcConfiguration);
|
webrtc::jni::JavaToNativeRTCConfiguration(env, jRtcConfigurationRef, &rtcConfiguration);
|
||||||
const char* rtpCapabilities = env->GetStringUTFChars(jRtpCapabilities, nullptr);
|
const char* rtpCapabilities = env->GetStringUTFChars(jRtpCapabilities, nullptr);
|
||||||
room->enterRoom(
|
room->enterRoom(
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ package com.acgist.taoyao.media;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.media.MediaCodecInfo;
|
|
||||||
import android.media.MediaCodecList;
|
|
||||||
import android.media.projection.MediaProjection;
|
import android.media.projection.MediaProjection;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
@@ -43,8 +41,6 @@ import org.webrtc.VideoTrack;
|
|||||||
import org.webrtc.audio.JavaAudioDeviceModule;
|
import org.webrtc.audio.JavaAudioDeviceModule;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.IntStream;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 媒体来源管理器
|
* 媒体来源管理器
|
||||||
@@ -93,10 +89,6 @@ public final class MediaManager {
|
|||||||
* 关键帧频率
|
* 关键帧频率
|
||||||
*/
|
*/
|
||||||
private int iFrameInterval;
|
private int iFrameInterval;
|
||||||
/**
|
|
||||||
* 传输通道类型
|
|
||||||
*/
|
|
||||||
private TransportType transportType;
|
|
||||||
/**
|
/**
|
||||||
* 视频来源类型
|
* 视频来源类型
|
||||||
*/
|
*/
|
||||||
@@ -214,7 +206,7 @@ public final class MediaManager {
|
|||||||
int imageQuantity, String audioQuantity, String videoQuantity,
|
int imageQuantity, String audioQuantity, String videoQuantity,
|
||||||
int channelCount, int iFrameInterval,
|
int channelCount, int iFrameInterval,
|
||||||
String imagePath, String videoPath,
|
String imagePath, String videoPath,
|
||||||
TransportType transportType, VideoSourceType videoSourceType
|
VideoSourceType videoSourceType
|
||||||
) {
|
) {
|
||||||
this.mainHandler = mainHandler;
|
this.mainHandler = mainHandler;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@@ -225,7 +217,6 @@ public final class MediaManager {
|
|||||||
this.iFrameInterval = iFrameInterval;
|
this.iFrameInterval = iFrameInterval;
|
||||||
this.imagePath = imagePath;
|
this.imagePath = imagePath;
|
||||||
this.videoPath = videoPath;
|
this.videoPath = videoPath;
|
||||||
this.transportType = transportType;
|
|
||||||
this.videoSourceType = videoSourceType;
|
this.videoSourceType = videoSourceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
package com.acgist.taoyao.media;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 传输类型
|
|
||||||
*
|
|
||||||
* @author acgist
|
|
||||||
*/
|
|
||||||
public enum TransportType {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RTP
|
|
||||||
* 注意:只能监控
|
|
||||||
*/
|
|
||||||
RTP,
|
|
||||||
/**
|
|
||||||
* WebRTC
|
|
||||||
*/
|
|
||||||
WEBRTC;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
package com.acgist.taoyao.media.audio;
|
package com.acgist.taoyao.media.audio;
|
||||||
|
|
||||||
import org.webrtc.voiceengine.WebRtcAudioManager;
|
|
||||||
import org.webrtc.voiceengine.WebRtcAudioRecord;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 混音
|
* 混音
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import android.util.Log;
|
|||||||
|
|
||||||
import com.acgist.taoyao.boot.utils.DateUtils;
|
import com.acgist.taoyao.boot.utils.DateUtils;
|
||||||
import com.acgist.taoyao.media.MediaManager;
|
import com.acgist.taoyao.media.MediaManager;
|
||||||
import com.acgist.taoyao.media.VideoSourceType;
|
|
||||||
import com.acgist.taoyao.media.signal.ITaoyao;
|
import com.acgist.taoyao.media.signal.ITaoyao;
|
||||||
|
|
||||||
import org.webrtc.VideoFrame;
|
import org.webrtc.VideoFrame;
|
||||||
|
|||||||
@@ -8,11 +8,8 @@ import com.acgist.taoyao.boot.utils.JSONUtils;
|
|||||||
import com.acgist.taoyao.boot.utils.MapUtils;
|
import com.acgist.taoyao.boot.utils.MapUtils;
|
||||||
import com.acgist.taoyao.boot.utils.PointerUtils;
|
import com.acgist.taoyao.boot.utils.PointerUtils;
|
||||||
import com.acgist.taoyao.media.RouterCallback;
|
import com.acgist.taoyao.media.RouterCallback;
|
||||||
import com.acgist.taoyao.media.VideoSourceType;
|
|
||||||
import com.acgist.taoyao.media.config.Config;
|
import com.acgist.taoyao.media.config.Config;
|
||||||
import com.acgist.taoyao.media.config.MediaAudioProperties;
|
|
||||||
import com.acgist.taoyao.media.config.MediaProperties;
|
import com.acgist.taoyao.media.config.MediaProperties;
|
||||||
import com.acgist.taoyao.media.config.MediaVideoProperties;
|
|
||||||
import com.acgist.taoyao.media.config.WebrtcProperties;
|
import com.acgist.taoyao.media.config.WebrtcProperties;
|
||||||
import com.acgist.taoyao.media.signal.ITaoyao;
|
import com.acgist.taoyao.media.signal.ITaoyao;
|
||||||
|
|
||||||
|
|||||||
@@ -4,17 +4,13 @@ import android.os.Handler;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.acgist.taoyao.boot.model.Message;
|
import com.acgist.taoyao.boot.model.Message;
|
||||||
import com.acgist.taoyao.boot.utils.JSONUtils;
|
|
||||||
import com.acgist.taoyao.boot.utils.ListUtils;
|
import com.acgist.taoyao.boot.utils.ListUtils;
|
||||||
import com.acgist.taoyao.boot.utils.MapUtils;
|
import com.acgist.taoyao.boot.utils.MapUtils;
|
||||||
import com.acgist.taoyao.media.VideoSourceType;
|
|
||||||
import com.acgist.taoyao.media.config.Config;
|
import com.acgist.taoyao.media.config.Config;
|
||||||
import com.acgist.taoyao.media.config.MediaProperties;
|
import com.acgist.taoyao.media.config.MediaProperties;
|
||||||
import com.acgist.taoyao.media.config.WebrtcProperties;
|
import com.acgist.taoyao.media.config.WebrtcProperties;
|
||||||
import com.acgist.taoyao.media.config.WebrtcStunProperties;
|
|
||||||
import com.acgist.taoyao.media.signal.ITaoyao;
|
import com.acgist.taoyao.media.signal.ITaoyao;
|
||||||
|
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
|
||||||
import org.webrtc.DataChannel;
|
import org.webrtc.DataChannel;
|
||||||
import org.webrtc.IceCandidate;
|
import org.webrtc.IceCandidate;
|
||||||
import org.webrtc.MediaConstraints;
|
import org.webrtc.MediaConstraints;
|
||||||
@@ -24,11 +20,9 @@ import org.webrtc.PeerConnectionFactory;
|
|||||||
import org.webrtc.SdpObserver;
|
import org.webrtc.SdpObserver;
|
||||||
import org.webrtc.SessionDescription;
|
import org.webrtc.SessionDescription;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ import org.apache.commons.lang3.ArrayUtils;
|
|||||||
import org.webrtc.PeerConnection;
|
import org.webrtc.PeerConnection;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WebRTC配置
|
* WebRTC配置
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import android.util.Log;
|
|||||||
|
|
||||||
import com.acgist.taoyao.boot.model.Message;
|
import com.acgist.taoyao.boot.model.Message;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,10 @@ make -C worker
|
|||||||
* [Medooze](https://github.com/medooze/media-server)
|
* [Medooze](https://github.com/medooze/media-server)
|
||||||
* [Mediasoup](https://github.com/versatica/mediasoup)
|
* [Mediasoup](https://github.com/versatica/mediasoup)
|
||||||
|
|
||||||
|
## RTP裸流
|
||||||
|
|
||||||
|
媒体服务主要使用`WebRTC`协议,同时支持接入`RTP`裸流,可以参考[RtpTest.java](../taoyao-signal-server/taoyao-server/src/test/java/com/acgist/taoyao/rtp/RtpTest.java)配合`ffmpeg`使用`RTP`推拉流,具体代码需要自行实现。
|
||||||
|
|
||||||
## 协议
|
## 协议
|
||||||
|
|
||||||
* https://www.ortc.org
|
* https://www.ortc.org
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
package com.acgist.taoyao.main;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
|
|
||||||
@SpringBootTest
|
|
||||||
class TaoyaoApplicationTests {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void contextLoads() {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.acgist.taoyao.signal;
|
package com.acgist.taoyao.rtp;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@@ -19,7 +19,7 @@ import com.acgist.taoyao.signal.utils.CipherUtils;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class SocketSignalTest {
|
public class RtpTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testSocket() throws Exception {
|
void testSocket() throws Exception {
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
package com.acgist.taoyao.service;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class Server {
|
|
||||||
|
|
||||||
public static final Executor EXECUTOR = Executors.newCachedThreadPool();
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testServer() throws Exception {
|
|
||||||
final ServerSocket server = new ServerSocket(9999);
|
|
||||||
while(!server.isClosed()) {
|
|
||||||
final Socket accept = server.accept();
|
|
||||||
EXECUTOR.execute(() -> {
|
|
||||||
try {
|
|
||||||
this.execute(accept);
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("异常", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
server.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void execute(Socket accept) throws IOException {
|
|
||||||
final InputStream inputStream = accept.getInputStream();
|
|
||||||
final OutputStream outputStream = accept.getOutputStream();
|
|
||||||
while(!accept.isClosed()) {
|
|
||||||
final byte[] bytes = new byte[1024];
|
|
||||||
final int length = inputStream.read(bytes);
|
|
||||||
log.info("收到消息:{}", new String(bytes, 0, length));
|
|
||||||
outputStream.write(bytes, 0, length);
|
|
||||||
outputStream.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package com.acgist.taoyao.signal;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
|
|
||||||
import com.acgist.taoyao.annotation.TaoyaoTest;
|
|
||||||
import com.acgist.taoyao.boot.model.MessageCodeException;
|
|
||||||
import com.acgist.taoyao.main.TaoyaoApplication;
|
|
||||||
import com.acgist.taoyao.signal.protocol.platform.PlatformErrorProtocol;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@TaoyaoTest(classes = TaoyaoApplication.class)
|
|
||||||
public class PlatformErrorProtocolTest {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private PlatformErrorProtocol platformErrorProtocol;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testException() {
|
|
||||||
log.info("{}", this.platformErrorProtocol.build(MessageCodeException.of("自定义")));
|
|
||||||
log.info("{}", this.platformErrorProtocol.build(new NullPointerException("空指针")));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
package com.acgist.taoyao.signal;
|
|
||||||
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.http.HttpClient;
|
|
||||||
import java.net.http.WebSocket;
|
|
||||||
import java.net.http.WebSocket.Listener;
|
|
||||||
import java.security.KeyManagementException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import java.util.concurrent.CompletionStage;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
|
||||||
import javax.net.ssl.TrustManager;
|
|
||||||
import javax.net.ssl.X509TrustManager;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class WebSocketClient {
|
|
||||||
|
|
||||||
public static final WebSocket build(String uri, String clientId) throws InterruptedException {
|
|
||||||
return build(uri, clientId, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final WebSocket build(String uri, String clientId, CountDownLatch count) throws InterruptedException {
|
|
||||||
final Object lock = new Object();
|
|
||||||
try {
|
|
||||||
return HttpClient
|
|
||||||
.newBuilder()
|
|
||||||
.sslContext(newSSLContext())
|
|
||||||
.build()
|
|
||||||
.newWebSocketBuilder()
|
|
||||||
.buildAsync(URI.create(uri), new Listener() {
|
|
||||||
@Override
|
|
||||||
public void onOpen(WebSocket webSocket) {
|
|
||||||
webSocket.sendText(String.format("""
|
|
||||||
{"header":{"signal":"client::register","v":"1.0.0","id":"1"},"body":{"username":"taoyao","password":"taoyao","ip":"127.0.0.1","clientId":"%s"}}
|
|
||||||
""", clientId), true);
|
|
||||||
Listener.super.onOpen(webSocket);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
|
|
||||||
synchronized (lock) {
|
|
||||||
lock.notifyAll();
|
|
||||||
}
|
|
||||||
if(count == null) {
|
|
||||||
log.debug("收到WebSocket消息:{}", data);
|
|
||||||
} else {
|
|
||||||
count.countDown();
|
|
||||||
log.debug("收到WebSocket消息:{}-{}", count.getCount(), data);
|
|
||||||
}
|
|
||||||
return Listener.super.onText(webSocket, data, last);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.join();
|
|
||||||
} finally {
|
|
||||||
synchronized (lock) {
|
|
||||||
lock.wait(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final SSLContext newSSLContext() {
|
|
||||||
SSLContext sslContext = null;
|
|
||||||
try {
|
|
||||||
// SSL协议:SSL、SSLv2、SSLv3、TLS、TLSv1、TLSv1.1、TLSv1.2、TLSv1.3
|
|
||||||
sslContext = SSLContext.getInstance("TLSv1.2");
|
|
||||||
sslContext.init(null, TRUST_ALL_CERT_MANAGER, new SecureRandom());
|
|
||||||
} catch (KeyManagementException | NoSuchAlgorithmException e) {
|
|
||||||
log.error("新建SSLContext异常", e);
|
|
||||||
try {
|
|
||||||
sslContext = SSLContext.getDefault();
|
|
||||||
} catch (NoSuchAlgorithmException ex) {
|
|
||||||
log.error("新建默认SSLContext异常", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sslContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final TrustManager[] TRUST_ALL_CERT_MANAGER = new TrustManager[] {
|
|
||||||
new X509TrustManager() {
|
|
||||||
@Override
|
|
||||||
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public X509Certificate[] getAcceptedIssuers() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
package com.acgist.taoyao.signal;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
import java.net.http.WebSocket;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import com.acgist.taoyao.annotation.CostedTest;
|
|
||||||
import com.acgist.taoyao.annotation.TaoyaoTest;
|
|
||||||
import com.acgist.taoyao.main.TaoyaoApplication;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@TaoyaoTest(classes = TaoyaoApplication.class)
|
|
||||||
class WebSocketSignalTest {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 防止GC
|
|
||||||
*/
|
|
||||||
private List<WebSocket> list = new ArrayList<>();
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSignal() throws InterruptedException {
|
|
||||||
final WebSocket clientA = WebSocketClient.build("wss://localhost:8888/websocket.signal", "clientA");
|
|
||||||
final WebSocket clientB = WebSocketClient.build("wss://localhost:8888/websocket.signal", "clientB");
|
|
||||||
clientA.sendText("""
|
|
||||||
{"header":{"signal":"client::heartbeat","v":"1.0.0","id":"1"},"body":{}}
|
|
||||||
""", true).join();
|
|
||||||
assertNotNull(clientA);
|
|
||||||
assertNotNull(clientB);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@CostedTest(thread = 10, count = 100, waitRelease = 5000L)
|
|
||||||
void testThread() throws InterruptedException {
|
|
||||||
final int total = 100;
|
|
||||||
final CountDownLatch count = new CountDownLatch(total);
|
|
||||||
final WebSocket clientA = WebSocketClient.build("wss://localhost:8888/websocket.signal", "clientA", count);
|
|
||||||
final long aTime = System.currentTimeMillis();
|
|
||||||
for (int index = 0; index < total; index++) {
|
|
||||||
clientA.sendText("""
|
|
||||||
{"header":{"signal":"client::status","v":"1.0.0","id":"1"},"body":{}}
|
|
||||||
""", true).join();
|
|
||||||
}
|
|
||||||
this.list.add(clientA);
|
|
||||||
// final ExecutorService executor = Executors.newFixedThreadPool(10);
|
|
||||||
// for (int index = 0; index < total; index++) {
|
|
||||||
// executor.execute(() -> {
|
|
||||||
// synchronized (clientA) {
|
|
||||||
// clientA.sendText("""
|
|
||||||
// {"header":{"signal":"client::status","v":"1.0.0","id":"1"},"body":{}}
|
|
||||||
// """, true).join();
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
count.await();
|
|
||||||
final long zTime = System.currentTimeMillis();
|
|
||||||
log.info("执行时间:{}", zTime - aTime);
|
|
||||||
log.info("当前连接数量:{}", this.list.size());
|
|
||||||
assertNotNull(clientA);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testMax() throws InterruptedException {
|
|
||||||
final int size = 1024;
|
|
||||||
final CountDownLatch count = new CountDownLatch(size);
|
|
||||||
for (int index = 0; index < size; index++) {
|
|
||||||
final WebSocket clientA = WebSocketClient.build("wss://localhost:8888/websocket.signal", "clientA", count);
|
|
||||||
assertNotNull(clientA);
|
|
||||||
assertTrue(!(clientA.isInputClosed() || clientA.isOutputClosed()));
|
|
||||||
}
|
|
||||||
count.await();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user