gengxin
author@CHENG <2393524978@qq.com>
Wed, 5 Jun 2024 12:17:45 +0000 (20:17 +0800)
committer@CHENG <2393524978@qq.com>
Wed, 5 Jun 2024 12:17:45 +0000 (20:17 +0800)
2.sdk/sdk/product/craneg_modem/pcac/wsclient/build/wsclient.mak
2.sdk/sdk/product/craneg_modem/pcac/wsclient/libwebsockets/inc/mmi_aigc_chat_websocket_client.h [new file with mode: 0644]
2.sdk/sdk/product/craneg_modem/pcac/wsclient/libwebsockets/inc/mmi_aigc_tts_websocket_client.h [new file with mode: 0644]
2.sdk/sdk/product/craneg_modem/pcac/wsclient/libwebsockets/inc/mmi_aigc_websocket.h
2.sdk/sdk/product/craneg_modem/pcac/wsclient/libwebsockets/src/mmi_aigc_chat_websocket.c
2.sdk/sdk/product/craneg_modem/pcac/wsclient/libwebsockets/src/mmi_aigc_chat_websocket_client.c [new file with mode: 0644]
2.sdk/sdk/product/craneg_modem/pcac/wsclient/libwebsockets/src/mmi_aigc_trans_websocket.c
2.sdk/sdk/product/craneg_modem/pcac/wsclient/libwebsockets/src/mmi_aigc_tts_websocket.c [new file with mode: 0644]
2.sdk/sdk/product/craneg_modem/pcac/wsclient/libwebsockets/src/mmi_aigc_tts_websocket_client.c [new file with mode: 0644]

index 46c14c1..3406e6f 100644 (file)
@@ -67,8 +67,12 @@ PACKAGE_SRC_FILES =                          \
                                        web_esp_tls_mbedtls.c           \
                                        sim_esp_tls.c                           \
                                        web_transport_ssl.c                     \
+                                       mmi_aigc_trans_websocket.c      \
+                                       mmi_aigc_chat_websocket_client.c \
                                        mmi_aigc_chat_websocket.c       \
-                                       mmi_aigc_trans_websocket.c
+                                       mmi_aigc_tts_websocket_client.c \
+                                       mmi_aigc_tts_websocket.c
+
 
 # These are the tool flags specific to the ci_stub package only.
 # The environment, target, and group also set flags.
