Skip to content

Commit cd3e60a

Browse files
committed
add network status
1 parent 0ced439 commit cd3e60a

10 files changed

Lines changed: 114 additions & 20 deletions

File tree

src/main/java/cn/ussshenzhou/channel/audio/OpusManager.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package cn.ussshenzhou.channel.audio;
22

3-
import cn.ussshenzhou.channel.util.ModConstant;
3+
import cn.ussshenzhou.channel.util.TimeCounter;
44
import com.mojang.logging.LogUtils;
55
import io.github.jaredmdobson.concentus.*;
66

77
import java.util.Arrays;
88
import java.util.HashMap;
9-
import java.util.Map;
109
import java.util.UUID;
1110

1211
/**
@@ -23,13 +22,15 @@ private record Decoder(int sampleRate, OpusDecoder decoder) {
2322

2423
private static Encoder encoder;
2524
private static HashMap<UUID, Decoder> decoders = new HashMap<>();
25+
public static final TimeCounter SEND_SPEED = new TimeCounter(1000);
2626

2727
public static byte[] encode(byte[] audio, int sampleRate) throws OpusException {
2828
if (encoder == null || encoder.sampleRate != sampleRate) {
2929
encoder = new Encoder(sampleRate, new OpusEncoder(sampleRate, 1, sampleRate <= 16000 ? OpusApplication.OPUS_APPLICATION_VOIP : OpusApplication.OPUS_APPLICATION_AUDIO));
3030
}
3131
byte[] result = new byte[audio.length];
3232
var length = encoder.encoder.encode(audio, 0, audio.length / 2, result, 0, result.length);
33+
SEND_SPEED.put(length);
3334
return Arrays.copyOf(result, length);
3435
}
3536

src/main/java/cn/ussshenzhou/channel/audio/Unit.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cn.ussshenzhou.channel.audio;
22

33
import cn.ussshenzhou.channel.util.AudioHelper;
4+
import cn.ussshenzhou.channel.util.ModConstant;
45
import cn.ussshenzhou.t88.gui.util.ITranslatable;
56

67
/**
@@ -33,10 +34,10 @@ public String getFS(double value) {
3334
}
3435

3536
@SuppressWarnings("AlibabaLowerCamelCaseVariableNaming")
36-
public String getFS90(double value) {
37+
public String getFSCorrected(double value) {
3738
return switch (this) {
38-
case DB -> value == 0 ? "-∞ dBFS" : String.format("%.1f dBFS", value - 90);
39-
case PERCENT -> String.format("%.2f", AudioHelper.db2factor((float) value - 90) * 100) + "%";
39+
case DB -> value == 0 ? "-∞ dBFS" : String.format("%.1f dBFS", value - ModConstant.ABS_MIN_DBFS);
40+
case PERCENT -> String.format("%.2f", AudioHelper.db2factor((float) value - ModConstant.ABS_MIN_DBFS) * 100) + "%";
4041
};
4142
}
4243

src/main/java/cn/ussshenzhou/channel/gui/InputConfigPanel.java

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import cn.ussshenzhou.channel.util.AudioHelper;
1313
import cn.ussshenzhou.channel.util.ModConstant;
1414
import cn.ussshenzhou.t88.gui.advanced.TOptionsPanel;
15-
import cn.ussshenzhou.t88.gui.notification.TSimpleNotification;
1615
import cn.ussshenzhou.t88.gui.util.ImageFit;
1716
import cn.ussshenzhou.t88.gui.widegt.TCycleButton;
1817
import cn.ussshenzhou.t88.gui.widegt.TImage;
@@ -25,7 +24,6 @@
2524
import org.joml.Vector2i;
2625

2726
import javax.sound.sampled.*;
28-
import java.util.LinkedHashSet;
2927
import java.util.List;
3028
import java.util.stream.Stream;
3129

@@ -59,17 +57,17 @@ public InputConfigPanel() {
5957
.getB().setTooltip(Tooltip.create(Component.translatable("channel.config.mic.samplebits.tooltip")));
6058
addOption(
6159
Component.translatable("channel.config.level"),
62-
new TProgressBar(90) {
60+
new TProgressBar(ModConstant.ABS_MIN_DBFS) {
6361
{
6462
//this.setProgressBarColorGradient(0xff44ff00, 0xffff5900);
6563
this.setProgressBarColorGradient(0x003c91ff, 0xff3c91ff);
66-
this.setTextMode(new TextMode((_, _, value) -> cfg.unit.getFS90(value)));
64+
this.setTextMode(new TextMode((_, _, value) -> cfg.unit.getFSCorrected(value)));
6765
this.setTooltip(Tooltip.create(Component.translatable("channel.config.level.raw.tooltip")));
6866
}
6967

7068
@Override
7169
public void tickT() {
72-
this.setValue(Mth.clamp(90 + AudioHelper.s2dbfs(LevelGatherer.getRaw()), 0, 90));
70+
this.setValue(Mth.clamp(ModConstant.ABS_MIN_DBFS + AudioHelper.s2dbfs(LevelGatherer.getRaw()), 0, ModConstant.ABS_MIN_DBFS));
7371
super.tickT();
7472
}
7573
}
@@ -119,7 +117,7 @@ public void tickT() {
119117
).getB().setTooltip(Tooltip.create(Component.translatable(cfg.trigger.directTranslateKey() + ".tooltip")));
120118
thresholdLevel = (HorizontalTitledOption<?>) addOptionSliderDoubleInit(
121119
Component.translatable("channel.config.pre.threshold"),
122-
-90, -1,
120+
-ModConstant.ABS_MIN_DBFS, -1,
123121
(_, v) -> Component.literal(cfg.unit.getFS(v)),
124122
Component.translatable("channel.config.pre.threshold.tooltip"),
125123
(slider, _) -> ChannelClientConfig.write(c -> c.triggerThresholdDBFS = (float) slider.getAbsValue()),
@@ -218,17 +216,17 @@ public Vector2i getPreferredSize() {
218216
maxGain.setVisibleT(cfg.autoGainControl);
219217
addOption(
220218
Component.translatable("channel.config.level"),
221-
new TProgressBar(90) {
219+
new TProgressBar(ModConstant.ABS_MIN_DBFS) {
222220
{
223221
//this.setProgressBarColorGradient(0xff44ff00, 0xffff5900);
224222
this.setProgressBarColorGradient(0x003c91ff, 0xff3c91ff);
225-
this.setTextMode(new TextMode((_, _, value) -> cfg.unit.getFS90(value)));
223+
this.setTextMode(new TextMode((_, _, value) -> cfg.unit.getFSCorrected(value)));
226224
this.setTooltip(Tooltip.create(Component.translatable("channel.config.level.pro.tooltip")));
227225
}
228226

229227
@Override
230228
public void tickT() {
231-
this.setValue(Mth.clamp(90 + AudioHelper.s2dbfs(LevelGatherer.getProcessed()), 0, 90));
229+
this.setValue(Mth.clamp(ModConstant.ABS_MIN_DBFS + AudioHelper.s2dbfs(LevelGatherer.getProcessed()), 0, ModConstant.ABS_MIN_DBFS));
232230
super.tickT();
233231
}
234232
}

src/main/java/cn/ussshenzhou/channel/gui/OutputConfigPanel.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,14 @@ public static class PlayerVolumePanel extends TPanel {
6363
public PlayerVolumePanel() {
6464
// FIXME remove
6565
update(Minecraft.getInstance().player.getUUID(), 0);
66+
dirty = true;
6667
}
6768

6869
public static void update(UUID id, float db) {
70+
if (!PLAYER_VOLUME.containsKey(id) || Math.abs(PLAYER_VOLUME.get(id) - db) > 0.001) {
71+
dirty = true;
72+
}
6973
PLAYER_VOLUME.put(id, db);
70-
dirty = true;
7174
}
7275

7376
@SubscribeEvent

src/main/java/cn/ussshenzhou/channel/gui/TransmitConfigPanel.java

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
package cn.ussshenzhou.channel.gui;
22

3+
import cn.ussshenzhou.channel.audio.OpusManager;
34
import cn.ussshenzhou.channel.config.ChannelClientConfig;
45
import cn.ussshenzhou.channel.util.ModConstant;
6+
import cn.ussshenzhou.t88.config.ConfigHelper;
57
import cn.ussshenzhou.t88.gui.advanced.TOptionsPanel;
8+
import cn.ussshenzhou.t88.gui.widegt.TLabel;
9+
import cn.ussshenzhou.t88.util.T88Config;
610
import net.minecraft.client.gui.components.Tooltip;
711
import net.minecraft.network.chat.Component;
812

13+
import java.text.DecimalFormat;
914
import java.util.ArrayList;
1015
import java.util.List;
1116
import java.util.stream.Collectors;
@@ -15,6 +20,9 @@
1520
* @author USS_Shenzhou
1621
*/
1722
public class TransmitConfigPanel extends TOptionsPanel {
23+
private TLabel bitrate;
24+
private TLabel speed;
25+
private int life = 0;
1826

1927
public TransmitConfigPanel() {
2028
var cfg = ChannelClientConfig.get();
@@ -27,12 +35,56 @@ public TransmitConfigPanel() {
2735
entry -> entry.getContent() == cfg.frameLengthMs
2836
).getB().setTooltip(Tooltip.create(Component.translatable("channel.config.net.length.tooltip")));
2937
var netSampleRate = addOptionCycleButtonInit(
30-
3138
Component.translatable("channel.config.net.samplerate"),
3239
ModConstant.USABLE_NETWORK_SAMPLE_RATE,
33-
f -> _ -> ChannelClientConfig.write(c -> c.networkSampleRate = f),
40+
f -> _ -> {
41+
ChannelClientConfig.write(c -> c.networkSampleRate = f);
42+
bitrate.setText(Component.literal(getBitRate()));
43+
},
3444
entry -> entry.getContent() == cfg.networkSampleRate
3545
).getB();
46+
bitrate = addOption(Component.translatable("channel.config.net.bitrate"), new TLabel(Component.literal(getBitRate()))).getB();
47+
speed = addOption(Component.translatable("channel.config.net.flow"), new TLabel(Component.empty())).getB();
3648
netSampleRate.setTooltip(Tooltip.create(Component.translatable("channel.config.net.samplerate.tooltip")));
3749
}
50+
51+
private String getBitRate() {
52+
var cfg = ChannelClientConfig.get();
53+
var df = new DecimalFormat("0.#");
54+
return df.format(cfg.networkSampleRate * 16 / 1000f);
55+
}
56+
57+
@Override
58+
public void tickT() {
59+
if (life % 10 == 0) {
60+
OpusManager.SEND_SPEED.update();
61+
speed.setText(Component.literal(getReadableSize(OpusManager.SEND_SPEED.averageIn1s())));
62+
}
63+
life++;
64+
super.tickT();
65+
}
66+
67+
68+
private String getReadableSize(double bytes) {
69+
var s = new StringBuilder();
70+
if (ConfigHelper.getConfigRead(T88Config.class).networkUnit == T88Config.NetworkUnit.BIT) {
71+
bytes *= 8;
72+
if (bytes < 1000) {
73+
s.append(bytes).append(" §7bps§r");
74+
} else if (bytes < 1000 * 1000) {
75+
s.append(String.format("%.1f §7Kbps§r", bytes / 1024));
76+
} else {
77+
s.append(String.format("%.2f §7Mbps§r", bytes / (1024 * 1024)));
78+
}
79+
} else {
80+
if (bytes < 1000) {
81+
s.append(bytes).append(" §7Bytes/S§r");
82+
} else if (bytes < 1000 * 1000) {
83+
s.append(String.format("%.1f §7KiB/S§r", bytes / 1024));
84+
} else {
85+
s.append(String.format("%.2f §7MiB/S§r", bytes / (1024 * 1024)));
86+
}
87+
}
88+
return s.toString();
89+
}
3890
}

