Skip to content

Commit

Permalink
New peer_connection_send and peer_connection_recv functions
Browse files Browse the repository at this point in the history
 - 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
  • Loading branch information
vikramdattu committed Feb 4, 2025
1 parent 7b8b61c commit 0cd22f1
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 1 deletion.
2 changes: 1 addition & 1 deletion idf_component.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ dependencies:
description: libpeer
license: MIT
url: https://github.com/sepfy/libpeer
version: 0.0.2
version: 0.0.3
127 changes: 127 additions & 0 deletions src/peer_connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
29 changes: 29 additions & 0 deletions src/peer_connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 0cd22f1

Please sign in to comment.