Files
esp-protocols/components/mosquitto/examples/serverless_mqtt/main/peer_impl_webrtc.c
David Cermak 76e45f7254 feat(mosq): Update brokerless example to work with esp-peer
* Relax CI criteria to build on v5.2+ (for the brokerless due to
  esp-peer dependency)
2025-07-18 12:49:34 +02:00

249 lines
6.7 KiB
C

/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "media_lib_os.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "media_lib_adapter.h"
#include "media_lib_os.h"
#include "esp_log.h"
#include "esp_webrtc_defaults.h"
#include "esp_peer_default.h"
#include "common.h"
#include "esp_check.h"
#include "peer_impl.h"
#include "sdkconfig.h"
#define WEBRTC_URL (CONFIG_EXAMPLE_WEBRTC_URL CONFIG_EXAMPLE_WEBRTC_ROOM_ID)
#define PEER_CONNECTED BIT(0)
#define PEER_DISCONNECTED BIT(1)
#define MAX_BUFFER_SIZE (4*1024)
static EventGroupHandle_t s_state = NULL;
static const char *TAG = "serverless_mqtt_webrtc";
void peer_get_buffer(char ** buffer, size_t *buffer_len)
{
static char s_buffer[MAX_BUFFER_SIZE];
if (buffer && buffer_len) {
*buffer = s_buffer;
*buffer_len = MAX_BUFFER_SIZE;
}
}
static int start_webrtc(char *url);
static int stop_webrtc(void);
static on_peer_recv_t s_on_recv = NULL;
static esp_peer_signaling_handle_t signaling = NULL;
static esp_peer_handle_t peer = NULL;
static bool peer_running = false;
static void thread_scheduler(const char *thread_name, media_lib_thread_cfg_t *thread_cfg)
{
if (strcmp(thread_name, "pc_task") == 0) {
thread_cfg->stack_size = 25 * 1024;
thread_cfg->priority = 18;
thread_cfg->core_id = 1;
}
}
esp_err_t peer_init(on_peer_recv_t cb)
{
esp_err_t ret = ESP_OK;
s_on_recv = cb;
s_state = xEventGroupCreate();
media_lib_add_default_adapter();
media_lib_thread_set_schedule_cb(thread_scheduler);
ESP_RETURN_ON_FALSE(s_state, ESP_ERR_NO_MEM, TAG, "Failed to create state event group");
ESP_GOTO_ON_FALSE(start_webrtc(WEBRTC_URL) == ESP_PEER_ERR_NONE, ESP_FAIL, err, TAG, "Failed to start webRTC");
ESP_LOGI(TAG, "Waiting for peer to connect");
int i = 0;
while (1) {
EventBits_t bits = xEventGroupWaitBits(s_state, PEER_CONNECTED, pdFALSE, pdFALSE, pdMS_TO_TICKS(1000));
if (bits & PEER_CONNECTED) {
ESP_LOGI(TAG, "Peer is connected!");
return ret;
}
ESP_GOTO_ON_FALSE(i++ < 100, ESP_ERR_TIMEOUT, err, TAG, "Peer connection timeout");
if (peer) {
esp_peer_query(peer);
}
}
err:
vEventGroupDelete(s_state);
return ret;
}
static int peer_state_handler(esp_peer_state_t state, void* ctx)
{
ESP_LOGI(TAG, "Peer state: %d", state);
if (state == ESP_PEER_STATE_CONNECTED) {
xEventGroupSetBits(s_state, PEER_CONNECTED);
} else if (state == ESP_PEER_STATE_DISCONNECTED) {
xEventGroupSetBits(s_state, PEER_DISCONNECTED);
}
return 0;
}
static int peer_msg_handler(esp_peer_msg_t* msg, void* ctx)
{
if (msg->type == ESP_PEER_MSG_TYPE_SDP) {
// Send local SDP to signaling server
esp_peer_signaling_send_msg(signaling, (esp_peer_signaling_msg_t *)msg);
}
return 0;
}
static int peer_video_info_handler(esp_peer_video_stream_info_t* info, void* ctx)
{
return 0;
}
static int peer_audio_info_handler(esp_peer_audio_stream_info_t* info, void* ctx)
{
return 0;
}
static int peer_audio_data_handler(esp_peer_audio_frame_t* frame, void* ctx)
{
ESP_LOGI(TAG, "Audio Sequence %d(%d)", (int)frame->pts, (int)frame->data[0]);
return 0;
}
static int peer_video_data_handler(esp_peer_video_frame_t* frame, void* ctx)
{
return 0;
}
static int peer_data_handler(esp_peer_data_frame_t* frame, void* ctx)
{
if (frame && frame->size > 0) {
s_on_recv((char*)frame->data, frame->size);
}
return 0;
}
static void pc_task(void *arg)
{
while (peer_running) {
esp_peer_main_loop(peer);
media_lib_thread_sleep(20);
}
media_lib_thread_destroy(NULL);
}
static int signaling_ice_info_handler(esp_peer_signaling_ice_info_t* info, void* ctx)
{
if (peer == NULL) {
esp_peer_default_cfg_t peer_cfg = {
.agent_recv_timeout = 500,
};
esp_peer_cfg_t cfg = {
.server_lists = &info->server_info,
.server_num = 1,
.audio_dir = ESP_PEER_MEDIA_DIR_SEND_RECV,
.audio_info = {
.codec = ESP_PEER_AUDIO_CODEC_G711A,
},
.enable_data_channel = true,
.role = info->is_initiator ? ESP_PEER_ROLE_CONTROLLING : ESP_PEER_ROLE_CONTROLLED,
.on_state = peer_state_handler,
.on_msg = peer_msg_handler,
.on_video_info = peer_video_info_handler,
.on_audio_info = peer_audio_info_handler,
.on_video_data = peer_video_data_handler,
.on_audio_data = peer_audio_data_handler,
.on_data = peer_data_handler,
.ctx = ctx,
.extra_cfg = &peer_cfg,
.extra_size = sizeof(esp_peer_default_cfg_t),
};
int ret = esp_peer_open(&cfg, esp_peer_get_default_impl(), &peer);
if (ret != ESP_PEER_ERR_NONE) {
return ret;
}
media_lib_thread_handle_t thread = NULL;
peer_running = true;
media_lib_thread_create_from_scheduler(&thread, "pc_task", pc_task, NULL);
if (thread == NULL) {
peer_running = false;
}
}
return 0;
}
static int signaling_connected_handler(void* ctx)
{
if (peer) {
return esp_peer_new_connection(peer);
}
return 0;
}
static int signaling_msg_handler(esp_peer_signaling_msg_t* msg, void* ctx)
{
if (msg->type == ESP_PEER_SIGNALING_MSG_BYE) {
esp_peer_close(peer);
peer = NULL;
} else if (msg->type == ESP_PEER_SIGNALING_MSG_SDP) {
// Receive remote SDP
if (peer) {
esp_peer_send_msg(peer, (esp_peer_msg_t*)msg);
}
}
return 0;
}
static int signaling_close_handler(void *ctx)
{
return 0;
}
static int start_signaling(char* url)
{
esp_peer_signaling_cfg_t cfg = {
.signal_url = url,
.on_ice_info = signaling_ice_info_handler,
.on_connected = signaling_connected_handler,
.on_msg = signaling_msg_handler,
.on_close = signaling_close_handler,
};
// Use APPRTC signaling
return esp_peer_signaling_start(&cfg, esp_signaling_get_apprtc_impl(), &signaling);
}
static int start_webrtc(char *url)
{
stop_webrtc();
return start_signaling(url);
}
static int stop_webrtc(void)
{
peer_running = false;
if (peer) {
esp_peer_close(peer);
peer = NULL;
}
if (signaling) {
esp_peer_signaling_stop(signaling);
signaling = NULL;
}
return 0;
}
void peer_send(char* data, size_t size)
{
esp_peer_data_frame_t data_frame = {
.type = ESP_PEER_DATA_CHANNEL_DATA,
.data = (uint8_t*)data,
.size = size,
};
esp_peer_send_data(peer, &data_frame);
}