From 891a10e69ce178346978b435bec9ea79825d5a5d Mon Sep 17 00:00:00 2001 From: luvletter2333 Date: Sat, 21 Aug 2021 04:23:27 +0800 Subject: [PATCH] Custom group voip audio bitrate --- .../org_telegram_messenger_voip_Instance.cpp | 5 +- .../tgcalls/group/GroupInstanceCustomImpl.cpp | 42 ++++++++++------- .../tgcalls/group/GroupInstanceCustomImpl.h | 1 + .../media/engine/webrtc_voice_engine.cc | 8 +++- .../messenger/voip/NativeInstance.java | 7 ++- .../java/tw/nekomimi/nekogram/NekoConfig.java | 12 +++++ .../NekoExperimentalSettingsActivity.java | 46 ++++++++++++++++++- .../src/main/res/values/strings_neko.xml | 1 + 8 files changed, 99 insertions(+), 23 deletions(-) diff --git a/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp b/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp index 20140b711..60c71614d 100644 --- a/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp +++ b/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp @@ -342,7 +342,7 @@ void initWebRTC(JNIEnv *env) { FinalStateInitMethod = env->GetMethodID(FinalStateClass, "", "([BLjava/lang/String;Lorg/telegram/messenger/voip/Instance$TrafficStats;Z)V"); } -JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_makeGroupNativeInstance(JNIEnv *env, jclass clazz, jobject instanceObj, jstring logFilePath, jboolean highQuality, jlong videoCapturer, jboolean screencast, jboolean noiseSupression) { +JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_makeGroupNativeInstance(JNIEnv *env, jclass clazz, jobject instanceObj, jstring logFilePath, jboolean highQuality, jlong videoCapturer, jboolean screencast, jboolean noiseSupression, jshort customBitrate) { initWebRTC(env); std::shared_ptr videoCapture = videoCapturer ? std::shared_ptr(reinterpret_cast(videoCapturer)) : nullptr; @@ -396,7 +396,8 @@ JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_makeGrou .videoCapture = videoCapture, .videoContentType = screencast ? VideoContentType::Screencast : VideoContentType::Generic, .initialEnableNoiseSuppression = (bool) noiseSupression, - .platformContext = platformContext + .platformContext = platformContext, + .outgoingAudioBitrateKbit = customBitrate }; if (!screencast) { descriptor.requestBroadcastPart = [](std::shared_ptr platformContext, int64_t timestamp, int64_t duration, std::function callback) -> std::shared_ptr { diff --git a/TMessagesProj/jni/voip/tgcalls/group/GroupInstanceCustomImpl.cpp b/TMessagesProj/jni/voip/tgcalls/group/GroupInstanceCustomImpl.cpp index 6db325929..12b922bb8 100644 --- a/TMessagesProj/jni/voip/tgcalls/group/GroupInstanceCustomImpl.cpp +++ b/TMessagesProj/jni/voip/tgcalls/group/GroupInstanceCustomImpl.cpp @@ -1240,6 +1240,8 @@ std::function videoCaptureToGetVideoSource } // namespace +int GroupInstanceCustomImpl::customAudioBitrate = 0; + class GroupInstanceCustomInternal : public sigslot::has_slots<>, public std::enable_shared_from_this { public: GroupInstanceCustomInternal(GroupInstanceDescriptor &&descriptor, std::shared_ptr threads) : @@ -1266,8 +1268,11 @@ public: _initialOutputDeviceId(std::move(descriptor.initialOutputDeviceId)), _missingPacketBuffer(50), _platformContext(descriptor.platformContext) { + RTC_LOG(LS_INFO) << "Init GroupInstanceCustomImpl with audio bitrate " << _outgoingAudioBitrateKbit << "kbps"; assert(_threads->getMediaThread()->IsCurrent()); + GroupInstanceCustomImpl::customAudioBitrate = _outgoingAudioBitrateKbit * 1000; + _threads->getWorkerThread()->Invoke(RTC_FROM_HERE, [this] { _workerThreadSafery = webrtc::PendingTaskSafetyFlag::Create(); }); @@ -1287,6 +1292,9 @@ public: } ~GroupInstanceCustomInternal() { + RTC_LOG(LS_WARNING) << "~GroupInstanceCustomInternal, reset customAudioBitrate to zero"; + GroupInstanceCustomImpl::customAudioBitrate = 0; + _incomingAudioChannels.clear(); _incomingVideoChannels.clear(); _serverBandwidthProbingVideoSsrc.reset(); @@ -1312,15 +1320,16 @@ public: void start() { const auto weak = std::weak_ptr(shared_from_this()); - webrtc::field_trial::InitFieldTrialsFromString( - "WebRTC-Audio-Allocation/min:32kbps,max:32kbps/" - "WebRTC-Audio-OpusMinPacketLossRate/Enabled-1/" - "WebRTC-TaskQueuePacer/Enabled/" - "WebRTC-VP8ConferenceTemporalLayers/1/" - "WebRTC-Audio-MinimizeResamplingOnMobile/Enabled/" - //"WebRTC-MutedStateKillSwitch/Enabled/" - //"WebRTC-VP8IosMaxNumberOfThread/max_thread:1/" - ); + std::ostringstream stringStream; + stringStream << "WebRTC-Audio-Allocation/min:" << _outgoingAudioBitrateKbit << "kbps,max:" << _outgoingAudioBitrateKbit << "kbps/" + << "WebRTC-Audio-OpusMinPacketLossRate/Enabled-1/" + << "WebRTC-TaskQueuePacer/Enabled/" + << "WebRTC-VP8ConferenceTemporalLayers/1/" + << "WebRTC-Audio-MinimizeResamplingOnMobile/Enabled/"; + // << "WebRTC-MutedStateKillSwitch/Enabled/" + // << "WebRTC-VP8IosMaxNumberOfThread/max_thread:1/" + + webrtc::field_trial::InitFieldTrialsFromString(stringStream.str().c_str()); _networkManager.reset(new ThreadLocalObject(_threads->getNetworkThread(), [weak, threads = _threads] () mutable { return new GroupNetworkManager( @@ -1693,6 +1702,7 @@ public: cricket::AudioOptions audioOptions; if (_disableOutgoingAudioProcessing || _videoContentType == VideoContentType::Screencast) { + RTC_LOG(LS_ERROR) << "outgoing audio processing disabled"; audioOptions.echo_cancellation = false; audioOptions.noise_suppression = false; audioOptions.auto_gain_control = false; @@ -1713,10 +1723,10 @@ public: _outgoingAudioChannel = _channelManager->CreateVoiceChannel(_call.get(), cricket::MediaConfig(), _rtpTransport, _threads->getWorkerThread(), "0", false, GroupNetworkManager::getDefaulCryptoOptions(), _uniqueRandomIdGenerator.get(), audioOptions); - const uint8_t opusMinBitrateKbps = _outgoingAudioBitrateKbit; - const uint8_t opusMaxBitrateKbps = _outgoingAudioBitrateKbit; - const uint8_t opusStartBitrateKbps = _outgoingAudioBitrateKbit; - const uint8_t opusPTimeMs = 120; + int opusMinBitrateKbps = _outgoingAudioBitrateKbit; + int opusMaxBitrateKbps = _outgoingAudioBitrateKbit; + int opusStartBitrateKbps = _outgoingAudioBitrateKbit; + const uint8_t opusPTimeMs = _outgoingAudioBitrateKbit == 32 ? 120 : 10; cricket::AudioCodec opusCodec(111, "opus", 48000, 0, 2); opusCodec.AddFeedbackParam(cricket::FeedbackParam(cricket::kRtcpFbParamTransportCc)); @@ -2293,11 +2303,11 @@ public: preferences.max_bitrate_bps = std::max(preferences.min_bitrate_bps, (1020 + 32) * 1000); } } else { - preferences.min_bitrate_bps = 32000; + preferences.min_bitrate_bps = _outgoingAudioBitrateKbit * 1024; if (resetStartBitrate) { - preferences.start_bitrate_bps = 32000; + preferences.start_bitrate_bps = _outgoingAudioBitrateKbit * 1024; } - preferences.max_bitrate_bps = 32000; + preferences.max_bitrate_bps = _outgoingAudioBitrateKbit * 1024; } settings.min_bitrate_bps = preferences.min_bitrate_bps; diff --git a/TMessagesProj/jni/voip/tgcalls/group/GroupInstanceCustomImpl.h b/TMessagesProj/jni/voip/tgcalls/group/GroupInstanceCustomImpl.h index 41f75c02d..2d9b2cffe 100644 --- a/TMessagesProj/jni/voip/tgcalls/group/GroupInstanceCustomImpl.h +++ b/TMessagesProj/jni/voip/tgcalls/group/GroupInstanceCustomImpl.h @@ -18,6 +18,7 @@ class Threads; class GroupInstanceCustomImpl final : public GroupInstanceInterface { public: + static int customAudioBitrate; explicit GroupInstanceCustomImpl(GroupInstanceDescriptor &&descriptor); ~GroupInstanceCustomImpl(); diff --git a/TMessagesProj/jni/voip/webrtc/media/engine/webrtc_voice_engine.cc b/TMessagesProj/jni/voip/webrtc/media/engine/webrtc_voice_engine.cc index a23d9ac24..eedfa8ee5 100644 --- a/TMessagesProj/jni/voip/webrtc/media/engine/webrtc_voice_engine.cc +++ b/TMessagesProj/jni/voip/webrtc/media/engine/webrtc_voice_engine.cc @@ -52,6 +52,7 @@ #include "rtc_base/third_party/base64/base64.h" #include "rtc_base/trace_event.h" #include "system_wrappers/include/metrics.h" +#include "../../../tgcalls/group/GroupInstanceCustomImpl.h" #if WEBRTC_ENABLE_PROTOBUF RTC_PUSH_IGNORING_WUNDEF() @@ -1105,6 +1106,11 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream max_send_bitrate_bps_, rtp_parameters_.encodings[0].max_bitrate_bps, *audio_codec_spec_); + if (tgcalls::GroupInstanceCustomImpl::customAudioBitrate != 0) { + config_.send_codec_spec->target_bitrate_bps = tgcalls::GroupInstanceCustomImpl::customAudioBitrate; + config_.max_bitrate_bps = tgcalls::GroupInstanceCustomImpl::customAudioBitrate; + config_.min_bitrate_bps = tgcalls::GroupInstanceCustomImpl::customAudioBitrate; + } UpdateAllowedBitrateRange(); // Encoder will only use two channels if the stereo parameter is set. @@ -1831,7 +1837,7 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs( // "unchanged" so that BWE isn't affected. bitrate_config.start_bitrate_bps = -1; } - call_->GetTransportControllerSend()->SetSdpBitrateParameters(bitrate_config); + call_->GetTransportControllerSend()->SetSdpBitrateParameters(bitrate_config); // here // Check if the transport cc feedback or NACK status has changed on the // preferred send codec, and in that case reconfigure all receive streams. diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/voip/NativeInstance.java b/TMessagesProj/src/main/java/org/telegram/messenger/voip/NativeInstance.java index 3b32b68e9..5a8d3a199 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/voip/NativeInstance.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/voip/NativeInstance.java @@ -11,6 +11,8 @@ import org.webrtc.VideoSink; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; +import tw.nekomimi.nekogram.NekoConfig; + public class NativeInstance { private Instance.OnStateUpdatedListener onStateUpdatedListener; @@ -63,6 +65,7 @@ public class NativeInstance { } public static NativeInstance makeGroup(String logPath, long videoCapturer, boolean screencast, boolean noiseSupression, PayloadCallback payloadCallback, AudioLevelsCallback audioLevelsCallback, VideoSourcesCallback unknownParticipantsCallback, RequestBroadcastPartCallback requestBroadcastPartCallback, RequestBroadcastPartCallback cancelRequestBroadcastPartCallback) { + // NekoX: Custom Audio Bitrate ContextUtils.initialize(ApplicationLoader.applicationContext); NativeInstance instance = new NativeInstance(); instance.payloadCallback = payloadCallback; @@ -71,7 +74,7 @@ public class NativeInstance { instance.requestBroadcastPartCallback = requestBroadcastPartCallback; instance.cancelRequestBroadcastPartCallback = cancelRequestBroadcastPartCallback; instance.isGroup = true; - instance.nativePtr = makeGroupNativeInstance(instance, logPath, SharedConfig.disableVoiceAudioEffects, videoCapturer, screencast, noiseSupression); + instance.nativePtr = makeGroupNativeInstance(instance, logPath, SharedConfig.disableVoiceAudioEffects, videoCapturer, screencast, noiseSupression, NekoConfig.customAudioBitrate); return instance; } @@ -188,7 +191,7 @@ public class NativeInstance { stopGroupNative(); } - private static native long makeGroupNativeInstance(NativeInstance instance, String persistentStateFilePath, boolean highQuality, long videoCapturer, boolean screencast, boolean noiseSupression); + private static native long makeGroupNativeInstance(NativeInstance instance, String persistentStateFilePath, boolean highQuality, long videoCapturer, boolean screencast, boolean noiseSupression, short customBitrate); private static native long makeNativeInstance(String version, NativeInstance instance, Instance.Config config, String persistentStateFilePath, Instance.Endpoint[] endpoints, Instance.Proxy proxy, int networkType, Instance.EncryptionKey encryptionKey, VideoSink remoteSink, long videoCapturer, float aspectRatio); public static native long createVideoCapturer(VideoSink localSink, int type); public static native void setVideoStateCapturer(long videoCapturer, int videoState); diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/NekoConfig.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/NekoConfig.java index e9f97b244..56a610a08 100644 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/NekoConfig.java +++ b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/NekoConfig.java @@ -156,6 +156,8 @@ public class NekoConfig { public static boolean enableStickerPin; public static boolean useMediaStreamInVoip; + public static short customAudioBitrate = 320; + public static boolean disableGroupVoipAudioProcessing = false; public static String getOpenPGPAppName() { @@ -326,6 +328,8 @@ public class NekoConfig { enableStickerPin = preferences.getBoolean("enableStickerPin", false); useMediaStreamInVoip = preferences.getBoolean("useMediaStreamInVoip", false); + customAudioBitrate = (short) preferences.getInt("customAudioBitrate", 32); + disableGroupVoipAudioProcessing = preferences.getBoolean("disableGroupVoipAudioProcessing", false); } @@ -835,6 +839,14 @@ public class NekoConfig { preferences.edit().putBoolean("useMediaStreamInVoip", useMediaStreamInVoip = !useMediaStreamInVoip).apply(); } + public static void setCustomAudioBitrate(int bitrate) { + preferences.edit().putInt("customAudioBitrate", customAudioBitrate = (short) bitrate).apply(); + } + + public static void toggleDisableGroupVoipAudioProcessing() { + preferences.edit().putBoolean("disableGroupVoipAudioProcessing", disableGroupVoipAudioProcessing = !disableGroupVoipAudioProcessing).apply(); + } + private static final String EMOJI_FONT_AOSP = "NotoColorEmoji.ttf"; public static Typeface getSystemEmojiTypeface() { diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoExperimentalSettingsActivity.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoExperimentalSettingsActivity.java index f5f065106..cfd7f918b 100644 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoExperimentalSettingsActivity.java +++ b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoExperimentalSettingsActivity.java @@ -40,8 +40,10 @@ import org.telegram.ui.Components.UndoView; import java.util.ArrayList; +import kotlin.Unit; import tw.nekomimi.nekogram.NekoConfig; import tw.nekomimi.nekogram.NekoXConfig; +import tw.nekomimi.nekogram.PopupBuilder; @SuppressLint("RtlHardcoded") public class NekoExperimentalSettingsActivity extends BaseFragment { @@ -66,6 +68,7 @@ public class NekoExperimentalSettingsActivity extends BaseFragment { private int unlimitedPinnedDialogsRow; private int enableStickerPinRow; private int useMediaStreamInVoipRow; + private int customAudioBitrateRow; private int experiment2Row; private UndoView tooltip; @@ -181,11 +184,33 @@ public class NekoExperimentalSettingsActivity extends BaseFragment { tooltip.setInfoText(AndroidUtilities.replaceTags(LocaleController.formatString("EnableStickerPinTip", R.string.EnableStickerPinTip))); tooltip.showWithAction(0, UndoView.ACTION_CACHE_WAS_CLEARED, null, null); } - } else if (position == useMediaStreamInVoipRow){ + } else if (position == useMediaStreamInVoipRow) { NekoConfig.toggleUseMediaStreamInVoip(); if (view instanceof TextCheckCell) { ((TextCheckCell) view).setChecked(NekoConfig.useMediaStreamInVoip); } + } else if (position == customAudioBitrateRow) { + PopupBuilder builder = new PopupBuilder(view); + builder.setItems(new String[]{ + "32 (" + LocaleController.getString("Default", R.string.Default) + ")", + "64", + "128", + "192", + "256", + "320" + }, (i, __)->{ + switch (i) { + case 0 : NekoConfig.setCustomAudioBitrate(32); break; + case 1 : NekoConfig.setCustomAudioBitrate(64); break; + case 2 : NekoConfig.setCustomAudioBitrate(128); break; + case 3 : NekoConfig.setCustomAudioBitrate(192); break; + case 4 : NekoConfig.setCustomAudioBitrate(256); break; + case 5 : NekoConfig.setCustomAudioBitrate(320); break; + } + listAdapter.notifyItemChanged(customAudioBitrateRow); + return Unit.INSTANCE; + }); + builder.show(); } }); @@ -218,6 +243,7 @@ public class NekoExperimentalSettingsActivity extends BaseFragment { unlimitedPinnedDialogsRow = rowCount++; enableStickerPinRow = rowCount++; useMediaStreamInVoipRow = rowCount++; + customAudioBitrateRow = rowCount++; experiment2Row = rowCount++; if (listAdapter != null) { listAdapter.notifyDataSetChanged(); @@ -334,6 +360,16 @@ public class NekoExperimentalSettingsActivity extends BaseFragment { } break; } + case 2: { + TextSettingsCell textCell = (TextSettingsCell) holder.itemView; + textCell.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + if (position == customAudioBitrateRow) { + String value = String.valueOf(NekoConfig.customAudioBitrate) + "kbps"; + if(NekoConfig.customAudioBitrate==32) value += " (" + LocaleController.getString("Default", R.string.Default) + ")"; + textCell.setTextAndValue(LocaleController.getString("customGroupVoipAudioBitrate", R.string.customGroupVoipAudioBitrate), value, true); + } + break; + } case 3: { TextCheckCell textCell = (TextCheckCell) holder.itemView; textCell.setEnabled(true, null); @@ -355,7 +391,7 @@ public class NekoExperimentalSettingsActivity extends BaseFragment { } else if (position == increaseVoiceMessageQualityRow) { textCell.setTextAndCheck(LocaleController.getString("IncreaseVoiceMessageQuality", R.string.IncreaseVoiceMessageQuality), NekoConfig.increaseVoiceMessageQuality, true); } else if (position == enableStickerPinRow) { - textCell.setTextAndValueAndCheck(LocaleController.getString("EnableStickerPin", R.string.EnableStickerPin), LocaleController.getString("EnableStickerPinAbout", R.string.EnableStickerPinAbout), NekoConfig.enableStickerPin, true,true); + textCell.setTextAndValueAndCheck(LocaleController.getString("EnableStickerPin", R.string.EnableStickerPin), LocaleController.getString("EnableStickerPinAbout", R.string.EnableStickerPinAbout), NekoConfig.enableStickerPin, true, true); } else if (position == useMediaStreamInVoipRow) { textCell.setTextAndCheck(LocaleController.getString("UseMediaStreamInVoip", R.string.UseMediaStreamInVoip), NekoConfig.useMediaStreamInVoip, true); } @@ -384,6 +420,10 @@ public class NekoExperimentalSettingsActivity extends BaseFragment { case 1: view = new ShadowSectionCell(mContext); break; + case 2: + view = new TextSettingsCell(mContext); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; case 3: view = new TextCheckCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); @@ -416,6 +456,8 @@ public class NekoExperimentalSettingsActivity extends BaseFragment { return 1; } else if (position == experimentRow) { return 4; + } else if (position == customAudioBitrateRow) { + return 2; } return 3; } diff --git a/TMessagesProj/src/main/res/values/strings_neko.xml b/TMessagesProj/src/main/res/values/strings_neko.xml index be7933282..24d7113d2 100644 --- a/TMessagesProj/src/main/res/values/strings_neko.xml +++ b/TMessagesProj/src/main/res/values/strings_neko.xml @@ -116,5 +116,6 @@ Hide time for stickers Use system DNS Custom DoH + Group Voip Audio Bitrate \ No newline at end of file