src/main/java/cn/ussshenzhou/channel/input/ModKeyMappingRegistry.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
*/
2121
@EventBusSubscriber(Dist.CLIENT)
2222
public class ModKeyMappingRegistry {
23-
public static final KeyMapping.Category CATEGORY = new KeyMapping.Category(Identifier.fromNamespaceAndPath(Channel.MODID, "key.categories.channel"));
23+
public static final KeyMapping.Category CATEGORY = new KeyMapping.Category(Identifier.fromNamespaceAndPath(Channel.MODID, "channel"));
2424
public static final KeyMapping CONFIG = new KeyMapping(
2525
"key.channel.config_screen", KeyConflictContext.UNIVERSAL, KeyModifier.ALT,
2626
InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_C,CATEGORY

src/main/java/cn/ussshenzhou/channel/util/ModConstant.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public class ModConstant {
1212
public static final List<Float> USABLE_NETWORK_SAMPLE_RATE = List.of(8000f, 12000f, 16000f, 24000f, 48000f);
1313
public static final List<Integer> USABLE_FRAME_LENGTH = List.of(10, 20, 40, 60);
1414
public static final int VAD_SMOOTH_WINDOW_LENGTH_MS = 1500;
15+
public static final int ABS_MIN_DBFS = 96;
1516

1617
public static final String SHORT_ID = "cha";
1718
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package cn.ussshenzhou.channel.util;
2+
3+
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
4+
import net.minecraft.util.Util;
5+
6+
/**
7+
* @author USS_Shenzhou
8+
*/
9+
public class TimeCounter {
10+
private final Long2IntOpenHashMap container = new Long2IntOpenHashMap();
11+
private final int windowsSizeMs;
12+
13+
public TimeCounter(int windowsSizeMs) {
14+
this.windowsSizeMs = windowsSizeMs;
15+
}
16+
17+
public TimeCounter() {
18+
this(2000);
19+
}
20+
21+
public synchronized void update() {
22+
long now = Util.getMillis();
23+
container.keySet().removeIf(then -> now - then > windowsSizeMs);
24+
}
25+
26+
public synchronized void put(int value) {
27+
update();
28+
container.put(Util.getMillis(), value);
29+
}
30+
31+
public synchronized double averageIn1s() {
32+
return container.values().intStream().sum() / (double) windowsSizeMs * 1000;
33+
}
34+
}

src/main/resources/assets/channel/lang/en_us.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"channel.welcome": "Press [%1$s] to open the Channel config screen,\nand adjust your microphone and audio processing options.",
33

4-
"key.categories.channel": "Channel",
4+
"key.category.channel.channel": "Channel",
55
"key.channel.config_screen": "Config Screen",
66
"key.channel.ptt": "Push to Talk",
77

@@ -78,6 +78,8 @@
7878
"channel.config.net.length.tooltip": "Determines how often data is sent to the server.\nA shorter frame helps reduce latency, while a longer frame helps reduce network usage.",
7979
"channel.config.net.samplerate": "Transmission Sample Rate (Hz)",
8080
"channel.config.net.samplerate.tooltip": "Determines the quality of the transmitted sound.\nThe highest sound frequency that can be transmitted is half of the sample rate.\nA lower sample rate helps reduce network usage,\nwhile a higher sample rate helps improve audio quality.",
81+
"channel.config.net.bitrate": "Bitrate (kbps)",
82+
"channel.config.net.flow": "Compressed Upload Rate",
8183

8284
"channel.config.tab.output": "Output",
8385
"channel.config.post": " Post-processing",

src/main/resources/assets/channel/lang/zh_cn.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"channel.welcome": "按下[%1$s]打开沉浸语音配置界面,\n调整您的麦克风和音频处理选项。",
33

4-
"key.categories.channel": "沉浸语音",
4+
"key.category.channel.channel": "沉浸语音",
55
"key.channel.config_screen": "配置界面",
66
"key.channel.ptt": "按住讲话",
77

@@ -78,6 +78,8 @@
7878
"channel.config.net.length.tooltip": "决定每隔多久向服务器发送一次数据。\n较短的帧有助于减小延迟,较长的帧有助于减小网络占用。",
7979
"channel.config.net.samplerate": "传输采样率(Hz)",
8080
"channel.config.net.samplerate.tooltip": "决定传输声音的质量。\n能传输的最高声音频率是采样率的一半。\n较低的采样率有助于减小网络占用,\n较高的采样率有助于提高音频质量。",
81+
"channel.config.net.bitrate": "比特率(kbps)",
82+
"channel.config.net.flow": "压缩后上传速率",
8183

8284
"channel.config.tab.output": "输出",
8385
"channel.config.post": " 后处理",

0 commit comments

Comments
 (0)