Merge branch 'dev' into release

This commit is contained in:
acgist
2024-11-14 10:17:36 +08:00
8 changed files with 180 additions and 31 deletions

View File

@@ -10,14 +10,14 @@ Maven >= 3.8.0
CMake >= 3.26.0 CMake >= 3.26.0
NodeJS >= v18.16.0 NodeJS >= v18.16.0
Python >= 3.8.0 with PIP Python >= 3.8.0 with PIP
ffmpeg >= 4.3.0 FFmpeg >= 4.3.0
gcc/g++ >= 10.2.0 GCC/G++ >= 10.2.0
Android >= 9.0 Android >= 9.0
``` ```
## Debian ## Debian
`CentOS 7`实在是太旧了,软件更新非常麻烦,所以直接使用`Debian`作为测试,系统配置全部使用`root`用户 `CentOS 7`实在是太旧了,软件更新非常麻烦,所以直接使用`Debian`作为测试。
### 系统参数 ### 系统参数
@@ -66,6 +66,7 @@ set nocompatible
vi /etc/network/interfaces vi /etc/network/interfaces
--- ---
auto enp0s3
iface enp0s3 inet static iface enp0s3 inet static
address 192.168.1.110 address 192.168.1.110
gateway 192.168.1.1 gateway 192.168.1.1
@@ -80,6 +81,17 @@ ifup enp0s3
### 设置国内镜像 ### 设置国内镜像
``` ```
# DNS
sudo vim /etc/systemd/resolved.conf
---
DNS=233.5.5.5 233.6.6.6 114.114.114.114 8.8.8.8
---
sudo systemctl restart systemd-resolved
sudo systemctl enable systemd-resolved
sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
# 配置 # 配置
vi /etc/apt/sources.list vi /etc/apt/sources.list
@@ -96,6 +108,7 @@ deb-src https://mirrors.aliyun.com/debian/ bullseye-backports main non-free cont
# 更新系统 # 更新系统
apt update apt update
apt upgrade
``` ```
### 安装依赖 ### 安装依赖
@@ -177,7 +190,7 @@ sudo apt install git
git --version git --version
``` ```
## 安装gcc/g++ ## 安装GCC/G++
``` ```
# 安装 # 安装
@@ -335,7 +348,7 @@ trusted-host = mirrors.aliyun.com
pip config list pip config list
``` ```
## 安装ffmpeg ## 安装FFmpeg
``` ```
mkdir -p /data/dev/ffmpeg ; cd $_ mkdir -p /data/dev/ffmpeg ; cd $_
@@ -395,11 +408,11 @@ wget http://www.ffmpeg.org/releases/ffmpeg-5.1.3.tar.xz
tar -Jxvf ffmpeg-5.1.3.tar.xz tar -Jxvf ffmpeg-5.1.3.tar.xz
cd ffmpeg-5.1.3/ cd ffmpeg-5.1.3/
PKG_CONFIG_PATH="/usr/local/lib/pkgconfig/" PKG_CONFIG_PATH="/usr/local/lib/pkgconfig/"
./configure \ ./configure \
--enable-static \ --enable-static \
--enable-shared \ --enable-shared \
--enable-gpl \ --enable-gpl \
--enable-libvpx \ --enable-libvpx \
--enable-libopus \ --enable-libopus \
--enable-libx264 \ --enable-libx264 \
--enable-libx265 \ --enable-libx265 \
@@ -407,6 +420,15 @@ PKG_CONFIG_PATH="/usr/local/lib/pkgconfig/"
--enable-encoder=libvpx_vp9 --enable-decoder=vp9 --enable-parser=vp9 --enable-encoder=libvpx_vp9 --enable-decoder=vp9 --enable-parser=vp9
make && sudo make install make && sudo make install
# 链接文件
vim /etc/ld.so.conf
---
/usr/local/lib/
---
ldconfig
# 验证 # 验证
ffmpeg -version ffmpeg -version
ffmpeg -decoders ffmpeg -decoders
@@ -488,7 +510,7 @@ pm2 start|stop|restart taoyao-client-media
> 下载依赖建议备份方便再次编译使用 > 下载依赖建议备份方便再次编译使用
### Mediasoup单独编译 ### Mediasoup单独编译(旧版)
编译媒体服务时会自动编译`mediasoup`所以忽略单独编译 编译媒体服务时会自动编译`mediasoup`所以忽略单独编译
@@ -502,6 +524,16 @@ make
make clean make clean
``` ```
### Mediasoup单独编译新版
* 需要`python3``pip3`
* 源码[mediasoup-3.13.16.zip](https://pan.baidu.com/s/1E_DXv32D9ODyj5J-o-ji_g?pwd=hudc)(包含依赖)
```
npm install
node npm-scripts.mjs worker:build
```
## 安装Web终端 ## 安装Web终端
`Nginx``PM2`选择一种启动即可 `Nginx``PM2`选择一种启动即可
@@ -625,7 +657,7 @@ openssl pkcs12 -export -clcerts -in server.crt -inkey server.key -out server.p12
# 设置密码:-deststorepass 123456 # 设置密码:-deststorepass 123456
``` ```
## gcc/g++路径配置 ## GCC/G++路径配置
``` ```
# 安装路径 # 安装路径
@@ -645,11 +677,11 @@ openssl pkcs12 -export -clcerts -in server.crt -inkey server.key -out server.p12
## 清理源码 ## 清理源码
``` ```
sudo rm -rf \ sudo rm -rf \
/data/dev/cmake \ /data/dev/cmake \
/data/dev/ffmpeg \ /data/dev/ffmpeg \
/data/dev/python \ /data/dev/python \
/data/dev/maven/apache-maven-3.8.8-bin.tar.gz \ /data/dev/maven/apache-maven-3.8.8-bin.tar.gz \
/data/dev/nodejs/node-v18.16.0-linux-x64.tar.xz \ /data/dev/nodejs/node-v18.16.0-linux-x64.tar.xz \
/data/dev/java/openjdk-17.0.2_linux-x64_bin.tar.gz /data/dev/java/openjdk-17.0.2_linux-x64_bin.tar.gz
``` ```

View File

@@ -37,6 +37,12 @@
* WebRtcAudioRecord * WebRtcAudioRecord
* WebRtcAudioTrack * WebRtcAudioTrack
## 动态修改码率
```
HardwareVideoEncoder#updateBitrate
```
## 学习资料 ## 学习资料
* https://developer.android.google.cn/docs?hl=zh-cn * https://developer.android.google.cn/docs?hl=zh-cn

View File

@@ -175,6 +175,14 @@ namespace acgist {
* @param env JNIEnv * @param env JNIEnv
*/ */
void closeRoom(JNIEnv* env); void closeRoom(JNIEnv* env);
/**
* 设置码率
*
* @param maxFramerate 最大帧率
* @param minBitrate 最小码率
* @param maxBitrate 最大码率
*/
void setBitrate(int maxFramerate, int minBitrate, int maxBitrate);
}; };
} }

