[*] 日常优化
This commit is contained in:
@@ -1032,7 +1032,7 @@ public final class Taoyao implements ITaoyao {
|
|||||||
roomId,
|
roomId,
|
||||||
key -> new Room(
|
key -> new Room(
|
||||||
roomId, this.name,
|
roomId, this.name,
|
||||||
this.clientId, password,
|
password, this.clientId,
|
||||||
this, this.mainHandler,
|
this, this.mainHandler,
|
||||||
resources.getBoolean(R.bool.preview),
|
resources.getBoolean(R.bool.preview),
|
||||||
resources.getBoolean(R.bool.playAudio),
|
resources.getBoolean(R.bool.playAudio),
|
||||||
@@ -1043,6 +1043,7 @@ public final class Taoyao implements ITaoyao {
|
|||||||
resources.getBoolean(R.bool.dataProduce),
|
resources.getBoolean(R.bool.dataProduce),
|
||||||
resources.getBoolean(R.bool.audioProduce),
|
resources.getBoolean(R.bool.audioProduce),
|
||||||
resources.getBoolean(R.bool.videoProduce),
|
resources.getBoolean(R.bool.videoProduce),
|
||||||
|
resources.getBoolean(R.bool.roomUseIceServer),
|
||||||
this.mediaManager.getMediaProperties(),
|
this.mediaManager.getMediaProperties(),
|
||||||
this.mediaManager.getWebrtcProperties()
|
this.mediaManager.getWebrtcProperties()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -40,6 +40,8 @@
|
|||||||
<integer name="channelCount">1</integer>
|
<integer name="channelCount">1</integer>
|
||||||
<!-- 视频关键帧频率 -->
|
<!-- 视频关键帧频率 -->
|
||||||
<integer name="iFrameInterval">1</integer>
|
<integer name="iFrameInterval">1</integer>
|
||||||
|
<!-- 视频房间是否使用iceServer -->
|
||||||
|
<bool name="roomUseIceServer">false</bool>
|
||||||
<!-- 图片存储目录 -->
|
<!-- 图片存储目录 -->
|
||||||
<string name="imagePath">/taoyao</string>
|
<string name="imagePath">/taoyao</string>
|
||||||
<!-- 视频存储目录 -->
|
<!-- 视频存储目录 -->
|
||||||
|
|||||||
@@ -33,64 +33,139 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
*/
|
*/
|
||||||
public class Room extends CloseableClient implements RouterCallback {
|
public class Room extends CloseableClient implements RouterCallback {
|
||||||
|
|
||||||
private final String name;
|
/**
|
||||||
|
* 房间ID
|
||||||
|
*/
|
||||||
private final String roomId;
|
private final String roomId;
|
||||||
private final String clientId;
|
/**
|
||||||
|
* 房间名称
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
/**
|
||||||
|
* 房间密码
|
||||||
|
*/
|
||||||
private final String password;
|
private final String password;
|
||||||
|
/**
|
||||||
|
* 当前终端ID
|
||||||
|
*/
|
||||||
|
private final String clientId;
|
||||||
|
/**
|
||||||
|
* 是否预览
|
||||||
|
*/
|
||||||
private final boolean preview;
|
private final boolean preview;
|
||||||
|
/**
|
||||||
|
* 是否播放音频
|
||||||
|
*/
|
||||||
private final boolean playAudio;
|
private final boolean playAudio;
|
||||||
|
/**
|
||||||
|
* 是否播放视频
|
||||||
|
*/
|
||||||
private final boolean playVideo;
|
private final boolean playVideo;
|
||||||
|
/**
|
||||||
|
* 是否消费数据
|
||||||
|
*/
|
||||||
private final boolean dataConsume;
|
private final boolean dataConsume;
|
||||||
|
/**
|
||||||
|
* 是否消费音频
|
||||||
|
*/
|
||||||
private final boolean audioConsume;
|
private final boolean audioConsume;
|
||||||
|
/**
|
||||||
|
* 是否消费视频
|
||||||
|
*/
|
||||||
private final boolean videoConsume;
|
private final boolean videoConsume;
|
||||||
|
/**
|
||||||
|
* 是否生产数据
|
||||||
|
*/
|
||||||
private final boolean dataProduce;
|
private final boolean dataProduce;
|
||||||
|
/**
|
||||||
|
* 是否生产音频
|
||||||
|
*/
|
||||||
private final boolean audioProduce;
|
private final boolean audioProduce;
|
||||||
|
/**
|
||||||
|
* 是否生产视频
|
||||||
|
*/
|
||||||
private final boolean videoProduce;
|
private final boolean videoProduce;
|
||||||
|
/**
|
||||||
|
* 是否使用IceServer
|
||||||
|
*/
|
||||||
|
private final boolean useIceServer;
|
||||||
|
/**
|
||||||
|
* 是否已经开始生产
|
||||||
|
*/
|
||||||
private boolean produce;
|
private boolean produce;
|
||||||
|
/**
|
||||||
|
* 媒体配置
|
||||||
|
*/
|
||||||
private final MediaProperties mediaProperties;
|
private final MediaProperties mediaProperties;
|
||||||
|
/**
|
||||||
|
* WebRTC配置
|
||||||
|
*/
|
||||||
private final WebrtcProperties webrtcProperties;
|
private final WebrtcProperties webrtcProperties;
|
||||||
private final Map<String, RemoteClient> remoteClients;
|
/**
|
||||||
|
* 房间指针
|
||||||
|
*/
|
||||||
private final long nativeRoomPointer;
|
private final long nativeRoomPointer;
|
||||||
|
/**
|
||||||
|
* 本地终端
|
||||||
|
*/
|
||||||
private LocalClient localClient;
|
private LocalClient localClient;
|
||||||
private PeerConnection.RTCConfiguration rtcConfiguration;
|
/**
|
||||||
private PeerConnectionFactory peerConnectionFactory;
|
* 远程终端
|
||||||
|
*/
|
||||||
|
private final Map<String, RemoteClient> remoteClients;
|
||||||
|
/**
|
||||||
|
* RTC能力
|
||||||
|
*/
|
||||||
private Object rtpCapabilities;
|
private Object rtpCapabilities;
|
||||||
|
/**
|
||||||
|
* SCTP能力
|
||||||
|
*/
|
||||||
private Object sctpCapabilities;
|
private Object sctpCapabilities;
|
||||||
|
/**
|
||||||
|
* RTC配置
|
||||||
|
*/
|
||||||
|
private PeerConnection.RTCConfiguration rtcConfiguration;
|
||||||
|
/**
|
||||||
|
* PeerConnectionFactory
|
||||||
|
*/
|
||||||
|
private PeerConnectionFactory peerConnectionFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param roomId 房间ID
|
* @param roomId 房间ID
|
||||||
* @param name 终端名称
|
* @param name 终端名称
|
||||||
* @param clientId 当前终端ID
|
* @param clientId 当前终端ID
|
||||||
* @param password 房间密码
|
* @param password 房间密码
|
||||||
* @param taoyao 信令
|
* @param taoyao 信令
|
||||||
* @param mainHandler MainHandler
|
* @param mainHandler MainHandler
|
||||||
* @param preview 是否预览视频
|
* @param preview 是否预览视频
|
||||||
* @param playAudio 是否播放音频
|
* @param playAudio 是否播放音频
|
||||||
* @param playVideo 是否播放视频
|
* @param playVideo 是否播放视频
|
||||||
* @param dataConsume 是否消费数据
|
* @param dataConsume 是否消费数据
|
||||||
* @param audioConsume 是否消费音频
|
* @param audioConsume 是否消费音频
|
||||||
* @param videoConsume 是否消费视频
|
* @param videoConsume 是否消费视频
|
||||||
* @param dataProduce 是否生产数据
|
* @param dataProduce 是否生产数据
|
||||||
* @param audioProduce 是否生产音频
|
* @param audioProduce 是否生产音频
|
||||||
* @param videoProduce 是否生产视频
|
* @param videoProduce 是否生产视频
|
||||||
|
* @param useIceServer 是否使用IceServer
|
||||||
* @param mediaProperties 媒体配置
|
* @param mediaProperties 媒体配置
|
||||||
* @param webrtcProperties WebRTC配置
|
* @param webrtcProperties WebRTC配置
|
||||||
*/
|
*/
|
||||||
public Room(
|
public Room(
|
||||||
String roomId, String name,
|
String roomId, String name,
|
||||||
String clientId, String password,
|
String password, String clientId,
|
||||||
ITaoyao taoyao, Handler mainHandler,
|
ITaoyao taoyao, Handler mainHandler,
|
||||||
boolean preview, boolean playAudio, boolean playVideo,
|
boolean preview, boolean playAudio, boolean playVideo,
|
||||||
boolean dataConsume, boolean audioConsume, boolean videoConsume,
|
boolean dataConsume, boolean audioConsume, boolean videoConsume,
|
||||||
boolean dataProduce, boolean audioProduce, boolean videoProduce,
|
boolean dataProduce, boolean audioProduce, boolean videoProduce,
|
||||||
|
boolean useIceServer,
|
||||||
MediaProperties mediaProperties, WebrtcProperties webrtcProperties
|
MediaProperties mediaProperties, WebrtcProperties webrtcProperties
|
||||||
) {
|
) {
|
||||||
super(taoyao, mainHandler);
|
super(taoyao, mainHandler);
|
||||||
this.roomId = roomId;
|
this.roomId = roomId;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.clientId = clientId;
|
this.password = password;
|
||||||
this.password = password;
|
this.clientId = clientId;
|
||||||
this.preview = preview;
|
this.preview = preview;
|
||||||
this.playAudio = playAudio;
|
this.playAudio = playAudio;
|
||||||
this.playVideo = playVideo;
|
this.playVideo = playVideo;
|
||||||
this.dataConsume = dataConsume;
|
this.dataConsume = dataConsume;
|
||||||
@@ -99,13 +174,17 @@ public class Room extends CloseableClient implements RouterCallback {
|
|||||||
this.dataProduce = dataProduce;
|
this.dataProduce = dataProduce;
|
||||||
this.audioProduce = audioProduce;
|
this.audioProduce = audioProduce;
|
||||||
this.videoProduce = videoProduce;
|
this.videoProduce = videoProduce;
|
||||||
|
this.useIceServer = useIceServer;
|
||||||
this.produce = false;
|
this.produce = false;
|
||||||
this.mediaProperties = mediaProperties;
|
this.mediaProperties = mediaProperties;
|
||||||
this.webrtcProperties = webrtcProperties;
|
this.webrtcProperties = webrtcProperties;
|
||||||
this.remoteClients = new ConcurrentHashMap<>();
|
this.remoteClients = new ConcurrentHashMap<>();
|
||||||
this.nativeRoomPointer = this.nativeNewRoom(roomId, this);
|
this.nativeRoomPointer = this.nativeNewRoom(roomId, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return 是否成功进入房间
|
||||||
|
*/
|
||||||
public boolean enter() {
|
public boolean enter() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (this.init) {
|
if (this.init) {
|
||||||
@@ -120,12 +199,18 @@ public class Room extends CloseableClient implements RouterCallback {
|
|||||||
this.localClient.playVideo();
|
this.localClient.playVideo();
|
||||||
}
|
}
|
||||||
// STUN | TURN
|
// STUN | TURN
|
||||||
final List<PeerConnection.IceServer> iceServers = new ArrayList<>();
|
final List<PeerConnection.IceServer> iceServers;
|
||||||
// 不用配置
|
if(this.useIceServer) {
|
||||||
// final List<PeerConnection.IceServer> iceServers = this.webrtcProperties.getIceServers();
|
// 不用配置:正常情况都是能够直接访问媒体服务
|
||||||
|
iceServers = this.webrtcProperties.getIceServers();
|
||||||
|
} else {
|
||||||
|
iceServers = new ArrayList<>();
|
||||||
|
}
|
||||||
this.rtcConfiguration = new PeerConnection.RTCConfiguration(iceServers);
|
this.rtcConfiguration = new PeerConnection.RTCConfiguration(iceServers);
|
||||||
|
// 开始协商
|
||||||
return this.taoyao.requestFuture(
|
return this.taoyao.requestFuture(
|
||||||
this.taoyao.buildMessage("media::router::rtp::capabilities", "roomId", this.roomId),
|
this.taoyao.buildMessage("media::router::rtp::capabilities", "roomId", this.roomId),
|
||||||
|
// 成功加载Mediasoup房间
|
||||||
response -> {
|
response -> {
|
||||||
this.nativeEnterRoom(
|
this.nativeEnterRoom(
|
||||||
this.nativeRoomPointer,
|
this.nativeRoomPointer,
|
||||||
@@ -135,6 +220,7 @@ public class Room extends CloseableClient implements RouterCallback {
|
|||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
// 失败关闭资源
|
||||||
response -> {
|
response -> {
|
||||||
this.close();
|
this.close();
|
||||||
return false;
|
return false;
|
||||||
@@ -143,11 +229,16 @@ public class Room extends CloseableClient implements RouterCallback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生产媒体
|
||||||
|
*/
|
||||||
public void mediaProduce() {
|
public void mediaProduce() {
|
||||||
if(this.produce) {
|
synchronized(this) {
|
||||||
return;
|
if(this.produce) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.produce = true;
|
||||||
}
|
}
|
||||||
this.produce = true;
|
|
||||||
if (this.audioProduce || this.videoProduce) {
|
if (this.audioProduce || this.videoProduce) {
|
||||||
this.createSendTransport();
|
this.createSendTransport();
|
||||||
}
|
}
|
||||||
@@ -164,6 +255,9 @@ public class Room extends CloseableClient implements RouterCallback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建发送媒体通道
|
||||||
|
*/
|
||||||
private void createSendTransport() {
|
private void createSendTransport() {
|
||||||
this.taoyao.requestFuture(
|
this.taoyao.requestFuture(
|
||||||
this.taoyao.buildMessage(
|
this.taoyao.buildMessage(
|
||||||
@@ -183,6 +277,9 @@ public class Room extends CloseableClient implements RouterCallback {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建接收媒体通道
|
||||||
|
*/
|
||||||
private void createRecvTransport() {
|
private void createRecvTransport() {
|
||||||
this.taoyao.requestFuture(
|
this.taoyao.requestFuture(
|
||||||
this.taoyao.buildMessage(
|
this.taoyao.buildMessage(
|
||||||
@@ -202,6 +299,12 @@ public class Room extends CloseableClient implements RouterCallback {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 媒体消费
|
||||||
|
*
|
||||||
|
* @param message 信令消息
|
||||||
|
* @param body 消息主体
|
||||||
|
*/
|
||||||
public void mediaConsume(Message message, Map<String, Object> body) {
|
public void mediaConsume(Message message, Map<String, Object> body) {
|
||||||
this.nativeMediaConsume(this.nativeRoomPointer, JSONUtils.toJSON(message));
|
this.nativeMediaConsume(this.nativeRoomPointer, JSONUtils.toJSON(message));
|
||||||
}
|
}
|
||||||
@@ -213,41 +316,63 @@ public class Room extends CloseableClient implements RouterCallback {
|
|||||||
*/
|
*/
|
||||||
public void newRemoteClientFromRoomEnter(Map<String, Object> body) {
|
public void newRemoteClientFromRoomEnter(Map<String, Object> body) {
|
||||||
final String clientId = MapUtils.get(body, "clientId");
|
final String clientId = MapUtils.get(body, "clientId");
|
||||||
|
// 忽略自己
|
||||||
if(this.clientId.equals(clientId)) {
|
if(this.clientId.equals(clientId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final Map<String, Object> status = MapUtils.get(body, "status");
|
final Map<String, Object> status = MapUtils.get(body, "status");
|
||||||
final String name = MapUtils.get(status, "name");
|
final String name = MapUtils.get(status, "name");
|
||||||
final RemoteClient remoteClient = new RemoteClient(name, clientId, this.taoyao, this.mainHandler);
|
final RemoteClient remoteClient = new RemoteClient(name, clientId, this.taoyao, this.mainHandler);
|
||||||
final RemoteClient old = this.remoteClients.put(clientId, remoteClient);
|
final RemoteClient oldRemoteClient = this.remoteClients.put(clientId, remoteClient);
|
||||||
if(old != null) {
|
if(oldRemoteClient != null) {
|
||||||
// 关闭旧的资源
|
// 关闭旧的资源
|
||||||
old.close();
|
this.closeRemoteClient(oldRemoteClient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增远程终端
|
||||||
|
*
|
||||||
|
* @param body 消息主体
|
||||||
|
*/
|
||||||
public void newRemoteClientFromRoomClientList(Map<String, Object> body) {
|
public void newRemoteClientFromRoomClientList(Map<String, Object> body) {
|
||||||
final List<Map<String, Object>> clients = MapUtils.get(body, "clients");
|
final List<Map<String, Object>> clients = MapUtils.get(body, "clients");
|
||||||
if(CollectionUtils.isEmpty(clients)) {
|
if(CollectionUtils.isEmpty(clients)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
clients.forEach(map -> {
|
clients.forEach(map -> {
|
||||||
final String name = MapUtils.get(map, "name");
|
final String name = MapUtils.get(map, "name");
|
||||||
final String clientId = MapUtils.get(map, "clientId");
|
final String clientId = MapUtils.get(map, "clientId");
|
||||||
|
// 忽略自己
|
||||||
if(this.clientId.equals(clientId)) {
|
if(this.clientId.equals(clientId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final RemoteClient remoteClient = new RemoteClient(name, clientId, this.taoyao, this.mainHandler);
|
final RemoteClient remoteClient = new RemoteClient(name, clientId, this.taoyao, this.mainHandler);
|
||||||
final RemoteClient old = this.remoteClients.put(clientId, remoteClient);
|
final RemoteClient oldRemoteClient = this.remoteClients.put(clientId, remoteClient);
|
||||||
if(old != null) {
|
if(oldRemoteClient != null) {
|
||||||
// 关闭旧的资源
|
// 关闭旧的资源
|
||||||
old.close();
|
this.closeRemoteClient(oldRemoteClient);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭远程终端
|
||||||
|
*
|
||||||
|
* @param clientId 远程终端ID
|
||||||
|
*/
|
||||||
public void closeRemoteClient(String clientId) {
|
public void closeRemoteClient(String clientId) {
|
||||||
final RemoteClient remoteClient = this.remoteClients.remove(clientId);
|
final RemoteClient remoteClient = this.remoteClients.remove(clientId);
|
||||||
|
this.closeRemoteClient(remoteClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭远程终端
|
||||||
|
* 注意:需要自己从列表中删除
|
||||||
|
*
|
||||||
|
* @param remoteClient 远程终端
|
||||||
|
*/
|
||||||
|
private void closeRemoteClient(RemoteClient remoteClient) {
|
||||||
if(remoteClient == null) {
|
if(remoteClient == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -265,88 +390,150 @@ public class Room extends CloseableClient implements RouterCallback {
|
|||||||
}
|
}
|
||||||
Log.i(Room.class.getSimpleName(), "关闭房间:" + this.roomId);
|
Log.i(Room.class.getSimpleName(), "关闭房间:" + this.roomId);
|
||||||
super.close();
|
super.close();
|
||||||
|
// 关闭Mediasoup房间
|
||||||
this.nativeCloseRoom(this.nativeRoomPointer);
|
this.nativeCloseRoom(this.nativeRoomPointer);
|
||||||
// 关闭远程媒体
|
// 关闭远程媒体
|
||||||
this.remoteClients.values().forEach(v -> this.closeRemoteClient(v.clientId));
|
this.remoteClients.values().forEach(this::closeRemoteClient);
|
||||||
this.remoteClients.clear();
|
this.remoteClients.clear();
|
||||||
// 关闭本地媒体
|
// 关闭本地媒体
|
||||||
this.localClient.close();
|
this.localClient.close();
|
||||||
|
// 释放终端
|
||||||
this.mediaManager.closeClient();
|
this.mediaManager.closeClient();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主动关闭消费者
|
||||||
|
*
|
||||||
|
* @param consumerId 消费者ID
|
||||||
|
*/
|
||||||
public void mediaConsumerClose(String consumerId) {
|
public void mediaConsumerClose(String consumerId) {
|
||||||
this.taoyao.push(this.taoyao.buildMessage(
|
this.taoyao.push(this.taoyao.buildMessage(
|
||||||
"media::consumer::close",
|
"media::consumer::close",
|
||||||
"roomId", this.roomId,
|
"roomId", this.roomId,
|
||||||
"consumerId", consumerId
|
"consumerId", consumerId
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭消费者回调(信令)
|
||||||
|
*
|
||||||
|
* @param body 消息主体
|
||||||
|
*/
|
||||||
public void mediaConsumerClose(Map<String, Object> body) {
|
public void mediaConsumerClose(Map<String, Object> body) {
|
||||||
final String consumerId = MapUtils.get(body, "consumerId");
|
final String consumerId = MapUtils.get(body, "consumerId");
|
||||||
this.nativeMediaConsumerClose(this.nativeRoomPointer, consumerId);
|
this.nativeMediaConsumerClose(this.nativeRoomPointer, consumerId);
|
||||||
this.remoteClients.values().forEach(v -> v.close(consumerId));
|
this.remoteClients.values().forEach(v -> v.close(consumerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主动暂停消费者
|
||||||
|
*
|
||||||
|
* @param consumerId 消费者ID
|
||||||
|
*/
|
||||||
public void mediaConsumerPause(String consumerId) {
|
public void mediaConsumerPause(String consumerId) {
|
||||||
this.taoyao.push(this.taoyao.buildMessage(
|
this.taoyao.push(this.taoyao.buildMessage(
|
||||||
"media::consumer::pause",
|
"media::consumer::pause",
|
||||||
"roomId", this.roomId,
|
"roomId", this.roomId,
|
||||||
"consumerId", consumerId
|
"consumerId", consumerId
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂停消费者回调(信令)
|
||||||
|
*
|
||||||
|
* @param body 消息主体
|
||||||
|
*/
|
||||||
public void mediaConsumerPause(Map<String, Object> body) {
|
public void mediaConsumerPause(Map<String, Object> body) {
|
||||||
this.nativeMediaConsumerPause(this.nativeRoomPointer, MapUtils.get(body, "consumerId"));
|
this.nativeMediaConsumerPause(this.nativeRoomPointer, MapUtils.get(body, "consumerId"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主动恢复消费者
|
||||||
|
*
|
||||||
|
* @param consumerId 消费者ID
|
||||||
|
*/
|
||||||
public void mediaConsumerResume(String consumerId) {
|
public void mediaConsumerResume(String consumerId) {
|
||||||
this.taoyao.push(this.taoyao.buildMessage(
|
this.taoyao.push(this.taoyao.buildMessage(
|
||||||
"media::consumer::resume",
|
"media::consumer::resume",
|
||||||
"roomId", this.roomId,
|
"roomId", this.roomId,
|
||||||
"consumerId", consumerId
|
"consumerId", consumerId
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复消费者回调(信令)
|
||||||
|
*
|
||||||
|
* @param body 消息主体
|
||||||
|
*/
|
||||||
public void mediaConsumerResume(Map<String, Object> body) {
|
public void mediaConsumerResume(Map<String, Object> body) {
|
||||||
this.nativeMediaConsumerResume(this.nativeRoomPointer, MapUtils.get(body, "consumerId"));
|
this.nativeMediaConsumerResume(this.nativeRoomPointer, MapUtils.get(body, "consumerId"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主动关闭生产者
|
||||||
|
*
|
||||||
|
* @param producerId 生产者ID
|
||||||
|
*/
|
||||||
public void mediaProducerClose(String producerId) {
|
public void mediaProducerClose(String producerId) {
|
||||||
this.taoyao.push(this.taoyao.buildMessage(
|
this.taoyao.push(this.taoyao.buildMessage(
|
||||||
"media::producer::close",
|
"media::producer::close",
|
||||||
"roomId", this.roomId,
|
"roomId", this.roomId,
|
||||||
"producerId", producerId
|
"producerId", producerId
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭生产者回调(信令)
|
||||||
|
*
|
||||||
|
* @param body 消息主体
|
||||||
|
*/
|
||||||
public void mediaProducerClose(Map<String, Object> body) {
|
public void mediaProducerClose(Map<String, Object> body) {
|
||||||
final String producerId = MapUtils.get(body, "producerId");
|
final String producerId = MapUtils.get(body, "producerId");
|
||||||
this.nativeMediaProducerClose(this.nativeRoomPointer, producerId);
|
this.nativeMediaProducerClose(this.nativeRoomPointer, producerId);
|
||||||
this.localClient.close(producerId);
|
this.localClient.close(producerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主动暂停生产者
|
||||||
|
*
|
||||||
|
* @param producerId 生产者ID
|
||||||
|
*/
|
||||||
public void mediaProducerPause(String producerId) {
|
public void mediaProducerPause(String producerId) {
|
||||||
this.taoyao.push(this.taoyao.buildMessage(
|
this.taoyao.push(this.taoyao.buildMessage(
|
||||||
"media::producer::pause",
|
"media::producer::pause",
|
||||||
"roomId", this.roomId,
|
"roomId", this.roomId,
|
||||||
"producerId", producerId
|
"producerId", producerId
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂停生产者回调(信令)
|
||||||
|
*
|
||||||
|
* @param body 消息主体
|
||||||
|
*/
|
||||||
public void mediaProducerPause(Map<String, Object> body) {
|
public void mediaProducerPause(Map<String, Object> body) {
|
||||||
this.nativeMediaProducerPause(this.nativeRoomPointer, MapUtils.get(body, "producerId"));
|
this.nativeMediaProducerPause(this.nativeRoomPointer, MapUtils.get(body, "producerId"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主动恢复生产者
|
||||||
|
*
|
||||||
|
* @param producerId 生产者ID
|
||||||
|
*/
|
||||||
public void mediaProducerResume(String producerId) {
|
public void mediaProducerResume(String producerId) {
|
||||||
this.taoyao.push(this.taoyao.buildMessage(
|
this.taoyao.push(this.taoyao.buildMessage(
|
||||||
"media::producer::resume",
|
"media::producer::resume",
|
||||||
"roomId", this.roomId,
|
"roomId", this.roomId,
|
||||||
"producerId", producerId
|
"producerId", producerId
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复生产者回调(信令)
|
||||||
|
*
|
||||||
|
* @param body 消息主体
|
||||||
|
*/
|
||||||
public void mediaProducerResume(Map<String, Object> body) {
|
public void mediaProducerResume(Map<String, Object> body) {
|
||||||
this.nativeMediaProducerResume(this.nativeRoomPointer, MapUtils.get(body, "producerId"));
|
this.nativeMediaProducerResume(this.nativeRoomPointer, MapUtils.get(body, "producerId"));
|
||||||
}
|
}
|
||||||
@@ -416,6 +603,18 @@ public class Room extends CloseableClient implements RouterCallback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void producerCloseCallback(String producerId) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void producerPauseCallback(String producerId) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void producerResumeCallback(String producerId) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void consumerNewCallback(String message, long consumerPointer, long consumerMediaTrackPointer) {
|
public void consumerNewCallback(String message, long consumerPointer, long consumerMediaTrackPointer) {
|
||||||
final Message response = JSONUtils.toJava(message, Message.class);
|
final Message response = JSONUtils.toJava(message, Message.class);
|
||||||
@@ -423,13 +622,12 @@ public class Room extends CloseableClient implements RouterCallback {
|
|||||||
final String kind = MapUtils.get(body, "kind");
|
final String kind = MapUtils.get(body, "kind");
|
||||||
final String sourceId = MapUtils.get(body, "sourceId");
|
final String sourceId = MapUtils.get(body, "sourceId");
|
||||||
final String consumerId = MapUtils.get(body, "consumerId");
|
final String consumerId = MapUtils.get(body, "consumerId");
|
||||||
final RemoteClient remoteClient = this.remoteClients.get(sourceId);
|
final RemoteClient remoteClient = this.remoteClients.computeIfAbsent(sourceId, key -> {
|
||||||
if(remoteClient == null) {
|
// 假如媒体上来时间比进入房间消息快:基本上不可能出现这种情况
|
||||||
// TODO:资源释放
|
Log.w(Room.class.getSimpleName(), "未知媒体来源:" + sourceId);
|
||||||
return;
|
return new RemoteClient(sourceId, sourceId, this.taoyao, this.mainHandler);
|
||||||
}
|
});
|
||||||
if(MediaStreamTrack.AUDIO_TRACK_KIND.equals(kind)) {
|
if(MediaStreamTrack.AUDIO_TRACK_KIND.equals(kind)) {
|
||||||
// WebRtcAudioTrack
|
|
||||||
final AudioTrack audioTrack = new AudioTrack(consumerMediaTrackPointer);
|
final AudioTrack audioTrack = new AudioTrack(consumerMediaTrackPointer);
|
||||||
audioTrack.setVolume(Config.DEFAULT_VOLUME);
|
audioTrack.setVolume(Config.DEFAULT_VOLUME);
|
||||||
remoteClient.tracks.put(consumerId, audioTrack);
|
remoteClient.tracks.put(consumerId, audioTrack);
|
||||||
@@ -442,25 +640,136 @@ public class Room extends CloseableClient implements RouterCallback {
|
|||||||
remoteClient.playVideo();
|
remoteClient.playVideo();
|
||||||
} else {
|
} else {
|
||||||
Log.w(Room.class.getSimpleName(), "未知媒体类型:" + kind);
|
Log.w(Room.class.getSimpleName(), "未知媒体类型:" + kind);
|
||||||
// TODO:资源释放
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.taoyao.push(response);
|
this.taoyao.push(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void consumerCloseCallback(String consumerId) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void consumerPauseCallback(String consumerId) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void consumerResumeCallback(String consumerId) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mediasoup创建房间
|
||||||
|
*
|
||||||
|
* @param roomId 房间ID
|
||||||
|
* @param routerCallback 路由回调
|
||||||
|
*
|
||||||
|
* @return Mediasoup房间指针
|
||||||
|
*/
|
||||||
private native long nativeNewRoom(String roomId, RouterCallback routerCallback);
|
private native long nativeNewRoom(String roomId, RouterCallback routerCallback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mediasou进入房间
|
||||||
|
*
|
||||||
|
* @param nativePointer 房间指针
|
||||||
|
* @param rtpCapabilities RTP能力
|
||||||
|
* @param peerConnectionFactoryPointer PeerConnectionFactory指针
|
||||||
|
* @param rtcConfiguration RTC配置
|
||||||
|
*/
|
||||||
private native void nativeEnterRoom(long nativePointer, String rtpCapabilities, long peerConnectionFactoryPointer, PeerConnection.RTCConfiguration rtcConfiguration);
|
private native void nativeEnterRoom(long nativePointer, String rtpCapabilities, long peerConnectionFactoryPointer, PeerConnection.RTCConfiguration rtcConfiguration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mediasoup关闭房间
|
||||||
|
*
|
||||||
|
* @param nativePointer 房间指针
|
||||||
|
*/
|
||||||
private native void nativeCloseRoom(long nativePointer);
|
private native void nativeCloseRoom(long nativePointer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mediasoup创建发送通道
|
||||||
|
*
|
||||||
|
* @param nativeRoomPointer 房间指针
|
||||||
|
* @param body 消息主体
|
||||||
|
*/
|
||||||
private native void nativeCreateSendTransport(long nativeRoomPointer, String body);
|
private native void nativeCreateSendTransport(long nativeRoomPointer, String body);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mediasoup创建接收通道
|
||||||
|
*
|
||||||
|
* @param nativeRoomPointer 房间指针
|
||||||
|
* @param body 消息主体
|
||||||
|
*/
|
||||||
private native void nativeCreateRecvTransport(long nativeRoomPointer, String body);
|
private native void nativeCreateRecvTransport(long nativeRoomPointer, String body);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mediasoup生产音频
|
||||||
|
*
|
||||||
|
* @param nativeRoomPointer 房间指针
|
||||||
|
* @param mediaStreamPointer 媒体指针
|
||||||
|
*/
|
||||||
private native void nativeMediaProduceAudio(long nativeRoomPointer, long mediaStreamPointer);
|
private native void nativeMediaProduceAudio(long nativeRoomPointer, long mediaStreamPointer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mediasoup生产视频
|
||||||
|
*
|
||||||
|
* @param nativeRoomPointer 房间指针
|
||||||
|
* @param mediaStreamPointer 媒体指针
|
||||||
|
*/
|
||||||
private native void nativeMediaProduceVideo(long nativeRoomPointer, long mediaStreamPointer);
|
private native void nativeMediaProduceVideo(long nativeRoomPointer, long mediaStreamPointer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mediasoup消费
|
||||||
|
*
|
||||||
|
* @param nativeRoomPointer 房间指针
|
||||||
|
* @param message 信令消息
|
||||||
|
*/
|
||||||
private native void nativeMediaConsume(long nativeRoomPointer, String message);
|
private native void nativeMediaConsume(long nativeRoomPointer, String message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mediasoup暂停生产者
|
||||||
|
*
|
||||||
|
* @param nativeRoomPointer 房间指针
|
||||||
|
* @param producerId 生产者ID
|
||||||
|
*/
|
||||||
private native void nativeMediaProducerPause(long nativeRoomPointer, String producerId);
|
private native void nativeMediaProducerPause(long nativeRoomPointer, String producerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mediasoup恢复生产者
|
||||||
|
*
|
||||||
|
* @param nativeRoomPointer 房间指针
|
||||||
|
* @param producerId 生产者ID
|
||||||
|
*/
|
||||||
private native void nativeMediaProducerResume(long nativeRoomPointer, String producerId);
|
private native void nativeMediaProducerResume(long nativeRoomPointer, String producerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mediasoup关闭生产者
|
||||||
|
*
|
||||||
|
* @param nativeRoomPointer 房间指针
|
||||||
|
* @param producerId 生产者ID
|
||||||
|
*/
|
||||||
private native void nativeMediaProducerClose(long nativeRoomPointer, String producerId);
|
private native void nativeMediaProducerClose(long nativeRoomPointer, String producerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mediasoup暂停消费者
|
||||||
|
*
|
||||||
|
* @param nativeRoomPointer 房间指针
|
||||||
|
* @param consumerId 消费者ID
|
||||||
|
*/
|
||||||
private native void nativeMediaConsumerPause(long nativeRoomPointer, String consumerId);
|
private native void nativeMediaConsumerPause(long nativeRoomPointer, String consumerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mediasoup恢复消费者
|
||||||
|
*
|
||||||
|
* @param nativeRoomPointer 房间指针
|
||||||
|
* @param consumerId 消费者ID
|
||||||
|
*/
|
||||||
private native void nativeMediaConsumerResume(long nativeRoomPointer, String consumerId);
|
private native void nativeMediaConsumerResume(long nativeRoomPointer, String consumerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mediasoup关闭消费者
|
||||||
|
*
|
||||||
|
* @param nativeRoomPointer 房间指针
|
||||||
|
* @param consumerId 消费者ID
|
||||||
|
*/
|
||||||
private native void nativeMediaConsumerClose(long nativeRoomPointer, String consumerId);
|
private native void nativeMediaConsumerClose(long nativeRoomPointer, String consumerId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,13 @@ module.exports = {
|
|||||||
// 信令密码
|
// 信令密码
|
||||||
password: "taoyao",
|
password: "taoyao",
|
||||||
},
|
},
|
||||||
|
// 录像配置
|
||||||
|
record: {
|
||||||
|
// 请求关键帧的最大次数
|
||||||
|
requestKeyFrameMaxIndex: 16,
|
||||||
|
// 请求关键帧的文件大小
|
||||||
|
requestKeyFrameFileSize: 32 * 1024,
|
||||||
|
},
|
||||||
// Mediasoup
|
// Mediasoup
|
||||||
mediasoup: {
|
mediasoup: {
|
||||||
// 配置Worker进程数量
|
// 配置Worker进程数量
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ async function connectSignalServer() {
|
|||||||
* 启动方法
|
* 启动方法
|
||||||
*/
|
*/
|
||||||
async function main() {
|
async function main() {
|
||||||
console.log(`
|
console.debug(`
|
||||||
桃之夭夭,灼灼其华。
|
桃之夭夭,灼灼其华。
|
||||||
之子于归,宜其室家。
|
之子于归,宜其室家。
|
||||||
|
|
||||||
|
|||||||
@@ -814,7 +814,7 @@ class Taoyao {
|
|||||||
audioTransport.clientId = clientId;
|
audioTransport.clientId = clientId;
|
||||||
room.transports.set(audioTransport.id, audioTransport);
|
room.transports.set(audioTransport.id, audioTransport);
|
||||||
audioTransport.observer.on("close", () => {
|
audioTransport.observer.on("close", () => {
|
||||||
console.log("controlServerRecord audioTransport close:", audioTransport.id);
|
console.debug("controlServerRecord audioTransport close:", audioTransport.id);
|
||||||
room.transports.delete(audioTransport.id)
|
room.transports.delete(audioTransport.id)
|
||||||
});
|
});
|
||||||
await audioTransport.connect({
|
await audioTransport.connect({
|
||||||
@@ -833,10 +833,10 @@ class Taoyao {
|
|||||||
audioConsumer.streamId = audioStreamId;
|
audioConsumer.streamId = audioStreamId;
|
||||||
room.consumers.set(audioConsumer.id, audioConsumer);
|
room.consumers.set(audioConsumer.id, audioConsumer);
|
||||||
audioConsumer.observer.on("close", () => {
|
audioConsumer.observer.on("close", () => {
|
||||||
console.log("controlServerRecord audioConsumer close:", audioConsumer.id);
|
console.debug("controlServerRecord audioConsumer close:", audioConsumer.id);
|
||||||
room.consumers.delete(audioConsumer.id);
|
room.consumers.delete(audioConsumer.id);
|
||||||
});
|
});
|
||||||
console.log("controlServerRecord audio", audioTransportId, audioConsumerId, audioTransport.tuple, audioRtpParameters);
|
console.debug("controlServerRecord audio", audioTransportId, audioConsumerId, audioTransport.tuple, audioRtpParameters);
|
||||||
}
|
}
|
||||||
if(videoProducerId) {
|
if(videoProducerId) {
|
||||||
const videoTransport = await room.mediasoupRouter.createPlainTransport(plainTransportOptions);
|
const videoTransport = await room.mediasoupRouter.createPlainTransport(plainTransportOptions);
|
||||||
@@ -845,7 +845,7 @@ class Taoyao {
|
|||||||
videoTransport.clientId = clientId;
|
videoTransport.clientId = clientId;
|
||||||
room.transports.set(videoTransport.id, videoTransport);
|
room.transports.set(videoTransport.id, videoTransport);
|
||||||
videoTransport.observer.on("close", () => {
|
videoTransport.observer.on("close", () => {
|
||||||
console.log("controlServerRecord videoTransport close:", videoTransport.id);
|
console.debug("controlServerRecord videoTransport close:", videoTransport.id);
|
||||||
room.transports.delete(videoTransport.id)
|
room.transports.delete(videoTransport.id)
|
||||||
});
|
});
|
||||||
await videoTransport.connect({
|
await videoTransport.connect({
|
||||||
@@ -864,10 +864,10 @@ class Taoyao {
|
|||||||
videoConsumer.streamId = videoStreamId;
|
videoConsumer.streamId = videoStreamId;
|
||||||
room.consumers.set(videoConsumer.id, videoConsumer);
|
room.consumers.set(videoConsumer.id, videoConsumer);
|
||||||
videoConsumer.observer.on("close", () => {
|
videoConsumer.observer.on("close", () => {
|
||||||
console.log("controlServerRecord videoConsumer close:", videoConsumer.id);
|
console.debug("controlServerRecord videoConsumer close:", videoConsumer.id);
|
||||||
room.consumers.delete(videoConsumer.id);
|
room.consumers.delete(videoConsumer.id);
|
||||||
});
|
});
|
||||||
console.log("controlServerRecord video:", videoTransportId, videoConsumerId, videoTransport.tuple, videoRtpParameters);
|
console.debug("controlServerRecord video:", videoTransportId, videoConsumerId, videoTransport.tuple, videoRtpParameters);
|
||||||
}
|
}
|
||||||
if(audioConsumer) {
|
if(audioConsumer) {
|
||||||
await audioConsumer.resume();
|
await audioConsumer.resume();
|
||||||
@@ -900,7 +900,7 @@ class Taoyao {
|
|||||||
if(!filepath || !videoConsumer) {
|
if(!filepath || !videoConsumer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(++index > 10) {
|
if(++index > config.record.requestKeyFrameMaxIndex) {
|
||||||
console.warn("请求录像关键帧次数超限", filepath, index);
|
console.warn("请求录像关键帧次数超限", filepath, index);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -909,7 +909,7 @@ class Taoyao {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 判断文件大小验证是否已经开始录像:创建文件 -> 视频信息 -> 视频数据 -> 封装视频
|
// 判断文件大小验证是否已经开始录像:创建文件 -> 视频信息 -> 视频数据 -> 封装视频
|
||||||
if(fs.existsSync(filepath) && fs.statSync(filepath).size >= 128 * 1024) {
|
if(fs.existsSync(filepath) && fs.statSync(filepath).size >= config.record.requestKeyFrameFileSize) {
|
||||||
console.debug("请求录像关键帧已经开始录像", filepath);
|
console.debug("请求录像关键帧已经开始录像", filepath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user