From 052bb99b2051480ca349723f2a660adf09d01916 Mon Sep 17 00:00:00 2001
From: acgist <289547414@qq.com>
Date: Thu, 18 May 2023 08:19:29 +0800
Subject: [PATCH] =?UTF-8?q?[*]=20=E5=85=BC=E5=AE=B9=E5=AE=89=E5=8D=939?=
=?UTF-8?q?=E3=80=81=E8=A7=A3=E5=86=B3=E5=BD=95=E5=83=8F=E6=B5=8F=E8=A7=88?=
=?UTF-8?q?=E5=99=A8=E6=97=A0=E6=B3=95=E6=92=AD=E6=94=BE=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/TODO.md | 6 ++-
taoyao-client-android/taoyao/README.md | 5 +++
.../taoyao/boot/build.gradle | 2 +-
.../taoyao/client/build.gradle | 2 +-
.../acgist/taoyao/client/signal/Taoyao.java | 11 ++++-
.../taoyao/media/build.gradle | 2 +-
.../taoyao/media/client/RecordClient.java | 41 +++++++++++--------
.../media/video/WatermarkProcesser.java | 7 +++-
taoyao-client-media/src/Config.js | 8 ++++
taoyao-client-web/src/App.vue | 2 +-
.../src/components/LocalClient.vue | 2 +-
.../src/components/RemoteClient.vue | 2 +-
.../src/components/SessionClient.vue | 2 +-
taoyao-client-web/src/components/Taoyao.js | 4 +-
.../boot/config/MediaVideoProperties.java | 2 +-
.../java/com/acgist/taoyao/rtp/RtpTest.java | 6 ++-
.../media/MediaTransportPlainProtocol.java | 4 +-
17 files changed, 74 insertions(+), 34 deletions(-)
diff --git a/docs/TODO.md b/docs/TODO.md
index e250f80..255420b 100644
--- a/docs/TODO.md
+++ b/docs/TODO.md
@@ -20,7 +20,7 @@
* 过时方法
* 缩进调整:`tab->space`
-* 方法调整:`getter/setter`
+* 方法改造:`getter/setter`
* 注释优化:详细描述、单位描述
* 日志优化:
* 添加测试:
@@ -30,13 +30,17 @@
## 计划任务
+* 发布版本:1.0.0
* 开机自启
* 录制底噪
+* 性能测试
+* 稳定性测试
* 分辨率调整
* 服务端录制
* 安卓预览按钮
* 降低视频录制大小
* 防止重复邀请拉取
+* 码率等等参数配置验证
* 查询消费者生产者信息
* 浏览器WebRTC监控页面关闭:`chrome://webrtc-internals/`
diff --git a/taoyao-client-android/taoyao/README.md b/taoyao-client-android/taoyao/README.md
index fe21cec..9acda3e 100644
--- a/taoyao-client-android/taoyao/README.md
+++ b/taoyao-client-android/taoyao/README.md
@@ -1,5 +1,10 @@
# 桃夭安卓
+## 版本
+
+* SDK:28~32
+* Andoird:9~12
+
## WebRTC源码修改
### JavaAudioDeviceModule
diff --git a/taoyao-client-android/taoyao/boot/build.gradle b/taoyao-client-android/taoyao/boot/build.gradle
index a04ef28..79a0ce0 100644
--- a/taoyao-client-android/taoyao/boot/build.gradle
+++ b/taoyao-client-android/taoyao/boot/build.gradle
@@ -6,7 +6,7 @@ android {
namespace 'com.acgist.client.boot'
compileSdk 32
defaultConfig {
- minSdk 30
+ minSdk 28
targetSdk 32
versionCode 100
versionName "1.0.0"
diff --git a/taoyao-client-android/taoyao/client/build.gradle b/taoyao-client-android/taoyao/client/build.gradle
index 7583a69..0fda6f5 100644
--- a/taoyao-client-android/taoyao/client/build.gradle
+++ b/taoyao-client-android/taoyao/client/build.gradle
@@ -6,7 +6,7 @@ android {
namespace 'com.acgist.taoyao.client'
compileSdk 32
defaultConfig {
- minSdk 30
+ minSdk 28
targetSdk 32
versionCode 100
versionName "1.0.0"
diff --git a/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/signal/Taoyao.java b/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/signal/Taoyao.java
index ada7a37..e2a87b0 100644
--- a/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/signal/Taoyao.java
+++ b/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/signal/Taoyao.java
@@ -9,6 +9,7 @@ import android.location.LocationManager;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.BatteryManager;
+import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.PowerManager;
@@ -1254,7 +1255,15 @@ public final class Taoyao implements ITaoyao {
if(wifiInfo == null) {
return -1;
}
- return this.wifiManager.calculateSignalLevel(wifiInfo.getRssi()) / this.wifiManager.getMaxSignalLevel() * 100;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ return this.wifiManager.calculateSignalLevel(wifiInfo.getRssi()) / this.wifiManager.getMaxSignalLevel() * 100;
+ } else {
+ // 0 ~ -50 : 优秀
+ // -50 ~ -70 : 良好
+ // -70 ~ -100: 较差
+ final int rssi = wifiInfo.getRssi();
+ return rssi <= -100 ? 0 : (100 + rssi);
+ }
}
/**
diff --git a/taoyao-client-android/taoyao/media/build.gradle b/taoyao-client-android/taoyao/media/build.gradle
index 623360f..f162ae8 100644
--- a/taoyao-client-android/taoyao/media/build.gradle
+++ b/taoyao-client-android/taoyao/media/build.gradle
@@ -10,7 +10,7 @@ android {
compileSdk 32
ndkVersion "23.1.7779620"
defaultConfig {
- minSdk 30
+ minSdk 28
targetSdk 32
versionCode 100
versionName "1.0.0"
diff --git a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/client/RecordClient.java b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/client/RecordClient.java
index a66907e..50a8cec 100644
--- a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/client/RecordClient.java
+++ b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/client/RecordClient.java
@@ -7,6 +7,7 @@ import android.media.MediaMuxer;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.SystemClock;
import android.util.Log;
import com.acgist.taoyao.boot.utils.DateUtils;
@@ -122,6 +123,11 @@ public class RecordClient extends Client implements VideoSink {
* 视频Handler
*/
private Handler videoHandler;
+ /**
+ * 是否已经开始录制
+ * 不能使用多线程wait/notify录制音频没有结束
+ */
+ private boolean start = false;
/**
* 媒体合成器
*/
@@ -216,16 +222,16 @@ public class RecordClient extends Client implements VideoSink {
if (!this.close && this.videoActive) {
Log.i(RecordClient.class.getSimpleName(), "开始录制文件:" + this.filename);
this.mediaMuxer.start();
- this.notifyAll();
- } else if (!this.close) {
- try {
- this.wait();
- } catch (InterruptedException e) {
- Log.e(RecordClient.class.getSimpleName(), "录制线程等待异常", e);
- }
+ this.start = true;
+ } else {
}
}
} else if (outputIndex >= 0) {
+ if(!this.start) {
+ // 还没开始直接丢弃数据防止通道阻塞
+ this.audioCodec.releaseOutputBuffer(outputIndex, false);
+ continue;
+ }
if(pts == 0L) {
pts = bufferInfo.presentationTimeUs;
}
@@ -234,6 +240,7 @@ public class RecordClient extends Client implements VideoSink {
outputBuffer.limit(bufferInfo.offset + bufferInfo.size);
bufferInfo.presentationTimeUs -= pts;
this.mediaMuxer.writeSampleData(trackIndex, outputBuffer, bufferInfo);
+ // TODO:验证第二个参数作用是否复用
this.audioCodec.releaseOutputBuffer(outputIndex, false);
// Log.d(RecordClient.class.getSimpleName(), "录制音频帧(时间戳):" + (bufferInfo.presentationTimeUs / 1_000_000F));
// if (bufferInfo.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME == MediaCodec.BUFFER_FLAG_KEY_FRAME) {
@@ -298,6 +305,7 @@ public class RecordClient extends Client implements VideoSink {
this.videoActive = true;
final MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
while (!this.close) {
+ // TODO:验证是否其他类型也要releaseOutputBuffer
outputIndex = this.videoCodec.dequeueOutputBuffer(bufferInfo, WAIT_TIME_US);
if (outputIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
// } else if (outputIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
@@ -308,17 +316,16 @@ public class RecordClient extends Client implements VideoSink {
if (!this.close && this.audioActive) {
Log.i(RecordClient.class.getSimpleName(), "开始录制文件:" + this.filename);
this.mediaMuxer.start();
- this.notifyAll();
- } else if (!this.close) {
- try {
- this.wait();
- } catch (InterruptedException e) {
- Log.e(RecordClient.class.getSimpleName(), "录制线程等待异常", e);
- }
+ this.start = true;
} else {
}
}
} else if (outputIndex >= 0) {
+ if(!this.start) {
+ // 还没开始直接丢弃数据防止通道阻塞
+ this.videoCodec.releaseOutputBuffer(outputIndex, false);
+ continue;
+ }
if(pts == 0L) {
pts = bufferInfo.presentationTimeUs / 1000;
}
@@ -396,6 +403,7 @@ public class RecordClient extends Client implements VideoSink {
return;
}
super.close();
+ this.start = false;
Log.i(RecordClient.class.getSimpleName(), "结束录制:" + this.filepath);
if(this.javaAudioDeviceModule != null) {
this.javaAudioDeviceModule.removeMixerProcesser();
@@ -422,7 +430,6 @@ public class RecordClient extends Client implements VideoSink {
Log.i(RecordClient.class.getSimpleName(), "删除没有录制数据文件:" + this.filepath);
file.delete();
}
- this.notifyAll();
this.mediaManager.closeClient();
}
}
@@ -440,7 +447,7 @@ public class RecordClient extends Client implements VideoSink {
* @param data PCM数据
*/
public void onPcm(long pts, byte[] data) {
- if(this.close || !this.audioActive) {
+ if(this.close || !this.audioActive || !this.videoActive) {
return;
}
final int index = this.audioCodec.dequeueInputBuffer(WAIT_TIME_US);
@@ -454,7 +461,7 @@ public class RecordClient extends Client implements VideoSink {
@Override
public void onFrame(VideoFrame videoFrame) {
- if (this.close || !this.videoActive) {
+ if (this.close || !this.audioActive || !this.videoActive) {
return;
}
// Log.d(RecordClient.class.getSimpleName(), "视频信息:" + videoFrame.getRotatedWidth() + " - " + videoFrame.getRotatedHeight());
diff --git a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/video/WatermarkProcesser.java b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/video/WatermarkProcesser.java
index a38d0a6..7492813 100644
--- a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/video/WatermarkProcesser.java
+++ b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/video/WatermarkProcesser.java
@@ -4,6 +4,7 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
+import android.os.Build;
import org.webrtc.VideoFrame;
@@ -88,7 +89,11 @@ public class WatermarkProcesser extends VideoProcesser {
final boolean[][] matrix = new boolean[width][height];
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
- matrix[i][j] = bitmap.getColor(i, j).toArgb() != 0;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ matrix[i][j] = bitmap.getColor(i, j).toArgb() != 0;
+ } else {
+ matrix[i][j] = bitmap.getPixel(i, j) != 0;
+ }
}
}
MATRICES[source] = new WatermarkMatrix(width, height, matrix);
diff --git a/taoyao-client-media/src/Config.js b/taoyao-client-media/src/Config.js
index d7b3899..a431449 100644
--- a/taoyao-client-media/src/Config.js
+++ b/taoyao-client-media/src/Config.js
@@ -73,6 +73,8 @@ module.exports = {
clockRate: 90000,
parameters: {
"x-google-start-bitrate": 1000,
+ // "x-google-min-bitrate": 800,
+ // "x-google-max-bitrate": 1600,
},
},
{
@@ -82,6 +84,8 @@ module.exports = {
parameters: {
"profile-id": 2,
"x-google-start-bitrate": 1000,
+ // "x-google-min-bitrate": 800,
+ // "x-google-max-bitrate": 1600,
},
},
{
@@ -93,6 +97,8 @@ module.exports = {
"profile-level-id": "4d0032",
"level-asymmetry-allowed": 1,
"x-google-start-bitrate": 1000,
+ // "x-google-min-bitrate": 800,
+ // "x-google-max-bitrate": 1600,
},
},
{
@@ -104,6 +110,8 @@ module.exports = {
"profile-level-id": "42e01f",
"level-asymmetry-allowed": 1,
"x-google-start-bitrate": 1000,
+ // "x-google-min-bitrate": 800,
+ // "x-google-max-bitrate": 1600,
},
},
],
diff --git a/taoyao-client-web/src/App.vue b/taoyao-client-web/src/App.vue
index 570e7b4..dbbb2dc 100644
--- a/taoyao-client-web/src/App.vue
+++ b/taoyao-client-web/src/App.vue
@@ -220,7 +220,7 @@ export default {
.client{float:left;width:50vw;height:50vh;box-shadow:0 0 1px 0px rgba(0,0,0,0.4);}
.client audio{display:none;}
.client video{width:100%;height:100%;}
-.client .mic{background:linear-gradient(to top, var(--el-color-primary) 10%, transparent 0%);}
+.client .mic{background:linear-gradient(to top, var(--el-color-primary) 100%, transparent 0%);}
.client .title{position:absolute;top:0;left:0;text-align:center;width:100%;}
.client .buttons{width:100%;bottom:0;left:0;text-align:center;position:absolute;padding:0.8rem 0;background:rgba(0,0,0,0.4);}
.client .buttons .el-button{margin:0 6px;}
diff --git a/taoyao-client-web/src/components/LocalClient.vue b/taoyao-client-web/src/components/LocalClient.vue
index cd0f640..1e05a38 100644
--- a/taoyao-client-web/src/components/LocalClient.vue
+++ b/taoyao-client-web/src/components/LocalClient.vue
@@ -107,5 +107,5 @@ export default {
};
diff --git a/taoyao-client-web/src/components/RemoteClient.vue b/taoyao-client-web/src/components/RemoteClient.vue
index 97e8b22..4d4aeab 100644
--- a/taoyao-client-web/src/components/RemoteClient.vue
+++ b/taoyao-client-web/src/components/RemoteClient.vue
@@ -114,5 +114,5 @@ export default {
};
diff --git a/taoyao-client-web/src/components/SessionClient.vue b/taoyao-client-web/src/components/SessionClient.vue
index 48e44d8..3ce61fd 100644
--- a/taoyao-client-web/src/components/SessionClient.vue
+++ b/taoyao-client-web/src/components/SessionClient.vue
@@ -105,5 +105,5 @@ export default {
};
diff --git a/taoyao-client-web/src/components/Taoyao.js b/taoyao-client-web/src/components/Taoyao.js
index 49b0008..9deb422 100644
--- a/taoyao-client-web/src/components/Taoyao.js
+++ b/taoyao-client-web/src/components/Taoyao.js
@@ -244,7 +244,7 @@ class Session {
// 远程终端名称
name;
// 音量
- volume = 100;
+ volume = "100%";
// 是否关闭
closed;
// 远程终端ID
@@ -382,7 +382,7 @@ class RemoteClient {
// 终端标识
clientId;
// 音量
- volume = 0;
+ volume = "100%";
// 代理对象
proxy;
// 数据消费者
diff --git a/taoyao-signal-server/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/MediaVideoProperties.java b/taoyao-signal-server/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/MediaVideoProperties.java
index 25c22b9..b55bd22 100644
--- a/taoyao-signal-server/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/MediaVideoProperties.java
+++ b/taoyao-signal-server/taoyao-boot/src/main/java/com/acgist/taoyao/boot/config/MediaVideoProperties.java
@@ -10,7 +10,7 @@ import lombok.Setter;
* 视频编码 = 压缩
* 8 = 颜色位数
* 3 / 2 = YUV | RGB
- * 码率(比特率):单位(kbps | kbit/s | kb/s)
+ * 码率(比特率):单位(kbps | kbit/s)
* 码率 = 文件字节大小 * 8 / 秒数 / 1000
* 1Byte = 8bit
*
diff --git a/taoyao-signal-server/taoyao-server/src/test/java/com/acgist/taoyao/rtp/RtpTest.java b/taoyao-signal-server/taoyao-server/src/test/java/com/acgist/taoyao/rtp/RtpTest.java
index f5c3e2e..0feee5e 100644
--- a/taoyao-signal-server/taoyao-server/src/test/java/com/acgist/taoyao/rtp/RtpTest.java
+++ b/taoyao-signal-server/taoyao-server/src/test/java/com/acgist/taoyao/rtp/RtpTest.java
@@ -82,11 +82,13 @@ public class RtpTest {
// {"header":{"v":"1.0.0","id":1215310510002009,"signal":"room::enter"},"body":{"roomId":"8260e615-3081-4bfc-96a8-574f4dd780d9"}}
// {"header":{"v":"1.0.0","id":1215310510002010,"signal":"media::transport::plain"},"body":{"roomId":"8260e615-3081-4bfc-96a8-574f4dd780d9","rtcpMux":false,"comedia":true}}
// {"header":{"v":"1.0.0","id":1215375110006012,"signal":"media::produce"},"body":{"kind":"video","roomId":"8260e615-3081-4bfc-96a8-574f4dd780d9","transportId":"14dc9307-bf9c-4442-a9ad-ce6a97623ef4","appData":{},"rtpParameters":{"codecs":[{"mimeType":"video/vp8","clockRate":90000,"payloadType":102,"rtcpFeedback":[]}],"encodings":[{"ssrc":123123}]}}}
+ // ffmpeg直接播放
+// ffmpeg -re -i video.mp4 -c:a copy -vn -map 0:1 -f rtp rtp://localhost:6666 > taoyao.sdp
+// ffmpeg -re -i video.mp4 -c:v copy -an -map 0:0 -f rtp rtp://localhost:6666 > taoyao.sdp
// ffplay -protocol_whitelist "file,udp,rtp" taoyao.sdp
-// ffmpeg -re -i video.mp4 -vcodec copy -map 0:0 -f rtp rtp://localhost:6666 > taoyao.sdp
// ffmpeg不支持rtcpMux
// ffmpeg -re -i video.mp4 -c:v libvpx -map 0:0 -f tee "[select=v:f=rtp:ssrc=123123:payload_type=102]rtp://192.168.1.110:40793?rtcpport=47218"
-// ffmpeg -re -i video.mp4 -vcodec vp8 -map 0:0 -f tee "[select=v:f=rtp:ssrc=123123:payload_type=102]rtp://192.168.1.110:40793?rtcpport=47218"
+// ffmpeg -re -i video.mp4 -c:v vp8 -map 0:0 -f tee "[select=v:f=rtp:ssrc=123123:payload_type=102]rtp://192.168.1.110:40793?rtcpport=47218"
final Scanner scanner = new Scanner(System.in);
do {
if(StringUtils.isEmpty(line)) {
diff --git a/taoyao-signal-server/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/media/MediaTransportPlainProtocol.java b/taoyao-signal-server/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/media/MediaTransportPlainProtocol.java
index 865ae58..2e2ff59 100644
--- a/taoyao-signal-server/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/media/MediaTransportPlainProtocol.java
+++ b/taoyao-signal-server/taoyao-signal/src/main/java/com/acgist/taoyao/signal/protocol/media/MediaTransportPlainProtocol.java
@@ -23,9 +23,9 @@ import lombok.extern.slf4j.Slf4j;
/**
* 创建RTP输入通道信令
* 注意:
- * 3. ffmpeg不支持rtcpMux
+ * 1. ffmpeg不支持rtcpMux
* 2. comedia必须开启srtp功能
- * 1. 如果关闭comedia不会自动升级双向通道
+ * 3. 如果关闭comedia不会自动升级双向通道
*
* @author acgist
*/