diff --git a/2.sdk/sdk/product/craneg_modem/pcac/wsclient/libwebsockets/inc/mmi_aigc_chat_websocket_client.h b/2.sdk/sdk/product/craneg_modem/pcac/wsclient/libwebsockets/inc/mmi_aigc_chat_websocket_client.h
new file mode 100644 (file)
index 0000000..2bf4d13
--- /dev/null
@@ -0,0 +1,285 @@
+// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __MMI_AIGC_CHAT_WEBSOCKET_CLIENT_H__
+#define __MMI_AIGC_CHAT_WEBSOCKET_CLIENT_H__
+
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include "web_esp_transport_ws.h"
+#include "esp_err.h"
+#include "web_esp_transport.h"
+#include "osa_old_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef unsigned long UINT32;
+
+#define sim_portTICK_RATE_MS   1000
+#define sim_portTICK_PERIOD_MS 1000
+
+//ESP_EVENT_DECLARE_BASE(WEBSOCKET_EVENTS);         // declaration of the task events family
+
+/******************************************
+ function declared in here
+ *****************************************/
+extern char* strdup(const char* str);
+extern void free( void *p );
+extern void *malloc( size_t Size );
+extern void *calloc( size_t nItems, size_t itemSize );
+//extern int strtol(const char *p1, char **p2, int base);
+
+typedef struct sim_esp_websocket_client *sim_esp_websocket_client_handle_t;
+typedef void   (*sim_esp_event_handler_t)(int32_t event_id, void* event_data); /**< function called when an event is posted to the queue */
+
+/**
+ * @brief Websocket Client events id
+ */
+typedef enum {
+    WEBSOCKET_EVENT_ANY = -1,
+    WEBSOCKET_EVENT_ERROR = 0,      /*!< This event occurs when there are any errors during execution */
+    WEBSOCKET_EVENT_CONNECTED,      /*!< Once the Websocket has been connected to the server, no data exchange has been performed */
+    WEBSOCKET_EVENT_DISCONNECTED,   /*!< The connection has been disconnected */
+    WEBSOCKET_EVENT_DATA,           /*!< When receiving data from the server, possibly multiple portions of the packet */
+       WEBSOCKET_EVENT_CLOSED,
+       WEBSOCKET_EVENT_MAX
+} sim_esp_websocket_event_id_t;
+
+/**
+ * @brief Websocket event data
+ */
+typedef struct {
+    char *data_ptr;                   /*!< Data pointer */
+    int data_len;                           /*!< Data length */
+    uint8_t op_code;                        /*!< Received opcode */
+    sim_esp_websocket_client_handle_t client;   /*!< sim_esp_websocket_client_handle_t context */
+    void *user_context;                     /*!< user_data context, from sim_esp_websocket_client_config_t user_data */
+    int payload_len;                        /*!< Total payload length, payloads exceeding buffer will be posted through multiple events */
+    int payload_offset;                     /*!< Actual offset for the data associated with this event */
+       sim_esp_websocket_event_id_t event;
+} sim_esp_websocket_event_data_t;
+
+typedef struct {
+    UINT32                      task_stack;
+    int                         task_prio;
+    char                        *uri;
+    char                        *p_host;
+    char                        host[64];
+    char                        *p_path;
+    char                        path[1024];
+    char                        scheme[16];
+    char                        *username;
+    char                        *password;
+    int                         port;
+    bool                        auto_reconnect;
+    void                        *user_context;
+    int                         network_timeout_ms;
+    char                        *subprotocol;
+} sim_websocket_config_storage_t;
+
+typedef enum {
+    WEBSOCKET_STATE_ERROR = -1,
+    WEBSOCKET_STATE_UNKNOW = 0,
+    WEBSOCKET_STATE_INIT,
+    WEBSOCKET_STATE_CONNECTED,
+    WEBSOCKET_STATE_WAIT_TIMEOUT,
+    WEBSOCKET_STATE_CLOSING,
+} sim_websocket_client_state_t;
+
+struct sim_esp_websocket_client {
+       sim_esp_event_handler_t         handler;
+    wb_esp_transport_list_handle_t transport_list;
+    wb_esp_transport_handle_t      transport;
+    sim_websocket_config_storage_t  *config;
+    sim_websocket_client_state_t    state;
+       OSAMutexRef                 lock;
+    UINT32                      keepalive_tick_ms;
+    UINT32                      reconnect_tick_ms;
+    UINT32                      ping_tick_ms;
+    int                         wait_timeout_ms;
+    int                         auto_reconnect;
+    char                        *rx_buffer;
+    char                        *tx_buffer;
+    int                         buffer_size;
+    ws_transport_opcodes_t      last_opcode;
+    int                         payload_len;
+    int                         payload_offset;
+};
+
+/**
+ * @brief Websocket Client transport
+ */
+typedef enum {
+    WEBSOCKET_TRANSPORT_UNKNOWN = 0x0,  /*!< Transport unknown */
+    WEBSOCKET_TRANSPORT_OVER_TCP,       /*!< Transport over tcp */
+    WEBSOCKET_TRANSPORT_OVER_SSL,       /*!< Transport over ssl */
+} sim_esp_websocket_transport_t;
+
+/**
+ * @brief Websocket client setup configuration
+ */
+typedef struct {
+    const char                  *uri;                       /*!< Websocket URI, the information on the URI can be overrides the other fields below, if any */
+    const char                  *host;                      /*!< Domain or IP as string */
+    int                         port;                       /*!< Port to connect, default depend on sim_esp_websocket_transport_t (80 or 443) */
+    const char                  *username;                  /*!< Using for Http authentication - Not supported for now */
+    const char                  *password;                  /*!< Using for Http authentication - Not supported for now */
+    const char                  *path;                      /*!< HTTP Path, if not set, default is `/` */
+    bool                        disable_auto_reconnect;     /*!< Disable the automatic reconnect function when disconnected */
+    void                        *user_context;              /*!< HTTP user data context */
+    int                         task_prio;                  /*!< Websocket task priority */
+    int                         task_stack;                 /*!< Websocket task stack */
+    int                         buffer_size;                /*!< Websocket buffer size */
+    const char                  *cert_pem;                  /*!< SSL Certification, PEM format as string, if the client requires to verify server */
+    sim_esp_websocket_transport_t   transport;                  /*!< Websocket transport type, see `sim_esp_websocket_transport_t */
+    char                        *subprotocol;               /*!< Websocket subprotocol */
+} sim_esp_websocket_client_config_t;
+
+/**
+ * @brief      Start a Websocket session
+ *             This function must be the first function to call,
+ *             and it returns a sim_esp_websocket_client_handle_t that you must use as input to other functions in the interface.
+ *             This call MUST have a corresponding call to sim_esp_websocket_client_destroy when the operation is complete.
+ *
+ * @param[in]  config  The configuration
+ *
+ * @return
+ *     - `sim_esp_websocket_client_handle_t`
+ *     - NULL if any errors
+ */
+sim_esp_websocket_client_handle_t chat_websocket_client_init(const sim_esp_websocket_client_config_t *config);
+
+/**
+ * @brief      Set URL for client, when performing this behavior, the options in the URL will replace the old ones
+ *             Must stop the WebSocket client before set URI if the client has been connected
+ *
+ * @param[in]  client  The client
+ * @param[in]  uri     The uri
+ *
+ * @return     esp_err_t
+ */
+esp_err_t chat_websocket_client_set_uri(sim_esp_websocket_client_handle_t client, const char *uri);
+
+/**
+ * @brief      Open the WebSocket connection
+ *
+ * @param[in]  client  The client
+ *
+ * @return     esp_err_t
+ */
+esp_err_t chat_websocket_client_start(sim_esp_websocket_client_handle_t client);
+
+/**
+ * @brief      Close the WebSocket connection
+ *
+ * @param[in]  client  The client
+ *
+ * @return     esp_err_t
+ */
+esp_err_t chat_websocket_client_stop(sim_esp_websocket_client_handle_t client);
+
+/**
+ * @brief      Destroy the WebSocket connection and free all resources.
+ *             This function must be the last function to call for an session.
+ *             It is the opposite of the sim_esp_websocket_client_init function and must be called with the same handle as input that a esp_websocket_client_init call returned.
+ *             This might close all connections this handle has used.
+ *
+ * @param[in]  client  The client
+ *
+ * @return     esp_err_t
+ */
+esp_err_t chat_websocket_client_destroy(sim_esp_websocket_client_handle_t client);
+
+/**
+ * @brief      Generic write data to the WebSocket connection; defaults to binary send
+ *
+ * @param[in]  client  The client
+ * @param[in]  data    The data
+ * @param[in]  len     The length
+ * @param[in]  timeout Write data timeout
+ *
+ * @return
+ *     - Number of data was sent
+ *     - (-1) if any errors
+ */
+int chat_websocket_client_send(sim_esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout);
+
+/**
+ * @brief      Write binary data to the WebSocket connection (data send with WS OPCODE=02, i.e. binary)
+ *
+ * @param[in]  client  The client
+ * @param[in]  data    The data
+ * @param[in]  len     The length
+ * @param[in]  timeout Write data timeout
+ *
+ * @return
+ *     - Number of data was sent
+ *     - (-1) if any errors
+ */
+int chat_websocket_client_send_bin(sim_esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout);
+
+static int chat_websocket_client_send_close(sim_esp_websocket_client_handle_t client, int code, const char *additional_data, int total_len, TickType_t timeout);
+
+static int chat_websocket_client_close_with_optional_body(sim_esp_websocket_client_handle_t client, bool send_body, int code, const char *data, int len, TickType_t timeout);
+
+int chat_websocket_client_close_with_code(sim_esp_websocket_client_handle_t client, int code, const char *data, int len, TickType_t timeout);
+
+int chat_websocket_client_close(sim_esp_websocket_client_handle_t client, TickType_t timeout);
+
+/**
+ * @brief      Write textual data to the WebSocket connection (data send with WS OPCODE=01, i.e. text)
+ *
+ * @param[in]  client  The client
+ * @param[in]  data    The data
+ * @param[in]  len     The length
+ * @param[in]  timeout Write data timeout
+ *
+ * @return
+ *     - Number of data was sent
+ *     - (-1) if any errors
+ */
+int chat_websocket_client_send_text(sim_esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout);
+
+/**
+ * @brief      Check the WebSocket connection status
+ *
+ * @param[in]  client  The client handle
+ *
+ * @return
+ *     - true
+ *     - false
+ */
+bool chat_websocket_client_is_connected(sim_esp_websocket_client_handle_t client);
+
+/**
+ * @brief Register the Websocket Events
+ *
+ * @param client            The client handle
+ * @param event             The event id
+ * @param event_handler     The callback function
+ * @param event_handler_arg User context
+ * @return esp_err_t
+ */
+esp_err_t chat_websocket_register_events(sim_esp_websocket_client_handle_t client,
+                                                                                       sim_esp_event_handler_t event_handler);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/2.sdk/sdk/product/craneg_modem/pcac/wsclient/libwebsockets/inc/mmi_aigc_tts_websocket_client.h b/2.sdk/sdk/product/craneg_modem/pcac/wsclient/libwebsockets/inc/mmi_aigc_tts_websocket_client.h
new file mode 100644 (file)
index 0000000..900773b
--- /dev/null
@@ -0,0 +1,285 @@
+// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __MMI_AIGC_TTS_WEBSOCKET_CLIENT_H__
+#define __MMI_AIGC_TTS_WEBSOCKET_CLIENT_H__
+
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include "web_esp_transport_ws.h"
+#include "esp_err.h"
+#include "web_esp_transport.h"
+#include "osa_old_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef unsigned long UINT32;
+
+#define sim_portTICK_RATE_MS   1000
+#define sim_portTICK_PERIOD_MS 1000
+
+//ESP_EVENT_DECLARE_BASE(WEBSOCKET_EVENTS);         // declaration of the task events family
+
+/******************************************
+ function declared in here
+ *****************************************/
+extern char* strdup(const char* str);
+extern void free( void *p );
+extern void *malloc( size_t Size );
+extern void *calloc( size_t nItems, size_t itemSize );
+//extern int strtol(const char *p1, char **p2, int base);
+
+typedef struct sim_esp_websocket_client *sim_esp_websocket_client_handle_t;
+typedef void   (*sim_esp_event_handler_t)(int32_t event_id, void* event_data); /**< function called when an event is posted to the queue */
+
+/**
+ * @brief Websocket Client events id
+ */
+typedef enum {
+    WEBSOCKET_EVENT_ANY = -1,
+    WEBSOCKET_EVENT_ERROR = 0,      /*!< This event occurs when there are any errors during execution */
+    WEBSOCKET_EVENT_CONNECTED,      /*!< Once the Websocket has been connected to the server, no data exchange has been performed */
+    WEBSOCKET_EVENT_DISCONNECTED,   /*!< The connection has been disconnected */
+    WEBSOCKET_EVENT_DATA,           /*!< When receiving data from the server, possibly multiple portions of the packet */
+       WEBSOCKET_EVENT_CLOSED,
+       WEBSOCKET_EVENT_MAX
+} sim_esp_websocket_event_id_t;
+
+/**
+ * @brief Websocket event data
+ */
+typedef struct {
+    char *data_ptr;                   /*!< Data pointer */
+    int data_len;                           /*!< Data length */
+    uint8_t op_code;                        /*!< Received opcode */
+    sim_esp_websocket_client_handle_t client;   /*!< sim_esp_websocket_client_handle_t context */
+    void *user_context;                     /*!< user_data context, from sim_esp_websocket_client_config_t user_data */
+    int payload_len;                        /*!< Total payload length, payloads exceeding buffer will be posted through multiple events */
+    int payload_offset;                     /*!< Actual offset for the data associated with this event */
+       sim_esp_websocket_event_id_t event;
+} sim_esp_websocket_event_data_t;
+
+typedef struct {
+    UINT32                      task_stack;
+    int                         task_prio;
+    char                        *uri;
+    char                        *p_host;
+    char                        host[64];
+    char                        *p_path;
+    char                        path[1024];
+    char                        scheme[16];
+    char                        *username;
+    char                        *password;
+    int                         port;
+    bool                        auto_reconnect;
+    void                        *user_context;
+    int                         network_timeout_ms;
+    char                        *subprotocol;
+} sim_websocket_config_storage_t;
+
+typedef enum {
+    WEBSOCKET_STATE_ERROR = -1,
+    WEBSOCKET_STATE_UNKNOW = 0,
+    WEBSOCKET_STATE_INIT,
+    WEBSOCKET_STATE_CONNECTED,
+    WEBSOCKET_STATE_WAIT_TIMEOUT,
+    WEBSOCKET_STATE_CLOSING,
+} sim_websocket_client_state_t;
+
+struct sim_esp_websocket_client {
+       sim_esp_event_handler_t         handler;
+    wb_esp_transport_list_handle_t transport_list;
+    wb_esp_transport_handle_t      transport;
+    sim_websocket_config_storage_t  *config;
+    sim_websocket_client_state_t    state;
+       OSAMutexRef                 lock;
+    UINT32                      keepalive_tick_ms;
+    UINT32                      reconnect_tick_ms;
+    UINT32                      ping_tick_ms;
+    int                         wait_timeout_ms;
+    int                         auto_reconnect;
+    char                        *rx_buffer;
+    char                        *tx_buffer;
+    int                         buffer_size;
+    ws_transport_opcodes_t      last_opcode;
+    int                         payload_len;
+    int                         payload_offset;
+};
+
+/**
+ * @brief Websocket Client transport
+ */
+typedef enum {
+    WEBSOCKET_TRANSPORT_UNKNOWN = 0x0,  /*!< Transport unknown */
+    WEBSOCKET_TRANSPORT_OVER_TCP,       /*!< Transport over tcp */
+    WEBSOCKET_TRANSPORT_OVER_SSL,       /*!< Transport over ssl */
+} sim_esp_websocket_transport_t;
+
+/**
+ * @brief Websocket client setup configuration
+ */
+typedef struct {
+    const char                  *uri;                       /*!< Websocket URI, the information on the URI can be overrides the other fields below, if any */
+    const char                  *host;                      /*!< Domain or IP as string */
+    int                         port;                       /*!< Port to connect, default depend on sim_esp_websocket_transport_t (80 or 443) */
+    const char                  *username;                  /*!< Using for Http authentication - Not supported for now */
+    const char                  *password;                  /*!< Using for Http authentication - Not supported for now */
+    const char                  *path;                      /*!< HTTP Path, if not set, default is `/` */
+    bool                        disable_auto_reconnect;     /*!< Disable the automatic reconnect function when disconnected */
+    void                        *user_context;              /*!< HTTP user data context */
+    int                         task_prio;                  /*!< Websocket task priority */
+    int                         task_stack;                 /*!< Websocket task stack */
+    int                         buffer_size;                /*!< Websocket buffer size */
+    const char                  *cert_pem;                  /*!< SSL Certification, PEM format as string, if the client requires to verify server */
+    sim_esp_websocket_transport_t   transport;                  /*!< Websocket transport type, see `sim_esp_websocket_transport_t */
+    char                        *subprotocol;               /*!< Websocket subprotocol */
+} sim_esp_websocket_client_config_t;
+
+/**
+ * @brief      Start a Websocket session
+ *             This function must be the first function to call,
+ *             and it returns a sim_esp_websocket_client_handle_t that you must use as input to other functions in the interface.
+ *             This call MUST have a corresponding call to sim_esp_websocket_client_destroy when the operation is complete.
+ *
+ * @param[in]  config  The configuration
+ *
+ * @return
+ *     - `sim_esp_websocket_client_handle_t`
+ *     - NULL if any errors
+ */
+sim_esp_websocket_client_handle_t tts_websocket_client_init(const sim_esp_websocket_client_config_t *config);
+
+/**
+ * @brief      Set URL for client, when performing this behavior, the options in the URL will replace the old ones
+ *             Must stop the WebSocket client before set URI if the client has been connected
+ *
+ * @param[in]  client  The client
+ * @param[in]  uri     The uri
+ *
+ * @return     esp_err_t
+ */
+esp_err_t tts_websocket_client_set_uri(sim_esp_websocket_client_handle_t client, const char *uri);
+
+/**
+ * @brief      Open the WebSocket connection
+ *
+ * @param[in]  client  The client
+ *
+ * @return     esp_err_t
+ */
+esp_err_t tts_websocket_client_start(sim_esp_websocket_client_handle_t client);
+
+/**
+ * @brief      Close the WebSocket connection
+ *
+ * @param[in]  client  The client
+ *
+ * @return     esp_err_t
+ */
+esp_err_t tts_websocket_client_stop(sim_esp_websocket_client_handle_t client);
+
+/**
+ * @brief      Destroy the WebSocket connection and free all resources.
+ *             This function must be the last function to call for an session.
+ *             It is the opposite of the sim_esp_websocket_client_init function and must be called with the same handle as input that a esp_websocket_client_init call returned.
+ *             This might close all connections this handle has used.
+ *
+ * @param[in]  client  The client
+ *
+ * @return     esp_err_t
+ */
+esp_err_t tts_websocket_client_destroy(sim_esp_websocket_client_handle_t client);
+
+/**
+ * @brief      Generic write data to the WebSocket connection; defaults to binary send
+ *
+ * @param[in]  client  The client
+ * @param[in]  data    The data
+ * @param[in]  len     The length
+ * @param[in]  timeout Write data timeout
+ *
+ * @return
+ *     - Number of data was sent
+ *     - (-1) if any errors
+ */
+int tts_websocket_client_send(sim_esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout);
+
+/**
+ * @brief      Write binary data to the WebSocket connection (data send with WS OPCODE=02, i.e. binary)
+ *
+ * @param[in]  client  The client
+ * @param[in]  data    The data
+ * @param[in]  len     The length
+ * @param[in]  timeout Write data timeout
+ *
+ * @return
+ *     - Number of data was sent
+ *     - (-1) if any errors
+ */
+int tts_websocket_client_send_bin(sim_esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout);
+
+static int tts_websocket_client_send_close(sim_esp_websocket_client_handle_t client, int code, const char *additional_data, int total_len, TickType_t timeout);
+
+static int tts_websocket_client_close_with_optional_body(sim_esp_websocket_client_handle_t client, bool send_body, int code, const char *data, int len, TickType_t timeout);
+
+int tts_websocket_client_close_with_code(sim_esp_websocket_client_handle_t client, int code, const char *data, int len, TickType_t timeout);
+
+int tts_websocket_client_close(sim_esp_websocket_client_handle_t client, TickType_t timeout);
+
+/**
+ * @brief      Write textual data to the WebSocket connection (data send with WS OPCODE=01, i.e. text)
+ *
+ * @param[in]  client  The client
+ * @param[in]  data    The data
+ * @param[in]  len     The length
+ * @param[in]  timeout Write data timeout
+ *
+ * @return
+ *     - Number of data was sent
+ *     - (-1) if any errors
+ */
+int tts_websocket_client_send_text(sim_esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout);
+
+/**
+ * @brief      Check the WebSocket connection status
+ *
+ * @param[in]  client  The client handle
+ *
+ * @return
+ *     - true
+ *     - false
+ */
+bool tts_websocket_client_is_connected(sim_esp_websocket_client_handle_t client);
+
+/**
+ * @brief Register the Websocket Events
+ *
+ * @param client            The client handle
+ * @param event             The event id
+ * @param event_handler     The callback function
+ * @param event_handler_arg User context
+ * @return esp_err_t
+ */
+esp_err_t tts_websocket_register_events(sim_esp_websocket_client_handle_t client,
+                                                                                       sim_esp_event_handler_t event_handler);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index e871cf2..79dcc9b 100644 (file)
@@ -21,8 +21,6 @@ extern "C" {
 #endif
 
 
-#define MMI_AIGC_TRANS_WEBSOCKET_URI "ws://121.40.67.151:9099/asr/ws"
-
 
 int mmi_aigc_trans_websocket_send_text_data(char * data_ptr, int data_len);
 int mmi_aigc_trans_websocket_send_binary_data(char * data_ptr, int data_len);
@@ -30,16 +28,17 @@ void mmi_aigc_trans_websocket_app_start(void);
 void mmi_aigc_trans_websocket_app_stop(void);
 
 
-
-#define MMI_AIGC_CHAT_WEBSOCKET_URI "ws://121.40.67.151:9099/chat/ws"
-
-
 int mmi_aigc_chat_websocket_send_text_data(char * data_ptr, int data_len);
 int mmi_aigc_chat_websocket_send_binary_data(char * data_ptr, int data_len);
 void mmi_aigc_chat_websocket_app_start(void);
 void mmi_aigc_chat_websocket_app_stop(void);
 
 
+int mmi_aigc_tts_websocket_send_text_data(char * data_ptr, int data_len);
+int mmi_aigc_tts_websocket_send_binary_data(char * data_ptr, int data_len);
+void mmi_aigc_tts_websocket_app_start(void);
+void mmi_aigc_tts_websocket_app_stop(void);
+
 
 #endif 
 
index 34d02e8..f353cff 100644 (file)
@@ -4,8 +4,10 @@
 #if 1 // def __MMI_CUSTOM_AIGC_SUPPORT__
 
 #include "uart.h"
-#include "sim_esp_websocket_client.h"
-#include "Mmi_aigc_chat_websocket.h"
+#include "mmi_aigc_chat_websocket_client.h"
+#include "mmi_aigc_websocket.h"
+
+#define MMI_AIGC_CHAT_WEBSOCKET_URI "ws://121.40.67.151:9099/chat/ws"
 
 static sim_esp_websocket_client_handle_t s_aigc_chat_ws_client_p = NULL;
 
@@ -18,7 +20,7 @@ int mmi_aigc_chat_websocket_send_text_data(char * data_ptr, int data_len)
        int ret = 0;
 
        AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: \n", __FUNCTION__, __LINE__);
-    ret = sim_esp_websocket_client_send_text(s_aigc_chat_ws_client_p, data_ptr, data_len, portMAX_DELAY);
+    ret = chat_websocket_client_send_text(s_aigc_chat_ws_client_p, data_ptr, data_len, portMAX_DELAY);
        if (0 > ret)
        {
                AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: \n", __FUNCTION__, __LINE__);
@@ -32,7 +34,7 @@ int mmi_aigc_chat_websocket_send_binary_data(char * data_ptr, int data_len)
        int ret = 0;
 
        AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: \n", __FUNCTION__, __LINE__);
-    ret = sim_esp_websocket_client_send_bin(s_aigc_chat_ws_client_p, data_ptr, data_len, portMAX_DELAY);
+    ret = chat_websocket_client_send_bin(s_aigc_chat_ws_client_p, data_ptr, data_len, portMAX_DELAY);
        if (0 > ret)
        {
                AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: \n", __FUNCTION__, __LINE__);
@@ -109,16 +111,16 @@ void mmi_aigc_chat_websocket_app_start(void)
 
        AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: url=%s\n", __FUNCTION__, __LINE__, websocket_cfg.uri);
 
-    s_aigc_chat_ws_client_p = sim_esp_websocket_client_init(&websocket_cfg);
+    s_aigc_chat_ws_client_p = chat_websocket_client_init(&websocket_cfg);
        if(NULL == s_aigc_chat_ws_client_p)
        {
                AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: websocket client init fail\n", __FUNCTION__, __LINE__);
                return;
        }
        
-    sim_esp_websocket_register_events(s_aigc_chat_ws_client_p, mmi_aigc_chat_websocket_event_handler);
+    chat_websocket_register_events(s_aigc_chat_ws_client_p, mmi_aigc_chat_websocket_event_handler);
        
-    esp_err_t err_no = sim_esp_websocket_client_start(s_aigc_chat_ws_client_p);
+    esp_err_t err_no = chat_websocket_client_start(s_aigc_chat_ws_client_p);
        if(ESP_OK != err_no)
        {
                AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: websocket client start fail,%d\n", __FUNCTION__, __LINE__, err_no);
@@ -134,7 +136,7 @@ void mmi_aigc_chat_websocket_app_stop(void)
 {
        AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: \n", __FUNCTION__, __LINE__);
        
-       sim_esp_websocket_client_destroy(s_aigc_chat_ws_client_p);
+       chat_websocket_client_destroy(s_aigc_chat_ws_client_p);
 }
 
 #endif
diff --git a/2.sdk/sdk/product/craneg_modem/pcac/wsclient/libwebsockets/src/mmi_aigc_chat_websocket_client.c b/2.sdk/sdk/product/craneg_modem/pcac/wsclient/libwebsockets/src/mmi_aigc_chat_websocket_client.c
new file mode 100644 (file)
index 0000000..f12ebaf
--- /dev/null
@@ -0,0 +1,826 @@
+// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stdio.h>
+
+#include "mmi_aigc_chat_websocket_client.h"
+#include "web_esp_transport.h"
+#include "web_esp_transport_tcp.h"
+#include "web_esp_transport_ssl.h"
+#include "web_esp_transport_ws.h"
+
+/* using uri parser */
+#include "web_http_parser.h"
+#include "queue.h"
+#include "esp_log.h"
+#include "sockets.h"
+#include "osa.h"
+
+static int       task_run = 0;
+static OSTaskRef chat_websocket_client_ref = NULL;
+static void *    chat_websocket_client_stack_ptr = NULL;
+
+#define websocket_version                              "asr_websocket_v1.10_20210926"
+#define WEBSOCKET_TCP_DEFAULT_PORT      (80)
+#define WEBSOCKET_SSL_DEFAULT_PORT      (443)
+#define WEBSOCKET_BUFFER_SIZE_BYTE      (8*1024)
+#define WEBSOCKET_RECONNECT_TIMEOUT_MS  (5*60*1000)
+#define WEBSOCKET_TASK_PRIORITY         (90)
+#define WEBSOCKET_TASK_STACK            (8*1024)
+#define WEBSOCKET_NETWORK_TIMEOUT_MS    (10*1000)
+#define WEBSOCKET_PING_TIMEOUT_MS       (15*60*1000)
+#define WEBSOCKET_EVENT_QUEUE_SIZE      (1)
+
+#define ESP_WS_CLIENT_MEM_CHECK(a, action) if (!(a)) {                                         \
+        ESP_LOGE("%s:%d (%s): %s", __FILE__, __LINE__, __FUNCTION__, "Memory exhausted");       \
+        action;                                                                                     \
+        }
+#define ESP_EVENT_DECLARE_BASE(id) extern esp_event_base_t id
+#define ESP_EVENT_DEFINE_BASE(id) esp_event_base_t id = #id
+
+static int chat_websocket_client_send_with_opcode(sim_esp_websocket_client_handle_t client, ws_transport_opcodes_t opcode, const char *data, int len, TickType_t timeout);
+static void asr_ws_loop_run_task(void *pv);
+extern OSMsgQRef asr_ws_msgQ_ref;
+extern int esp_transport_ws_poll_connection_closed(wb_esp_transport_handle_t t, int timeout_ms);
+
+static UINT32 _tick_get_ms(void)
+{
+       return (5*OSAGetTicks());       //get ms
+    //return esp_timer_get_time()/1000;
+}
+
+static int chat_websocket_client_dispatch_event(sim_esp_websocket_client_handle_t client,
+                                                     sim_esp_websocket_event_id_t event,
+                                                     const char *data,
+                                                     int data_len)
+{
+       if (client->handler) {
+               if (NULL == data) {
+                       client->handler(event, NULL);
+               } else {
+                       sim_esp_websocket_event_data_t *event_data = NULL;
+                       event_data = malloc(sizeof(sim_esp_websocket_event_data_t));
+                       if (NULL == event_data) {
+                               ESP_LOGE("%s, event_data malloc failed", __FUNCTION__);
+                               return -1;
+                       } else {
+                               memset(event_data, '\0', sizeof(sim_esp_websocket_event_data_t));
+                               event_data->data_ptr = malloc(data_len);
+                               if (event_data->data_ptr) {
+                                       memset(event_data->data_ptr, 0, data_len);
+                                       memcpy(event_data->data_ptr, data, data_len);
+                               }
+                       }
+
+                       event_data->data_len = data_len;
+               event_data->op_code  = client->last_opcode;
+            //shenxj+++
+            event_data->payload_len = client->payload_len;
+            event_data->payload_offset = client->payload_offset;
+            //shenxj---
+
+                       client->handler(event, event_data);
+               }
+       }
+
+       return 0;
+}
+
+static int chat_websocket_client_abort_connection(sim_esp_websocket_client_handle_t client)
+{
+       int ret = 0;
+       
+    wb_esp_transport_close(client->transport);
+    client->wait_timeout_ms = WEBSOCKET_RECONNECT_TIMEOUT_MS;
+    client->reconnect_tick_ms = _tick_get_ms();
+    client->state = WEBSOCKET_STATE_WAIT_TIMEOUT;
+    ESP_LOGI("Reconnect after %d ms", client->wait_timeout_ms);
+    ret = chat_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_DISCONNECTED, NULL, 0);
+       ESP_LOGD("%s, client abort connection ret is %d", __FUNCTION__, ret);
+    return ret;
+}
+
+static esp_err_t chat_websocket_client_set_config(sim_esp_websocket_client_handle_t client, const sim_esp_websocket_client_config_t *config)
+{
+    sim_websocket_config_storage_t *cfg = client->config;
+    cfg->task_prio = config->task_prio;
+    if (cfg->task_prio <= 0) {
+        cfg->task_prio = WEBSOCKET_TASK_PRIORITY;
+    }
+
+    cfg->task_stack = config->task_stack;
+    if (cfg->task_stack == 0) {
+        cfg->task_stack = WEBSOCKET_TASK_STACK;
+    }
+
+    if (config->host) {
+        cfg->p_host = strdup(config->host);
+               memcpy(cfg->host, cfg->p_host, strlen(config->host));
+        ESP_WS_CLIENT_MEM_CHECK(cfg->host, return ESP_ERR_NO_MEM);
+    }
+
+    if (config->port) {
+        cfg->port = config->port;
+    }
+
+    if (config->username) {
+        //free(cfg->username);
+        cfg->username = strdup(config->username);
+        ESP_WS_CLIENT_MEM_CHECK(cfg->username, return ESP_ERR_NO_MEM);
+    }
+
+    if (config->password) {
+        //free(cfg->password);
+        cfg->password = strdup(config->password);
+        ESP_WS_CLIENT_MEM_CHECK(cfg->password, return ESP_ERR_NO_MEM);
+    }
+
+    if (config->uri) {
+        //free(cfg->uri);
+        cfg->uri = strdup(config->uri);
+        ESP_WS_CLIENT_MEM_CHECK(cfg->uri, return ESP_ERR_NO_MEM);
+    }
+    if (config->path) {
+        //free(cfg->path);
+        cfg->p_path = strdup(config->path);
+               memcpy(cfg->path, cfg->p_path, strlen(config->path));
+        ESP_WS_CLIENT_MEM_CHECK(cfg->path, return ESP_ERR_NO_MEM);
+    }
+    if (config->subprotocol) {
+        //free(cfg->subprotocol);
+        cfg->subprotocol = strdup(config->subprotocol);
+        ESP_WS_CLIENT_MEM_CHECK(cfg->subprotocol, return ESP_ERR_NO_MEM);
+    }
+
+    cfg->network_timeout_ms = WEBSOCKET_NETWORK_TIMEOUT_MS;
+    cfg->user_context = config->user_context;
+    cfg->auto_reconnect = true;
+    if (config->disable_auto_reconnect) {
+        cfg->auto_reconnect = false;
+    }
+
+
+    return ESP_OK;
+}
+
+static esp_err_t chat_websocket_client_destroy_config(sim_esp_websocket_client_handle_t client)
+{
+    if (client == NULL) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    sim_websocket_config_storage_t *cfg = client->config;
+    if (client->config == NULL) {
+        return ESP_ERR_INVALID_ARG;
+    }
+       
+       if (NULL != cfg->p_host) {
+               free(cfg->p_host);
+               cfg->p_host = NULL;
+       }
+       if (NULL != cfg->uri) {
+               free(cfg->uri);
+               cfg->uri = NULL;
+       }
+       if (NULL != cfg->p_path) {
+               free(cfg->p_path);
+               cfg->p_path = NULL;
+       }
+       if (NULL != cfg->username) {
+               free(cfg->username);
+               cfg->username = NULL;
+       }
+       if (NULL != cfg->password) {
+               free(cfg->password);
+               cfg->password = NULL;
+       }
+       if (NULL != cfg->subprotocol) {
+               free(cfg->subprotocol);
+               cfg->subprotocol = NULL;
+       }
+
+    memset(cfg, 0, sizeof(sim_websocket_config_storage_t));
+    free(client->config);
+    client->config = NULL;
+    return ESP_OK;
+}
+
+static void set_websocket_transport_optional_settings(sim_esp_websocket_client_handle_t client, wb_esp_transport_handle_t trans)
+{
+    if (trans && client->config->path) {
+        wb_esp_transport_ws_set_path(trans, client->config->path);
+    }
+    if (trans && client->config->subprotocol) {
+        wb_esp_transport_ws_set_subprotocol(trans, client->config->subprotocol);
+    }
+}
+
+sim_esp_websocket_client_handle_t chat_websocket_client_init(const sim_esp_websocket_client_config_t *config)
+{
+    wb_esp_transport_handle_t tcp = NULL;
+    wb_esp_transport_handle_t ws  = NULL;
+    wb_esp_transport_handle_t ssl = NULL;
+    wb_esp_transport_handle_t wss = NULL;
+    int buffer_size = 0;    
+       OS_STATUS status;
+       
+    sim_esp_websocket_client_handle_t client = (sim_esp_websocket_client_handle_t)malloc(1*sizeof(struct sim_esp_websocket_client));
+    ESP_WS_CLIENT_MEM_CHECK(client, return NULL);
+       memset(client, '\0', sizeof(struct sim_esp_websocket_client));
+       client->state = WEBSOCKET_STATE_UNKNOW;
+       
+       status = OSAMutexCreate(&client->lock, OSA_FIFO);
+       if (OS_SUCCESS != status) {
+               ESP_LOGE("Failed to create client lock");
+       }
+       
+    client->config = calloc(1, sizeof(sim_websocket_config_storage_t));
+    ESP_WS_CLIENT_MEM_CHECK(client->config, goto _websocket_init_fail);
+
+    client->transport_list = wb_esp_transport_list_init();
+    ESP_WS_CLIENT_MEM_CHECK(client->transport_list, goto _websocket_init_fail);
+
+    tcp = wb_esp_transport_tcp_init();
+    ESP_WS_CLIENT_MEM_CHECK(tcp, goto _websocket_init_fail);
+
+    wb_esp_transport_set_default_port(tcp, WEBSOCKET_TCP_DEFAULT_PORT);
+    wb_esp_transport_list_add(client->transport_list, tcp, "_tcp"); // need to save to transport list, for cleanup
+
+
+    ws = wb_esp_transport_ws_init(tcp);
+    ESP_WS_CLIENT_MEM_CHECK(ws, goto _websocket_init_fail);
+
+    wb_esp_transport_set_default_port(ws, WEBSOCKET_TCP_DEFAULT_PORT);
+    wb_esp_transport_list_add(client->transport_list, ws, "ws");
+    if (config->transport == WEBSOCKET_TRANSPORT_OVER_TCP) {
+        sprintf(client->config->scheme, "%s", "ws");
+        ESP_WS_CLIENT_MEM_CHECK(client->config->scheme, goto _websocket_init_fail);
+    }
+
+    ssl = wb_esp_transport_ssl_init();
+    ESP_WS_CLIENT_MEM_CHECK(ssl, goto _websocket_init_fail);
+
+    wb_esp_transport_set_default_port(ssl, WEBSOCKET_SSL_DEFAULT_PORT);
+    if (config->cert_pem) {
+        wb_esp_transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem));
+    }
+    wb_esp_transport_list_add(client->transport_list, ssl, "_ssl"); // need to save to transport list, for cleanup
+
+    wss = wb_esp_transport_ws_init(ssl);
+    ESP_WS_CLIENT_MEM_CHECK(wss, goto _websocket_init_fail);
+
+    wb_esp_transport_set_default_port(wss, WEBSOCKET_SSL_DEFAULT_PORT);
+
+    wb_esp_transport_list_add(client->transport_list, wss, "wss");
+    if (config->transport == WEBSOCKET_TRANSPORT_OVER_SSL) {
+        sprintf(client->config->scheme, "%s", "wss");
+        ESP_WS_CLIENT_MEM_CHECK(client->config->scheme, goto _websocket_init_fail);
+    }
+
+    if (config->uri) {
+        if (chat_websocket_client_set_uri(client, config->uri) != ESP_OK) {
+            ESP_LOGE("Invalid uri");
+            goto _websocket_init_fail;
+        }
+    }
+
+    if (chat_websocket_client_set_config(client, config) != ESP_OK) {
+        ESP_LOGE("Failed to set the configuration");
+        goto _websocket_init_fail;
+    }
+
+    if (client->config->scheme == NULL) {
+        sprintf(client->config->scheme, "%s", "ws");
+        ESP_WS_CLIENT_MEM_CHECK(client->config->scheme, goto _websocket_init_fail);
+    }
+
+    set_websocket_transport_optional_settings(client, wb_esp_transport_list_get_transport(client->transport_list, "ws"));
+    set_websocket_transport_optional_settings(client, wb_esp_transport_list_get_transport(client->transport_list, "wss"));
+
+    client->keepalive_tick_ms = _tick_get_ms();
+    client->reconnect_tick_ms = _tick_get_ms();
+    client->ping_tick_ms = _tick_get_ms();
+
+    buffer_size = config->buffer_size;
+    if (buffer_size <= 0) {
+        buffer_size = WEBSOCKET_BUFFER_SIZE_BYTE;
+    }
+    client->rx_buffer = malloc(buffer_size);
+    ESP_WS_CLIENT_MEM_CHECK(client->rx_buffer, {
+        goto _websocket_init_fail;
+    });
+    client->tx_buffer = malloc(buffer_size);
+    ESP_WS_CLIENT_MEM_CHECK(client->tx_buffer, {
+        goto _websocket_init_fail;
+    });
+
+    client->buffer_size = buffer_size;
+    return client;
+
+_websocket_init_fail:
+    chat_websocket_client_destroy(client);
+    return NULL;
+}
+
+esp_err_t chat_websocket_client_destroy(sim_esp_websocket_client_handle_t client)
+{
+    if (client == NULL) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if (1 == task_run) {
+        chat_websocket_client_stop(client);
+    }
+       
+       OSAMutexDelete(client->lock);
+
+    chat_websocket_client_destroy_config(client);
+               
+    wb_esp_transport_list_destroy(client->transport_list);
+       
+       if (NULL != client->tx_buffer) {
+               free(client->tx_buffer);
+               client->tx_buffer = NULL;
+       }
+       if (NULL != client->rx_buffer) {
+               free(client->rx_buffer);
+               client->rx_buffer = NULL;
+       }
+       if (NULL != client) {
+               free(client);
+               client = NULL;
+       }
+       
+    return ESP_OK;
+}
+
+esp_err_t chat_websocket_client_set_uri(sim_esp_websocket_client_handle_t client, const char *uri)
+{
+    if (client == NULL || uri == NULL) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    struct http_parser_url puri;
+    wb_http_parser_url_init(&puri);
+    int parser_status = wb_http_parser_parse_url(uri, strlen(uri), 0, &puri);
+    if (parser_status != 0) {
+        ESP_LOGE("Error parse uri = %s", uri);
+        return ESP_FAIL;
+    }
+    if (puri.field_data[UF_SCHEMA].len) {
+        //free(client->config->scheme);
+        sprintf(client->config->scheme, "%.*s", puri.field_data[UF_SCHEMA].len, uri + puri.field_data[UF_SCHEMA].off);
+        ESP_WS_CLIENT_MEM_CHECK(client->config->scheme, return ESP_ERR_NO_MEM);
+    }
+
+    if (puri.field_data[UF_HOST].len) {
+        //free(client->config->host);
+        sprintf(client->config->host, "%.*s", puri.field_data[UF_HOST].len, uri + puri.field_data[UF_HOST].off);
+        ESP_WS_CLIENT_MEM_CHECK(client->config->host, return ESP_ERR_NO_MEM);
+    }
+
+
+    if (puri.field_data[UF_PATH].len || puri.field_data[UF_QUERY].len) {
+        //free(client->config->path);
+        if (puri.field_data[UF_QUERY].len == 0) {
+            sprintf(client->config->path, "%.*s", puri.field_data[UF_PATH].len, uri + puri.field_data[UF_PATH].off);
+        } else if (puri.field_data[UF_PATH].len == 0)  {
+            sprintf(client->config->path, "/?%.*s", puri.field_data[UF_QUERY].len, uri + puri.field_data[UF_QUERY].off);
+        } else {
+            sprintf(client->config->path, "%.*s?%.*s", puri.field_data[UF_PATH].len, uri + puri.field_data[UF_PATH].off,
+                    puri.field_data[UF_QUERY].len, uri + puri.field_data[UF_QUERY].off);
+        }
+        ESP_WS_CLIENT_MEM_CHECK(client->config->path, return ESP_ERR_NO_MEM);
+    }
+    if (puri.field_data[UF_PORT].off) {
+        client->config->port = strtol((const char*)(uri + puri.field_data[UF_PORT].off), NULL, 10);
+    }
+
+    if (puri.field_data[UF_USERINFO].len) {
+        char user_info[1024];
+        memset(user_info, '\0', 1024);
+        sprintf(user_info, "%.*s", puri.field_data[UF_USERINFO].len, uri + puri.field_data[UF_USERINFO].off);
+        if (user_info) {
+            char *pass = strchr(user_info, ':');
+            if (pass) {
+                pass[0] = 0; //terminal username
+                pass ++;
+                //free(client->config->password);
+                client->config->password = strdup(pass);
+                ESP_WS_CLIENT_MEM_CHECK(client->config->password, return ESP_ERR_NO_MEM);
+            }
+            //free(client->config->username);
+            client->config->username = strdup(user_info);
+            ESP_WS_CLIENT_MEM_CHECK(client->config->username, return ESP_ERR_NO_MEM);
+            //free(user_info);
+        } else {
+            return ESP_ERR_NO_MEM;
+        }
+    }
+    return ESP_OK;
+}
+
+static esp_err_t chat_websocket_client_recv(sim_esp_websocket_client_handle_t client)
+{
+    int rlen;
+    client->payload_offset = 0;
+       memset(client->rx_buffer, 0, client->buffer_size);
+    do {
+        rlen = wb_esp_transport_read(client->transport, client->rx_buffer, client->buffer_size, client->config->network_timeout_ms);
+        if (rlen <= 0) {
+            ESP_LOGE("Error read data");
+            chat_websocket_client_abort_connection(client);
+            return ESP_FAIL;
+        }
+        client->payload_len = wb_esp_transport_ws_get_read_payload_len(client->transport);
+        client->last_opcode = wb_esp_transport_ws_get_read_opcode(client->transport);
+
+        chat_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_DATA, client->rx_buffer, rlen);
+
+        client->payload_offset += rlen;
+    } while (client->payload_offset < client->payload_len);
+
+    // if a PING message received -> send out the PONG, this will not work for PING messages with payload longer than buffer len
+    if (client->last_opcode == WS_TRANSPORT_OPCODES_PING) {
+        const char *data = (client->payload_len == 0) ? NULL : client->rx_buffer;
+        wb_esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PONG, data, client->payload_len,
+                                  client->config->network_timeout_ms);
+    } else if (client->last_opcode == WS_TRANSPORT_OPCODES_CLOSE) {
+        ESP_LOGD("Received close frame");
+        client->state = WEBSOCKET_STATE_CLOSING;
+    }
+
+    return ESP_OK;
+}
+
+static void chat_websocket_client_task(void *pv)
+{
+       OSA_STATUS status;
+       int ret = 0;
+    const int lock_timeout = portMAX_DELAY;
+    sim_esp_websocket_client_handle_t client = (sim_esp_websocket_client_handle_t) pv;
+    task_run = 1;
+
+    //get transport by scheme
+    client->transport = wb_esp_transport_list_get_transport(client->transport_list, client->config->scheme);
+
+    if (client->transport == NULL) {
+        ESP_LOGE("There are no transports valid, stop websocket client");
+        task_run = 0;
+    }
+    //default port
+    if (client->config->port == 0) {
+        client->config->port = wb_esp_transport_get_default_port(client->transport);
+    }
+
+    client->state = WEBSOCKET_STATE_INIT;
+    int read_select = 0;
+    while (1) {
+               if (0 == task_run) {
+                       ESP_LOGE("%s: task_run=0 and task exit", __FUNCTION__);
+                       break;
+               }
+       
+               //ESP_LOGD("%s, client state is %d, client->run is %d", 
+               //                      __FUNCTION__, (int)client->state, task_run);
+  
+               status = OSAMutexLock(client->lock, OSA_SUSPEND);
+               if (status != OS_SUCCESS) {
+                       ESP_LOGE("%s: get lock failed and task exit", __FUNCTION__);
+                       break;
+               }
+        switch ((int)client->state) {
+            case WEBSOCKET_STATE_INIT:
+                if (client->transport == NULL) {
+                    ESP_LOGE("There are no transport");
+                    task_run = 0;
+                    break;
+                }
+                               
+                if (wb_esp_transport_connect(client->transport,
+                                          client->config->host,
+                                          client->config->port,
+                                          client->config->network_timeout_ms) < 0) {
+                    ESP_LOGE("Error transport connect");
+                    ret  = chat_websocket_client_abort_connection(client);
+                                       ESP_LOGD("%s, client abort connection ret is %d", __FUNCTION__, ret);
+                    break;
+                }
+                ESP_LOGD("Transport connected to %s://%s:%d", client->config->scheme, client->config->host, client->config->port);
+
+                client->state = WEBSOCKET_STATE_CONNECTED;
+                chat_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_CONNECTED, NULL, 0);
+
+                break;
+            case WEBSOCKET_STATE_CONNECTED:
+                if (_tick_get_ms() - client->ping_tick_ms > WEBSOCKET_PING_TIMEOUT_MS) {
+                    client->ping_tick_ms = _tick_get_ms();
+                    ESP_LOGD("Sending PING...");
+                    wb_esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PING, NULL, 0, client->config->network_timeout_ms);
+                }
+
+                if (read_select == 0) {
+                    //ESP_LOGV("Read poll timeout: skipping esp_transport_read()...");
+                    break;
+                }
+                client->ping_tick_ms = _tick_get_ms();
+
+                if (chat_websocket_client_recv(client) == ESP_FAIL) {
+                    ESP_LOGE("Error receive data");
+                    chat_websocket_client_abort_connection(client);
+                    break;
+                }
+                break;
+            case WEBSOCKET_STATE_WAIT_TIMEOUT:
+                if (!client->config->auto_reconnect) {
+                    task_run = 0;
+                    break;
+                }
+                if (_tick_get_ms() - client->reconnect_tick_ms > client->wait_timeout_ms) {
+                    client->state = WEBSOCKET_STATE_INIT;
+                    client->reconnect_tick_ms = _tick_get_ms();
+                    ESP_LOGD("Reconnecting...");
+                } else {
+                                       client->state = WEBSOCKET_STATE_WAIT_TIMEOUT;
+                                       ESP_LOGD("Waiting connect...");
+                               }
+                break;
+                       case WEBSOCKET_STATE_CLOSING:
+                               // if closing not initiated by the client echo the close message back
+                               ESP_LOGD("Closing initiated by the server, sending close frame");
+                               wb_esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_CLOSE | WS_TRANSPORT_OPCODES_FIN, NULL, 0, client->config->network_timeout_ms);
+                               break;
+
+                       default:                                
+                               ESP_LOGD("Client run iteration in a default state: %d", client->state);
+                               break;
+        }
+               OSAMutexUnlock(client->lock); 
+
+               if (WEBSOCKET_STATE_CONNECTED == client->state) {
+            read_select = wb_esp_transport_poll_read(client->transport, 1000); //Poll every 1000ms
+            if (read_select < 0) {
+                ESP_LOGE("Network error: esp_transport_poll_read() returned %d, errno=%d", read_select, errno);
+                chat_websocket_client_abort_connection(client);
+            }
+        } else if (WEBSOCKET_STATE_WAIT_TIMEOUT == client->state) {
+            // waiting for reconnecting...
+            OSATaskSleep(client->wait_timeout_ms / 2 / sim_portTICK_RATE_MS);
+        } else if (WEBSOCKET_STATE_CLOSING == client->state) {
+            ESP_LOGD(" Waiting for TCP connection to be closed by the server");
+            ret = esp_transport_ws_poll_connection_closed(client->transport, 1000);
+            if (ret == 0) {
+                // still waiting
+                break;
+            }
+            if (ret < 0) {
+                ESP_LOGW("Connection terminated while waiting for clean TCP close");
+            }
+            task_run = 0;
+            client->state = WEBSOCKET_STATE_UNKNOW;
+            chat_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_CLOSED, NULL, 0);
+            break;
+        }
+    }
+       
+    wb_esp_transport_close(client->transport);
+    client->state = WEBSOCKET_STATE_UNKNOW;
+    ESP_LOGD("%s task exit!task_run=%d, client state=%d",
+        __FUNCTION__, task_run, client->state);
+       return;
+}
+
+esp_err_t chat_websocket_client_start(sim_esp_websocket_client_handle_t client)
+{
+       OS_STATUS status = OS_SUCCESS;
+
+    if (client == NULL) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if (client->state > WEBSOCKET_STATE_INIT) {
+        ESP_LOGE("The client has started and client state is %d", client->state);
+        return ESP_FAIL;
+    }
+
+       if (NULL == chat_websocket_client_ref) {
+               if (NULL == chat_websocket_client_stack_ptr) {
+                       chat_websocket_client_stack_ptr = malloc(8*1024);
+                       if (NULL == chat_websocket_client_stack_ptr)    {
+                               ESP_LOGE("websocket task stack malloc failed.");
+                               return ESP_ERR_NO_MEM;
+                       }
+               }
+               status = OSATaskCreate(&chat_websocket_client_ref, 
+                                                         chat_websocket_client_stack_ptr,
+                                                         8*1024,
+                                                         90,
+                                                         "chat_ws_task",
+                                                         chat_websocket_client_task,
+                                                         (void *)client);
+               if (OS_SUCCESS != status) {
+                       if (chat_websocket_client_stack_ptr) {
+                               free(chat_websocket_client_stack_ptr);
+                               chat_websocket_client_stack_ptr = NULL;
+                       }
+                       ESP_LOGE("Error create websocket task");
+               }
+       } else {
+               ESP_LOGD("websocket task is exist!");
+       }
+       
+    ESP_LOGD("websocket_version: %s.", websocket_version);
+       ESP_LOGD("create ws task SUCCESS!");
+    return ESP_OK;
+}
+
+esp_err_t chat_websocket_client_stop(sim_esp_websocket_client_handle_t client)
+{
+    if (client == NULL) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if (0 == task_run) {
+        ESP_LOGW("Client was not started");
+        return ESP_FAIL;
+    }
+    task_run = 0;      
+    client->state = WEBSOCKET_STATE_UNKNOW;
+    //delete task
+    if(chat_websocket_client_ref == NULL) {
+        ESP_LOGD("websocket task is not exist!");
+        return ESP_FAIL;
+    }
+    ESP_LOGD("task deleting...");
+#if 1 //liangrf @ fixed Bug #50522 (release select_cb)
+    lwip_trigger_process("select", chat_websocket_client_ref);
+#endif
+    OSA_STATUS delete_status = OSATaskDelete(chat_websocket_client_ref);
+    ESP_LOGD("task deleted, deleteTaskRet is %d...", delete_status);
+    if(chat_websocket_client_stack_ptr) {
+        free(chat_websocket_client_stack_ptr);
+        chat_websocket_client_stack_ptr = NULL;
+    }
+    chat_websocket_client_ref = NULL;
+    //delete task
+    
+    ESP_LOGD("%s, client state is %d, task_run is %d", 
+               __FUNCTION__, (int)client->state, task_run);
+    return ESP_OK;
+}
+
+static int chat_websocket_client_send_close(sim_esp_websocket_client_handle_t client, int code, const char *additional_data, int total_len, TickType_t timeout)
+{
+    char *close_status_data = NULL;
+    // RFC6455#section-5.5.1: The Close frame MAY contain a body (indicated by total_len >= 2)
+    if (total_len >= 2) {
+        close_status_data = calloc(1, total_len);
+        ESP_WS_CLIENT_MEM_CHECK(close_status_data, return -1);
+        // RFC6455#section-5.5.1: The first two bytes of the body MUST be a 2-byte representing a status
+        uint16_t *code_network_order = (uint16_t *) close_status_data;
+        *code_network_order = htons(code);
+        memcpy(close_status_data + 2, additional_data, total_len - 2);
+    }
+    int ret = chat_websocket_client_send_with_opcode(client, WS_TRANSPORT_OPCODES_CLOSE, close_status_data, total_len, timeout);
+       if (NULL != close_status_data) {
+               free(close_status_data);
+               close_status_data = NULL;
+       }
+    return ret;
+}
+
+
+static int chat_websocket_client_close_with_optional_body(sim_esp_websocket_client_handle_t client, bool send_body, int code, const char *data, int len, TickType_t timeout)
+{
+       int ret = 0;
+       
+    if (client == NULL) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if (0 == task_run) {
+        ESP_LOGW("Client was not started");
+        return ESP_FAIL;
+    }
+
+    if (send_body) {
+        ret = chat_websocket_client_send_close(client, code, data, len + 2, portMAX_DELAY); // len + 2 -> always sending the code
+    } else {
+        ret = chat_websocket_client_send_close(client, 0, NULL, 0, portMAX_DELAY); // only opcode frame
+    }
+
+    // If could not close gracefully within timeout, stop the client and disconnect
+    //task_run = 0;
+    //client->state = WEBSOCKET_STATE_UNKNOW;
+    if (ret >= 0) {
+               return ESP_OK;
+       } else {
+               ESP_LOGW("Client send close failed");
+               return ESP_FAIL;
+       }
+}
+
+int chat_websocket_client_close_with_code(sim_esp_websocket_client_handle_t client, int code, const char *data, int len, TickType_t timeout)
+{
+    return chat_websocket_client_close_with_optional_body(client, true, code, data, len, timeout);
+}
+
+int chat_websocket_client_close(sim_esp_websocket_client_handle_t client, TickType_t timeout)
+{
+    return chat_websocket_client_close_with_optional_body(client, false, 0, NULL, 0, timeout);
+}
+
+int chat_websocket_client_send_text(sim_esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout)
+{
+    return chat_websocket_client_send_with_opcode(client, WS_TRANSPORT_OPCODES_TEXT, data, len, timeout);
+}
+
+int chat_websocket_client_send(sim_esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout)
+{
+    return chat_websocket_client_send_with_opcode(client, WS_TRANSPORT_OPCODES_BINARY, data, len, timeout);
+}
+
+int chat_websocket_client_send_bin(sim_esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout)
+{
+    return chat_websocket_client_send_with_opcode(client, WS_TRANSPORT_OPCODES_BINARY, data, len, timeout);
+}
+
+static int chat_websocket_client_send_with_opcode(sim_esp_websocket_client_handle_t client, ws_transport_opcodes_t opcode, const char *data, int len, TickType_t timeout)
+{
+    int need_write = len;
+    int wlen = 0, widx = 0;
+    int ret = ESP_FAIL;
+    UINT32 current_opcode = opcode;
+       OSA_STATUS status;
+
+    if (client == NULL || len < 0 ||
+        (opcode != WS_TRANSPORT_OPCODES_CLOSE && (data == NULL || len <= 0))) {
+        ESP_LOGE("Invalid arguments");
+        return ESP_FAIL;
+    }
+       
+       status = OSAMutexLock(client->lock, timeout);
+       if (status != OS_SUCCESS) {
+               ESP_LOGE("%s: get lock failed and return error", __FUNCTION__);
+               return ESP_FAIL;
+       }
+    if (!chat_websocket_client_is_connected(client)) {
+        ESP_LOGE("Websocket client is not connected");
+        goto unlock_and_return;
+    }
+
+    if (client->transport == NULL) {
+        ESP_LOGE("Invalid transport");
+        goto unlock_and_return;
+    }
+
+    while (widx < len || current_opcode) {  // allow for sending "current_opcode" only message with len==0
+        if (need_write > client->buffer_size) {
+            need_write = client->buffer_size;
+        } else {
+            current_opcode |= WS_TRANSPORT_OPCODES_FIN;
+        }
+        memcpy(client->tx_buffer, data + widx, need_write);
+        // send with ws specific way and specific opcode
+        wlen = wb_esp_transport_ws_send_raw(client->transport, current_opcode, (char *)client->tx_buffer, need_write,
+                                        (timeout==portMAX_DELAY)? -1 : timeout * sim_portTICK_PERIOD_MS);
+        if (wlen < 0 || (wlen == 0 && need_write != 0)) {
+            ret = wlen;
+            ESP_LOGE("Network error: esp_transport_write() returned %d, errno=%d", ret, errno);
+            chat_websocket_client_abort_connection(client);
+            goto unlock_and_return;
+        }
+        current_opcode = 0;
+        widx += wlen;
+        need_write = len - widx;
+    }
+
+    ret = widx;
+unlock_and_return:
+       OSAMutexUnlock(client->lock);
+    return ret;
+}
+
+bool chat_websocket_client_is_connected(sim_esp_websocket_client_handle_t client)
+{
+    if (client == NULL) {
+        return false;
+    }
+    return client->state == WEBSOCKET_STATE_CONNECTED;
+}
+
+esp_err_t chat_websocket_register_events(sim_esp_websocket_client_handle_t client,
+                                        sim_esp_event_handler_t event_handler)
+{
+    if (client == NULL) {
+        return -1;
+    }
+       ESP_LOGD("client handler register success!!");
+       client->handler = event_handler;
+    return 0;
+}
index 1890242..d58e597 100644 (file)
@@ -5,7 +5,9 @@
 
 #include "uart.h"
 #include "sim_esp_websocket_client.h"
