From 7b8b61c0e11cbd6258ac34845c28277335f4898d Mon Sep 17 00:00:00 2001 From: Vikram Dattu Date: Tue, 4 Feb 2025 11:51:58 +0530 Subject: [PATCH 1/2] peer_connection.c: fix strcat overlap warnings --- src/peer_connection.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/peer_connection.c b/src/peer_connection.c index c7709cfb..fdf4052a 100644 --- a/src/peer_connection.c +++ b/src/peer_connection.c @@ -360,31 +360,30 @@ static void peer_connection_state_new(PeerConnection* pc, DtlsSrtpRole role, int sdp_append_h264(&pc->local_sdp); sdp_append(&pc->local_sdp, "a=fingerprint:sha-256 %s", pc->dtls_srtp.local_fingerprint); sdp_append(&pc->local_sdp, peer_connection_dtls_role_setup_value(role)); - strcat(pc->local_sdp.content, description); + sdp_append(&pc->local_sdp, "%s", description); } switch (pc->config.audio_codec) { case CODEC_PCMA: - sdp_append_pcma(&pc->local_sdp); sdp_append(&pc->local_sdp, "a=fingerprint:sha-256 %s", pc->dtls_srtp.local_fingerprint); sdp_append(&pc->local_sdp, peer_connection_dtls_role_setup_value(role)); - strcat(pc->local_sdp.content, description); + sdp_append(&pc->local_sdp, "%s", description); break; case CODEC_PCMU: - sdp_append_pcmu(&pc->local_sdp); sdp_append(&pc->local_sdp, "a=fingerprint:sha-256 %s", pc->dtls_srtp.local_fingerprint); sdp_append(&pc->local_sdp, peer_connection_dtls_role_setup_value(role)); - strcat(pc->local_sdp.content, description); + sdp_append(&pc->local_sdp, "%s", description); break; case CODEC_OPUS: sdp_append_opus(&pc->local_sdp); sdp_append(&pc->local_sdp, "a=fingerprint:sha-256 %s", pc->dtls_srtp.local_fingerprint); sdp_append(&pc->local_sdp, peer_connection_dtls_role_setup_value(role)); - strcat(pc->local_sdp.content, description); + sdp_append(&pc->local_sdp, "%s", description); + break; default: break; @@ -394,7 +393,7 @@ static void peer_connection_state_new(PeerConnection* pc, DtlsSrtpRole role, int sdp_append_datachannel(&pc->local_sdp); sdp_append(&pc->local_sdp, "a=fingerprint:sha-256 %s", pc->dtls_srtp.local_fingerprint); sdp_append(&pc->local_sdp, peer_connection_dtls_role_setup_value(role)); - strcat(pc->local_sdp.content, description); + sdp_append(&pc->local_sdp, "%s", description); } pc->b_local_description_created = 1; From 0cd22f1782a0519b06e5471c417eb44974403330 Mon Sep 17 00:00:00 2001 From: Vikram Dattu Date: Tue, 4 Feb 2025 11:53:56 +0530 Subject: [PATCH 2/2] New peer_connection_send and peer_connection_recv functions - These two function can be called in a loop from seperate threads for better performance - idf_component.yml: Increased the patch version with the same --- idf_component.yml | 2 +- src/peer_connection.c | 127 ++++++++++++++++++++++++++++++++++++++++++ src/peer_connection.h | 29 ++++++++++ 3 files changed, 157 insertions(+), 1 deletion(-) diff --git a/idf_component.yml b/idf_component.yml index a011f9d7..4bf861bc 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -4,4 +4,4 @@ dependencies: description: libpeer license: MIT url: https://github.com/sepfy/libpeer -version: 0.0.2 +version: 0.0.3 diff --git a/src/peer_connection.c b/src/peer_connection.c index fdf4052a..3f312af5 100644 --- a/src/peer_connection.c +++ b/src/peer_connection.c @@ -403,6 +403,133 @@ static void peer_connection_state_new(PeerConnection* pc, DtlsSrtpRole role, int } } +int peer_connection_recv(PeerConnection* pc) { + if (!pc) return -1; + + int total_bytes = 0; + + switch (pc->state) { + case PEER_CONNECTION_NEW: + if (!pc->b_local_description_created) { + peer_connection_state_new(pc, DTLS_SRTP_ROLE_SERVER, 1); + } + break; + + case PEER_CONNECTION_CHECKING: + if (agent_select_candidate_pair(&pc->agent) < 0) { + STATE_CHANGED(pc, PEER_CONNECTION_FAILED); + return -1; + } + if (agent_connectivity_check(&pc->agent) == 0) { + STATE_CHANGED(pc, PEER_CONNECTION_CONNECTED); + } + break; + + case PEER_CONNECTION_CONNECTED: + if (dtls_srtp_handshake(&pc->dtls_srtp, NULL) == 0) { + if (pc->config.datachannel) { + // Close any existing SCTP association first + if (pc->sctp.sock) { + sctp_destroy_association(&pc->sctp); + } + sctp_create_association(&pc->sctp, &pc->dtls_srtp); + pc->sctp.userdata = pc->config.user_data; + } + STATE_CHANGED(pc, PEER_CONNECTION_COMPLETED); + } + break; + + case PEER_CONNECTION_COMPLETED: { + // Process incoming data + int ret; + while ((ret = agent_recv(&pc->agent, pc->agent_buf, sizeof(pc->agent_buf))) > 0) { + pc->agent_ret = ret; + total_bytes += ret; + + if (rtcp_probe(pc->agent_buf, pc->agent_ret)) { + dtls_srtp_decrypt_rtcp_packet(&pc->dtls_srtp, pc->agent_buf, &pc->agent_ret); + peer_connection_incoming_rtcp(pc, pc->agent_buf, pc->agent_ret); + } else if (dtls_srtp_probe(pc->agent_buf)) { + // Check if the packet is a data channel packet + ret = dtls_srtp_read(&pc->dtls_srtp, pc->temp_buf, sizeof(pc->temp_buf)); + if (ret > 0) { + sctp_incoming_data(&pc->sctp, (char*)pc->temp_buf, ret); + } + } else if (rtp_packet_validate(pc->agent_buf, pc->agent_ret)) { + dtls_srtp_decrypt_rtp_packet(&pc->dtls_srtp, pc->agent_buf, &pc->agent_ret); + uint32_t ssrc = rtp_get_ssrc(pc->agent_buf); + if (ssrc == pc->remote_assrc) { + rtp_decoder_decode(&pc->artp_decoder, pc->agent_buf, pc->agent_ret); + } else if (ssrc == pc->remote_vssrc) { + rtp_decoder_decode(&pc->vrtp_decoder, pc->agent_buf, pc->agent_ret); + } + } + } + + // Check connection timeout + if (KEEPALIVE_CONNCHECK > 0 && + (ports_get_epoch_time() - pc->agent.binding_request_time) > KEEPALIVE_CONNCHECK) { + STATE_CHANGED(pc, PEER_CONNECTION_CLOSED); + return -1; + } + break; + } + + case PEER_CONNECTION_FAILED: + case PEER_CONNECTION_DISCONNECTED: + case PEER_CONNECTION_CLOSED: + return -1; + + default: + break; + } + return total_bytes; +} + +int peer_connection_send(PeerConnection* pc) { + if (!pc) return -1; + + // Only send data in COMPLETED state + if (pc->state == PEER_CONNECTION_COMPLETED) { + uint8_t* data; + int bytes; + int total_bytes = 0; + +#if (CONFIG_VIDEO_BUFFER_SIZE) > 0 + data = buffer_peak_head(pc->video_rb, &bytes); + if (data) { + rtp_encoder_encode(&pc->vrtp_encoder, data, bytes); + buffer_pop_head(pc->video_rb); + total_bytes += bytes; + } +#endif + +#if (CONFIG_AUDIO_BUFFER_SIZE) > 0 + data = buffer_peak_head(pc->audio_rb, &bytes); + if (data) { + rtp_encoder_encode(&pc->artp_encoder, data, bytes); + buffer_pop_head(pc->audio_rb); + total_bytes += bytes; + } +#endif + +#if (CONFIG_DATA_BUFFER_SIZE) > 0 + data = buffer_peak_head(pc->data_rb, &bytes); + if (data) { + if (pc->config.datachannel == DATA_CHANNEL_STRING) { + sctp_outgoing_data(&pc->sctp, (char*)data, bytes, PPID_STRING, 0); + } else { + sctp_outgoing_data(&pc->sctp, (char*)data, bytes, PPID_BINARY, 0); + } + buffer_pop_head(pc->data_rb); + total_bytes += bytes; + } +#endif + return total_bytes; + } + return 0; +} + int peer_connection_loop(PeerConnection* pc) { int bytes; uint8_t* data = NULL; diff --git a/src/peer_connection.h b/src/peer_connection.h index dca32718..5cb9df68 100644 --- a/src/peer_connection.h +++ b/src/peer_connection.h @@ -92,6 +92,35 @@ void peer_connection_destroy(PeerConnection* pc); void peer_connection_close(PeerConnection* pc); +/** + * @brief recv data from peer connection + * + * This function can be called in a loop to keep receiving data from peer connection. + * + * @param[in] peer connection + * @return 0 if success, -1 if error + */ +int peer_connection_recv(PeerConnection* pc); + +/** + * @brief send data to peer connection + * + * This function can be called in a loop to keep sending data to peer connection. + * + * @param[in] peer connection + * @return 0 if success, -1 if error + */ +int peer_connection_send(PeerConnection* pc); + +/** + * @brief loop peer connection + * + * This function is used to loop peer connection. + * This handles both incoming and outgoing data in a single loop. + * + * @param[in] peer connection + * @note More efficient than calling peer_connection_recv() and peer_connection_send() separately. + */ int peer_connection_loop(PeerConnection* pc); int peer_connection_create_datachannel(PeerConnection* pc, DecpChannelType channel_type, uint16_t priority, uint32_t reliability_parameter, char* label, char* protocol);