diff --git a/examples/esp32/.gitignore b/examples/esp32/.gitignore index b7521d7..7bf5642 100644 --- a/examples/esp32/.gitignore +++ b/examples/esp32/.gitignore @@ -1,4 +1,5 @@ components/srtp +components/usrsctp build dependencies.lock managed_components diff --git a/examples/esp32/README.md b/examples/esp32/README.md index 42f1af0..ee52347 100644 --- a/examples/esp32/README.md +++ b/examples/esp32/README.md @@ -26,6 +26,7 @@ $ cd libpeer/examples/esp32 $ idf.py add-dependency "espressif/esp32-camera^2.0.4" $ idf.py add-dependency "mdns" $ git clone --recursive https://github.com/sepfy/esp_ports.git components/srtp +$ git clone -b components https://github.com/sepfy/usrsctp-esp32.git components/usrsctp ``` ### Configure diff --git a/examples/esp32/components/peer/CMakeLists.txt b/examples/esp32/components/peer/CMakeLists.txt index df40339..f6ce729 100644 --- a/examples/esp32/components/peer/CMakeLists.txt +++ b/examples/esp32/components/peer/CMakeLists.txt @@ -16,7 +16,7 @@ file(GLOB CODES "${PEER_PROJECT_PATH}/src/*.c") idf_component_register( SRCS ${CODES} ${HTTP_SOURCES} ${MQTT_SOURCES} ${MQTT_SERIALIZER_SOURCES} INCLUDE_DIRS "${PEER_PROJECT_PATH}/src" ${HTTP_INCLUDE_PUBLIC_DIRS} ${MQTT_INCLUDE_PUBLIC_DIRS} - REQUIRES mbedtls srtp json mdns + REQUIRES mbedtls srtp json usrsctp mdns ) add_definitions("-DESP32 -DHTTP_DO_NOT_USE_CUSTOM_CONFIG -DMQTT_DO_NOT_USE_CUSTOM_CONFIG") diff --git a/examples/esp32/sdkconfig.defaults b/examples/esp32/sdkconfig.defaults index 7287cb7..1d6df8a 100644 --- a/examples/esp32/sdkconfig.defaults +++ b/examples/esp32/sdkconfig.defaults @@ -1,23 +1,26 @@ # This file was generated using idf.py save-defconfig. It can be edited manually. # Espressif IoT Development Framework (ESP-IDF) 5.2.2 Project Minimal Configuration # +CONFIG_IDF_TARGET="esp32s3" CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 -CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_ESP32S3_XIAO_SENSE=y CONFIG_EXAMPLE_CONNECT_IPV6=n CONFIG_ESP_PHY_REDUCE_TX_POWER=y CONFIG_SPIRAM=y -CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y -CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2048 -CONFIG_ESP_MAIN_TASK_STACK_SIZE=8102 -CONFIG_ESP_INT_WDT_TIMEOUT_MS=300 +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y +CONFIG_ESP_MAIN_TASK_STACK_SIZE=35840 +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=n CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=n -CONFIG_ESP_IPC_TASK_STACK_SIZE=2048 -CONFIG_LWIP_IPV6_AUTOCONFIG=y -CONFIG_LWIP_IPV6_DHCP6=y CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5744 CONFIG_LWIP_TCP_WND_DEFAULT=5744 +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=8192 CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y +CONFIG_MBEDTLS_SSL_DTLS_SRTP=y CONFIG_MBEDTLS_SSL_PROTO_DTLS=y -CONFIG_MDNS_TASK_STACK_SIZE=2048 -CONFIG_MDNS_NETWORKING_SOCKET=y +CONFIG_PTHREAD_TASK_PRIO_DEFAULT=15 +CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=8192 +CONFIG_PTHREAD_STACK_MIN=16 +CONFIG_PTHREAD_DEFAULT_CORE_1=y diff --git a/src/agent.c b/src/agent.c index 4368bf3..e1aa4c5 100644 --- a/src/agent.c +++ b/src/agent.c @@ -14,7 +14,6 @@ #include "agent.h" #include "ports.h" -#define AGENT_POLL_TIMEOUT 1 #define AGENT_CONNCHECK_MAX 300 #define AGENT_CONNCHECK_PERIOD 100 @@ -37,15 +36,15 @@ static int agent_create_sockets(Agent *agent) { return 0; } -static int agent_socket_recv(Agent *agent, Address *addr, uint8_t *buf, int len) { +static int agent_socket_recv(Agent *agent, Address *addr, uint8_t *buf, int len, int timeout) { int ret = -1; int i = 0; int maxfd = 0; fd_set rfds; struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = AGENT_POLL_TIMEOUT * 1000; + tv.tv_sec = timeout/1000; + tv.tv_usec = timeout%1000*1000; FD_ZERO(&rfds); for (i = 0; i < 2; i++) { @@ -128,12 +127,7 @@ static int agent_create_bind_addr(Agent *agent, Address *serv_addr) { } // blocking 1 second - while (retry < 1000) { - ret = agent_socket_recv(agent, NULL, recv_msg.buf, sizeof(recv_msg.buf)); - if (ret > 0) { - break; - } - } + ret = agent_socket_recv(agent, NULL, recv_msg.buf, sizeof(recv_msg.buf), 1000); if (ret <= 0) { LOGD("Failed to receive STUN Binding Response."); @@ -168,12 +162,7 @@ static int agent_create_turn_addr(Agent *agent, Address *serv_addr, const char * } // blocking 1 second - while (retry < 1000) { - ret = agent_socket_recv(agent, NULL, recv_msg.buf, sizeof(recv_msg.buf)); - if (ret > 0) { - break; - } - } + ret = agent_socket_recv(agent, NULL, recv_msg.buf, sizeof(recv_msg.buf), 1000); if (ret <= 0) { LOGD("Failed to receive STUN Binding Response."); @@ -203,7 +192,7 @@ static int agent_create_turn_addr(Agent *agent, Address *serv_addr, const char * } memset(&recv_msg, 0, sizeof(recv_msg)); - ret = agent_socket_recv(agent, NULL, recv_msg.buf, sizeof(recv_msg.buf)); + ret = agent_socket_recv(agent, NULL, recv_msg.buf, sizeof(recv_msg.buf), 1000); if (ret <= 0) { LOGD("Failed to receive TURN Binding Response."); return ret; @@ -370,12 +359,12 @@ void agent_process_stun_response(Agent *agent, StunMessage *stun_msg) { } -int agent_recv(Agent *agent, uint8_t *buf, int len) { +int agent_recv(Agent *agent, uint8_t *buf, int len, int timeout) { int ret = -1; StunMessage stun_msg; Address addr; - if ((ret = agent_socket_recv(agent, &addr, buf, len)) > 0 && stun_probe(buf, len) == 0) { + if ((ret = agent_socket_recv(agent, &addr, buf, len, timeout)) > 0 && stun_probe(buf, len) == 0) { memcpy(stun_msg.buf, buf, ret); stun_msg.size = ret; @@ -475,7 +464,7 @@ int agent_connectivity_check(Agent *agent) { agent_socket_send(agent, &agent->nominated_pair->remote->addr, msg.buf, msg.size); } - agent_recv(agent, buf, sizeof(buf)); + agent_recv(agent, buf, sizeof(buf), 1); // XXX: FULL ICE if (agent->nominated_pair->state == ICE_CANDIDATE_STATE_SUCCEEDED) { diff --git a/src/agent.h b/src/agent.h index 58567fc..0a017d0 100644 --- a/src/agent.h +++ b/src/agent.h @@ -81,7 +81,7 @@ int agent_loop(Agent *agent); int agent_send(Agent *agent, const uint8_t *buf, int len); -int agent_recv(Agent *agent, uint8_t *buf, int len); +int agent_recv(Agent *agent, uint8_t *buf, int len, int timeout); void agent_set_remote_description(Agent *agent, char *description); diff --git a/src/config.h b/src/config.h index b3ba16c..96baad1 100644 --- a/src/config.h +++ b/src/config.h @@ -4,6 +4,7 @@ #define SCTP_MTU (1200) #define CONFIG_MTU (1300) #define RSA_KEY_LENGTH 1024 +#define HAVE_USRSCTP #ifdef ESP32 #define VIDEO_RB_DATA_LENGTH (CONFIG_MTU * 64) @@ -11,7 +12,6 @@ #define DATA_RB_DATA_LENGTH (SCTP_MTU * 128) #define AUDIO_LATENCY 40 // ms #else -#define HAVE_USRSCTP #define VIDEO_RB_DATA_LENGTH (CONFIG_MTU * 256) #define AUDIO_RB_DATA_LENGTH (CONFIG_MTU * 256) #define DATA_RB_DATA_LENGTH (SCTP_MTU * 128) diff --git a/src/peer_connection.c b/src/peer_connection.c index 91b7066..bcb8e08 100644 --- a/src/peer_connection.c +++ b/src/peer_connection.c @@ -74,7 +74,7 @@ static int peer_connection_dtls_srtp_recv(void *ctx, unsigned char *buf, size_t while (recv_max < MAX_RECV) { - ret = agent_recv(&pc->agent, buf, len); + ret = agent_recv(&pc->agent, buf, len, 100); if (ret > 0) { break; @@ -186,14 +186,16 @@ PeerConnection* peer_connection_create(PeerConfiguration *config) { pc->dtls_srtp.udp_recv = peer_connection_dtls_srtp_recv; pc->dtls_srtp.udp_send = peer_connection_dtls_srtp_send; +#if 0 if (pc->config.datachannel) { LOGI("Datachannel allocates heap size: %d", DATA_RB_DATA_LENGTH); pc->data_rb = buffer_new(DATA_RB_DATA_LENGTH); } +#endif if (pc->config.audio_codec) { - LOGI("Audio allocates heap size: %d", AUDIO_RB_DATA_LENGTH); - pc->audio_rb = buffer_new(AUDIO_RB_DATA_LENGTH); + //LOGI("Audio allocates heap size: %d", AUDIO_RB_DATA_LENGTH); + //pc->audio_rb = buffer_new(AUDIO_RB_DATA_LENGTH); rtp_encoder_init(&pc->artp_encoder, pc->config.audio_codec, peer_connection_outgoing_rtp_packet, (void*)pc); @@ -203,8 +205,8 @@ PeerConnection* peer_connection_create(PeerConfiguration *config) { } if (pc->config.video_codec) { - LOGI("Video allocates heap size: %d", VIDEO_RB_DATA_LENGTH); - pc->video_rb = buffer_new(VIDEO_RB_DATA_LENGTH); + //LOGI("Video allocates heap size: %d", VIDEO_RB_DATA_LENGTH); + //pc->video_rb = buffer_new(VIDEO_RB_DATA_LENGTH); rtp_encoder_init(&pc->vrtp_encoder, pc->config.video_codec, peer_connection_outgoing_rtp_packet, (void*)pc); @@ -220,9 +222,9 @@ void peer_connection_destroy(PeerConnection *pc) { if (pc) { - buffer_free(pc->data_rb); - buffer_free(pc->audio_rb); - buffer_free(pc->video_rb); + //buffer_free(pc->data_rb); + //buffer_free(pc->audio_rb); + //buffer_free(pc->video_rb); free(pc); pc = NULL; @@ -255,10 +257,10 @@ int peer_connection_send_video(PeerConnection *pc, const uint8_t *buf, size_t le } int peer_connection_datachannel_send(PeerConnection *pc, char *message, size_t len) { - return peer_connection_datachannel_send_sid(pc, message, len, 0); + return peer_connection_datachannel_send_ext(pc, message, len, 0, SVC_PARTIALLY_RELIABLE); } -int peer_connection_datachannel_send_sid(PeerConnection *pc, char *message, size_t len, uint16_t sid) { +int peer_connection_datachannel_send_ext(PeerConnection *pc, char *message, size_t len, uint16_t sid, SctpService service) { if(!sctp_is_connected(&pc->sctp)) { LOGE("sctp not connected"); @@ -266,9 +268,9 @@ int peer_connection_datachannel_send_sid(PeerConnection *pc, char *message, size } if (pc->config.datachannel == DATA_CHANNEL_STRING) - return sctp_outgoing_data(&pc->sctp, message, len, PPID_STRING, sid); + return sctp_outgoing_data(&pc->sctp, message, len, PPID_STRING, sid, service); else - return sctp_outgoing_data(&pc->sctp, message, len, PPID_BINARY, sid); + return sctp_outgoing_data(&pc->sctp, message, len, PPID_BINARY, sid, service); } static void peer_connection_state_new(PeerConnection *pc) { @@ -352,9 +354,18 @@ static void peer_connection_state_new(PeerConnection *pc) { } } +static void print_hex_buffer(uint8_t *buf, int len) { + printf("data (%d): ", len); + for (int i = 0; i < len; i++) { + printf("%02X ", buf[i]); + } + printf("\n"); +} + int peer_connection_loop(PeerConnection *pc) { int bytes; + int result = 0; uint8_t *data = NULL; uint32_t ssrc = 0; memset(pc->agent_buf, 0, sizeof(pc->agent_buf)); @@ -394,6 +405,7 @@ int peer_connection_loop(PeerConnection *pc) { break; case PEER_CONNECTION_COMPLETED: +#if 0 data = buffer_peak_head(pc->video_rb, &bytes); if (data) { rtp_encoder_encode(&pc->vrtp_encoder, data, bytes); @@ -410,13 +422,13 @@ int peer_connection_loop(PeerConnection *pc) { if (data) { if (pc->config.datachannel == DATA_CHANNEL_STRING) - sctp_outgoing_data(&pc->sctp, (char*)data, bytes, PPID_STRING, 0); + sctp_outgoing_data(&pc->sctp, (char*)data, bytes, PPID_STRING, 0, SVC_RELIABLE); else - sctp_outgoing_data(&pc->sctp, (char*)data, bytes, PPID_BINARY, 0); + sctp_outgoing_data(&pc->sctp, (char*)data, bytes, PPID_BINARY, 0, SVC_RELIABLE); buffer_pop_head(pc->data_rb); } - - if ((pc->agent_ret = agent_recv(&pc->agent, pc->agent_buf, sizeof(pc->agent_buf))) > 0) { +#endif + if ((pc->agent_ret = agent_recv(&pc->agent, pc->agent_buf, sizeof(pc->agent_buf), 0)) > 0) { LOGD("agent_recv %d", pc->agent_ret); if (rtcp_probe(pc->agent_buf, pc->agent_ret)) { @@ -425,14 +437,13 @@ int peer_connection_loop(PeerConnection *pc) { peer_connection_incoming_rtcp(pc, pc->agent_buf, pc->agent_ret); } else if (dtls_srtp_probe(pc->agent_buf)) { - int ret = dtls_srtp_read(&pc->dtls_srtp, pc->temp_buf, sizeof(pc->temp_buf)); LOGD("Got DTLS data %d", ret); if (ret > 0) { + result = 1; sctp_incoming_data(&pc->sctp, (char*)pc->temp_buf, ret); } - } else if (rtp_packet_validate(pc->agent_buf, pc->agent_ret)) { LOGD("Got RTP packet"); @@ -468,7 +479,7 @@ int peer_connection_loop(PeerConnection *pc) { break; } - return 0; + return result; } void peer_connection_set_remote_description(PeerConnection *pc, const char *sdp_text) { diff --git a/src/peer_connection.h b/src/peer_connection.h index 1b620e1..ad873af 100644 --- a/src/peer_connection.h +++ b/src/peer_connection.h @@ -93,9 +93,10 @@ int peer_connection_loop(PeerConnection *pc); * @param[in] message buffer * @param[in] length of message */ + int peer_connection_datachannel_send(PeerConnection *pc, char *message, size_t len); -int peer_connection_datachannel_send_sid(PeerConnection *pc, char *message, size_t len, uint16_t sid); +int peer_connection_datachannel_send_ext(PeerConnection *pc, char *message, size_t len, uint16_t sid, SctpService service); int peer_connection_send_audio(PeerConnection *pc, const uint8_t *packet, size_t bytes); diff --git a/src/ports.c b/src/ports.c index e10519d..dd575b5 100644 --- a/src/ports.c +++ b/src/ports.c @@ -185,11 +185,12 @@ int ports_resolve_mdns_host(const char *host, Address *addr) { return ret; } LOGE("Query Failed: %s", esp_err_to_name(err)); - return ret; + return ret; } + addr->family = AF_INET; memcpy(addr->ipv4, &esp_addr.addr, 4); - return ret; + return 0; #else return ports_resolve_addr(host, addr); #endif diff --git a/src/sctp.c b/src/sctp.c index 1a8a472..0d8c909 100644 --- a/src/sctp.c +++ b/src/sctp.c @@ -109,13 +109,21 @@ static int sctp_outgoing_data_cb(void *userdata, void *buf, size_t len, uint8_t return 0; } -int sctp_outgoing_data(Sctp *sctp, char *buf, size_t len, SctpDataPpid ppid, uint16_t sid) { +int sctp_outgoing_data(Sctp *sctp, char *buf, size_t len, SctpDataPpid ppid, uint16_t sid,SctpService service) { #ifdef HAVE_USRSCTP int res; struct sctp_sendv_spa spa = {0}; spa.sendv_flags = SCTP_SEND_SNDINFO_VALID; + if (service==SVC_PARTIALLY_RELIABLE) + { + spa.sendv_flags |= SCTP_SEND_PRINFO_VALID; + spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL; + spa.sendv_prinfo.pr_value = 10; + //spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX; + //spa.sendv_prinfo.pr_value = 0; + } spa.sendv_sndinfo.snd_sid = sid; spa.sendv_sndinfo.snd_flags = SCTP_EOR; @@ -214,7 +222,17 @@ void sctp_parse_data_channel_open(Sctp *sctp, uint16_t sid, char *data, size_t l } } + +static void print_hex_buffer(uint8_t *buf, int len) { + printf("data (%d): ", len); + for (int i = 0; i < len; i++) { + printf("%02X ", buf[i]); + } + printf("\n"); +} + void sctp_handle_sctp_packet(Sctp *sctp, char *buf, size_t len) { + //print_hex_buffer((uint8_t *)buf, len); if (len<=29) return; @@ -407,7 +425,7 @@ static int sctp_handle_incoming_data(Sctp *sctp, char *data, size_t len, uint32_ case DATA_CHANNEL_PPID_DOMSTRING_PARTIAL: case DATA_CHANNEL_PPID_BINARY_PARTIAL: - LOGD("Got message (size = %ld)", len); + LOGD("Got message (size = %d)", len); if(sctp->onmessage) { sctp->onmessage(data, len, sctp->userdata, sid); } @@ -426,12 +444,11 @@ static int sctp_handle_incoming_data(Sctp *sctp, char *data, size_t len, uint32_ static void sctp_process_notification(Sctp *sctp, union sctp_notification *notification, size_t len) { - if(notification->sn_header.sn_length != (uint32_t)len) { - return; - } + if(notification->sn_header.sn_length != (uint32_t)len) { + return; + } switch (notification->sn_header.sn_type) { - case SCTP_ASSOC_CHANGE: switch (notification->sn_assoc_change.sac_state) { @@ -464,12 +481,12 @@ static void sctp_process_notification(Sctp *sctp, union sctp_notification *notif static int sctp_incoming_data_cb(struct socket *sock, union sctp_sockstore addr, void *data, size_t len, struct sctp_rcvinfo recv_info, int flags, void *userdata) { Sctp *sctp = (Sctp*)userdata; - LOGD("Data of length %u received on stream %u with SSN %u, TSN %u, PPID %u", - (uint32_t)len, - recv_info.rcv_sid, - recv_info.rcv_ssn, - recv_info.rcv_tsn, - ntohl(recv_info.rcv_ppid)); + LOGD("Data of length %d received on stream %"PRIu16" with SSN %"PRIu16", TSN %"PRIu32", PPID %"PRIu32"", + len, + recv_info.rcv_sid, + recv_info.rcv_ssn, + recv_info.rcv_tsn, + ntohl(recv_info.rcv_ppid)); if(flags & MSG_NOTIFICATION) { sctp_process_notification(sctp, (union sctp_notification *)data, len); } else { diff --git a/src/sctp.h b/src/sctp.h index ddcabca..461778c 100644 --- a/src/sctp.h +++ b/src/sctp.h @@ -136,6 +136,11 @@ typedef enum SctpDataPpid { } SctpDataPpid; +typedef enum SctpService { + SVC_RELIABLE, + SVC_PARTIALLY_RELIABLE +} SctpService; + #define SCTP_MAX_STREAMS 5 typedef struct { @@ -177,7 +182,7 @@ int sctp_is_connected(Sctp *sctp); void sctp_incoming_data(Sctp *sctp, char *buf, size_t len); -int sctp_outgoing_data(Sctp *sctp, char *buf, size_t len, SctpDataPpid ppid, uint16_t sid); +int sctp_outgoing_data(Sctp *sctp, char *buf, size_t len, SctpDataPpid ppid, uint16_t sid, SctpService service); void sctp_onmessage(Sctp *sctp, void (*onmessage)(char *msg, size_t len, void *userdata, uint16_t sid));