实时通讯
This commit is contained in:
105
src/main/java/com/realtime/service/DoubaoVoiceService.java
Normal file
105
src/main/java/com/realtime/service/DoubaoVoiceService.java
Normal file
@@ -0,0 +1,105 @@
|
||||
package com.realtime.service;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.realtime.config.DoubaoVoiceConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.*;
|
||||
import okio.ByteString;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.socket.BinaryMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DoubaoVoiceService {
|
||||
private final DoubaoVoiceConfig config;
|
||||
private final OkHttpClient okHttpClient;
|
||||
private WebSocket doubaoWebSocket; // 与豆包 API 的 WebSocket 连接
|
||||
|
||||
public DoubaoVoiceService(DoubaoVoiceConfig config) {
|
||||
this.config = config;
|
||||
this.okHttpClient = new OkHttpClient.Builder()
|
||||
.readTimeout(0, TimeUnit.MILLISECONDS) // 实时流禁用超时
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 建立与豆包实时语音接口的 WebSocket 连接
|
||||
* @param clientSession 客户端的 WebSocket 会话(用于将结果返回给客户端)
|
||||
*/
|
||||
public void connect(WebSocketSession clientSession) {
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.addHeader("X-Api-App-ID",config.getAppId())
|
||||
.addHeader("X-Api-Access-Key",config.getAccessToken())
|
||||
.addHeader("X-Api-Resource-Id","volc.speech.dialog").addHeader("X-Api-App-Key",config.getApiKey())
|
||||
.url("wss://openspeech.bytedance.com/api/v3/realtime/dialogue")
|
||||
.build();
|
||||
|
||||
// 连接豆包 API 并处理回调
|
||||
doubaoWebSocket = okHttpClient.newWebSocket(request, new WebSocketListener() {
|
||||
@Override
|
||||
public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) {
|
||||
// 连接成功:可发送初始化参数(如语音类型、采样率)
|
||||
sendInitParams(webSocket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(@NotNull WebSocket webSocket, ByteString bytes) {
|
||||
// 接收豆包返回的实时结果(如识别文本、合成语音)
|
||||
try {
|
||||
// 将结果转发给客户端
|
||||
clientSession.sendMessage(new BinaryMessage(bytes.toByteArray()));
|
||||
} catch (IOException e) {
|
||||
log.error("转发结果到客户端失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
|
||||
System.out.println(t.getMessage());
|
||||
log.error("豆包 WebSocket 连接失败", t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 向豆包 API 发送音频数据(实时流)
|
||||
*/
|
||||
public void sendAudio(byte[] audioData) {
|
||||
if (doubaoWebSocket != null) {
|
||||
doubaoWebSocket.send(ByteString.of(audioData));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送初始化参数(根据豆包 API 要求)
|
||||
*/
|
||||
private void sendInitParams(WebSocket webSocket) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("action", "init");
|
||||
params.put("format", "pcm"); // 音频格式
|
||||
params.put("sample_rate", 16000); // 采样率
|
||||
params.put("mode", "realtime"); // 实时模式
|
||||
try {
|
||||
webSocket.send(new ObjectMapper().writeValueAsString(params));
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("发送初始化参数失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭连接
|
||||
*/
|
||||
public void close() {
|
||||
if (doubaoWebSocket != null) {
|
||||
doubaoWebSocket.close(1000, "正常关闭");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user