diff --git a/docs/Deploy.md b/docs/Deploy.md index 48eb85d..bf7ad3b 100644 --- a/docs/Deploy.md +++ b/docs/Deploy.md @@ -10,14 +10,14 @@ Maven >= 3.8.0 CMake >= 3.26.0 NodeJS >= v18.16.0 Python >= 3.8.0 with PIP -ffmpeg >= 4.3.0 -gcc/g++ >= 10.2.0 +FFmpeg >= 4.3.0 +GCC/G++ >= 10.2.0 Android >= 9.0 ``` ## Debian -`CentOS 7`实在是太旧了,软件更新非常麻烦,所以直接使用`Debian`作为测试,系统配置全部使用`root`用户。 +`CentOS 7`实在是太旧了,软件更新非常麻烦,所以直接使用`Debian`作为测试。 ### 系统参数 @@ -66,6 +66,7 @@ set nocompatible vi /etc/network/interfaces --- +auto enp0s3 iface enp0s3 inet static address 192.168.1.110 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 @@ -96,6 +108,7 @@ deb-src https://mirrors.aliyun.com/debian/ bullseye-backports main non-free cont # 更新系统 apt update +apt upgrade ``` ### 安装依赖 @@ -177,7 +190,7 @@ sudo apt install git git --version ``` -## 安装gcc/g++ +## 安装GCC/G++ ``` # 安装 @@ -335,7 +348,7 @@ trusted-host = mirrors.aliyun.com pip config list ``` -## 安装ffmpeg +## 安装FFmpeg ``` 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 cd ffmpeg-5.1.3/ PKG_CONFIG_PATH="/usr/local/lib/pkgconfig/" -./configure \ ---enable-static \ ---enable-shared \ ---enable-gpl \ ---enable-libvpx \ +./configure \ +--enable-static \ +--enable-shared \ +--enable-gpl \ +--enable-libvpx \ --enable-libopus \ --enable-libx264 \ --enable-libx265 \ @@ -407,6 +420,15 @@ PKG_CONFIG_PATH="/usr/local/lib/pkgconfig/" --enable-encoder=libvpx_vp9 --enable-decoder=vp9 --enable-parser=vp9 make && sudo make install +# 链接文件 +vim /etc/ld.so.conf + +--- +/usr/local/lib/ +--- + +ldconfig + # 验证 ffmpeg -version ffmpeg -decoders @@ -488,7 +510,7 @@ pm2 start|stop|restart taoyao-client-media > 下载依赖建议备份方便再次编译使用 -### Mediasoup单独编译 +### Mediasoup单独编译(旧版) 编译媒体服务时会自动编译`mediasoup`所以忽略单独编译 @@ -502,6 +524,16 @@ make 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终端 `Nginx`和`PM2`选择一种启动即可 @@ -625,7 +657,7 @@ openssl pkcs12 -export -clcerts -in server.crt -inkey server.key -out server.p12 # 设置密码:-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 \ -/data/dev/cmake \ +sudo rm -rf \ +/data/dev/cmake \ /data/dev/ffmpeg \ /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/java/openjdk-17.0.2_linux-x64_bin.tar.gz ``` diff --git a/taoyao-client-android/README.md b/taoyao-client-android/README.md index 2d631d4..f3c4ce7 100644 --- a/taoyao-client-android/README.md +++ b/taoyao-client-android/README.md @@ -37,6 +37,12 @@ * WebRtcAudioRecord * WebRtcAudioTrack +## 动态修改码率 + +``` +HardwareVideoEncoder#updateBitrate +``` + ## 学习资料 * https://developer.android.google.cn/docs?hl=zh-cn diff --git a/taoyao-client-android/taoyao/media/src/main/cpp/include/Room.hpp b/taoyao-client-android/taoyao/media/src/main/cpp/include/Room.hpp index 346c3f6..69e1a0e 100644 --- a/taoyao-client-android/taoyao/media/src/main/cpp/include/Room.hpp +++ b/taoyao-client-android/taoyao/media/src/main/cpp/include/Room.hpp @@ -175,6 +175,14 @@ namespace acgist { * @param env JNIEnv */ void closeRoom(JNIEnv* env); + /** + * 设置码率 + * + * @param maxFramerate 最大帧率 + * @param minBitrate 最小码率 + * @param maxBitrate 最大码率 + */ + void setBitrate(int maxFramerate, int minBitrate, int maxBitrate); }; } \ No newline at end of file diff --git a/taoyao-client-android/taoyao/media/src/main/cpp/webrtc/Room.cpp b/taoyao-client-android/taoyao/media/src/main/cpp/webrtc/Room.cpp index a45c0b5..dd71358 100644 --- a/taoyao-client-android/taoyao/media/src/main/cpp/webrtc/Room.cpp +++ b/taoyao-client-android/taoyao/media/src/main/cpp/webrtc/Room.cpp @@ -342,6 +342,8 @@ namespace acgist { } this->factory = factory; 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; options.config = rtcConfiguration; options.factory = factory; @@ -418,7 +420,7 @@ namespace acgist { nlohmann::json codecOptions = { // x-google-start-bitrate - { "videoGoogleStartBitrate", 400 }, + { "videoGoogleStartBitrate", 1200 }, // x-google-min-bitrate { "videoGoogleMinBitrate", 800 }, // x-google-max-bitrate @@ -552,6 +554,53 @@ namespace acgist { 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 Java_com_acgist_taoyao_media_client_Room_nativeNewRoom( JNIEnv* env, jobject me, @@ -727,4 +776,13 @@ namespace acgist { 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); + } + } diff --git a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/client/Room.java b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/client/Room.java index 9f89a1d..0170524 100644 --- a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/client/Room.java +++ b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/client/Room.java @@ -207,6 +207,7 @@ public class Room extends CloseableClient implements RouterCallback { iceServers = new ArrayList<>(); } this.rtcConfiguration = new PeerConnection.RTCConfiguration(iceServers); +// this.rtcConfiguration.enableCpuOveruseDetection = true; // 开始协商 return this.taoyao.requestFuture( this.taoyao.buildMessage("media::router::rtp::capabilities", "roomId", this.roomId), @@ -288,7 +289,7 @@ public class Room extends CloseableClient implements RouterCallback { "forceTcp", false, "producing", false, "consuming", true, - "sctpCapabilities", this.dataProduce ? this.sctpCapabilities : null + "sctpCapabilities", this.dataConsume ? this.sctpCapabilities : null ), response -> { this.nativeCreateRecvTransport(this.nativeRoomPointer, JSONUtils.toJSON(response.body())); @@ -382,6 +383,19 @@ public class Room extends CloseableClient implements RouterCallback { 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 public void close() { synchronized (this) { @@ -773,4 +787,14 @@ public class Room extends CloseableClient implements RouterCallback { */ 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); + } diff --git a/taoyao-client-web/src/components/Taoyao.js b/taoyao-client-web/src/components/Taoyao.js index de963bb..3c670f2 100644 --- a/taoyao-client-web/src/components/Taoyao.js +++ b/taoyao-client-web/src/components/Taoyao.js @@ -2329,6 +2329,9 @@ class Taoyao extends RemoteClient { videoSource: this.videoSource }, }); + // let oldParameters = this.videoProducer.rtpSender.getParameters(); + // oldParameters.encodings[0].maxBitrate = 800000; + // this.videoProducer.rtpSender.setParameters(oldParameters); this.callbackTrack(this.clientId, track); if (this.proxy && this.proxy.media) { this.proxy.media(track, this.videoProducer); @@ -2839,7 +2842,7 @@ class Taoyao extends RemoteClient { forceTcp : this.forceTcp, producing : false, consuming : true, - sctpCapabilities: this.dataProduce ? this.mediasoupDevice.sctpCapabilities : undefined, + sctpCapabilities: this.dataConsume ? this.mediasoupDevice.sctpCapabilities : undefined, })); const { transportId, diff --git a/taoyao-signal-server/taoyao-boot/src/main/java/com/acgist/taoyao/boot/utils/DateUtils.java b/taoyao-signal-server/taoyao-boot/src/main/java/com/acgist/taoyao/boot/utils/DateUtils.java index c9fdf0f..6aa384a 100644 --- a/taoyao-signal-server/taoyao-boot/src/main/java/com/acgist/taoyao/boot/utils/DateUtils.java +++ b/taoyao-signal-server/taoyao-boot/src/main/java/com/acgist/taoyao/boot/utils/DateUtils.java @@ -207,7 +207,7 @@ public final class DateUtils { * * @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; } @@ -219,7 +219,7 @@ public final class DateUtils { * * @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; } @@ -231,7 +231,7 @@ public final class DateUtils { * * @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; } diff --git a/taoyao-signal-server/taoyao-boot/src/main/java/com/acgist/taoyao/boot/utils/ErrorUtils.java b/taoyao-signal-server/taoyao-boot/src/main/java/com/acgist/taoyao/boot/utils/ErrorUtils.java index 54dce19..55a4f85 100644 --- a/taoyao-signal-server/taoyao-boot/src/main/java/com/acgist/taoyao/boot/utils/ErrorUtils.java +++ b/taoyao-signal-server/taoyao-boot/src/main/java/com/acgist/taoyao/boot/utils/ErrorUtils.java @@ -102,11 +102,14 @@ public final class ErrorUtils { final MessageCode messageCode = messageCodeException.getMessageCode(); status = messageCode.getStatus(); 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(); - message = Message.fail(messageCode, ErrorUtils.message(messageCode, throwable)); + message = Message.fail(messageCode, ErrorUtils.message(messageCode, rootThrowable)); } else { // 没有异常 final MessageCode messageCode = MessageCode.of(status); @@ -193,20 +196,35 @@ public final class ErrorUtils { } /** - * @param status 原始状态编码 - * @param throwable 异常 + * @see #messageCode(int, Throwable, 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 DefaultHandlerExceptionResolver */ - public static final MessageCode messageCode(int status, Throwable throwable) { - final Class clazz = throwable.getClass(); + public static final MessageCode messageCode(int status, Throwable globalThrowable, Throwable rootThrowable) { + if(rootThrowable == null || globalThrowable == null) { + return MessageCode.CODE_9999; + } + final Class rootClazz = rootThrowable.getClass(); + final Class globalClazz = globalThrowable.getClass(); return CODE_MAPPING.entrySet().stream() .filter(entry -> { 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) .findFirst() @@ -271,7 +289,7 @@ public final class ErrorUtils { if(cause instanceof MessageCodeException) { return cause; } - } while(cause != null && (cause = cause.getCause()) != null); + } while(cause != null && cause.getCause() != null && (cause = cause.getCause()) != null); // 返回原始异常 return t; }