IntercomTestClient.java
4.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package com.genersoft.iot.vmp;
import com.alibaba.fastjson2.JSONObject;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Base64;
import java.util.Timer;
import java.util.TimerTask;
public class IntercomTestClient {
// 【配置】修改为你的测试 SIM 卡号 (注意补全12位)
private static final String SIM = "040028816490";
// 【配置】网关地址
private static final String WS_URL = "ws://118.113.164.50:10202?sim=" + SIM;
public static void main(String[] args) throws Exception {
System.out.println("正在连接 WebSocket: " + WS_URL);
WebSocketClient client = new WebSocketClient(new URI(WS_URL)) {
private Timer audioTimer;
@Override
public void onOpen(ServerHandshake handshakedata) {
System.out.println("✅ WebSocket 连接成功");
// 1. 发送注册包 (模拟前端逻辑)
JSONObject registerMsg = new JSONObject();
registerMsg.put("type", "register");
registerMsg.put("stream_id", SIM);
send(registerMsg.toJSONString());
System.out.println(">> 发送注册包: " + registerMsg.toJSONString());
// 2. 开启定时任务,模拟由麦克风产生的音频流 (每40ms发送一次)
startSendingAudio();
}
@Override
public void onMessage(String message) {
System.out.println("<< 收到消息: " + message);
}
@Override
public void onClose(int code, String reason, boolean remote) {
System.out.println("❌ 连接关闭: " + reason);
if (audioTimer != null) audioTimer.cancel();
}
@Override
public void onError(Exception ex) {
ex.printStackTrace();
}
// 模拟发送音频流
private void startSendingAudio() {
audioTimer = new Timer();
// 生成 8000Hz 的正弦波数据 (模拟 '滴-----' 的声音)
// 每次发送 320 字节 (160个采样点, 20ms数据,或者根据网关调整)
// 这里发送 40ms 数据 = 320采样点 * 2字节 = 640字节
final byte[] pcmData = generateSineWave(8000, 440, 320);
audioTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if (isOpen()) {
try {
// 1. Base64 编码
String base64Audio = Base64.getEncoder().encodeToString(pcmData);
// 2. 封装 JSON (完全模仿 Vue 代码结构)
JSONObject audioMsg = new JSONObject();
audioMsg.put("type", "audio_data");
audioMsg.put("stream_id", SIM);
audioMsg.put("audio_data", base64Audio);
audioMsg.put("format", "pcm16");
audioMsg.put("sample_rate", 8000);
audioMsg.put("channels", 1);
send(audioMsg.toJSONString());
// System.out.print("."); // 打印点表示正在发送
} catch (Exception e) {
e.printStackTrace();
}
}
}
}, 0, 40); // 每40ms发送一次
System.out.println(">> 开始持续发送音频流 (标准正弦波)...");
}
};
client.connect();
}
/**
* 生成 PCM16 正弦波音频数据 (标准的“滴”声)
* @param sampleRate 采样率 (8000)
* @param frequency 频率 (440Hz = 标准音A)
* @param samples 采样点数量
*/
private static byte[] generateSineWave(int sampleRate, int frequency, int samples) {
ByteBuffer buffer = ByteBuffer.allocate(samples * 2);
buffer.order(ByteOrder.LITTLE_ENDIAN); // 对应前端 view.setInt16(..., true)
double period = (double) sampleRate / frequency;
for (int i = 0; i < samples; i++) {
double angle = 2.0 * Math.PI * i / period;
// 生成正弦波,振幅 0x4000 (稍微大一点声音)
short sample = (short) (Math.sin(angle) * 0x4000);
buffer.putShort(sample);
}
return buffer.array();
}
}