[*] 日常优化

This commit is contained in:
acgist
2023-06-12 08:31:14 +08:00
parent e3b6da03c8
commit c35869df0c
7 changed files with 176 additions and 72 deletions

View File

@@ -1178,7 +1178,6 @@ public final class Taoyao implements ITaoyao {
this.mediaManager.getWebrtcProperties() this.mediaManager.getWebrtcProperties()
); );
this.sessions.put(sessionId, sessionClient); this.sessions.put(sessionId, sessionClient);
sessionClient.init();
sessionClient.offer(); sessionClient.offer();
} }

View File

@@ -7,6 +7,7 @@ import com.acgist.taoyao.media.config.Config;
import com.acgist.taoyao.media.signal.ITaoyao; import com.acgist.taoyao.media.signal.ITaoyao;
import org.webrtc.SurfaceViewRenderer; import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoTrack;
/** /**
* 终端 * 终端
@@ -98,6 +99,20 @@ public abstract class Client extends CloseableClient {
this.resumeVideo(); this.resumeVideo();
} }
/**
* 创建视频预览
*
* @param flag Config.WHAT_*
* @param videoTrack 视频媒体流Track
*/
protected void buildSurfaceViewRenderer(final int flag, final VideoTrack videoTrack) {
if(this.surfaceViewRenderer == null) {
this.surfaceViewRenderer = this.mediaManager.buildSurfaceViewRenderer(flag, videoTrack);
} else {
Log.w(Client.class.getSimpleName(), "视频预览已经存在");
}
}
@Override @Override
public void close() { public void close() {
super.close(); super.close();

View File

@@ -104,9 +104,7 @@ public class LocalClient extends RoomClient {
} }
this.mediaStream.videoTracks.forEach(videoTrack -> { this.mediaStream.videoTracks.forEach(videoTrack -> {
videoTrack.setEnabled(true); videoTrack.setEnabled(true);
if(this.surfaceViewRenderer == null) { this.buildSurfaceViewRenderer(Config.WHAT_NEW_LOCAL_VIDEO, videoTrack);
this.surfaceViewRenderer = this.mediaManager.buildSurfaceViewRenderer(Config.WHAT_NEW_LOCAL_VIDEO, videoTrack);
}
}); });
} }

View File

@@ -89,9 +89,7 @@ public class RemoteClient extends RoomClient {
.map(v -> (VideoTrack) v) .map(v -> (VideoTrack) v)
.forEach(videoTrack -> { .forEach(videoTrack -> {
videoTrack.setEnabled(true); videoTrack.setEnabled(true);
if(this.surfaceViewRenderer == null) { this.buildSurfaceViewRenderer(Config.WHAT_NEW_REMOTE_VIDEO, videoTrack);
this.surfaceViewRenderer = this.mediaManager.buildSurfaceViewRenderer(Config.WHAT_NEW_REMOTE_VIDEO, videoTrack);
}
}); });
} }

View File