-#include "Mmi_aigc_trans_websocket.h"
+#include "mmi_aigc_websocket.h"
+
+#define MMI_AIGC_TRANS_WEBSOCKET_URI "ws://121.40.67.151:9099/asr/ws"
 
 static sim_esp_websocket_client_handle_t s_aigc_trans_ws_client_p = NULL;
 
diff --git a/2.sdk/sdk/product/craneg_modem/pcac/wsclient/libwebsockets/src/mmi_aigc_tts_websocket.c b/2.sdk/sdk/product/craneg_modem/pcac/wsclient/libwebsockets/src/mmi_aigc_tts_websocket.c
new file mode 100644 (file)
index 0000000..19bee17
--- /dev/null
@@ -0,0 +1,143 @@
+
+
+
+#if 1 // def __MMI_CUSTOM_AIGC_SUPPORT__
+
+#include "uart.h"
+#include "mmi_aigc_tts_websocket_client.h"
+#include "mmi_aigc_websocket.h"
+
+#define MMI_AIGC_TTS_WEBSOCKET_URI "ws://121.40.67.151:9099/tts/stream"
+
+static sim_esp_websocket_client_handle_t s_aigc_tts_ws_client_p = NULL;
+
+extern void mmi_aigc_tts_websocket_recv_data_handler(char * data_ptr, int data_len, int payload_len, int payload_offset);
+
+
+
+int mmi_aigc_tts_websocket_send_text_data(char * data_ptr, int data_len)
+{
+       int ret = 0;
+
+       AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: \n", __FUNCTION__, __LINE__);
+    ret = tts_websocket_client_send_text(s_aigc_tts_ws_client_p, data_ptr, data_len, portMAX_DELAY);
+       if (0 > ret)
+       {
+               AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: \n", __FUNCTION__, __LINE__);
+       }
+
+       return ret;
+}
+
+int mmi_aigc_tts_websocket_send_binary_data(char * data_ptr, int data_len)
+{
+       int ret = 0;
+
+       AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: \n", __FUNCTION__, __LINE__);
+    ret = tts_websocket_client_send_bin(s_aigc_tts_ws_client_p, data_ptr, data_len, portMAX_DELAY);
+       if (0 > ret)
+       {
+               AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: \n", __FUNCTION__, __LINE__);
+       }
+
+       return ret;
+}
+
+static void mmi_aigc_tts_websocket_event_handler(int32_t event_id, void *event_data)
+{
+    sim_esp_websocket_event_data_t *data = (sim_esp_websocket_event_data_t *)event_data;
+       
+       AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: event_id=%d\n", __FUNCTION__, __LINE__, event_id);
+    switch (event_id)
+       {
+           case WEBSOCKET_EVENT_CONNECTED:
+                       AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%d]: WEBSOCKET_EVENT_CONNECTED\n", __LINE__);
+               break;
+                       
+           case WEBSOCKET_EVENT_DISCONNECTED:
+                       AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%d]: WEBSOCKET_EVENT_DISCONNECTED\n", __LINE__);
+               break;
+                       
+           case WEBSOCKET_EVENT_DATA:
+                       AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%d]: WEBSOCKET_EVENT_DATA\n", __LINE__);
+               AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG]: data opcode=%d,data len=%d", data->op_code, data->data_len);
+               AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG]: Total payload len=%d,current payload offset=%d\r\n", data->payload_len, data->payload_offset);
+               if (data->op_code == 0x08 && data->data_len == 2) {
+                   AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG]: Received closed message with code=%d", 256*data->data_ptr[0] + data->data_ptr[1]);
+               }
+                       else
+                       {
+                   AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG]: Received=%.*s", data->data_len, (char *)data->data_ptr);
+                               mmi_aigc_tts_websocket_recv_data_handler(data->data_ptr, data->data_len, data->payload_len, data->payload_offset);
+               }
+                       //OSATimerStart(shutdown_signal_timer, portMAX_DELAY, 0, shutdown_signaler, 0);
+                       break;
+                       
+           case WEBSOCKET_EVENT_ERROR:
+                       AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%d]: WEBSOCKET_EVENT_ERROR\n", __LINE__);
+               break;
+                       
+               case WEBSOCKET_EVENT_CLOSED:
+                       AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%d]: WEBSOCKET_EVENT_CLOSED\n", __LINE__);
+                       break;
+                       
+               default:
+                       AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%d]: default\n", __LINE__);
+                       break;
+    }
+
+       if (NULL != data)
+       {
+               if (NULL != data->data_ptr)
+               {
+                       free(data->data_ptr);
+                       data->data_ptr = NULL;
+                       AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: free data ptr\n", __FUNCTION__, __LINE__);
+               }
+
+               free(data);
+               data = NULL;
+               AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: free data\n", __FUNCTION__, __LINE__);
+       }
+}
+
+void mmi_aigc_tts_websocket_app_start(void)
+{
+       OS_STATUS status = 0;
+       int ret = 0;
+    sim_esp_websocket_client_config_t websocket_cfg = {0};
+
+    websocket_cfg.uri = MMI_AIGC_TTS_WEBSOCKET_URI;
+
+       AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: url=%s\n", __FUNCTION__, __LINE__, websocket_cfg.uri);
+
+    s_aigc_tts_ws_client_p = tts_websocket_client_init(&websocket_cfg);
+       if(NULL == s_aigc_tts_ws_client_p)
+       {
+               AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: websocket client init fail\n", __FUNCTION__, __LINE__);
+               return;
+       }
+       
+    tts_websocket_register_events(s_aigc_tts_ws_client_p, mmi_aigc_tts_websocket_event_handler);
+       
+    esp_err_t err_no = tts_websocket_client_start(s_aigc_tts_ws_client_p);
+       if(ESP_OK != err_no)
+       {
+               AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: websocket client start fail,%d\n", __FUNCTION__, __LINE__, err_no);
+               return;
+       }
+       else
+       {
+
+       }
+}
+
+void mmi_aigc_tts_websocket_app_stop(void)
+{
+       AIGC_WB_DEBUG_PRINTF("[@CHENG_DEBUG][%s][%d]: \n", __FUNCTION__, __LINE__);
+       
+       tts_websocket_client_destroy(s_aigc_tts_ws_client_p);
+}
+
+#endif
+
diff --git a/2.sdk/sdk/product/craneg_modem/pcac/wsclient/libwebsockets/src/mmi_aigc_tts_websocket_client.c b/2.sdk/sdk/product/craneg_modem/pcac/wsclient/libwebsockets/src/mmi_aigc_tts_websocket_client.c
new file mode 100644 (file)
index 0000000..0eb7392
--- /dev/null
@@ -0,0 +1,826 @@
+// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stdio.h>
+
+#include "mmi_aigc_tts_websocket_client.h"
+#include "web_esp_transport.h"
+#include "web_esp_transport_tcp.h"
+#include "web_esp_transport_ssl.h"
+#include "web_esp_transport_ws.h"
+
+/* using uri parser */
+#include "web_http_parser.h"
+#include "queue.h"
+#include "esp_log.h"
+#include "sockets.h"
+#include "osa.h"
+
+static int       task_run = 0;
+static OSTaskRef tts_websocket_client_ref = NULL;
+static void *    tts_websocket_client_stack_ptr = NULL;
+
+#define websocket_version                              "asr_websocket_v1.10_20210926"
+#define WEBSOCKET_TCP_DEFAULT_PORT      (80)
+#define WEBSOCKET_SSL_DEFAULT_PORT      (443)
+#define WEBSOCKET_BUFFER_SIZE_BYTE      (8*1024)
+#define WEBSOCKET_RECONNECT_TIMEOUT_MS  (5*60*1000)
+#define WEBSOCKET_TASK_PRIORITY         (90)
+#define WEBSOCKET_TASK_STACK            (8*1024)
+#define WEBSOCKET_NETWORK_TIMEOUT_MS    (10*1000)
+#define WEBSOCKET_PING_TIMEOUT_MS       (15*60*1000)
+#define WEBSOCKET_EVENT_QUEUE_SIZE      (1)
+
+#define ESP_WS_CLIENT_MEM_CHECK(a, action) if (!(a)) {                                         \
+        ESP_LOGE("%s:%d (%s): %s", __FILE__, __LINE__, __FUNCTION__, "Memory exhausted");       \
+        action;                                                                                     \
+        }
+#define ESP_EVENT_DECLARE_BASE(id) extern esp_event_base_t id
+#define ESP_EVENT_DEFINE_BASE(id) esp_event_base_t id = #id
+
+static int tts_websocket_client_send_with_opcode(sim_esp_websocket_client_handle_t client, ws_transport_opcodes_t opcode, const char *data, int len, TickType_t timeout);
+static void asr_ws_loop_run_task(void *pv);
+extern OSMsgQRef asr_ws_msgQ_ref;
+extern int esp_transport_ws_poll_connection_closed(wb_esp_transport_handle_t t, int timeout_ms);
+
+static UINT32 _tick_get_ms(void)
+{
+       return (5*OSAGetTicks());       //get ms
+    //return esp_timer_get_time()/1000;
+}
+
+static int tts_websocket_client_dispatch_event(sim_esp_websocket_client_handle_t client,
+                                                     sim_esp_websocket_event_id_t event,
+                                                     const char *data,
+                                                     int data_len)
+{
+       if (client->handler) {
+               if (NULL == data) {
+                       client->handler(event, NULL);
+               } else {
+                       sim_esp_websocket_event_data_t *event_data = NULL;
+                       event_data = malloc(sizeof(sim_esp_websocket_event_data_t));
+                       if (NULL == event_data) {
+                               ESP_LOGE("%s, event_data malloc failed", __FUNCTION__);
+                               return -1;
+                       } else {
+                               memset(event_data, '\0', sizeof(sim_esp_websocket_event_data_t));
+                               event_data->data_ptr = malloc(data_len);
+                               if (event_data->data_ptr) {
+                                       memset(event_data->data_ptr, 0, data_len);
+                                       memcpy(event_data->data_ptr, data, data_len);
+                               }
+                       }
+
+                       event_data->data_len = data_len;
+               event_data->op_code  = client->last_opcode;
+            //shenxj+++
+            event_data->payload_len = client->payload_len;
+            event_data->payload_offset = client->payload_offset;
+            //shenxj---
+
+                       client->handler(event, event_data);
+               }
+       }
+
+       return 0;
+}
+
+static int tts_websocket_client_abort_connection(sim_esp_websocket_client_handle_t client)
+{
+       int ret = 0;
+       
+    wb_esp_transport_close(client->transport);
+    client->wait_timeout_ms = WEBSOCKET_RECONNECT_TIMEOUT_MS;
+    client->reconnect_tick_ms = _tick_get_ms();
+    client->state = WEBSOCKET_STATE_WAIT_TIMEOUT;
+    ESP_LOGI("Reconnect after %d ms", client->wait_timeout_ms);
+    ret = tts_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_DISCONNECTED, NULL, 0);
+       ESP_LOGD("%s, client abort connection ret is %d", __FUNCTION__, ret);
+    return ret;
+}
+
+static esp_err_t tts_websocket_client_set_config(sim_esp_websocket_client_handle_t client, const sim_esp_websocket_client_config_t *config)
+{
+    sim_websocket_config_storage_t *cfg = client->config;
+    cfg->task_prio = config->task_prio;
+    if (cfg->task_prio <= 0) {
+        cfg->task_prio = WEBSOCKET_TASK_PRIORITY;
+    }
+
+    cfg->task_stack = config->task_stack;
+    if (cfg->task_stack == 0) {
+        cfg->task_stack = WEBSOCKET_TASK_STACK;
+    }
+
+    if (config->host) {
+        cfg->p_host = strdup(config->host);
+               memcpy(cfg->host, cfg->p_host, strlen(config->host));
+        ESP_WS_CLIENT_MEM_CHECK(cfg->host, return ESP_ERR_NO_MEM);
+    }
+
+    if (config->port) {
+        cfg->port = config->port;
+    }
+
+    if (config->username) {
+        //free(cfg->username);
+        cfg->username = strdup(config->username);
+        ESP_WS_CLIENT_MEM_CHECK(cfg->username, return ESP_ERR_NO_MEM);
+    }
+
+    if (config->password) {
+        //free(cfg->password);
+        cfg->password = strdup(config->password);
+        ESP_WS_CLIENT_MEM_CHECK(cfg->password, return ESP_ERR_NO_MEM);
+    }
+
+    if (config->uri) {
+        //free(cfg->uri);
+        cfg->uri = strdup(config->uri);
+        ESP_WS_CLIENT_MEM_CHECK(cfg->uri, return ESP_ERR_NO_MEM);
+    }
+    if (config->path) {
+        //free(cfg->path);
+        cfg->p_path = strdup(config->path);
+               memcpy(cfg->path, cfg->p_path, strlen(config->path));
+        ESP_WS_CLIENT_MEM_CHECK(cfg->path, return ESP_ERR_NO_MEM);
+    }
+    if (config->subprotocol) {
+        //free(cfg->subprotocol);
+        cfg->subprotocol = strdup(config->subprotocol);
+        ESP_WS_CLIENT_MEM_CHECK(cfg->subprotocol, return ESP_ERR_NO_MEM);
+    }
+
+    cfg->network_timeout_ms = WEBSOCKET_NETWORK_TIMEOUT_MS;
+    cfg->user_context = config->user_context;
+    cfg->auto_reconnect = true;
+    if (config->disable_auto_reconnect) {
+        cfg->auto_reconnect = false;
+    }
+
+
+    return ESP_OK;
+}
+
+static esp_err_t tts_websocket_client_destroy_config(sim_esp_websocket_client_handle_t client)
+{
+    if (client == NULL) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    sim_websocket_config_storage_t *cfg = client->config;
+    if (client->config == NULL) {
+        return ESP_ERR_INVALID_ARG;
+    }
+       
+       if (NULL != cfg->p_host) {
+               free(cfg->p_host);
+               cfg->p_host = NULL;
+       }
+       if (NULL != cfg->uri) {
+               free(cfg->uri);
+               cfg->uri = NULL;
+       }
+       if (NULL != cfg->p_path) {
+               free(cfg->p_path);
+               cfg->p_path = NULL;
+       }
+       if (NULL != cfg->username) {
+               free(cfg->username);
+               cfg->username = NULL;
+       }
+       if (NULL != cfg->password) {
+               free(cfg->password);
+               cfg->password = NULL;
+       }
+       if (NULL != cfg->subprotocol) {
+               free(cfg->subprotocol);
+               cfg->subprotocol = NULL;
+       }
+
+    memset(cfg, 0, sizeof(sim_websocket_config_storage_t));
+    free(client->config);
+    client->config = NULL;
+    return ESP_OK;
+}
+
+static void set_websocket_transport_optional_settings(sim_esp_websocket_client_handle_t client, wb_esp_transport_handle_t trans)
+{
+    if (trans && client->config->path) {
+        wb_esp_transport_ws_set_path(trans, client->config->path);
+    }
+    if (trans && client->config->subprotocol) {
+        wb_esp_transport_ws_set_subprotocol(trans, client->config->subprotocol);
+    }
+}
+
+sim_esp_websocket_client_handle_t tts_websocket_client_init(const sim_esp_websocket_client_config_t *config)
+{
+    wb_esp_transport_handle_t tcp = NULL;
+    wb_esp_transport_handle_t ws  = NULL;
+    wb_esp_transport_handle_t ssl = NULL;
+    wb_esp_transport_handle_t wss = NULL;
+    int buffer_size = 0;    
+       OS_STATUS status;
+       
+    sim_esp_websocket_client_handle_t client = (sim_esp_websocket_client_handle_t)malloc(1*sizeof(struct sim_esp_websocket_client));
+    ESP_WS_CLIENT_MEM_CHECK(client, return NULL);
+       memset(client, '\0', sizeof(struct sim_esp_websocket_client));
+       client->state = WEBSOCKET_STATE_UNKNOW;
+       
+       status = OSAMutexCreate(&client->lock, OSA_FIFO);
+       if (OS_SUCCESS != status) {
+               ESP_LOGE("Failed to create client lock");
+       }
+       
+    client->config = calloc(1, sizeof(sim_websocket_config_storage_t));
+    ESP_WS_CLIENT_MEM_CHECK(client->config, goto _websocket_init_fail);
+
+    client->transport_list = wb_esp_transport_list_init();
+    ESP_WS_CLIENT_MEM_CHECK(client->transport_list, goto _websocket_init_fail);
+
+    tcp = wb_esp_transport_tcp_init();
+    ESP_WS_CLIENT_MEM_CHECK(tcp, goto _websocket_init_fail);
+
+    wb_esp_transport_set_default_port(tcp, WEBSOCKET_TCP_DEFAULT_PORT);
+    wb_esp_transport_list_add(client->transport_list, tcp, "_tcp"); // need to save to transport list, for cleanup
+
+
+    ws = wb_esp_transport_ws_init(tcp);
+    ESP_WS_CLIENT_MEM_CHECK(ws, goto _websocket_init_fail);
+
+    wb_esp_transport_set_default_port(ws, WEBSOCKET_TCP_DEFAULT_PORT);
+    wb_esp_transport_list_add(client->transport_list, ws, "ws");
+    if (config->transport == WEBSOCKET_TRANSPORT_OVER_TCP) {
+        sprintf(client->config->scheme, "%s", "ws");
+        ESP_WS_CLIENT_MEM_CHECK(client->config->scheme, goto _websocket_init_fail);
+    }
+
+    ssl = wb_esp_transport_ssl_init();
+    ESP_WS_CLIENT_MEM_CHECK(ssl, goto _websocket_init_fail);
+
+    wb_esp_transport_set_default_port(ssl, WEBSOCKET_SSL_DEFAULT_PORT);
+    if (config->cert_pem) {
+        wb_esp_transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem));
+    }
+    wb_esp_transport_list_add(client->transport_list, ssl, "_ssl"); // need to save to transport list, for cleanup
+
+    wss = wb_esp_transport_ws_init(ssl);
+    ESP_WS_CLIENT_MEM_CHECK(wss, goto _websocket_init_fail);
+
+    wb_esp_transport_set_default_port(wss, WEBSOCKET_SSL_DEFAULT_PORT);
+
+    wb_esp_transport_list_add(client->transport_list, wss, "wss");
+    if (config->transport == WEBSOCKET_TRANSPORT_OVER_SSL) {
+        sprintf(client->config->scheme, "%s", "wss");
+        ESP_WS_CLIENT_MEM_CHECK(client->config->scheme, goto _websocket_init_fail);
+    }
+
+    if (config->uri) {
+        if (tts_websocket_client_set_uri(client, config->uri) != ESP_OK) {
+            ESP_LOGE("Invalid uri");
+            goto _websocket_init_fail;
+        }
+    }
+
+    if (tts_websocket_client_set_config(client, config) != ESP_OK) {
+        ESP_LOGE("Failed to set the configuration");
+        goto _websocket_init_fail;
+    }
+
+    if (client->config->scheme == NULL) {
+        sprintf(client->config->scheme, "%s", "ws");
+        ESP_WS_CLIENT_MEM_CHECK(client->config->scheme, goto _websocket_init_fail);
+    }
+
+    set_websocket_transport_optional_settings(client, wb_esp_transport_list_get_transport(client->transport_list, "ws"));
+    set_websocket_transport_optional_settings(client, wb_esp_transport_list_get_transport(client->transport_list, "wss"));
+
+    client->keepalive_tick_ms = _tick_get_ms();
+    client->reconnect_tick_ms = _tick_get_ms();
+    client->ping_tick_ms = _tick_get_ms();
+
+    buffer_size = config->buffer_size;
+    if (buffer_size <= 0) {
+        buffer_size = WEBSOCKET_BUFFER_SIZE_BYTE;
+    }
+    client->rx_buffer = malloc(buffer_size);
+    ESP_WS_CLIENT_MEM_CHECK(client->rx_buffer, {
+        goto _websocket_init_fail;
+    });
+    client->tx_buffer = malloc(buffer_size);
+    ESP_WS_CLIENT_MEM_CHECK(client->tx_buffer, {
+        goto _websocket_init_fail;
+    });
+
+    client->buffer_size = buffer_size;
+    return client;
+
+_websocket_init_fail:
+    tts_websocket_client_destroy(client);
+    return NULL;
+}
+
+esp_err_t tts_websocket_client_destroy(sim_esp_websocket_client_handle_t client)
+{
+    if (client == NULL) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if (1 == task_run) {
+        tts_websocket_client_stop(client);
+    }
+       
+       OSAMutexDelete(client->lock);
+
+    tts_websocket_client_destroy_config(client);
+               
+    wb_esp_transport_list_destroy(client->transport_list);
+       
+       if (NULL != client->tx_buffer) {
+               free(client->tx_buffer);
+               client->tx_buffer = NULL;
+       }
+       if (NULL != client->rx_buffer) {
+               free(client->rx_buffer);
+               client->rx_buffer = NULL;
+       }
+       if (NULL != client) {
+               free(client);
+               client = NULL;
+       }
+       
+    return ESP_OK;
+}
+
+esp_err_t tts_websocket_client_set_uri(sim_esp_websocket_client_handle_t client, const char *uri)
+{
+    if (client == NULL || uri == NULL) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    struct http_parser_url puri;
+    wb_http_parser_url_init(&puri);
+    int parser_status = wb_http_parser_parse_url(uri, strlen(uri), 0, &puri);
+    if (parser_status != 0) {
+        ESP_LOGE("Error parse uri = %s", uri);
+        return ESP_FAIL;
+    }
+    if (puri.field_data[UF_SCHEMA].len) {
+        //free(client->config->scheme);
+        sprintf(client->config->scheme, "%.*s", puri.field_data[UF_SCHEMA].len, uri + puri.field_data[UF_SCHEMA].off);
+        ESP_WS_CLIENT_MEM_CHECK(client->config->scheme, return ESP_ERR_NO_MEM);
+    }
+
+    if (puri.field_data[UF_HOST].len) {
+        //free(client->config->host);
+        sprintf(client->config->host, "%.*s", puri.field_data[UF_HOST].len, uri + puri.field_data[UF_HOST].off);
+        ESP_WS_CLIENT_MEM_CHECK(client->config->host, return ESP_ERR_NO_MEM);
+    }
+
+
+    if (puri.field_data[UF_PATH].len || puri.field_data[UF_QUERY].len) {
+        //free(client->config->path);
+        if (puri.field_data[UF_QUERY].len == 0) {
+            sprintf(client->config->path, "%.*s", puri.field_data[UF_PATH].len, uri + puri.field_data[UF_PATH].off);
+        } else if (puri.field_data[UF_PATH].len == 0)  {
+            sprintf(client->config->path, "/?%.*s", puri.field_data[UF_QUERY].len, uri + puri.field_data[UF_QUERY].off);
+        } else {
+            sprintf(client->config->path, "%.*s?%.*s", puri.field_data[UF_PATH].len, uri + puri.field_data[UF_PATH].off,
+                    puri.field_data[UF_QUERY].len, uri + puri.field_data[UF_QUERY].off);
+        }
+        ESP_WS_CLIENT_MEM_CHECK(client->config->path, return ESP_ERR_NO_MEM);
+    }
+    if (puri.field_data[UF_PORT].off) {
+        client->config->port = strtol((const char*)(uri + puri.field_data[UF_PORT].off), NULL, 10);
+    }
+
+    if (puri.field_data[UF_USERINFO].len) {
+        char user_info[1024];
+        memset(user_info, '\0', 1024);
+        sprintf(user_info, "%.*s", puri.field_data[UF_USERINFO].len, uri + puri.field_data[UF_USERINFO].off);
+        if (user_info) {
+            char *pass = strchr(user_info, ':');
+            if (pass) {
+                pass[0] = 0; //terminal username
+                pass ++;
+                //free(client->config->password);
+                client->config->password = strdup(pass);
+                ESP_WS_CLIENT_MEM_CHECK(client->config->password, return ESP_ERR_NO_MEM);
+            }
+            //free(client->config->username);
+            client->config->username = strdup(user_info);
+            ESP_WS_CLIENT_MEM_CHECK(client->config->username, return ESP_ERR_NO_MEM);
+            //free(user_info);
+        } else {
+            return ESP_ERR_NO_MEM;
+        }
+    }
+    return ESP_OK;
+}
+
+static esp_err_t tts_websocket_client_recv(sim_esp_websocket_client_handle_t client)
+{
+    int rlen;
+    client->payload_offset = 0;
+       memset(client->rx_buffer, 0, client->buffer_size);
+    do {
+        rlen = wb_esp_transport_read(client->transport, client->rx_buffer, client->buffer_size, client->config->network_timeout_ms);
+        if (rlen <= 0) {
+            ESP_LOGE("Error read data");
+            tts_websocket_client_abort_connection(client);
+            return ESP_FAIL;
+        }
+        client->payload_len = wb_esp_transport_ws_get_read_payload_len(client->transport);
+        client->last_opcode = wb_esp_transport_ws_get_read_opcode(client->transport);
+
+        tts_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_DATA, client->rx_buffer, rlen);
+
+        client->payload_offset += rlen;
+    } while (client->payload_offset < client->payload_len);
+
+    // if a PING message received -> send out the PONG, this will not work for PING messages with payload longer than buffer len
+    if (client->last_opcode == WS_TRANSPORT_OPCODES_PING) {
+        const char *data = (client->payload_len == 0) ? NULL : client->rx_buffer;
+        wb_esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PONG, data, client->payload_len,
+                                  client->config->network_timeout_ms);
+    } else if (client->last_opcode == WS_TRANSPORT_OPCODES_CLOSE) {
+        ESP_LOGD("Received close frame");
+        client->state = WEBSOCKET_STATE_CLOSING;
+    }
+
+    return ESP_OK;
+}
+
+static void tts_websocket_client_task(void *pv)
+{
+       OSA_STATUS status;
+       int ret = 0;
+    const int lock_timeout = portMAX_DELAY;
+    sim_esp_websocket_client_handle_t client = (sim_esp_websocket_client_handle_t) pv;
+    task_run = 1;
+
+    //get transport by scheme
+    client->transport = wb_esp_transport_list_get_transport(client->transport_list, client->config->scheme);
+
+    if (client->transport == NULL) {
+        ESP_LOGE("There are no transports valid, stop websocket client");
+        task_run = 0;
+    }
+    //default port
+    if (client->config->port == 0) {
+        client->config->port = wb_esp_transport_get_default_port(client->transport);
+    }
+
+    client->state = WEBSOCKET_STATE_INIT;
+    int read_select = 0;
+    while (1) {
+               if (0 == task_run) {
+                       ESP_LOGE("%s: task_run=0 and task exit", __FUNCTION__);
+                       break;
+               }
+       
+               //ESP_LOGD("%s, client state is %d, client->run is %d", 
+               //                      __FUNCTION__, (int)client->state, task_run);
+  
+               status = OSAMutexLock(client->lock, OSA_SUSPEND);
+               if (status != OS_SUCCESS) {
+                       ESP_LOGE("%s: get lock failed and task exit", __FUNCTION__);
+                       break;
+               }
+        switch ((int)client->state) {
+            case WEBSOCKET_STATE_INIT:
+                if (client->transport == NULL) {
+                    ESP_LOGE("There are no transport");
+                    task_run = 0;
+                    break;
+                }
+                               
+                if (wb_esp_transport_connect(client->transport,
+                                          client->config->host,
+                                          client->config->port,
+                                          client->config->network_timeout_ms) < 0) {
+                    ESP_LOGE("Error transport connect");
+                    ret  = tts_websocket_client_abort_connection(client);
+                                       ESP_LOGD("%s, client abort connection ret is %d", __FUNCTION__, ret);
+                    break;
+                }
+                ESP_LOGD("Transport connected to %s://%s:%d", client->config->scheme, client->config->host, client->config->port);
+
+                client->state = WEBSOCKET_STATE_CONNECTED;
+                tts_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_CONNECTED, NULL, 0);
+
+                break;
+            case WEBSOCKET_STATE_CONNECTED:
+                if (_tick_get_ms() - client->ping_tick_ms > WEBSOCKET_PING_TIMEOUT_MS) {
+                    client->ping_tick_ms = _tick_get_ms();
+                    ESP_LOGD("Sending PING...");
+                    wb_esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PING, NULL, 0, client->config->network_timeout_ms);
+                }
+
+                if (read_select == 0) {
+                    //ESP_LOGV("Read poll timeout: skipping esp_transport_read()...");
+                    break;
+                }
+                client->ping_tick_ms = _tick_get_ms();
+
+                if (tts_websocket_client_recv(client) == ESP_FAIL) {
+                    ESP_LOGE("Error receive data");
+                    tts_websocket_client_abort_connection(client);
+                    break;
+                }
+                break;
+            case WEBSOCKET_STATE_WAIT_TIMEOUT:
+                if (!client->config->auto_reconnect) {
+                    task_run = 0;
+                    break;
+                }
+                if (_tick_get_ms() - client->reconnect_tick_ms > client->wait_timeout_ms) {
+                    client->state = WEBSOCKET_STATE_INIT;
+                    client->reconnect_tick_ms = _tick_get_ms();
+                    ESP_LOGD("Reconnecting...");
+                } else {
+                                       client->state = WEBSOCKET_STATE_WAIT_TIMEOUT;
+                                       ESP_LOGD("Waiting connect...");
+                               }
+                break;
+                       case WEBSOCKET_STATE_CLOSING:
+                               // if closing not initiated by the client echo the close message back
+                               ESP_LOGD("Closing initiated by the server, sending close frame");
+                               wb_esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_CLOSE | WS_TRANSPORT_OPCODES_FIN, NULL, 0, client->config->network_timeout_ms);
+                               break;
+
+                       default:                                
+                               ESP_LOGD("Client run iteration in a default state: %d", client->state);
+                               break;
+        }
+               OSAMutexUnlock(client->lock); 
+
+               if (WEBSOCKET_STATE_CONNECTED == client->state) {
+            read_select = wb_esp_transport_poll_read(client->transport, 1000); //Poll every 1000ms
+            if (read_select < 0) {
+                ESP_LOGE("Network error: esp_transport_poll_read() returned %d, errno=%d", read_select, errno);
+                tts_websocket_client_abort_connection(client);
+            }
+        } else if (WEBSOCKET_STATE_WAIT_TIMEOUT == client->state) {
+            // waiting for reconnecting...
+            OSATaskSleep(client->wait_timeout_ms / 2 / sim_portTICK_RATE_MS);
+        } else if (WEBSOCKET_STATE_CLOSING == client->state) {
+            ESP_LOGD(" Waiting for TCP connection to be closed by the server");
+            ret = esp_transport_ws_poll_connection_closed(client->transport, 1000);
+            if (ret == 0) {
+                // still waiting
+                break;
+            }
+            if (ret < 0) {
+                ESP_LOGW("Connection terminated while waiting for clean TCP close");
+            }
+            task_run = 0;
+            client->state = WEBSOCKET_STATE_UNKNOW;
+            tts_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_CLOSED, NULL, 0);
+            break;
+        }
+    }
+       
+    wb_esp_transport_close(client->transport);
+    client->state = WEBSOCKET_STATE_UNKNOW;
+    ESP_LOGD("%s task exit!task_run=%d, client state=%d",
+        __FUNCTION__, task_run, client->state);
+       return;
+}
+
+esp_err_t tts_websocket_client_start(sim_esp_websocket_client_handle_t client)
+{
+       OS_STATUS status = OS_SUCCESS;
+
+    if (client == NULL) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if (client->state > WEBSOCKET_STATE_INIT) {
+        ESP_LOGE("The client has started and client state is %d", client->state);
+        return ESP_FAIL;
+    }
+
+       if (NULL == tts_websocket_client_ref) {
+               if (NULL == tts_websocket_client_stack_ptr) {
+                       tts_websocket_client_stack_ptr = malloc(8*1024);
+                       if (NULL == tts_websocket_client_stack_ptr)     {
+                               ESP_LOGE("websocket task stack malloc failed.");
+                               return ESP_ERR_NO_MEM;
+                       }
+               }
+               status = OSATaskCreate(&tts_websocket_client_ref, 
+                                                         tts_websocket_client_stack_ptr,
+                                                         8*1024,
+                                                         90,
+                                                         "tts_ws_task",
+                                                         tts_websocket_client_task,
+                                                         (void *)client);
+               if (OS_SUCCESS != status) {
+                       if (tts_websocket_client_stack_ptr) {
+                               free(tts_websocket_client_stack_ptr);
+                               tts_websocket_client_stack_ptr = NULL;
+                       }
+                       ESP_LOGE("Error create websocket task");
+               }
+       } else {
+               ESP_LOGD("websocket task is exist!");
+       }
+       
+    ESP_LOGD("websocket_version: %s.", websocket_version);
+       ESP_LOGD("create ws task SUCCESS!");
+    return ESP_OK;
+}
+
+esp_err_t tts_websocket_client_stop(sim_esp_websocket_client_handle_t client)
+{
+    if (client == NULL) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if (0 == task_run) {
+        ESP_LOGW("Client was not started");
+        return ESP_FAIL;
+    }
+    task_run = 0;      
+    client->state = WEBSOCKET_STATE_UNKNOW;
+    //delete task
+    if(tts_websocket_client_ref == NULL) {
+        ESP_LOGD("websocket task is not exist!");
+        return ESP_FAIL;
+    }
+    ESP_LOGD("task deleting...");
+#if 1 //liangrf @ fixed Bug #50522 (release select_cb)
+    lwip_trigger_process("select", tts_websocket_client_ref);
+#endif
+    OSA_STATUS delete_status = OSATaskDelete(tts_websocket_client_ref);
+    ESP_LOGD("task deleted, deleteTaskRet is %d...", delete_status);
+    if(tts_websocket_client_stack_ptr) {
+        free(tts_websocket_client_stack_ptr);
+        tts_websocket_client_stack_ptr = NULL;
+    }
+    tts_websocket_client_ref = NULL;
+    //delete task
+    
+    ESP_LOGD("%s, client state is %d, task_run is %d", 
+               __FUNCTION__, (int)client->state, task_run);
+    return ESP_OK;
+}
+
+static int tts_websocket_client_send_close(sim_esp_websocket_client_handle_t client, int code, const char *additional_data, int total_len, TickType_t timeout)
+{
+    char *close_status_data = NULL;
+    // RFC6455#section-5.5.1: The Close frame MAY contain a body (indicated by total_len >= 2)
+    if (total_len >= 2) {
+        close_status_data = calloc(1, total_len);
+        ESP_WS_CLIENT_MEM_CHECK(close_status_data, return -1);
+        // RFC6455#section-5.5.1: The first two bytes of the body MUST be a 2-byte representing a status
+        uint16_t *code_network_order = (uint16_t *) close_status_data;
+        *code_network_order = htons(code);
+        memcpy(close_status_data + 2, additional_data, total_len - 2);
+    }
+    int ret = tts_websocket_client_send_with_opcode(client, WS_TRANSPORT_OPCODES_CLOSE, close_status_data, total_len, timeout);
+       if (NULL != close_status_data) {
+               free(close_status_data);
+               close_status_data = NULL;
+       }
+    return ret;
+}
+
+
+static int tts_websocket_client_close_with_optional_body(sim_esp_websocket_client_handle_t client, bool send_body, int code, const char *data, int len, TickType_t timeout)
+{
+       int ret = 0;
+       
+    if (client == NULL) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if (0 == task_run) {
+        ESP_LOGW("Client was not started");
+        return ESP_FAIL;
+    }
+
+    if (send_body) {
+        ret = tts_websocket_client_send_close(client, code, data, len + 2, portMAX_DELAY); // len + 2 -> always sending the code
+    } else {
+        ret = tts_websocket_client_send_close(client, 0, NULL, 0, portMAX_DELAY); // only opcode frame
+    }
+
+    // If could not close gracefully within timeout, stop the client and disconnect
+    //task_run = 0;
+    //client->state = WEBSOCKET_STATE_UNKNOW;
+    if (ret >= 0) {
+               return ESP_OK;
+       } else {
+               ESP_LOGW("Client send close failed");
+               return ESP_FAIL;
+       }
+}
+
+int tts_websocket_client_close_with_code(sim_esp_websocket_client_handle_t client, int code, const char *data, int len, TickType_t timeout)
+{
+    return tts_websocket_client_close_with_optional_body(client, true, code, data, len, timeout);
+}
+
+int tts_websocket_client_close(sim_esp_websocket_client_handle_t client, TickType_t timeout)
+{
+    return tts_websocket_client_close_with_optional_body(client, false, 0, NULL, 0, timeout);
+}
+
+int tts_websocket_client_send_text(sim_esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout)
+{
+    return tts_websocket_client_send_with_opcode(client, WS_TRANSPORT_OPCODES_TEXT, data, len, timeout);
+}
+
+int tts_websocket_client_send(sim_esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout)
+{
+    return tts_websocket_client_send_with_opcode(client, WS_TRANSPORT_OPCODES_BINARY, data, len, timeout);
+}
+
+int tts_websocket_client_send_bin(sim_esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout)
+{
+    return tts_websocket_client_send_with_opcode(client, WS_TRANSPORT_OPCODES_BINARY, data, len, timeout);
+}
+
+static int tts_websocket_client_send_with_opcode(sim_esp_websocket_client_handle_t client, ws_transport_opcodes_t opcode, const char *data, int len, TickType_t timeout)
+{
+    int need_write = len;
+    int wlen = 0, widx = 0;
+    int ret = ESP_FAIL;
+    UINT32 current_opcode = opcode;
+       OSA_STATUS status;
+
+    if (client == NULL || len < 0 ||
+        (opcode != WS_TRANSPORT_OPCODES_CLOSE && (data == NULL || len <= 0))) {
+        ESP_LOGE("Invalid arguments");
+        return ESP_FAIL;
+    }
+       
+       status = OSAMutexLock(client->lock, timeout);
+       if (status != OS_SUCCESS) {
+               ESP_LOGE("%s: get lock failed and return error", __FUNCTION__);
+               return ESP_FAIL;
+       }
+    if (!tts_websocket_client_is_connected(client)) {
+        ESP_LOGE("Websocket client is not connected");
+        goto unlock_and_return;
+    }
+
+    if (client->transport == NULL) {
+        ESP_LOGE("Invalid transport");
+        goto unlock_and_return;
+    }
+
+    while (widx < len || current_opcode) {  // allow for sending "current_opcode" only message with len==0
+        if (need_write > client->buffer_size) {
+            need_write = client->buffer_size;
+        } else {
+            current_opcode |= WS_TRANSPORT_OPCODES_FIN;
+        }
+        memcpy(client->tx_buffer, data + widx, need_write);
+        // send with ws specific way and specific opcode
+        wlen = wb_esp_transport_ws_send_raw(client->transport, current_opcode, (char *)client->tx_buffer, need_write,
+                                        (timeout==portMAX_DELAY)? -1 : timeout * sim_portTICK_PERIOD_MS);
+        if (wlen < 0 || (wlen == 0 && need_write != 0)) {
+            ret = wlen;
+            ESP_LOGE("Network error: esp_transport_write() returned %d, errno=%d", ret, errno);
+            tts_websocket_client_abort_connection(client);
+            goto unlock_and_return;
+        }
+        current_opcode = 0;
+        widx += wlen;
+        need_write = len - widx;
+    }
+
+    ret = widx;
+unlock_and_return:
+       OSAMutexUnlock(client->lock);
+    return ret;
+}
+
+bool tts_websocket_client_is_connected(sim_esp_websocket_client_handle_t client)
+{
+    if (client == NULL) {
+        return false;
+    }
+    return client->state == WEBSOCKET_STATE_CONNECTED;
+}
+
+esp_err_t tts_websocket_register_events(sim_esp_websocket_client_handle_t client,
+                                        sim_esp_event_handler_t event_handler)
+{
+    if (client == NULL) {
+        return -1;
+    }
+       ESP_LOGD("client handler register success!!");
+       client->handler = event_handler;
+    return 0;
+}