1. 优化了与服务端数据传输时的架构设计
2. 解决了一些杂项内容
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
//
|
||||
// Created by misaki on 2026/1/13.
|
||||
//
|
||||
#include "AudioDataTransferObject.h"
|
||||
#include <QJsonValue>
|
||||
// 构造函数实现(初始化列表)
|
||||
AudioDataTransferObject::AudioDataTransferObject(const QString& owner,
|
||||
bool isStream,
|
||||
bool isStart,
|
||||
bool isEnd,
|
||||
int sequence,
|
||||
const QByteArray& data,
|
||||
int sampleRate,
|
||||
int channelCount,
|
||||
int bitDepth,
|
||||
double duration,
|
||||
const QString& text)
|
||||
: m_owner(owner)
|
||||
, m_isStream(isStream)
|
||||
, m_isStart(isStart)
|
||||
, m_isEnd(isEnd)
|
||||
, m_sequence(sequence)
|
||||
, m_data(data)
|
||||
, m_sampleRate(sampleRate)
|
||||
, m_channelCount(channelCount)
|
||||
, m_bitDepth(bitDepth)
|
||||
, m_duration(duration)
|
||||
, m_text(text) {
|
||||
}
|
||||
|
||||
// 静态工厂方法:从 JSON 反序列化
|
||||
AudioDataTransferObject AudioDataTransferObject::fromJson(const QJsonObject& json) {
|
||||
// 逐个字段读取,不存在则用默认值
|
||||
QString owner = json.value("Owner").toString("server");
|
||||
bool isStream = json.value("isStream").toBool(false);
|
||||
bool isStart = json.value("isStart").toBool(false);
|
||||
bool isEnd = json.value("isEnd").toBool(false);
|
||||
int sequence = json.value("sequence").toInt(0);
|
||||
// 处理 base64 编码的 data 字段
|
||||
QByteArray data;
|
||||
if (json.contains("data")) {
|
||||
const QString base64Str = json.value("data").toString();
|
||||
data = QByteArray::fromBase64(base64Str.toUtf8());
|
||||
}
|
||||
int sampleRate = json.value("sampleRate").toInt(16000);
|
||||
int channelCount = json.value("channelCount").toInt(1);
|
||||
int bitDepth = json.value("bitDepth").toInt(16);
|
||||
double duration = json.value("duration").toDouble(0.0);
|
||||
QString text = json.value("text").toString();
|
||||
|
||||
// 调用构造函数创建对象
|
||||
return AudioDataTransferObject(owner, isStream, isStart, isEnd,
|
||||
sequence, data, sampleRate, channelCount,
|
||||
bitDepth, duration, text);
|
||||
}
|
||||
|
||||
// 序列化为 JSON
|
||||
QJsonObject AudioDataTransferObject::toJson() const {
|
||||
QJsonObject json;
|
||||
json["Owner"] = m_owner;
|
||||
json["isStream"] = m_isStream;
|
||||
json["isStart"] = m_isStart;
|
||||
json["isEnd"] = m_isEnd;
|
||||
json["sequence"] = m_sequence;
|
||||
// data 字段 base64 编码
|
||||
json["data"] = QString(m_data.toBase64());
|
||||
json["sampleRate"] = m_sampleRate;
|
||||
json["channelCount"] = m_channelCount;
|
||||
json["bitDepth"] = m_bitDepth;
|
||||
json["duration"] = m_duration;
|
||||
json["text"] = m_text;
|
||||
return json;
|
||||
}
|
||||
|
||||
// 链式设置
|
||||
AudioDataTransferObject& AudioDataTransferObject::setData(const QString& key,
|
||||
const QJsonValue& value) {
|
||||
if (key == "Owner") {
|
||||
m_owner = value.toString();
|
||||
} else if (key == "isStream") {
|
||||
m_isStream = value.toBool();
|
||||
} else if (key == "isStart") {
|
||||
m_isStart = value.toBool();
|
||||
} else if (key == "isEnd") {
|
||||
m_isEnd = value.toBool();
|
||||
} else if (key == "sequence") {
|
||||
m_sequence = value.toInt();
|
||||
} else if (key == "data") {
|
||||
// 这里要求已是 base64 字符串
|
||||
m_data = QByteArray::fromBase64(value.toString().toUtf8());
|
||||
} else if (key == "sampleRate") {
|
||||
m_sampleRate = value.toInt();
|
||||
} else if (key == "channelCount") {
|
||||
m_channelCount = value.toInt();
|
||||
} else if (key == "bitDepth") {
|
||||
m_bitDepth = value.toInt();
|
||||
} else if (key == "duration") {
|
||||
m_duration = value.toDouble();
|
||||
} else if (key == "text") {
|
||||
m_text = value.toString();
|
||||
}
|
||||
// 如果 key 不存在,默认忽略
|
||||
return *this; // 返回自身引用,支持链式调用
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
//
|
||||
// Created by misaki on 2026/1/13.
|
||||
//
|
||||
#include "DataTransferObjectBase.h"
|
||||
+12
-52
@@ -48,71 +48,31 @@ void NetworkDO::registerSender(SenderFunc sender)
|
||||
m_sender = std::move(sender);
|
||||
}
|
||||
|
||||
void NetworkDO::sendAudioPacket(const AudioDataPacket& packet)
|
||||
void NetworkDO::sendPacket(const DataTransferObjectBase &packet)
|
||||
{
|
||||
// 检查发送器是否已注入
|
||||
if (!m_sender) {
|
||||
emit errorOccurred("Sender not registered! Call registerSender() first.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 封装数据 (DTO -> JSON)
|
||||
QJsonObject dataObj;
|
||||
dataObj["text"] = packet.text;
|
||||
// 音频转 Base64 字符串传输
|
||||
dataObj["audio"] = QString::fromLatin1(packet.audioData.toBase64());
|
||||
dataObj["sampleRate"] = packet.sampleRate;
|
||||
dataObj["channels"] = packet.channels;
|
||||
dataObj["duration"] = packet.duration;
|
||||
|
||||
// 调用底层发送 (解耦)
|
||||
// "textAudio" 是与后端约定的协议类型
|
||||
m_sender("textAudio", dataObj);
|
||||
}
|
||||
|
||||
void NetworkDO::sendControlPacket(const ControlDataPacket& packet)
|
||||
{
|
||||
if (!m_sender) return;
|
||||
|
||||
QJsonObject dataObj;
|
||||
dataObj["action"] = static_cast<int>(packet.action);
|
||||
dataObj["x"] = packet.x;
|
||||
dataObj["y"] = packet.y;
|
||||
|
||||
m_sender("control", dataObj);
|
||||
// 依赖注入 + 多态实现完美解耦
|
||||
m_sender(packet.type(), packet.toJson());
|
||||
}
|
||||
|
||||
// 接受并没有完全解耦
|
||||
void NetworkDO::onDataReceived(const QString& type, const QJsonObject& data)
|
||||
{
|
||||
// 根据类型分发
|
||||
if (type == "textAudio") {
|
||||
handleAudioMessage(data);
|
||||
// 根据类型分发数据包
|
||||
// 为什么分发做在这里,而不是统一数据再去分发,如果不在这里做分发通知,分开发信号,而使用统一的信号
|
||||
// 如果有多个观察者,让观察者自动识别数据包,这会导致信号广播,容易引起性能问题(因为这里依赖的是Qt的信号与槽机制)
|
||||
// TODO: 在此处使用工厂模式,根据type内容快速创建对应的对象
|
||||
if (type == "audio_data") {
|
||||
emit audioPacketReceived(AudioDataTransferObject::fromJson(data)); // 构造并发送音频对象
|
||||
}
|
||||
else if (type == "control") {
|
||||
// handleControlMessage(data);
|
||||
else if (type == "control_data") {
|
||||
|
||||
}
|
||||
else {
|
||||
qWarning() << "[NetworkDO] Received unknown type:" << type;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkDO::handleAudioMessage(const QJsonObject& data)
|
||||
{
|
||||
AudioDataPacket packet;
|
||||
|
||||
// 解析基础字段 (JSON -> DTO)
|
||||
packet.text = data.value("text").toString();
|
||||
packet.sampleRate = data.value("sampleRate").toInt(16000);
|
||||
packet.channels = data.value("channels").toInt(1);
|
||||
// 注意类型转换,确保 long long 精度
|
||||
packet.duration = static_cast<qint64>(data.value("duration").toDouble());
|
||||
|
||||
// 解析音频 (Base64 -> Binary)
|
||||
QString base64Audio = data.value("audio").toString();
|
||||
if (!base64Audio.isEmpty()) {
|
||||
packet.audioData = QByteArray::fromBase64(base64Audio.toLatin1());
|
||||
}
|
||||
|
||||
// 通知上层业务
|
||||
emit audioPacketReceived(packet);
|
||||
}
|
||||
Reference in New Issue
Block a user