@@ -50,7 +50,7 @@ public class Room extends CloseableClient implements RouterCallback {
*/ */
private final String clientId; private final String clientId;
/** /**
* 是否预览 * 是否预览视频
*/ */
private final boolean preview; private final boolean preview;
/** /**

View File

@@ -12,7 +12,6 @@ import com.acgist.taoyao.media.signal.ITaoyao;
import org.webrtc.DataChannel; import org.webrtc.DataChannel;
import org.webrtc.IceCandidate; import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream; import org.webrtc.MediaStream;
import org.webrtc.MediaStreamTrack; import org.webrtc.MediaStreamTrack;
import org.webrtc.PeerConnection; import org.webrtc.PeerConnection;
@@ -44,26 +43,58 @@ public class SessionClient extends Client {
* 会话ID * 会话ID
*/ */
private final String sessionId; private final String sessionId;
private final boolean preview;
private final boolean playAudio;
private final boolean playVideo;
private final boolean dataConsume;
private final boolean audioConsume;
private final boolean videoConsume;
private final boolean dataProduce;
private final boolean audioProduce;
private final boolean videoProduce;
private final MediaProperties mediaProperties;
private final WebrtcProperties webrtcProperties;
private SurfaceViewRenderer localSurfaceViewRenderer;
/** /**
* 本地媒体 * 是否预览视频
*/ */
private MediaStream mediaStream; private final boolean preview;
/**
* 是否播放音频
*/
private final boolean playAudio;
/**
* 是否播放视频
*/
private final boolean playVideo;
/**
* 是否消费数据
*/
private final boolean dataConsume;
/**
* 是否消费音频
*/
private final boolean audioConsume;
/**
* 是否消费视频
*/
private final boolean videoConsume;
/**
* 是否生产数据
*/
private final boolean dataProduce;
/**
* 是否生产音频
*/
private final boolean audioProduce;
/**
* 是否生产视频
*/
private final boolean videoProduce;
/**
* 媒体配置
*/
private final MediaProperties mediaProperties;
/**
* WebRTC配置
*/
private final WebrtcProperties webrtcProperties;
/** /**
* 数据通道 * 数据通道
*/ */
private DataChannel dataChannel; private DataChannel dataChannel;
/**
* 本地媒体
*/
private MediaStream localMediaStream;
/** /**
* 远程媒体 * 远程媒体
*/ */
@@ -77,12 +108,15 @@ public class SessionClient extends Client {
*/ */
private PeerConnection.Observer observer; private PeerConnection.Observer observer;
/** /**
* Peer连接工厂 * PeerConnectionFactory
*/ */
private PeerConnectionFactory peerConnectionFactory; private PeerConnectionFactory peerConnectionFactory;
/**
* 本地视频预览
*/
private SurfaceViewRenderer localSurfaceViewRenderer;
/** /**
*
* @param sessionId 会话ID * @param sessionId 会话ID
* @param name 远程终端名称 * @param name 远程终端名称
* @param clientId 远程终端ID * @param clientId 远程终端ID
@@ -109,7 +143,7 @@ public class SessionClient extends Client {
) { ) {
super(name, clientId, taoyao, mainHandler); super(name, clientId, taoyao, mainHandler);
this.sessionId = sessionId; this.sessionId = sessionId;
this.preview = preview; this.preview = preview;
this.playAudio = playAudio; this.playAudio = playAudio;
this.playVideo = playVideo; this.playVideo = playVideo;
this.dataConsume = dataConsume; this.dataConsume = dataConsume;
@@ -134,25 +168,28 @@ public class SessionClient extends Client {
final List<PeerConnection.IceServer> iceServers = this.webrtcProperties.getIceServers(); final List<PeerConnection.IceServer> iceServers = this.webrtcProperties.getIceServers();
final PeerConnection.RTCConfiguration configuration = new PeerConnection.RTCConfiguration(iceServers); final PeerConnection.RTCConfiguration configuration = new PeerConnection.RTCConfiguration(iceServers);
this.observer = this.observer(); this.observer = this.observer();
this.mediaStream = this.mediaManager.buildLocalMediaStream(this.audioProduce, this.videoProduce); this.localMediaStream = this.mediaManager.buildLocalMediaStream(this.audioProduce, this.videoProduce);
this.peerConnection = this.peerConnectionFactory.createPeerConnection(configuration, this.observer); this.peerConnection = this.peerConnectionFactory.createPeerConnection(configuration, this.observer);
this.peerConnection.addStream(this.mediaStream); this.peerConnection.addStream(this.localMediaStream);
if(this.preview) {
this.previewLocal();
}
// 设置streamId同步
// final List<String> streamIds = new ArrayList<>(); // final List<String> streamIds = new ArrayList<>();
// ListUtils.getOnlyOne(this.mediaStream.audioTracks, audioTrack -> { // this.localMediaStream.audioTracks.forEach(audioTrack -> {
// this.peerConnection.addTrack(audioTrack, streamIds); // this.peerConnection.addTrack(audioTrack, streamIds);
// return audioTrack;
// }); // });
// ListUtils.getOnlyOne(this.mediaStream.videoTracks, videoTrack -> { // this.localMediaStream.videoTracks.forEach(videoTrack -> {
// this.peerConnection.addTrack(videoTrack, streamIds); // this.peerConnection.addTrack(videoTrack, streamIds);
// return videoTrack;
// }); // });
if(this.preview) {
this.previewLocalVideo();
}
} }
} }
/**
* 媒体交换
*
* @param message 信令消息
* @param body 消息主体
*/
public void exchange(Message message, Map<String, Object> body) { public void exchange(Message message, Map<String, Object> body) {
final String type = MapUtils.get(body, "type"); final String type = MapUtils.get(body, "type");
switch(type) { switch(type) {
@@ -164,10 +201,10 @@ public class SessionClient extends Client {
} }
/** /**
* 提供媒体服务 * 提供本地终端媒体
*/ */
public synchronized void offer() { public synchronized void offer() {
final MediaConstraints mediaConstraints = this.mediaManager.buildMediaConstraints(); this.init();
this.peerConnection.createOffer(this.sdpObserver( this.peerConnection.createOffer(this.sdpObserver(
"主动Offer", "主动Offer",
sessionDescription -> { sessionDescription -> {
@@ -178,9 +215,15 @@ public class SessionClient extends Client {
), sessionDescription); ), sessionDescription);
}, },
null null
), mediaConstraints); ), this.mediaManager.buildMediaConstraints());
} }
/**
* 远程终端提供媒体
*
* @param message 信令消息
* @param body 消息主体
*/
private void offer(Message message, Map<String, Object> body) { private void offer(Message message, Map<String, Object> body) {
this.init(); this.init();
final String sdp = MapUtils.get(body, "sdp"); final String sdp = MapUtils.get(body, "sdp");
@@ -203,6 +246,12 @@ public class SessionClient extends Client {
), new SessionDescription(sdpType, sdp)); ), new SessionDescription(sdpType, sdp));
} }
/**
* 远程终端响应媒体
*
* @param message 信令消息
* @param body 消息主体
*/
private void answer(Message message, Map<String, Object> body) { private void answer(Message message, Map<String, Object> body) {
final String sdp = MapUtils.get(body, "sdp"); final String sdp = MapUtils.get(body, "sdp");
final String type = MapUtils.get(body, "type"); final String type = MapUtils.get(body, "type");
@@ -214,6 +263,12 @@ public class SessionClient extends Client {
), new SessionDescription(sdpType, sdp)); ), new SessionDescription(sdpType, sdp));
} }
/**
* 远程终端媒体协商
*
* @param message 信令消息
* @param body 消息主体
*/
private void candidate(Message message, Map<String, Object> body) { private void candidate(Message message, Map<String, Object> body) {
final Map<String, Object> candidate = MapUtils.get(body, "candidate"); final Map<String, Object> candidate = MapUtils.get(body, "candidate");
final String sdp = MapUtils.get(candidate, "candidate"); final String sdp = MapUtils.get(candidate, "candidate");
@@ -268,9 +323,7 @@ public class SessionClient extends Client {
} }
this.remoteMediaStream.videoTracks.forEach(videoTrack -> { this.remoteMediaStream.videoTracks.forEach(videoTrack -> {
videoTrack.setEnabled(true); videoTrack.setEnabled(true);
if(this.surfaceViewRenderer == null) { this.buildSurfaceViewRenderer(Config.WHAT_NEW_REMOTE_VIDEO, videoTrack);
this.surfaceViewRenderer = this.mediaManager.buildSurfaceViewRenderer(Config.WHAT_NEW_REMOTE_VIDEO, videoTrack);
}
}); });
} }
@@ -296,45 +349,69 @@ public class SessionClient extends Client {
}); });
} }
/**
* 暂停本地媒体
*
* @param type 媒体类型
*/
public void pauseLocal(String type) { public void pauseLocal(String type) {
if(this.localMediaStream == null) {
return;
}
if(MediaStreamTrack.AUDIO_TRACK_KIND.equals(type)) { if(MediaStreamTrack.AUDIO_TRACK_KIND.equals(type)) {
this.mediaStream.audioTracks.forEach(audioTrack -> { this.localMediaStream.audioTracks.forEach(audioTrack -> {
audioTrack.setEnabled(false); audioTrack.setEnabled(false);
}); });
} else if(MediaStreamTrack.VIDEO_TRACK_KIND.equals(type)) { } else if(MediaStreamTrack.VIDEO_TRACK_KIND.equals(type)) {
this.mediaStream.videoTracks.forEach(videoTrack -> { this.localMediaStream.videoTracks.forEach(videoTrack -> {
videoTrack.setEnabled(false); videoTrack.setEnabled(false);
}); });
} else { } else {
} }
} }
/**
* 恢复本地媒体
*
* @param type 媒体类型
*/
public void resumeLocal(String type) { public void resumeLocal(String type) {
if(this.localMediaStream == null) {
return;
}
if(MediaStreamTrack.AUDIO_TRACK_KIND.equals(type)) { if(MediaStreamTrack.AUDIO_TRACK_KIND.equals(type)) {
this.mediaStream.audioTracks.forEach(audioTrack -> { this.localMediaStream.audioTracks.forEach(audioTrack -> {
audioTrack.setEnabled(true); audioTrack.setEnabled(true);
}); });
} else if(MediaStreamTrack.VIDEO_TRACK_KIND.equals(type)) { } else if(MediaStreamTrack.VIDEO_TRACK_KIND.equals(type)) {
this.mediaStream.videoTracks.forEach(videoTrack -> { this.localMediaStream.videoTracks.forEach(videoTrack -> {
videoTrack.setEnabled(true); videoTrack.setEnabled(true);
}); });
} else { } else {
} }
} }
private void previewLocal() { /**
if(this.mediaStream == null) { * 预览本地视频
*/
private void previewLocalVideo() {
if(this.localMediaStream == null) {
return; return;
} }
this.mediaStream.videoTracks.forEach(videoTrack -> { this.localMediaStream.videoTracks.forEach(videoTrack -> {
videoTrack.setEnabled(true); videoTrack.setEnabled(true);
if(this.localSurfaceViewRenderer == null) { if(this.localSurfaceViewRenderer == null) {
this.localSurfaceViewRenderer = this.mediaManager.buildSurfaceViewRenderer(Config.WHAT_NEW_LOCAL_VIDEO, videoTrack); this.localSurfaceViewRenderer = this.mediaManager.buildSurfaceViewRenderer(Config.WHAT_NEW_LOCAL_VIDEO, videoTrack);
} else {
Log.w(SessionClient.class.getSimpleName(), "视频预览已经存在");
} }
}); });
} }
private void releaseLocal() { /**
* 释放本地媒体
*/
private void releaseLocalVideo() {
// 释放本地视频资源 // 释放本地视频资源
if(this.localSurfaceViewRenderer != null) { if(this.localSurfaceViewRenderer != null) {
// 释放资源 // 释放资源
@@ -353,7 +430,7 @@ public class SessionClient extends Client {
return; return;
} }
super.close(); super.close();
this.releaseLocal(); this.releaseLocalVideo();
try { try {
// PeerConnection自动释放mediaStream、remoteMediaStream // PeerConnection自动释放mediaStream、remoteMediaStream
if(this.peerConnection != null) { if(this.peerConnection != null) {
@@ -367,28 +444,28 @@ public class SessionClient extends Client {
} }
/** /**
* @return 监听 * @return PC观察者
*/ */
private PeerConnection.Observer observer() { private PeerConnection.Observer observer() {
return new PeerConnection.Observer() { return new PeerConnection.Observer() {
@Override @Override
public void onSignalingChange(PeerConnection.SignalingState signalingState) { public void onSignalingChange(PeerConnection.SignalingState signalingState) {
Log.d(SessionClient.class.getSimpleName(), "PC信令状态改变:" + signalingState); Log.d(SessionClient.class.getSimpleName(), "PCSignalingState改变:" + signalingState);
SessionClient.this.logState(); SessionClient.this.logState();
} }
@Override @Override
public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) { public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
Log.d(SessionClient.class.getSimpleName(), "PCIce收集状态改变:" + iceGatheringState); Log.d(SessionClient.class.getSimpleName(), "PCIceGatheringState改变:" + iceGatheringState);
SessionClient.this.logState(); SessionClient.this.logState();
} }
@Override @Override
public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) { public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
Log.d(SessionClient.class.getSimpleName(), "PCIce连接状态改变" + iceConnectionState);
SessionClient.this.logState();
// disconnected暂时连接不上可能自我恢复 // disconnected暂时连接不上可能自我恢复
Log.d(SessionClient.class.getSimpleName(), "PCIceConnectionState改变" + iceConnectionState);
SessionClient.this.logState();
} }
@Override @Override
@@ -397,17 +474,8 @@ public class SessionClient extends Client {
@Override @Override
public void onIceCandidate(IceCandidate iceCandidate) { public void onIceCandidate(IceCandidate iceCandidate) {
Log.d(SessionClient.class.getSimpleName(), "发送媒体协商:" + SessionClient.this.sessionId); Log.d(SessionClient.class.getSimpleName(), "媒体协商:" + SessionClient.this.sessionId);
final Map<String, Object> candidate = new HashMap<>(); SessionClient.this.exchangeIceCandidate(iceCandidate);
candidate.put("sdpMid", iceCandidate.sdpMid);
candidate.put("candidate", iceCandidate.sdp);
candidate.put("sdpMLineIndex", iceCandidate.sdpMLineIndex);
SessionClient.this.taoyao.push(SessionClient.this.taoyao.buildMessage(
"session::exchange",
"type", "candidate",
"candidate", candidate,
"sessionId", SessionClient.this.sessionId
));
} }
@Override @Override
@@ -429,6 +497,7 @@ public class SessionClient extends Client {
public void onRemoveStream(MediaStream mediaStream) { public void onRemoveStream(MediaStream mediaStream) {
Log.i(SessionClient.class.getSimpleName(), "删除远程媒体:" + SessionClient.this.clientId); Log.i(SessionClient.class.getSimpleName(), "删除远程媒体:" + SessionClient.this.clientId);
mediaStream.dispose(); mediaStream.dispose();
SessionClient.this.remoteMediaStream = null;
} }
@Override @Override
@@ -444,9 +513,8 @@ public class SessionClient extends Client {
public void onRenegotiationNeeded() { public void onRenegotiationNeeded() {
Log.d(SessionClient.class.getSimpleName(), "重新协商媒体:" + SessionClient.this.sessionId); Log.d(SessionClient.class.getSimpleName(), "重新协商媒体:" + SessionClient.this.sessionId);
if(SessionClient.this.peerConnection.connectionState() == PeerConnection.PeerConnectionState.CONNECTED) { if(SessionClient.this.peerConnection.connectionState() == PeerConnection.PeerConnectionState.CONNECTED) {
// SessionClient.this.peerConnection.restartIce(); // TODO验证
// TODO重新协商 SessionClient.this.peerConnection.restartIce();
// SessionClient.this.offer();
} }
} }
@@ -496,19 +564,44 @@ public class SessionClient extends Client {
}; };
} }
/**
* @param iceCandidate 媒体协商
*/
private void exchangeIceCandidate(IceCandidate iceCandidate) {
if(iceCandidate == null) {
return;
}
final Map<String, Object> candidate = new HashMap<>();
candidate.put("sdpMid", iceCandidate.sdpMid);
candidate.put("candidate", iceCandidate.sdp);
candidate.put("sdpMLineIndex", iceCandidate.sdpMLineIndex);
this.taoyao.push(this.taoyao.buildMessage(
"session::exchange",
"type", "candidate",
"candidate", candidate,
"sessionId", this.sessionId
));
}
/**
* @param sessionDescription SDP
*/
private void exchangeSessionDescription(SessionDescription sessionDescription) { private void exchangeSessionDescription(SessionDescription sessionDescription) {
if(sessionDescription == null) { if(sessionDescription == null) {
return; return;
} }
final String type = sessionDescription.type.toString().toLowerCase(); final String type = sessionDescription.type.toString().toLowerCase();
SessionClient.this.taoyao.push(SessionClient.this.taoyao.buildMessage( this.taoyao.push(this.taoyao.buildMessage(
"session::exchange", "session::exchange",
"sdp", sessionDescription.description, "sdp", sessionDescription.description,
"type", type, "type", type,
"sessionId", SessionClient.this.sessionId "sessionId", this.sessionId
)); ));
} }
/**
* 记录PC状态
*/
private void logState() { private void logState() {
Log.d(SessionClient.class.getSimpleName(), String.format( Log.d(SessionClient.class.getSimpleName(), String.format(
""" """

View File

@@ -2449,6 +2449,7 @@ class Taoyao extends RemoteClient {
console.debug("buildPeerConnection onnegotiationneeded", event); console.debug("buildPeerConnection onnegotiationneeded", event);
if(peerConnection.connectionState === "connected") { if(peerConnection.connectionState === "connected") {
// TODO重连 // TODO重连
peerConnection.restartIce();
} }
} }
const localStream = await me.getStream(); const localStream = await me.getStream();