forked from xiaozhi/xiaozhi-esp32
Add MCP server
This commit is contained in:
@@ -182,17 +182,7 @@ bool MqttProtocol::OpenAudioChannel() {
|
||||
session_id_ = "";
|
||||
xEventGroupClearBits(event_group_handle_, MQTT_PROTOCOL_SERVER_HELLO_EVENT);
|
||||
|
||||
// 发送 hello 消息申请 UDP 通道
|
||||
std::string message = "{";
|
||||
message += "\"type\":\"hello\",";
|
||||
message += "\"version\": 3,";
|
||||
message += "\"transport\":\"udp\",";
|
||||
#if CONFIG_USE_SERVER_AEC
|
||||
message += "\"features\":{\"aec\":true},";
|
||||
#endif
|
||||
message += "\"audio_params\":{";
|
||||
message += "\"format\":\"opus\", \"sample_rate\":16000, \"channels\":1, \"frame_duration\":" + std::to_string(OPUS_FRAME_DURATION_MS);
|
||||
message += "}}";
|
||||
auto message = GetHelloMessage();
|
||||
if (!SendText(message)) {
|
||||
return false;
|
||||
}
|
||||
@@ -262,6 +252,33 @@ bool MqttProtocol::OpenAudioChannel() {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string MqttProtocol::GetHelloMessage() {
|
||||
// 发送 hello 消息申请 UDP 通道
|
||||
cJSON* root = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(root, "type", "hello");
|
||||
cJSON_AddNumberToObject(root, "version", 3);
|
||||
cJSON_AddStringToObject(root, "transport", "udp");
|
||||
cJSON* features = cJSON_CreateObject();
|
||||
#if CONFIG_USE_SERVER_AEC
|
||||
cJSON_AddBoolToObject(features, "aec", true);
|
||||
#endif
|
||||
#if CONFIG_IOT_PROTOCOL_MCP
|
||||
cJSON_AddBoolToObject(features, "mcp", true);
|
||||
#endif
|
||||
cJSON_AddItemToObject(root, "features", features);
|
||||
cJSON* audio_params = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(audio_params, "format", "opus");
|
||||
cJSON_AddNumberToObject(audio_params, "sample_rate", 16000);
|
||||
cJSON_AddNumberToObject(audio_params, "channels", 1);
|
||||
cJSON_AddNumberToObject(audio_params, "frame_duration", OPUS_FRAME_DURATION_MS);
|
||||
cJSON_AddItemToObject(root, "audio_params", audio_params);
|
||||
auto json_str = cJSON_PrintUnformatted(root);
|
||||
std::string message(json_str);
|
||||
cJSON_free(json_str);
|
||||
cJSON_Delete(root);
|
||||
return message;
|
||||
}
|
||||
|
||||
void MqttProtocol::ParseServerHello(const cJSON* root) {
|
||||
auto transport = cJSON_GetObjectItem(root, "transport");
|
||||
if (transport == nullptr || strcmp(transport->valuestring, "udp") != 0) {
|
||||
|
||||
@@ -51,6 +51,7 @@ private:
|
||||
std::string DecodeHexString(const std::string& hex_string);
|
||||
|
||||
bool SendText(const std::string& text) override;
|
||||
std::string GetHelloMessage();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -115,6 +115,11 @@ void Protocol::SendIotStates(const std::string& states) {
|
||||
SendText(message);
|
||||
}
|
||||
|
||||
void Protocol::SendMcpMessage(const std::string& payload) {
|
||||
std::string message = "{\"session_id\":\"" + session_id_ + "\",\"type\":\"mcp\",\"payload\":" + payload + "}";
|
||||
SendText(message);
|
||||
}
|
||||
|
||||
bool Protocol::IsTimeout() const {
|
||||
const int kTimeoutSeconds = 120;
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
|
||||
@@ -71,6 +71,7 @@ public:
|
||||
virtual void SendAbortSpeaking(AbortReason reason);
|
||||
virtual void SendIotDescriptors(const std::string& descriptors);
|
||||
virtual void SendIotStates(const std::string& states);
|
||||
virtual void SendMcpMessage(const std::string& message);
|
||||
|
||||
protected:
|
||||
std::function<void(const cJSON* root)> on_incoming_json_;
|
||||
|
||||
@@ -180,22 +180,12 @@ bool WebsocketProtocol::OpenAudioChannel() {
|
||||
ESP_LOGI(TAG, "Connecting to websocket server: %s with version: %d", url.c_str(), version_);
|
||||
if (!websocket_->Connect(url.c_str())) {
|
||||
ESP_LOGE(TAG, "Failed to connect to websocket server");
|
||||
SetError(Lang::Strings::SERVER_NOT_FOUND);
|
||||
SetError(Lang::Strings::SERVER_NOT_CONNECTED);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send hello message to describe the client
|
||||
// keys: message type, version, audio_params (format, sample_rate, channels)
|
||||
std::string message = "{";
|
||||
message += "\"type\":\"hello\",";
|
||||
message += "\"version\": " + std::to_string(version_) + ",";
|
||||
#if CONFIG_USE_SERVER_AEC
|
||||
message += "\"features\":{\"aec\":true},";
|
||||
#endif
|
||||
message += "\"transport\":\"websocket\",";
|
||||
message += "\"audio_params\":{";
|
||||
message += "\"format\":\"opus\", \"sample_rate\":16000, \"channels\":1, \"frame_duration\":" + std::to_string(OPUS_FRAME_DURATION_MS);
|
||||
message += "}}";
|
||||
auto message = GetHelloMessage();
|
||||
if (!SendText(message)) {
|
||||
return false;
|
||||
}
|
||||
@@ -215,6 +205,33 @@ bool WebsocketProtocol::OpenAudioChannel() {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string WebsocketProtocol::GetHelloMessage() {
|
||||
// keys: message type, version, audio_params (format, sample_rate, channels)
|
||||
cJSON* root = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(root, "type", "hello");
|
||||
cJSON_AddNumberToObject(root, "version", version_);
|
||||
cJSON* features = cJSON_CreateObject();
|
||||
#if CONFIG_USE_SERVER_AEC
|
||||
cJSON_AddBoolToObject(features, "aec", true);
|
||||
#endif
|
||||
#if CONFIG_IOT_PROTOCOL_MCP
|
||||
cJSON_AddBoolToObject(features, "mcp", true);
|
||||
#endif
|
||||
cJSON_AddItemToObject(root, "features", features);
|
||||
cJSON_AddStringToObject(root, "transport", "websocket");
|
||||
cJSON* audio_params = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(audio_params, "format", "opus");
|
||||
cJSON_AddNumberToObject(audio_params, "sample_rate", 16000);
|
||||
cJSON_AddNumberToObject(audio_params, "channels", 1);
|
||||
cJSON_AddNumberToObject(audio_params, "frame_duration", OPUS_FRAME_DURATION_MS);
|
||||
cJSON_AddItemToObject(root, "audio_params", audio_params);
|
||||
auto json_str = cJSON_PrintUnformatted(root);
|
||||
std::string message(json_str);
|
||||
cJSON_free(json_str);
|
||||
cJSON_Delete(root);
|
||||
return message;
|
||||
}
|
||||
|
||||
void WebsocketProtocol::ParseServerHello(const cJSON* root) {
|
||||
auto transport = cJSON_GetObjectItem(root, "transport");
|
||||
if (transport == nullptr || strcmp(transport->valuestring, "websocket") != 0) {
|
||||
|
||||
@@ -28,6 +28,7 @@ private:
|
||||
|
||||
void ParseServerHello(const cJSON* root);
|
||||
bool SendText(const std::string& text) override;
|
||||
std::string GetHelloMessage();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user