Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,18 @@ libpeer is a WebRTC implementation written in C, developed with BSD socket. The
- Copy URL from the test [website](https://sepfy.github.io/libpeer)
- Build and run the example
```bash
$ sudo apt -y install git cmake
$ sudo apt -y install git cmake wget ffmpeg
$ git clone --recursive https://github.com/sepfy/libpeer
$ cd libpeer
$ cmake -S . -B build && cmake --build build
$ wget http://www.live555.com/liveMedia/public/264/test.264 # Download test video file
$ wget https://mauvecloud.net/sounds/alaw08m.wav # Download test audio file
$ ./examples/generic/sample -u <URL>
$ wget -O sample.mp4 \
https://download.samplelib.com/mp4/sample-30s.mp4
$ ffmpeg -i sample.mp4 \
-map 0:v:0 -vf fps=25 -c:v libx264 -profile:v baseline -pix_fmt yuv420p \
-x264-params bframes=0:keyint=25:min-keyint=25:scenecut=0:repeat-headers=1 \
-f h264 test.264 \
-map 0:a:0 -ac 1 -ar 8000 -c:a pcm_alaw -f wav test.wav
$ ./build/examples/generic/sample -u <URL>
```
- Click Connect button on the website

Expand Down
2 changes: 1 addition & 1 deletion examples/esp32/main/app_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ static void oniceconnectionstatechange(PeerConnectionState state, void* user_dat
ESP_LOGI(TAG, "PeerConnectionState: %d", state);
eState = state;
// not support datachannel close event
if (eState != PEER_CONNECTION_COMPLETED) {
if (eState != PEER_CONNECTION_CONNECTED) {
gDataChannelOpened = 0;
}
}
Expand Down
2 changes: 1 addition & 1 deletion examples/esp32/main/audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ void audio_task(void* arg) {
ESP_LOGI(TAG, "audio task started");

for (;;) {
if (eState == PEER_CONNECTION_COMPLETED) {
if (eState == PEER_CONNECTION_CONNECTED) {
ret = audio_get_samples(aenc_in_frame.buffer, aenc_in_frame.len);

if (ret == aenc_in_frame.len) {
Expand Down
2 changes: 1 addition & 1 deletion examples/esp32/main/camera.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ void camera_task(void* pvParameters) {
last_time = get_timestamp();

for (;;) {
if ((eState == PEER_CONNECTION_COMPLETED) && gDataChannelOpened) {
if ((eState == PEER_CONNECTION_CONNECTED) && gDataChannelOpened) {
fb = esp_camera_fb_get();

if (!fb) {
Expand Down
2 changes: 1 addition & 1 deletion examples/generic/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ int main(int argc, char* argv[]) {
reader_init();

while (!g_interrupted) {
if (g_state == PEER_CONNECTION_COMPLETED) {
if (g_state == PEER_CONNECTION_CONNECTED) {
curr_time = get_timestamp();

// FPS 25
Expand Down
2 changes: 1 addition & 1 deletion examples/generic/reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ int reader_init() {
FILE* video_fp = NULL;
FILE* audio_fp = NULL;
char videofile[] = "test.264";
char audiofile[] = "alaw08m.wav";
char audiofile[] = "test.wav";

video_fp = fopen(videofile, "rb");

Expand Down
2 changes: 1 addition & 1 deletion examples/pico/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ static void dma_i2s_in_handler(void) {
}
#endif

if (eState == PEER_CONNECTION_COMPLETED) {
if (eState == PEER_CONNECTION_CONNECTED) {
peer_connection_send_audio(g_pc, alaw, AUDIO_BUFFER_FRAMES);
}

Expand Down
2 changes: 1 addition & 1 deletion examples/raspberrypi/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Media g_media;
static void onconnectionstatechange(PeerConnectionState state, void* data) {
printf("state is changed: %d\n", state);
g_state = state;
if (g_state == PEER_CONNECTION_COMPLETED) {
if (g_state == PEER_CONNECTION_CONNECTED) {
gst_element_set_state(g_media.camera_pipeline, GST_STATE_PLAYING);
gst_element_set_state(g_media.mic_pipeline, GST_STATE_PLAYING);
gst_element_set_state(g_media.spk_pipeline, GST_STATE_PLAYING);
Expand Down
12 changes: 10 additions & 2 deletions src/address.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
#ifndef ADDRESS_H_
#define ADDRESS_H_

#include <stdint.h>

#include "config.h"
#if CONFIG_USE_LWIP

#if CONFIG_USE_ZEPHYR
#include <zephyr/posix/arpa/inet.h>
#include <zephyr/posix/netinet/in.h>
#include <zephyr/posix/sys/socket.h>
#include <zephyr/posix/unistd.h>
#elif CONFIG_USE_LWIP
#include <lwip/sockets.h>
#else
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
#include <stdint.h>

#define ADDRSTRLEN INET6_ADDRSTRLEN

Expand Down
69 changes: 54 additions & 15 deletions src/agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,10 @@ static int agent_socket_recv(Agent* agent, Address* addr, uint8_t* buf, int len)
int maxfd = -1;
fd_set rfds;
struct timeval tv;
int addr_type[] = { AF_INET,
int addr_type[] = {
AF_INET,
#if CONFIG_IPV6
AF_INET6,
AF_INET6,
#endif
};

Expand Down Expand Up @@ -126,9 +127,10 @@ static int agent_create_host_addr(Agent* agent) {
int i, j;
const char* iface_prefx[] = {CONFIG_IFACE_PREFIX};
IceCandidate* ice_candidate;
int addr_type[] = { AF_INET,
int addr_type[] = {
AF_INET,
#if CONFIG_IPV6
AF_INET6,
AF_INET6,
#endif
};

Expand Down Expand Up @@ -173,8 +175,8 @@ static int agent_create_stun_addr(Agent* agent, Address* serv_addr) {

stun_parse_msg_buf(&recv_msg);
memcpy(&bind_addr, &recv_msg.mapped_addr, sizeof(Address));
IceCandidate* ice_candidate = agent->local_candidates + agent->local_candidates_count++;
ice_candidate_create(ice_candidate, agent->local_candidates_count, ICE_CANDIDATE_TYPE_SRFLX, &bind_addr);
IceCandidate* ice_candidate = agent->local_candidates + agent->local_candidates_count;
ice_candidate_create(ice_candidate, agent->local_candidates_count++, ICE_CANDIDATE_TYPE_SRFLX, &bind_addr);
return ret;
}

Expand Down Expand Up @@ -257,6 +259,7 @@ void agent_gather_candidate(Agent* agent, const char* urls, const char* username
}

port = atoi(pos + 1);
printf("port => %s\n", pos + 1);
if (port <= 0) {
LOGE("Cannot parse port");
return;
Expand Down Expand Up @@ -339,6 +342,26 @@ static void agent_create_binding_request(Agent* agent, StunMessage* msg) {
stun_msg_finish(msg, STUN_CREDENTIAL_SHORT_TERM, agent->remote_upwd, strlen(agent->remote_upwd));
}

int agent_send_binding_request(Agent* agent) {
StunMessage msg;
StunHeader* header;
int ret;

if (agent->nominated_pair == NULL) {
return -1;
}

memset(&msg, 0, sizeof(msg));
agent_create_binding_request(agent, &msg);
agent->binding_request_sent_time = ports_get_epoch_time();
header = (StunHeader*)msg.buf;
memcpy(agent->binding_request_transaction_id, header->transaction_id,
sizeof(agent->binding_request_transaction_id));
agent->binding_request_pending = 1;
ret = agent_socket_send(agent, &agent->nominated_pair->remote->addr, msg.buf, msg.size);
return ret;
}

void agent_process_stun_request(Agent* agent, StunMessage* stun_msg, Address* addr) {
StunMessage msg;
StunHeader* header;
Expand All @@ -349,7 +372,6 @@ void agent_process_stun_request(Agent* agent, StunMessage* stun_msg, Address* ad
memcpy(agent->transaction_id, header->transaction_id, sizeof(header->transaction_id));
agent_create_binding_response(agent, &msg, addr);
agent_socket_send(agent, addr, msg.buf, msg.size);
agent->binding_request_time = ports_get_epoch_time();
}
break;
default:
Expand All @@ -360,8 +382,13 @@ void agent_process_stun_request(Agent* agent, StunMessage* stun_msg, Address* ad
void agent_process_stun_response(Agent* agent, StunMessage* stun_msg) {
switch (stun_msg->stunmethod) {
case STUN_METHOD_BINDING:
if (stun_msg_is_valid(stun_msg->buf, stun_msg->size, agent->remote_upwd) == 0) {
if (stun_msg_is_valid(stun_msg->buf, stun_msg->size, agent->remote_upwd) == 0 &&
agent->binding_request_pending &&
memcmp(((StunHeader*)stun_msg->buf)->transaction_id,
agent->binding_request_transaction_id,
sizeof(agent->binding_request_transaction_id)) == 0) {
agent->nominated_pair->state = ICE_CANDIDATE_STATE_SUCCEEDED;
agent->binding_request_pending = 0;
}
break;
default:
Expand Down Expand Up @@ -436,7 +463,11 @@ void agent_set_remote_description(Agent* agent, char* description) {

void agent_update_candidate_pairs(Agent* agent) {
int i, j;
char local_addr_string[ADDRSTRLEN];
char remote_addr_string[ADDRSTRLEN];
int candidate_pairs_num = agent->candidate_pairs_num;
// Please set gather candidates before set remote description
agent->candidate_pairs_num = 0;
for (i = 0; i < agent->local_candidates_count; i++) {
for (j = 0; j < agent->remote_candidates_count; j++) {
if (agent->local_candidates[i].addr.family == agent->remote_candidates[j].addr.family) {
Expand All @@ -448,26 +479,34 @@ void agent_update_candidate_pairs(Agent* agent) {
}
}
}
LOGD("candidate pairs num: %d", agent->candidate_pairs_num);

if (candidate_pairs_num != agent->candidate_pairs_num) {
LOGI("candidate pairs num %d:", agent->candidate_pairs_num);
for (i = 0; i < agent->candidate_pairs_num; i++) {
addr_to_string(&agent->candidate_pairs[i].local->addr, local_addr_string, sizeof(local_addr_string));
addr_to_string(&agent->candidate_pairs[i].remote->addr, remote_addr_string, sizeof(remote_addr_string));
LOGI("[%d] %s > %s", i, local_addr_string, remote_addr_string);
}
}
}

int agent_connectivity_check(Agent* agent) {
char addr_string[ADDRSTRLEN];
uint8_t buf[1400];
StunMessage msg;

if (agent_select_candidate_pair(agent) < 0) {
agent_update_candidate_pairs(agent);
return -1;
}
if (agent->nominated_pair->state != ICE_CANDIDATE_STATE_INPROGRESS) {
LOGI("nominated pair is not in progress");
return -1;
}

memset(&msg, 0, sizeof(msg));

if (agent->nominated_pair->conncheck % AGENT_CONNCHECK_PERIOD == 0) {
addr_to_string(&agent->nominated_pair->remote->addr, addr_string, sizeof(addr_string));
LOGD("send binding request to remote ip: %s, port: %d", addr_string, agent->nominated_pair->remote->addr.port);
agent_create_binding_request(agent, &msg);
agent_socket_send(agent, &agent->nominated_pair->remote->addr, msg.buf, msg.size);
agent_send_binding_request(agent);
}

agent_recv(agent, buf, sizeof(buf));
Expand Down Expand Up @@ -497,7 +536,7 @@ int agent_select_candidate_pair(Agent* agent) {
agent->candidate_pairs[i].state = ICE_CANDIDATE_STATE_FAILED;
} else if (agent->candidate_pairs[i].state == ICE_CANDIDATE_STATE_FAILED) {
} else if (agent->candidate_pairs[i].state == ICE_CANDIDATE_STATE_SUCCEEDED) {
agent->selected_pair = &agent->candidate_pairs[i];
// agent->selected_pair = &agent->candidate_pairs[i];
return 0;
}
}
Expand Down
15 changes: 5 additions & 10 deletions src/agent.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,6 @@
#define AGENT_MAX_CANDIDATE_PAIRS 100
#endif

typedef enum AgentState {

AGENT_STATE_GATHERING_ENDED = 0,
AGENT_STATE_GATHERING_STARTED,
AGENT_STATE_GATHERING_COMPLETED,

} AgentState;

typedef enum AgentMode {

AGENT_MODE_CONTROLLED = 0,
Expand All @@ -58,8 +50,9 @@ struct Agent {

Address host_addr;
int b_host_addr;
uint64_t binding_request_time;
AgentState state;
uint32_t binding_request_sent_time;
uint8_t binding_request_transaction_id[12];
int binding_request_pending;

AgentMode mode;

Expand Down Expand Up @@ -88,6 +81,8 @@ int agent_select_candidate_pair(Agent* agent);

int agent_connectivity_check(Agent* agent);

int agent_send_binding_request(Agent* agent);

void agent_clear_candidates(Agent* agent);

int agent_create(Agent* agent);
Expand Down
23 changes: 20 additions & 3 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@
#define SCTP_MTU (1200)
#define CONFIG_MTU (1300)

#ifndef CONFIG_USE_ZEPHYR
#ifdef __ZEPHYR__
#define CONFIG_USE_ZEPHYR 1
#else
#define CONFIG_USE_ZEPHYR 0
#endif
#endif

#ifndef CONFIG_USE_LWIP
#define CONFIG_USE_LWIP 0
#endif
Expand Down Expand Up @@ -49,16 +57,25 @@
#define CONFIG_TLS_READ_TIMEOUT 3000
#endif

#ifndef CONFIG_KEEPALIVE_TIMEOUT
#define CONFIG_KEEPALIVE_TIMEOUT 10000
#ifndef CONFIG_STUN_KEEPALIVE_INTERVAL
#define CONFIG_STUN_KEEPALIVE_INTERVAL 0
#endif

#ifndef CONFIG_STUN_KEEPALIVE_TIMEOUT
#define CONFIG_STUN_KEEPALIVE_TIMEOUT 15000
#endif

#if CONFIG_STUN_KEEPALIVE_INTERVAL > 0 && \
CONFIG_STUN_KEEPALIVE_TIMEOUT <= CONFIG_STUN_KEEPALIVE_INTERVAL
#error "CONFIG_STUN_KEEPALIVE_TIMEOUT must be greater than CONFIG_STUN_KEEPALIVE_INTERVAL"
#endif

#ifndef CONFIG_AUDIO_DURATION
#define CONFIG_AUDIO_DURATION 20
#endif

#ifndef CONFIG_MAX_NALU_SIZE
#define CONFIG_MAX_NALU_SIZE (10 * 1024) // 10KB
#define CONFIG_MAX_NALU_SIZE (100 * 1024) // 100KB
#endif

#define CONFIG_IPV6 0
Expand Down
Loading
Loading