[*] 日常优化
This commit is contained in:
@@ -563,6 +563,8 @@ sudo ufw allow 8888/tcp
|
|||||||
sudo ufw allow 9999/tcp
|
sudo ufw allow 9999/tcp
|
||||||
# 媒体服务
|
# 媒体服务
|
||||||
sudo ufw allow 40000:49999/udp
|
sudo ufw allow 40000:49999/udp
|
||||||
|
# 允许网段
|
||||||
|
#sudo ufw allow from 192.168.1.0/24 to any
|
||||||
|
|
||||||
# 删除端口
|
# 删除端口
|
||||||
#sudo ufw delete allow 443/tcp
|
#sudo ufw delete allow 443/tcp
|
||||||
|
|||||||
90
docs/NetworkTopology.md
Normal file
90
docs/NetworkTopology.md
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
# 拓扑网络
|
||||||
|
|
||||||
|
多子网环境下的部署配置
|
||||||
|
|
||||||
|
## 两个子网
|
||||||
|
|
||||||
|
```
|
||||||
|
# 配置`TURN`服务
|
||||||
|
`coturn`
|
||||||
|
|
||||||
|
#配置地址重写
|
||||||
|
`ip-rewrite`
|
||||||
|
```
|
||||||
|
|
||||||
|
## 三个及其以上子网
|
||||||
|
|
||||||
|
### 配置端口转发
|
||||||
|
|
||||||
|
```
|
||||||
|
# 配置转发:两个配置一个即可
|
||||||
|
vim /etc/default/ufw
|
||||||
|
---
|
||||||
|
DEFAULT_FORWARD_POLICY="ACCEPT"
|
||||||
|
---
|
||||||
|
vim /etc/sysctl.conf | vim /etc/ufw/sysctl.conf
|
||||||
|
---
|
||||||
|
net.ipv4.ip_forward=1 | net/ipv4/ip_forward=1
|
||||||
|
---
|
||||||
|
sysctl -p
|
||||||
|
|
||||||
|
# *filter之前添加
|
||||||
|
vim /etc/ufw/before.rules
|
||||||
|
---
|
||||||
|
*nat
|
||||||
|
:PREROUTING ACCEPT [0:0]
|
||||||
|
:POSTROUTING ACCEPT [0:0]
|
||||||
|
-A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
|
||||||
|
-A POSTROUTING -j MASQUERADE
|
||||||
|
COMMIT
|
||||||
|
---
|
||||||
|
ufw reload
|
||||||
|
|
||||||
|
# 配置`TURN`服务
|
||||||
|
`coturn`
|
||||||
|
|
||||||
|
#配置地址重写
|
||||||
|
`ip-rewrite`
|
||||||
|
```
|
||||||
|
|
||||||
|
## 端口转发
|
||||||
|
|
||||||
|
* DNAT: 目标IP转换
|
||||||
|
* SNAT: 源IP转换
|
||||||
|
* REDIRECT: 端口重定向
|
||||||
|
* MASQUERADE:源地址动态伪装
|
||||||
|
|
||||||
|
```
|
||||||
|
-A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
|
||||||
|
-A PREROUTING -d 192.168.1.100 -p tcp --dport 80 -j REDIRECT --to-port 8080
|
||||||
|
-A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.2.100:8080
|
||||||
|
-A PREROUTING -d 192.168.1.100 -p tcp --dport 80 -j DNAT --to-destination 192.168.2.100:8080
|
||||||
|
-A POSTROUTING -p tcp --dport 80 -j SNAT --to-source 192.168.2.100
|
||||||
|
-A POSTROUTING -s 192.168.1.0/24 -j SNAT --to-source 192.168.2.100
|
||||||
|
-A POSTROUTING -j MASQUERADE
|
||||||
|
-A POSTROUTING -s 192.168.1.0/24 -j MASQUERADE
|
||||||
|
```
|
||||||
|
|
||||||
|
## iptables
|
||||||
|
|
||||||
|
```
|
||||||
|
# 查看nat
|
||||||
|
iptables -L -t nat
|
||||||
|
# 清理nat
|
||||||
|
iptables -F -t nat
|
||||||
|
```
|
||||||
|
|
||||||
|
### 四张表
|
||||||
|
|
||||||
|
* nat: NAT功能(端口映射、地址映射等等)
|
||||||
|
* raw: 优先级最高
|
||||||
|
* filter:过滤功能
|
||||||
|
* mangle:修改特定数据包
|
||||||
|
|
||||||
|
### 五条链
|
||||||
|
|
||||||
|
* INPUT: 通过路由表后目的地为本机
|
||||||
|
* OUTPUT: 由本机产生向外转发
|
||||||
|
* FORWARDING: 通过路由表后目的地不为本机
|
||||||
|
* PREROUTING: 数据包进入路由表之前
|
||||||
|
* POSTROUTING:发送到网卡接口之前
|
||||||
@@ -155,11 +155,11 @@ public class MediaService extends Service {
|
|||||||
resources.getInteger(R.integer.imageQuantity),
|
resources.getInteger(R.integer.imageQuantity),
|
||||||
resources.getString(R.string.audioQuantity),
|
resources.getString(R.string.audioQuantity),
|
||||||
resources.getString(R.string.videoQuantity),
|
resources.getString(R.string.videoQuantity),
|
||||||
resources.getBoolean(R.bool.broadcaster),
|
|
||||||
resources.getInteger(R.integer.channelCount),
|
resources.getInteger(R.integer.channelCount),
|
||||||
resources.getInteger(R.integer.iFrameInterval),
|
resources.getInteger(R.integer.iFrameInterval),
|
||||||
resources.getString(R.string.imagePath),
|
resources.getString(R.string.imagePath),
|
||||||
resources.getString(R.string.videoPath),
|
resources.getString(R.string.videoPath),
|
||||||
|
resources.getString(R.string.videoFile),
|
||||||
resources.getString(R.string.watermark),
|
resources.getString(R.string.watermark),
|
||||||
VideoSourceType.valueOf(resources.getString(R.string.videoSourceType))
|
VideoSourceType.valueOf(resources.getString(R.string.videoSourceType))
|
||||||
);
|
);
|
||||||
@@ -237,7 +237,7 @@ public class MediaService extends Service {
|
|||||||
.setContentIntent(pendingIntent);
|
.setContentIntent(pendingIntent);
|
||||||
final Notification notification = notificationBuilder.build();
|
final Notification notification = notificationBuilder.build();
|
||||||
this.startForeground((int) System.currentTimeMillis(), notification);
|
this.startForeground((int) System.currentTimeMillis(), notification);
|
||||||
MediaManager.getInstance().initScreen(intent.getParcelableExtra("data"));
|
MediaManager.getInstance().initScreenCapturer(intent.getParcelableExtra("data"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -34,8 +34,6 @@
|
|||||||
<string name="audioQuantity">fd-audio</string>
|
<string name="audioQuantity">fd-audio</string>
|
||||||
<!-- 视频质量 -->
|
<!-- 视频质量 -->
|
||||||
<string name="videoQuantity">fd-video</string>
|
<string name="videoQuantity">fd-video</string>
|
||||||
<!-- 语音播报 -->
|
|
||||||
<bool name="broadcaster">false</bool>
|
|
||||||
<!-- 音频通道数量 -->
|
<!-- 音频通道数量 -->
|
||||||
<integer name="channelCount">1</integer>
|
<integer name="channelCount">1</integer>
|
||||||
<!-- 视频关键帧频率 -->
|
<!-- 视频关键帧频率 -->
|
||||||
@@ -46,6 +44,8 @@
|
|||||||
<string name="imagePath">/taoyao</string>
|
<string name="imagePath">/taoyao</string>
|
||||||
<!-- 视频存储目录 -->
|
<!-- 视频存储目录 -->
|
||||||
<string name="videoPath">/taoyao</string>
|
<string name="videoPath">/taoyao</string>
|
||||||
|
<!-- 分享视频文件路径 -->
|
||||||
|
<string name="videoFile"></string>
|
||||||
<!-- 水印 -->
|
<!-- 水印 -->
|
||||||
<string name="watermark">"'TAOYAO' yyyy-MM-dd HH:mm:ss"</string>
|
<string name="watermark">"'TAOYAO' yyyy-MM-dd HH:mm:ss"</string>
|
||||||
<!-- 视频来源:FILE|BACK|FRONT|SCREEN -->
|
<!-- 视频来源:FILE|BACK|FRONT|SCREEN -->
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import android.media.MediaCodecInfo;
|
|||||||
import android.media.MediaCodecList;
|
import android.media.MediaCodecList;
|
||||||
import android.media.projection.MediaProjection;
|
import android.media.projection.MediaProjection;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.speech.tts.TextToSpeech;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.acgist.taoyao.media.client.PhotographClient;
|
import com.acgist.taoyao.media.client.PhotographClient;
|
||||||
@@ -30,6 +29,7 @@ import org.webrtc.CapturerObserver;
|
|||||||
import org.webrtc.DefaultVideoDecoderFactory;
|
import org.webrtc.DefaultVideoDecoderFactory;
|
||||||
import org.webrtc.DefaultVideoEncoderFactory;
|
import org.webrtc.DefaultVideoEncoderFactory;
|
||||||
import org.webrtc.EglBase;
|
import org.webrtc.EglBase;
|
||||||
|
import org.webrtc.FileVideoCapturer;
|
||||||
import org.webrtc.MediaConstraints;
|
import org.webrtc.MediaConstraints;
|
||||||
import org.webrtc.MediaStream;
|
import org.webrtc.MediaStream;
|
||||||
import org.webrtc.PeerConnectionFactory;
|
import org.webrtc.PeerConnectionFactory;
|
||||||
@@ -44,9 +44,8 @@ import org.webrtc.VideoSource;
|
|||||||
import org.webrtc.VideoTrack;
|
import org.webrtc.VideoTrack;
|
||||||
import org.webrtc.audio.JavaAudioDeviceModule;
|
import org.webrtc.audio.JavaAudioDeviceModule;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
@@ -57,24 +56,22 @@ import java.util.stream.IntStream;
|
|||||||
*/
|
*/
|
||||||
public final class MediaManager {
|
public final class MediaManager {
|
||||||
|
|
||||||
private static final MediaManager INSTANCE = new MediaManager();
|
|
||||||
|
|
||||||
public static final MediaManager getInstance() {
|
|
||||||
return INSTANCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前终端数量
|
* 当前终端数量
|
||||||
*/
|
*/
|
||||||
private volatile int clientCount;
|
private volatile int clientCount;
|
||||||
/**
|
/**
|
||||||
* 视频路径
|
* 图片路径
|
||||||
*/
|
*/
|
||||||
private String imagePath;
|
private String imagePath;
|
||||||
/**
|
/**
|
||||||
* 图片路径
|
* 视频路径
|
||||||
*/
|
*/
|
||||||
private String videoPath;
|
private String videoPath;
|
||||||
|
/**
|
||||||
|
* 分享视频文件路径
|
||||||
|
*/
|
||||||
|
private String videoFile;
|
||||||
/**
|
/**
|
||||||
* 图片质量
|
* 图片质量
|
||||||
*/
|
*/
|
||||||
@@ -87,10 +84,6 @@ public final class MediaManager {
|
|||||||
* 视频质量
|
* 视频质量
|
||||||
*/
|
*/
|
||||||
private String videoQuantity;
|
private String videoQuantity;
|
||||||
/**
|
|
||||||
* 语音播报
|
|
||||||
*/
|
|
||||||
private boolean broadcaster;
|
|
||||||
/**
|
/**
|
||||||
* 通道数量
|
* 通道数量
|
||||||
*/
|
*/
|
||||||
@@ -103,16 +96,12 @@ public final class MediaManager {
|
|||||||
* 水印
|
* 水印
|
||||||
*/
|
*/
|
||||||
private String watermark;
|
private String watermark;
|
||||||
/**
|
|
||||||
* 视频来源类型
|
|
||||||
*/
|
|
||||||
private VideoSourceType videoSourceType;
|
|
||||||
/**
|
/**
|
||||||
* 信令
|
* 信令
|
||||||
*/
|
*/
|
||||||
private ITaoyao taoyao;
|
private ITaoyao taoyao;
|
||||||
/**
|
/**
|
||||||
* Handler
|
* MainHandler
|
||||||
*/
|
*/
|
||||||
private Handler mainHandler;
|
private Handler mainHandler;
|
||||||
/**
|
/**
|
||||||
@@ -139,10 +128,6 @@ public final class MediaManager {
|
|||||||
* 音频来源
|
* 音频来源
|
||||||
*/
|
*/
|
||||||
private AudioSource audioSource;
|
private AudioSource audioSource;
|
||||||
/**
|
|
||||||
* 视频捕获
|
|
||||||
*/
|
|
||||||
private VideoCapturer videoCapturer;
|
|
||||||
/**
|
/**
|
||||||
* 主码流视频来源
|
* 主码流视频来源
|
||||||
*/
|
*/
|
||||||
@@ -152,11 +137,15 @@ public final class MediaManager {
|
|||||||
*/
|
*/
|
||||||
private VideoSource shareVideoSource;
|
private VideoSource shareVideoSource;
|
||||||
/**
|
/**
|
||||||
* 录像终端
|
* 视频来源类型
|
||||||
*/
|
*/
|
||||||
private RecordClient recordClient;
|
private VideoSourceType videoSourceType;
|
||||||
/**
|
/**
|
||||||
* 视频来源
|
* 视频捕获
|
||||||
|
*/
|
||||||
|
private VideoCapturer videoCapturer;
|
||||||
|
/**
|
||||||
|
* SurfaceTextureHelper
|
||||||
*/
|
*/
|
||||||
private SurfaceTextureHelper surfaceTextureHelper;
|
private SurfaceTextureHelper surfaceTextureHelper;
|
||||||
/**
|
/**
|
||||||
@@ -168,32 +157,32 @@ public final class MediaManager {
|
|||||||
*/
|
*/
|
||||||
private JavaAudioDeviceModule javaAudioDeviceModule;
|
private JavaAudioDeviceModule javaAudioDeviceModule;
|
||||||
/**
|
/**
|
||||||
* 语音播报
|
* 录屏等待锁
|
||||||
*/
|
*/
|
||||||
private TextToSpeech textToSpeech;
|
private final Object screenLock;
|
||||||
|
/**
|
||||||
|
* 录像终端
|
||||||
|
*/
|
||||||
|
private RecordClient recordClient;
|
||||||
/**
|
/**
|
||||||
* 视频处理
|
* 视频处理
|
||||||
*/
|
*/
|
||||||
private VideoProcesser videoProcesser;
|
private VideoProcesser videoProcesser;
|
||||||
/**
|
|
||||||
* 录屏等待锁
|
|
||||||
*/
|
|
||||||
private final Object screenLock = new Object();
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// // 设置采样
|
// 设置采样
|
||||||
// WebRtcAudioUtils.setDefaultSampleRateHz(48000);
|
// WebRtcAudioUtils.setDefaultSampleRateHz(48000);
|
||||||
// // 噪声消除
|
// 噪声消除
|
||||||
// WebRtcAudioUtils.setWebRtcBasedNoiseSuppressor(true);
|
// WebRtcAudioUtils.setWebRtcBasedNoiseSuppressor(true);
|
||||||
// // 回声消除
|
// 回声消除
|
||||||
// WebRtcAudioUtils.setWebRtcBasedAcousticEchoCanceler(true);
|
// WebRtcAudioUtils.setWebRtcBasedAcousticEchoCanceler(true);
|
||||||
// // 自动增益
|
// 自动增益
|
||||||
// WebRtcAudioUtils.setWebRtcBasedAutomaticGainControl(true);
|
// WebRtcAudioUtils.setWebRtcBasedAutomaticGainControl(true);
|
||||||
// // 支持的编码解码器
|
// 支持的编码解码器
|
||||||
final MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
|
final MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
|
||||||
for (MediaCodecInfo mediaCodecInfo : mediaCodecList.getCodecInfos()) {
|
for (MediaCodecInfo mediaCodecInfo : mediaCodecList.getCodecInfos()) {
|
||||||
// OMX.google = 软编
|
|
||||||
// OMX.core = 硬编
|
// OMX.core = 硬编
|
||||||
|
// OMX.google = 软编
|
||||||
final String[] supportedTypes = mediaCodecInfo.getSupportedTypes();
|
final String[] supportedTypes = mediaCodecInfo.getSupportedTypes();
|
||||||
final String type = mediaCodecInfo.isEncoder() ? "编码器" : "解码器";
|
final String type = mediaCodecInfo.isEncoder() ? "编码器" : "解码器";
|
||||||
Log.d(MediaManager.class.getSimpleName(), type + "名称:" + mediaCodecInfo.getName());
|
Log.d(MediaManager.class.getSimpleName(), type + "名称:" + mediaCodecInfo.getName());
|
||||||
@@ -208,19 +197,27 @@ public final class MediaManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final MediaManager INSTANCE = new MediaManager();
|
||||||
|
|
||||||
|
public static final MediaManager getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
private MediaManager() {
|
private MediaManager() {
|
||||||
this.clientCount = 0;
|
this.clientCount = 0;
|
||||||
|
this.screenLock = new Object();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return 是否可用(所有配置加载完成)
|
* @return 是否可用
|
||||||
*/
|
*/
|
||||||
public boolean available() {
|
public boolean available() {
|
||||||
return
|
return
|
||||||
this.taoyao != null &&
|
this.taoyao != null &&
|
||||||
this.context != null &&
|
this.context != null &&
|
||||||
this.mainHandler != null &&
|
this.mainHandler != null &&
|
||||||
this.mediaProperties != null;
|
this.mediaProperties != null &&
|
||||||
|
this.webrtcProperties != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -250,19 +247,19 @@ public final class MediaManager {
|
|||||||
* @param imageQuantity 图片质量
|
* @param imageQuantity 图片质量
|
||||||
* @param audioQuantity 音频质量
|
* @param audioQuantity 音频质量
|
||||||
* @param videoQuantity 视频质量
|
* @param videoQuantity 视频质量
|
||||||
* @param broadcaster 是否语音播报
|
|
||||||
* @param channelCount 音频通道数量
|
* @param channelCount 音频通道数量
|
||||||
* @param iFrameInterval 关键帧频率
|
* @param iFrameInterval 关键帧频率
|
||||||
* @param imagePath 图片保存路径
|
* @param imagePath 图片保存路径
|
||||||
* @param videoPath 视频保存路径
|
* @param videoPath 视频保存路径
|
||||||
|
* @param videoFile 分享视频文件路径
|
||||||
* @param watermark 水印信息
|
* @param watermark 水印信息
|
||||||
* @param videoSourceType 视频来源类型
|
* @param videoSourceType 视频来源类型
|
||||||
*/
|
*/
|
||||||
public void initContext(
|
public void initContext(
|
||||||
Handler mainHandler, Context context,
|
Handler mainHandler, Context context,
|
||||||
int imageQuantity, String audioQuantity, String videoQuantity,
|
int imageQuantity, String audioQuantity, String videoQuantity,
|
||||||
boolean broadcaster, int channelCount, int iFrameInterval,
|
int channelCount, int iFrameInterval,
|
||||||
String imagePath, String videoPath,
|
String imagePath, String videoPath, String videoFile,
|
||||||
String watermark, VideoSourceType videoSourceType
|
String watermark, VideoSourceType videoSourceType
|
||||||
) {
|
) {
|
||||||
this.mainHandler = mainHandler;
|
this.mainHandler = mainHandler;
|
||||||
@@ -270,11 +267,11 @@ public final class MediaManager {
|
|||||||
this.imageQuantity = imageQuantity;
|
this.imageQuantity = imageQuantity;
|
||||||
this.audioQuantity = audioQuantity;
|
this.audioQuantity = audioQuantity;
|
||||||
this.videoQuantity = videoQuantity;
|
this.videoQuantity = videoQuantity;
|
||||||
this.broadcaster = broadcaster;
|
|
||||||
this.channelCount = channelCount;
|
this.channelCount = channelCount;
|
||||||
this.iFrameInterval = iFrameInterval;
|
this.iFrameInterval = iFrameInterval;
|
||||||
this.imagePath = imagePath;
|
this.imagePath = imagePath;
|
||||||
this.videoPath = videoPath;
|
this.videoPath = videoPath;
|
||||||
|
this.videoFile = videoFile;
|
||||||
this.watermark = watermark;
|
this.watermark = watermark;
|
||||||
this.videoSourceType = videoSourceType;
|
this.videoSourceType = videoSourceType;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
@@ -292,18 +289,6 @@ public final class MediaManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void broadcast(String text) {
|
|
||||||
if(!this.broadcaster) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(this.textToSpeech == null) {
|
|
||||||
this.textToSpeech = new TextToSpeech(this.context, new MediaManager.TextToSpeechInitListener());
|
|
||||||
}
|
|
||||||
this.textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null, UUID.randomUUID().toString());
|
|
||||||
// this.textToSpeech.stop();
|
|
||||||
// this.textToSpeech.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新建终端
|
* 新建终端
|
||||||
*
|
*
|
||||||
@@ -333,6 +318,7 @@ public final class MediaManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 关闭一个终端
|
* 关闭一个终端
|
||||||
|
* 所有终端关闭之后释放PeerConnectionFactory
|
||||||
*
|
*
|
||||||
* @return 剩余终端数量
|
* @return 剩余终端数量
|
||||||
*/
|
*/
|
||||||
@@ -341,7 +327,6 @@ public final class MediaManager {
|
|||||||
this.clientCount--;
|
this.clientCount--;
|
||||||
if (this.clientCount <= 0) {
|
if (this.clientCount <= 0) {
|
||||||
Log.i(MediaManager.class.getSimpleName(), "释放PeerConnectionFactory");
|
Log.i(MediaManager.class.getSimpleName(), "释放PeerConnectionFactory");
|
||||||
// 注意顺序
|
|
||||||
this.stopVideoCapture();
|
this.stopVideoCapture();
|
||||||
this.closeMedia();
|
this.closeMedia();
|
||||||
this.nativeStop();
|
this.nativeStop();
|
||||||
@@ -351,6 +336,9 @@ public final class MediaManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载PeerConnectionFactory
|
||||||
|
*/
|
||||||
private void initPeerConnectionFactory() {
|
private void initPeerConnectionFactory() {
|
||||||
PeerConnectionFactory.initialize(
|
PeerConnectionFactory.initialize(
|
||||||
PeerConnectionFactory.InitializationOptions.builder(this.context)
|
PeerConnectionFactory.InitializationOptions.builder(this.context)
|
||||||
@@ -364,6 +352,9 @@ public final class MediaManager {
|
|||||||
this.eglContext = this.eglBase.getEglBaseContext();
|
this.eglContext = this.eglBase.getEglBaseContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 释放PeerConnectionFactory
|
||||||
|
*/
|
||||||
private void stopPeerConnectionFactory() {
|
private void stopPeerConnectionFactory() {
|
||||||
if (this.eglBase != null) {
|
if (this.eglBase != null) {
|
||||||
this.eglBase.release();
|
this.eglBase.release();
|
||||||
@@ -389,37 +380,41 @@ public final class MediaManager {
|
|||||||
// .setAudioEncoderFactoryFactory(new BuiltinAudioEncoderFactoryFactory())
|
// .setAudioEncoderFactoryFactory(new BuiltinAudioEncoderFactoryFactory())
|
||||||
// .setAudioDecoderFactoryFactory(new BuiltinAudioDecoderFactoryFactory())
|
// .setAudioDecoderFactoryFactory(new BuiltinAudioDecoderFactoryFactory())
|
||||||
.createPeerConnectionFactory();
|
.createPeerConnectionFactory();
|
||||||
Arrays.stream(videoEncoderFactory.getSupportedCodecs()).forEach(v -> {
|
Arrays.stream(videoDecoderFactory.getSupportedCodecs()).forEach(v -> {
|
||||||
Log.d(MediaManager.class.getSimpleName(), "支持的视频解码器:" + v.name);
|
Log.d(MediaManager.class.getSimpleName(), "支持的视频解码器:" + v.name);
|
||||||
});
|
});
|
||||||
|
Arrays.stream(videoEncoderFactory.getSupportedCodecs()).forEach(v -> {
|
||||||
|
Log.d(MediaManager.class.getSimpleName(), "支持的视频编码器:" + v.name);
|
||||||
|
});
|
||||||
this.initAudio();
|
this.initAudio();
|
||||||
this.initVideo();
|
this.initVideo();
|
||||||
this.initWatermark();
|
this.initWatermark();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return JavaAudioDeviceModule
|
||||||
|
*/
|
||||||
private JavaAudioDeviceModule javaAudioDeviceModule() {
|
private JavaAudioDeviceModule javaAudioDeviceModule() {
|
||||||
|
// 本地声音回调:只有本地音频而且建立媒体之后才有回调
|
||||||
|
// WebRtcAudioRecord.setOnAudioSamplesReady(audioSamples -> {});
|
||||||
|
// 配置音频
|
||||||
// final AudioAttributes audioAttributes = new AudioAttributes.Builder()
|
// final AudioAttributes audioAttributes = new AudioAttributes.Builder()
|
||||||
// .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
|
// .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
|
||||||
// .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
|
// .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
|
||||||
// .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
|
// .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
|
||||||
// .build();
|
// .build();
|
||||||
// WebRtcAudioRecord.setOnAudioSamplesReady(audioSamples -> {
|
|
||||||
// if(this.recordClient != null) {
|
|
||||||
// this.recordClient.onWebRtcAudioRecordSamplesReady(audioSamples);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
final JavaAudioDeviceModule javaAudioDeviceModule = JavaAudioDeviceModule.builder(this.context)
|
final JavaAudioDeviceModule javaAudioDeviceModule = JavaAudioDeviceModule.builder(this.context)
|
||||||
// .setSampleRate(48000)
|
// .setSampleRate(48000)
|
||||||
// .setSampleRate(mediaAudioProperties.getSampleRate())
|
// .setSampleRate(mediaAudioProperties.getSampleRate())
|
||||||
// .setAudioFormat(AudioFormat.ENCODING_PCM_16BIT)
|
// .setAudioFormat(AudioFormat.ENCODING_PCM_16BIT)
|
||||||
// .setAudioSource(MediaRecorder.AudioSource.MIC)
|
// .setAudioSource(MediaRecorder.AudioSource.MIC)
|
||||||
// .setAudioAttributes(audioAttributes)
|
// .setAudioAttributes(audioAttributes)
|
||||||
// 超低延迟
|
|
||||||
// .setUseLowLatency()
|
// .setUseLowLatency()
|
||||||
// .setUseStereoInput()
|
// .setUseStereoInput()
|
||||||
// .setUseStereoOutput()
|
// .setUseStereoOutput()
|
||||||
// 本地声音
|
// .setSamplesReadyCallback(audioSamples -> {})
|
||||||
// .setSamplesReadyCallback()
|
// .setUseHardwareNoiseSuppressor(true)
|
||||||
|
// .setUseHardwareAcousticEchoCanceler(true)
|
||||||
.setAudioTrackErrorCallback(new JavaAudioDeviceModule.AudioTrackErrorCallback() {
|
.setAudioTrackErrorCallback(new JavaAudioDeviceModule.AudioTrackErrorCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onWebRtcAudioTrackInitError(String errorMessage) {
|
public void onWebRtcAudioTrackInitError(String errorMessage) {
|
||||||
@@ -468,11 +463,7 @@ public final class MediaManager {
|
|||||||
Log.i(MediaManager.class.getSimpleName(), "WebRTC本地音频录像结束");
|
Log.i(MediaManager.class.getSimpleName(), "WebRTC本地音频录像结束");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// .setUseHardwareNoiseSuppressor(true)
|
|
||||||
// .setUseHardwareAcousticEchoCanceler(true)
|
|
||||||
.createAudioDeviceModule();
|
.createAudioDeviceModule();
|
||||||
// javaAudioDeviceModule.setSpeakerMute(false);
|
|
||||||
// javaAudioDeviceModule.setMicrophoneMute(false);
|
|
||||||
return javaAudioDeviceModule;
|
return javaAudioDeviceModule;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,11 +483,11 @@ public final class MediaManager {
|
|||||||
// 加载视频
|
// 加载视频
|
||||||
Log.i(MediaManager.class.getSimpleName(), "加载视频:" + this.videoSourceType);
|
Log.i(MediaManager.class.getSimpleName(), "加载视频:" + this.videoSourceType);
|
||||||
if (this.videoSourceType == VideoSourceType.FILE) {
|
if (this.videoSourceType == VideoSourceType.FILE) {
|
||||||
this.initFile();
|
this.initFileCapturer();
|
||||||
} else if (this.videoSourceType.isCamera()) {
|
} else if (this.videoSourceType.isCamera()) {
|
||||||
this.initCamera();
|
this.initCameraCapturer();
|
||||||
} else if (this.videoSourceType == VideoSourceType.SCREEN) {
|
} else if (this.videoSourceType == VideoSourceType.SCREEN) {
|
||||||
this.initScreenPromise();
|
this.initScreenCapturerPromise();
|
||||||
} else {
|
} else {
|
||||||
// 其他来源
|
// 其他来源
|
||||||
}
|
}
|
||||||
@@ -505,15 +496,19 @@ public final class MediaManager {
|
|||||||
/**
|
/**
|
||||||
* 加载文件采集
|
* 加载文件采集
|
||||||
*/
|
*/
|
||||||
private void initFile() {
|
private void initFileCapturer() {
|
||||||
// 自己实现
|
try {
|
||||||
// new FileVideoCapturer();
|
this.videoCapturer = new FileVideoCapturer(this.videoFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(MediaManager.class.getSimpleName(), "加载视频异常:" + this.videoFile, e);
|
||||||
|
}
|
||||||
|
this.initVideoSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载摄像头采集
|
* 加载摄像头采集
|
||||||
*/
|
*/
|
||||||
private void initCamera() {
|
private void initCameraCapturer() {
|
||||||
final CameraEnumerator cameraEnumerator = new Camera2Enumerator(this.context);
|
final CameraEnumerator cameraEnumerator = new Camera2Enumerator(this.context);
|
||||||
final String[] names = cameraEnumerator.getDeviceNames();
|
final String[] names = cameraEnumerator.getDeviceNames();
|
||||||
for (String name : names) {
|
for (String name : names) {
|
||||||
@@ -531,7 +526,7 @@ public final class MediaManager {
|
|||||||
/**
|
/**
|
||||||
* 加载屏幕采集
|
* 加载屏幕采集
|
||||||
*/
|
*/
|
||||||
private void initScreenPromise() {
|
private void initScreenCapturerPromise() {
|
||||||
this.mainHandler.obtainMessage(Config.WHAT_SCREEN_CAPTURE).sendToTarget();
|
this.mainHandler.obtainMessage(Config.WHAT_SCREEN_CAPTURE).sendToTarget();
|
||||||
synchronized (this.screenLock) {
|
synchronized (this.screenLock) {
|
||||||
try {
|
try {
|
||||||
@@ -547,7 +542,7 @@ public final class MediaManager {
|
|||||||
*
|
*
|
||||||
* @param intent Intent
|
* @param intent Intent
|
||||||
*/
|
*/
|
||||||
public void initScreen(Intent intent) {
|
public void initScreenCapturer(Intent intent) {
|
||||||
this.videoCapturer = new ScreenCapturerAndroid(intent, new ScreenCallback());
|
this.videoCapturer = new ScreenCapturerAndroid(intent, new ScreenCallback());
|
||||||
this.initVideoSource();
|
this.initVideoSource();
|
||||||
synchronized (this.screenLock) {
|
synchronized (this.screenLock) {
|
||||||
@@ -561,18 +556,22 @@ public final class MediaManager {
|
|||||||
private void initVideoSource() {
|
private void initVideoSource() {
|
||||||
// 加载视频
|
// 加载视频
|
||||||
this.surfaceTextureHelper = SurfaceTextureHelper.create("MediaVideoThread", this.eglContext);
|
this.surfaceTextureHelper = SurfaceTextureHelper.create("MediaVideoThread", this.eglContext);
|
||||||
// 主码流
|
|
||||||
this.mainVideoSource = this.peerConnectionFactory.createVideoSource(this.videoCapturer.isScreencast());
|
this.mainVideoSource = this.peerConnectionFactory.createVideoSource(this.videoCapturer.isScreencast());
|
||||||
// 次码流
|
|
||||||
this.shareVideoSource = this.peerConnectionFactory.createVideoSource(this.videoCapturer.isScreencast());
|
this.shareVideoSource = this.peerConnectionFactory.createVideoSource(this.videoCapturer.isScreencast());
|
||||||
|
// 视频配置
|
||||||
final MediaVideoProperties mediaVideoProperties = this.mediaProperties.getVideo();
|
final MediaVideoProperties mediaVideoProperties = this.mediaProperties.getVideo();
|
||||||
this.shareVideoSource.adaptOutputFormat(mediaVideoProperties.getWidth(), mediaVideoProperties.getHeight(), mediaVideoProperties.getFrameRate());
|
this.shareVideoSource.adaptOutputFormat(mediaVideoProperties.getWidth(), mediaVideoProperties.getHeight(), mediaVideoProperties.getFrameRate());
|
||||||
// 视频捕获
|
// 视频捕获
|
||||||
this.videoCapturer.initialize(this.surfaceTextureHelper, this.context, new VideoCapturerObserver());
|
this.videoCapturer.initialize(this.surfaceTextureHelper, this.context, new VideoCapturerObserver());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载水印
|
||||||
|
*/
|
||||||
private void initWatermark() {
|
private void initWatermark() {
|
||||||
if(StringUtils.isNotEmpty(this.watermark)) {
|
if(StringUtils.isEmpty(this.watermark)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
final MediaVideoProperties mediaVideoProperties = this.mediaProperties.getVideos().get(this.videoQuantity);
|
final MediaVideoProperties mediaVideoProperties = this.mediaProperties.getVideos().get(this.videoQuantity);
|
||||||
if(this.videoProcesser == null) {
|
if(this.videoProcesser == null) {
|
||||||
this.videoProcesser = new WatermarkProcesser(this.watermark, mediaVideoProperties.getWidth(), mediaVideoProperties.getHeight());
|
this.videoProcesser = new WatermarkProcesser(this.watermark, mediaVideoProperties.getWidth(), mediaVideoProperties.getHeight());
|
||||||
@@ -580,20 +579,31 @@ public final class MediaManager {
|
|||||||
this.videoProcesser = new WatermarkProcesser(this.watermark, mediaVideoProperties.getWidth(), mediaVideoProperties.getHeight(), this.videoProcesser);
|
this.videoProcesser = new WatermarkProcesser(this.watermark, mediaVideoProperties.getWidth(), mediaVideoProperties.getHeight(), this.videoProcesser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 静音远程媒体
|
||||||
|
*/
|
||||||
public void muteAllRemote() {
|
public void muteAllRemote() {
|
||||||
this.javaAudioDeviceModule.setSpeakerMute(true);
|
this.javaAudioDeviceModule.setSpeakerMute(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消远程媒体静音
|
||||||
|
*/
|
||||||
public void unmuteAllRemote() {
|
public void unmuteAllRemote() {
|
||||||
this.javaAudioDeviceModule.setSpeakerMute(false);
|
this.javaAudioDeviceModule.setSpeakerMute(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 静音本地媒体
|
||||||
|
*/
|
||||||
public void muteAllLocal() {
|
public void muteAllLocal() {
|
||||||
this.javaAudioDeviceModule.setMicrophoneMute(true);
|
this.javaAudioDeviceModule.setMicrophoneMute(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消本地媒体静音
|
||||||
|
*/
|
||||||
public void unmuteAllLocal() {
|
public void unmuteAllLocal() {
|
||||||
this.javaAudioDeviceModule.setMicrophoneMute(false);
|
this.javaAudioDeviceModule.setMicrophoneMute(false);
|
||||||
}
|
}
|
||||||
@@ -612,32 +622,55 @@ public final class MediaManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新音频配置
|
||||||
|
*
|
||||||
|
* @param mediaAudioProperties 音频配置
|
||||||
|
*/
|
||||||
public void updateAudioConfig(MediaAudioProperties mediaAudioProperties) {
|
public void updateAudioConfig(MediaAudioProperties mediaAudioProperties) {
|
||||||
this.mediaProperties.setAudio(mediaAudioProperties);
|
this.mediaProperties.setAudio(mediaAudioProperties);
|
||||||
this.updateAudioConfig();
|
this.updateAudioConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新音频配置
|
||||||
|
*/
|
||||||
private void updateAudioConfig() {
|
private void updateAudioConfig() {
|
||||||
MediaAudioProperties mediaAudioProperties = this.mediaProperties.getAudio();
|
MediaAudioProperties mediaAudioProperties = this.mediaProperties.getAudio();
|
||||||
// TODO:调整音频
|
// TODO:调整音频
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新视频配置
|
||||||
|
*
|
||||||
|
* @param mediaVideoProperties 视频配置
|
||||||
|
*/
|
||||||
public void updateVideoConfig(MediaVideoProperties mediaVideoProperties) {
|
public void updateVideoConfig(MediaVideoProperties mediaVideoProperties) {
|
||||||
this.mediaProperties.setVideo(mediaVideoProperties);
|
this.mediaProperties.setVideo(mediaVideoProperties);
|
||||||
this.updateVideoConfig();
|
this.updateVideoConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新视频配置
|
||||||
|
*/
|
||||||
private void updateVideoConfig() {
|
private void updateVideoConfig() {
|
||||||
|
// 更新视频采集
|
||||||
if(this.videoCapturer != null) {
|
if(this.videoCapturer != null) {
|
||||||
final MediaVideoProperties mediaVideoProperties = this.mediaProperties.getVideos().get(this.videoQuantity);
|
final MediaVideoProperties mediaVideoProperties = this.mediaProperties.getVideos().get(this.videoQuantity);
|
||||||
this.videoCapturer.changeCaptureFormat(mediaVideoProperties.getWidth(), mediaVideoProperties.getHeight(), mediaVideoProperties.getFrameRate());
|
this.videoCapturer.changeCaptureFormat(mediaVideoProperties.getWidth(), mediaVideoProperties.getHeight(), mediaVideoProperties.getFrameRate());
|
||||||
}
|
}
|
||||||
|
// 更新共享视频
|
||||||
if(this.shareVideoSource != null) {
|
if(this.shareVideoSource != null) {
|
||||||
final MediaVideoProperties mediaVideoProperties = this.mediaProperties.getVideo();
|
final MediaVideoProperties mediaVideoProperties = this.mediaProperties.getVideo();
|
||||||
this.shareVideoSource.adaptOutputFormat(mediaVideoProperties.getWidth(), mediaVideoProperties.getHeight(), mediaVideoProperties.getFrameRate());
|
this.shareVideoSource.adaptOutputFormat(mediaVideoProperties.getWidth(), mediaVideoProperties.getHeight(), mediaVideoProperties.getFrameRate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新WebRTC配置
|
||||||
|
*
|
||||||
|
* @param webrtcProperties WebRTC配置
|
||||||
|
*/
|
||||||
public void updateWebrtcConfig(WebrtcProperties webrtcProperties) {
|
public void updateWebrtcConfig(WebrtcProperties webrtcProperties) {
|
||||||
this.webrtcProperties = webrtcProperties;
|
this.webrtcProperties = webrtcProperties;
|
||||||
}
|
}
|
||||||
@@ -647,7 +680,7 @@ public final class MediaManager {
|
|||||||
*
|
*
|
||||||
* @param videoSourceType 来源类型
|
* @param videoSourceType 来源类型
|
||||||
*/
|
*/
|
||||||
public void updateVideoSource(VideoSourceType videoSourceType) {
|
public void switchVideoSource(VideoSourceType videoSourceType) {
|
||||||
if (this.videoSourceType == videoSourceType) {
|
if (this.videoSourceType == videoSourceType) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -668,11 +701,20 @@ public final class MediaManager {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
// TODO:测试
|
||||||
// this.initVideo();
|
// this.initVideo();
|
||||||
// 切换所有VideoTrack视频来源
|
// 切换所有VideoTrack视频来源
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新建本地媒体
|
||||||
|
*
|
||||||
|
* @param audioProduce 是否生产音频
|
||||||
|
* @param videoProduce 是否生产视频
|
||||||
|
*
|
||||||
|
* @return 本地媒体
|
||||||
|
*/
|
||||||
public MediaStream buildLocalMediaStream(boolean audioProduce, boolean videoProduce) {
|
public MediaStream buildLocalMediaStream(boolean audioProduce, boolean videoProduce) {
|
||||||
final long id = Thread.currentThread().getId();
|
final long id = Thread.currentThread().getId();
|
||||||
final MediaStream mediaStream = this.peerConnectionFactory.createLocalMediaStream("TaoyaoM" + id);
|
final MediaStream mediaStream = this.peerConnectionFactory.createLocalMediaStream("TaoyaoM" + id);
|
||||||
@@ -687,12 +729,17 @@ public final class MediaManager {
|
|||||||
if(videoProduce) {
|
if(videoProduce) {
|
||||||
final VideoTrack videoTrack = this.peerConnectionFactory.createVideoTrack("TaoyaoV" + id, this.shareVideoSource);
|
final VideoTrack videoTrack = this.peerConnectionFactory.createVideoTrack("TaoyaoV" + id, this.shareVideoSource);
|
||||||
videoTrack.setEnabled(true);
|
videoTrack.setEnabled(true);
|
||||||
Log.i(MediaManager.class.getSimpleName(), "加载视频(次码流):" + videoTrack.id());
|
|
||||||
mediaStream.addTrack(videoTrack);
|
mediaStream.addTrack(videoTrack);
|
||||||
|
Log.i(MediaManager.class.getSimpleName(), "加载视频:" + videoTrack.id());
|
||||||
}
|
}
|
||||||
return mediaStream;
|
return mediaStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新建媒体约束
|
||||||
|
*
|
||||||
|
* @return 媒体约束
|
||||||
|
*/
|
||||||
public MediaConstraints buildMediaConstraints() {
|
public MediaConstraints buildMediaConstraints() {
|
||||||
final MediaConstraints mediaConstraints = new MediaConstraints();
|
final MediaConstraints mediaConstraints = new MediaConstraints();
|
||||||
// ================ PC ================ //
|
// ================ PC ================ //
|
||||||
@@ -726,14 +773,21 @@ public final class MediaManager {
|
|||||||
return mediaConstraints;
|
return mediaConstraints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始采集
|
||||||
|
*/
|
||||||
private void startVideoCapture() {
|
private void startVideoCapture() {
|
||||||
if(this.videoCapturer == null) {
|
if(this.videoCapturer == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final MediaVideoProperties mediaVideoProperties = this.mediaProperties.getVideos().get(this.videoQuantity);
|
final MediaVideoProperties mediaVideoProperties = this.mediaProperties.getVideos().get(this.videoQuantity);
|
||||||
this.videoCapturer.startCapture(mediaVideoProperties.getWidth(), mediaVideoProperties.getHeight(), mediaVideoProperties.getFrameRate());
|
this.videoCapturer.startCapture(mediaVideoProperties.getWidth(), mediaVideoProperties.getHeight(), mediaVideoProperties.getFrameRate());
|
||||||
|
Log.i(MediaManager.class.getSimpleName(), "开始视频采集:" + mediaVideoProperties.getWidth() + "*" + mediaVideoProperties.getHeight() + " - " + mediaVideoProperties.getFrameRate());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭采集
|
||||||
|
*/
|
||||||
private void stopVideoCapture() {
|
private void stopVideoCapture() {
|
||||||
if(this.videoCapturer == null) {
|
if(this.videoCapturer == null) {
|
||||||
return;
|
return;
|
||||||
@@ -741,10 +795,15 @@ public final class MediaManager {
|
|||||||
try {
|
try {
|
||||||
this.videoCapturer.stopCapture();
|
this.videoCapturer.stopCapture();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Log.e(MediaManager.class.getSimpleName(), "关闭视频捕获异常", e);
|
Log.e(MediaManager.class.getSimpleName(), "关闭视频采集异常", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始拍照
|
||||||
|
*
|
||||||
|
* @return 图片文件地址
|
||||||
|
*/
|
||||||
public String photograph() {
|
public String photograph() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
final PhotographClient photographClient = new PhotographClient(this.imageQuantity, this.imagePath);
|
final PhotographClient photographClient = new PhotographClient(this.imageQuantity, this.imagePath);
|
||||||
@@ -758,6 +817,11 @@ public final class MediaManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始录像
|
||||||
|
*
|
||||||
|
* @return 录像终端
|
||||||
|
*/
|
||||||
public RecordClient startRecord() {
|
public RecordClient startRecord() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if(this.recordClient != null) {
|
if(this.recordClient != null) {
|
||||||
@@ -778,6 +842,11 @@ public final class MediaManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束录像
|
||||||
|
*
|
||||||
|
* @return 视频文件地址
|
||||||
|
*/
|
||||||
public String stopRecord() {
|
public String stopRecord() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if(this.recordClient == null) {
|
if(this.recordClient == null) {
|
||||||
@@ -793,6 +862,8 @@ public final class MediaManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 预览视频
|
||||||
|
*
|
||||||
* @param flag Config.WHAT_*
|
* @param flag Config.WHAT_*
|
||||||
* @param videoTrack 视频媒体流Track
|
* @param videoTrack 视频媒体流Track
|
||||||
*
|
*
|
||||||
@@ -822,6 +893,9 @@ public final class MediaManager {
|
|||||||
return surfaceViewRenderer;
|
return surfaceViewRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭媒体
|
||||||
|
*/
|
||||||
private void closeMedia() {
|
private void closeMedia() {
|
||||||
if(this.audioSource != null) {
|
if(this.audioSource != null) {
|
||||||
this.audioSource.dispose();
|
this.audioSource.dispose();
|
||||||
@@ -864,7 +938,13 @@ public final class MediaManager {
|
|||||||
*/
|
*/
|
||||||
private class VideoCapturerObserver implements CapturerObserver {
|
private class VideoCapturerObserver implements CapturerObserver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主码流观察者
|
||||||
|
*/
|
||||||
private CapturerObserver mainObserver;
|
private CapturerObserver mainObserver;
|
||||||
|
/**
|
||||||
|
* 次码流观察者
|
||||||
|
*/
|
||||||
private CapturerObserver shareObserver;
|
private CapturerObserver shareObserver;
|
||||||
|
|
||||||
public VideoCapturerObserver() {
|
public VideoCapturerObserver() {
|
||||||
@@ -963,18 +1043,6 @@ public final class MediaManager {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TextToSpeechInitListener implements TextToSpeech.OnInitListener {
|
|
||||||
@Override
|
|
||||||
public void onInit(int status) {
|
|
||||||
Log.i(MediaManager.class.getSimpleName(), "加载语音播报:" + status);
|
|
||||||
if(status == TextToSpeech.SUCCESS) {
|
|
||||||
MediaManager.this.textToSpeech.setLanguage(Locale.CANADA);
|
|
||||||
MediaManager.this.textToSpeech.setPitch(1.0F);
|
|
||||||
MediaManager.this.textToSpeech.setSpeechRate(1.0F);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载MediasoupClient
|
* 加载MediasoupClient
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import java.util.TimerTask;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 水印处理器
|
* 水印处理器
|
||||||
|
* 只支持时间字符串水印
|
||||||
*
|
*
|
||||||
* 性能优化:
|
* 性能优化:
|
||||||
* 没有水印:20~25波动
|
* 没有水印:20~25波动
|
||||||
|
|||||||
Reference in New Issue
Block a user