View File

@@ -342,6 +342,8 @@ namespace acgist {
} }
this->factory = factory; this->factory = factory;
this->rtcConfiguration = new webrtc::PeerConnectionInterface::RTCConfiguration(rtcConfiguration); this->rtcConfiguration = new webrtc::PeerConnectionInterface::RTCConfiguration(rtcConfiguration);
// this->rtcConfiguration->set_cpu_adaptation(false);
// this->rtcConfiguration->set_experiment_cpu_load_estimator(false);
mediasoupclient::PeerConnection::Options options; mediasoupclient::PeerConnection::Options options;
options.config = rtcConfiguration; options.config = rtcConfiguration;
options.factory = factory; options.factory = factory;
@@ -418,7 +420,7 @@ namespace acgist {
nlohmann::json codecOptions = nlohmann::json codecOptions =
{ {
// x-google-start-bitrate // x-google-start-bitrate
{ "videoGoogleStartBitrate", 400 }, { "videoGoogleStartBitrate", 1200 },
// x-google-min-bitrate // x-google-min-bitrate
{ "videoGoogleMinBitrate", 800 }, { "videoGoogleMinBitrate", 800 },
// x-google-max-bitrate // x-google-max-bitrate
@@ -552,6 +554,53 @@ namespace acgist {
this->closeRoomCallback(env); this->closeRoomCallback(env);
} }
void Room::setBitrate(int maxFramerate, int minBitrate, int maxBitrate) {
// if(
// this->sendTransport == nullptr ||
// this->sendTransport->sendHandler == nullptr ||
// this->sendTransport->sendHandler->pc == nullptr ||
// this->sendTransport->sendHandler->pc->pc == nullptr
// ) {
// return;
// }
// webrtc::BitrateSettings settings;
// settings.min_bitrate_bps = minBitrate;
// settings.max_bitrate_bps = maxBitrate;
// settings.start_bitrate_bps = minBitrate;
// this->sendTransport->sendHandler->pc->pc->SetBitrate(settings);
webrtc::RtpSenderInterface* rtpSender;
if(
this->videoProducer == nullptr ||
(rtpSender = this->videoProducer->GetRtpSender()) == nullptr
) {
return;
}
webrtc::RtpParameters rtpParameters = rtpSender->GetParameters();
auto& encodings = rtpParameters.encodings;
for(
auto iterator = encodings.begin();
iterator != encodings.end();
++iterator
) {
if(maxFramerate > 0) {
LOG_I("当前最大帧率:%d - %d", maxFramerate, iterator->max_framerate);
iterator->max_framerate = maxFramerate;
}
if(minBitrate > 0) {
LOG_I("当前最小码率:%d - %d", minBitrate, iterator->min_bitrate_bps);
iterator->min_bitrate_bps = minBitrate;
}
if(maxBitrate > 0) {
LOG_I("当前最大码率:%d - %d", maxBitrate, iterator->max_bitrate_bps);
iterator->max_bitrate_bps = maxBitrate;
}
// iterator->bitrate_priority = 4.0;
// iterator->network_priority = webrtc::Priority::kHigh;
// iterator->scale_resolution_down_by = 2;
}
rtpSender->SetParameters(rtpParameters);
}
extern "C" JNIEXPORT jlong JNICALL extern "C" JNIEXPORT jlong JNICALL
Java_com_acgist_taoyao_media_client_Room_nativeNewRoom( Java_com_acgist_taoyao_media_client_Room_nativeNewRoom(
JNIEnv* env, jobject me, JNIEnv* env, jobject me,
@@ -727,4 +776,13 @@ namespace acgist {
env->ReleaseStringUTFChars(jConsumerId, consumerId); env->ReleaseStringUTFChars(jConsumerId, consumerId);
} }
extern "C" JNIEXPORT void JNICALL
Java_com_acgist_taoyao_media_client_Room_nativeSetBitrate(JNIEnv* env, jobject me, jlong nativeRoomPointer, jint maxFramerate, jint minBitrate, jint maxBitrate) {
Room* room = (Room*) nativeRoomPointer;
if(room == nullptr) {
return;
}
room->setBitrate(maxFramerate, minBitrate, maxBitrate);
}
} }

View File

@@ -207,6 +207,7 @@ public class Room extends CloseableClient implements RouterCallback {
iceServers = new ArrayList<>(); iceServers = new ArrayList<>();
} }
this.rtcConfiguration = new PeerConnection.RTCConfiguration(iceServers); this.rtcConfiguration = new PeerConnection.RTCConfiguration(iceServers);
// this.rtcConfiguration.enableCpuOveruseDetection = true;
// 开始协商 // 开始协商
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),
@@ -288,7 +289,7 @@ public class Room extends CloseableClient implements RouterCallback {
"forceTcp", false, "forceTcp", false,
"producing", false, "producing", false,
"consuming", true, "consuming", true,
"sctpCapabilities", this.dataProduce ? this.sctpCapabilities : null "sctpCapabilities", this.dataConsume ? this.sctpCapabilities : null
), ),
response -> { response -> {
this.nativeCreateRecvTransport(this.nativeRoomPointer, JSONUtils.toJSON(response.body())); this.nativeCreateRecvTransport(this.nativeRoomPointer, JSONUtils.toJSON(response.body()));
@@ -382,6 +383,19 @@ public class Room extends CloseableClient implements RouterCallback {
remoteClient.close(); remoteClient.close();
} }
/**
* 动态设置帧率码率
*
* HardwareVideoEncoder#updateBitrate()
*
* @param maxFramerate 最大帧率
* @param minBitrate 最小码率
* @param maxBitrate 最大码率
*/
public void setBitrate(int maxFramerate, int minBitrate, int maxBitrate) {
this.nativeSetBitrate(this.nativeRoomPointer, maxFramerate, minBitrate, maxBitrate);
}
@Override @Override
public void close() { public void close() {
synchronized (this) { synchronized (this) {
@@ -773,4 +787,14 @@ public class Room extends CloseableClient implements RouterCallback {
*/ */
private native void nativeMediaConsumerClose(long nativeRoomPointer, String consumerId); private native void nativeMediaConsumerClose(long nativeRoomPointer, String consumerId);
/**
* Mediasoup设置码率
*
* @param nativeRoomPointer 房间指针
* @param maxFramerate 最大帧率
* @param minBitrate 最小码率
* @param maxBitrate 最大码率
*/
private native void nativeSetBitrate(long nativeRoomPointer, int maxFramerate, int minBitrate, int maxBitrate);
} }

View File

@@ -2329,6 +2329,9 @@ class Taoyao extends RemoteClient {
videoSource: this.videoSource videoSource: this.videoSource
}, },
}); });
// let oldParameters = this.videoProducer.rtpSender.getParameters();
// oldParameters.encodings[0].maxBitrate = 800000;
// this.videoProducer.rtpSender.setParameters(oldParameters);
this.callbackTrack(this.clientId, track); this.callbackTrack(this.clientId, track);
if (this.proxy && this.proxy.media) { if (this.proxy && this.proxy.media) {
this.proxy.media(track, this.videoProducer); this.proxy.media(track, this.videoProducer);
@@ -2839,7 +2842,7 @@ class Taoyao extends RemoteClient {
forceTcp : this.forceTcp, forceTcp : this.forceTcp,
producing : false, producing : false,
consuming : true, consuming : true,
sctpCapabilities: this.dataProduce ? this.mediasoupDevice.sctpCapabilities : undefined, sctpCapabilities: this.dataConsume ? this.mediasoupDevice.sctpCapabilities : undefined,
})); }));
const { const {
transportId, transportId,

View File

@@ -207,7 +207,7 @@ public final class DateUtils {
* *
* @return 日期字符串 * @return 日期字符串
*/ */
public static String format(LocalDate localDate, DateStyle format) { public static final String format(LocalDate localDate, DateStyle format) {
return localDate != null && format != null ? format.getDateTimeFormatter().format(localDate) : null; return localDate != null && format != null ? format.getDateTimeFormatter().format(localDate) : null;
} }
@@ -219,7 +219,7 @@ public final class DateUtils {
* *
* @return 时间字符串 * @return 时间字符串
*/ */
public static String format(LocalTime localTime, TimeStyle format) { public static final String format(LocalTime localTime, TimeStyle format) {
return localTime != null && format != null ? format.getDateTimeFormatter().format(localTime) : null; return localTime != null && format != null ? format.getDateTimeFormatter().format(localTime) : null;
} }
@@ -231,7 +231,7 @@ public final class DateUtils {
* *
* @return 日期时间字符串 * @return 日期时间字符串
*/ */
public static String format(LocalDateTime localDateTime, DateTimeStyle format) { public static final String format(LocalDateTime localDateTime, DateTimeStyle format) {
return localDateTime != null && format != null ? format.getDateTimeFormatter().format(localDateTime) : null; return localDateTime != null && format != null ? format.getDateTimeFormatter().format(localDateTime) : null;
} }

View File

@@ -102,11 +102,14 @@ public final class ErrorUtils {
final MessageCode messageCode = messageCodeException.getMessageCode(); final MessageCode messageCode = messageCodeException.getMessageCode();
status = messageCode.getStatus(); status = messageCode.getStatus();
message = Message.fail(messageCode, messageCodeException.getMessage()); message = Message.fail(messageCode, messageCodeException.getMessage());
} else if(rootError instanceof Throwable throwable) { } else if(
rootError instanceof Throwable rootThrowable &&
globalError instanceof Throwable globalThrowable
) {
// 未知异常:异常转换 // 未知异常:异常转换
final MessageCode messageCode = ErrorUtils.messageCode(status, throwable); final MessageCode messageCode = ErrorUtils.messageCode(status, globalThrowable, rootThrowable);
status = messageCode.getStatus(); status = messageCode.getStatus();
message = Message.fail(messageCode, ErrorUtils.message(messageCode, throwable)); message = Message.fail(messageCode, ErrorUtils.message(messageCode, rootThrowable));
} else { } else {
// 没有异常 // 没有异常
final MessageCode messageCode = MessageCode.of(status); final MessageCode messageCode = MessageCode.of(status);
@@ -193,20 +196,35 @@ public final class ErrorUtils {
} }
/** /**
* @param status 原始状态编码 * @see #messageCode(int, Throwable, Throwable)
* @param throwable 异常 */
public static final MessageCode messageCode(int status, Throwable throwable) {
return ErrorUtils.messageCode(status, throwable, throwable);
}
/**
* @param status 原始状态
* @param globalThrowable 外层异常
* @param rootThrowable 原始异常
* *
* @return 状态编码 * @return 响应状态
* *
* @see ResponseEntityExceptionHandler * @see ResponseEntityExceptionHandler
* @see DefaultHandlerExceptionResolver * @see DefaultHandlerExceptionResolver
*/ */
public static final MessageCode messageCode(int status, Throwable throwable) { public static final MessageCode messageCode(int status, Throwable globalThrowable, Throwable rootThrowable) {
final Class<?> clazz = throwable.getClass(); if(rootThrowable == null || globalThrowable == null) {
return MessageCode.CODE_9999;
}
final Class<?> rootClazz = rootThrowable.getClass();
final Class<?> globalClazz = globalThrowable.getClass();
return CODE_MAPPING.entrySet().stream() return CODE_MAPPING.entrySet().stream()
.filter(entry -> { .filter(entry -> {
final Class<?> mappingClazz = entry.getKey(); final Class<?> mappingClazz = entry.getKey();
return mappingClazz.equals(clazz) || mappingClazz.isAssignableFrom(clazz); return mappingClazz.equals(globalClazz) ||
mappingClazz.isAssignableFrom(globalClazz) ||
mappingClazz.equals(rootClazz) ||
mappingClazz.isAssignableFrom(rootClazz);
}) })
.map(Map.Entry::getValue) .map(Map.Entry::getValue)
.findFirst() .findFirst()
@@ -271,7 +289,7 @@ public final class ErrorUtils {
if(cause instanceof MessageCodeException) { if(cause instanceof MessageCodeException) {
return cause; return cause;
} }
} while(cause != null && (cause = cause.getCause()) != null); } while(cause != null && cause.getCause() != null && (cause = cause.getCause()) != null);
// 返回原始异常 // 返回原始异常
return t; return t;
} }