Commit 7f0fd331 authored by 957dd's avatar 957dd

第三次未改完提交

parent 2eb47ff8
......@@ -725,6 +725,41 @@ int orange_pi_save_wifi(const char *ssid, const char *password) {
return 0;
}
int orange_pi_connect_wifi(const char *ssid, const char *password) {
char command[512];
int ret;
if (!ssid || !ssid[0])
return -1;
if (password && password[0]) {
if (validate_wifi_credentials(ssid, password) != 0)
return -1;
} else if (strlen(ssid) >= SSID_MAX_LENGTH || strpbrk(ssid, "\"`$|;\\")) {
my_zlog_error("SSID无效");
return -1;
}
if (!wifi_connection_exists(ssid) && enforce_saved_wifi_limit(ssid) != 0)
return -1;
if (password && password[0]) {
snprintf(command, sizeof(command),
"nmcli device wifi connect '%s' password '%s'", ssid, password);
} else {
snprintf(command, sizeof(command), "nmcli device wifi connect '%s'", ssid);
}
ret = system(command);
if (ret != 0) {
my_zlog_error("nmcli connect 失败: %s (ret=%d)", ssid, ret);
return -1;
}
my_zlog_info("[SUCCESS] 已连接WiFi: %s", ssid);
return 0;
}
static int ensure_wifi_pool(void) {
pthread_mutex_lock(&s_wifi_pool_mutex);
if (!s_wifi_pool)
......
......@@ -12,4 +12,10 @@ void device_wifi_rec_delete(cJSON *body);
//接收到保存wifi消息
void device_wifi_rec_sava(cJSON *body);
/* 保存 WiFi 配置(含满 10 个自动删最旧逻辑),不立即连接 */
int orange_pi_save_wifi(const char *ssid, const char *password);
/* 保存并立即连接 WiFi(含满 10 个自动删最旧逻辑) */
int orange_pi_connect_wifi(const char *ssid, const char *password);
#endif
\ No newline at end of file
......@@ -72,6 +72,11 @@ static int init_ipc_unix_server(void)
return ipc_start_unix_server(NULL);
}
static int init_wifi_config_agent(void)
{
return wifi_config_agent_start();
}
static int init_worker_threads(void)
{
return thread_start_init(thread_exit_time, thread_mqtt_beat,
......@@ -99,6 +104,7 @@ static const AppInitStep s_init_steps[] = {
{APP_INIT_MODULE_SERVICE, "mqtt_video", http_mqtt_video_init, 1, -6, "请求mqtt服务器和video数据失败"},
{APP_INIT_MODULE_SERVICE, "go_deploy", init_go_deploy, 0, 0, "Go 程序检查/部署失败"},
{APP_INIT_MODULE_SERVICE, "ipc_unix_server", init_ipc_unix_server, 1, -8, "IPC Unix Socket Server 启动失败"},
{APP_INIT_MODULE_SERVICE, "wifi_config_agent", init_wifi_config_agent, 0, 0, "WiFi配置助手UDP服务启动失败"},
{APP_INIT_RUNTIME, "worker_threads", init_worker_threads, 1, -7, "多线程初始化失败"},
};
......@@ -137,6 +143,7 @@ static int run_init_steps(void)
static void app_shutdown(void)
{
wifi_config_agent_stop();
thread_end_close();
device_end_close(g_device_type);
self_control_thread_close(); // 销毁自控的线程
......
......@@ -68,10 +68,13 @@ void *thread_exit_time(void *arg)
}
}
if (g_devcontrol_exit_count >= 5)
if (g_devcontrol_exit_count == 5)
{
device_stop(g_device_type);
g_devcontrol_exit_count = 6;
}
else if (g_devcontrol_exit_count > 5)
{
g_devcontrol_exit_count = 5;
}
pthread_mutex_unlock(&g_exit_count_mutex);
}
......@@ -148,8 +151,14 @@ static void run_chromium_cam_loop(void)
delay_s(5);
while (1) {
if (s_webrtc_index == 1) {
if (is_browser_running() == true)
if (!browser_auto_restart_allowed()) {
delay_ms(200);
continue;
}
if (is_browser_running() == true) {
delay_ms(200);
continue;
}
my_zlog_info("open cam (Chromium fallback)");
opencamsh();
}
......
No preview for this file type
This diff is collapsed.
......@@ -6,4 +6,9 @@ void car0107_middle_pwm(void);
void car0107_control_steering_change_process(int *buf);
void car0107_steering_smooth_all(void);
void car0107_notify_control_activity(void);
long long car0107_last_control_ms(void);
int car0107_esc_is_active(void);
void car0107_steering_set_angle_sync(int angle);
#endif
#include "car0107_idle.h"
#include "car0107_control.h"
#include "devcontrol_common.h"
#include "modules_common.h"
#include "gpio_common.h"
#define CAR0107_IDLE_CHECK_MS 10000
#define CAR0107_IDLE_TIMEOUT_MS (5 * 60 * 1000)
#define CAR0107_IDLE_STEER_HOLD_MS 450
#define CAR0107_IDLE_STEER_LEFT 115
#define CAR0107_IDLE_STEER_RIGHT 65
typedef struct {
pthread_mutex_t mutex;
ThreadPool_t *pool;
bool shutdown;
bool pool_ready;
int next_left;
} car0107_idle_ctx_t;
static car0107_idle_ctx_t s_idle_ctx = {
.mutex = PTHREAD_MUTEX_INITIALIZER,
.pool = NULL,
.shutdown = false,
.pool_ready = false,
.next_left = 1,
};
static void car0107_idle_lock(void)
{
pthread_mutex_lock(&s_idle_ctx.mutex);
}
static void car0107_idle_unlock(void)
{
pthread_mutex_unlock(&s_idle_ctx.mutex);
}
static bool car0107_idle_shutdown_get(void)
{
bool shutdown;
car0107_idle_lock();
shutdown = s_idle_ctx.shutdown;
car0107_idle_unlock();
return shutdown;
}
static int car0107_idle_pool_init(void)
{
car0107_idle_lock();
if (s_idle_ctx.pool_ready) {
car0107_idle_unlock();
return 0;
}
s_idle_ctx.pool = thread_pool_init(1, 1);
if (!s_idle_ctx.pool) {
car0107_idle_unlock();
my_zlog_error("car0107 idle thread pool init failed");
return -1;
}
s_idle_ctx.pool_ready = true;
car0107_idle_unlock();
my_zlog_info("car0107 idle monitor thread pool opened");
return 0;
}
static void car0107_idle_nudge_steering(int turn_left)
{
int angle = turn_left ? CAR0107_IDLE_STEER_LEFT : CAR0107_IDLE_STEER_RIGHT;
/* 刷新电调中位,避免长时间无 PWM 后接收机休眠 */
pwmWrite(PWM_PIN_SPEED, 75);
car0107_steering_set_angle_sync(angle);
delay_ms(CAR0107_IDLE_STEER_HOLD_MS);
car0107_steering_set_angle_sync(90);
pwmWrite(PWM_PIN_SPEED, 75);
}
static void car0107_idle_monitor_task(void *arg)
{
(void)arg;
my_zlog_info("car0107 idle monitor task start");
while (!car0107_idle_shutdown_get()) {
long long now;
long long last;
int turn_left;
delay_ms(CAR0107_IDLE_CHECK_MS);
if (car0107_idle_shutdown_get() || g_device_type != DEVICE_CAR0107) {
break;
}
now = get_current_time_millis();
last = car0107_last_control_ms();
if (last <= 0 || (now - last) < CAR0107_IDLE_TIMEOUT_MS) {
continue;
}
if (car0107_esc_is_active()) {
continue;
}
car0107_idle_lock();
turn_left = s_idle_ctx.next_left;
s_idle_ctx.next_left = !s_idle_ctx.next_left;
car0107_idle_unlock();
my_zlog_info("car0107 idle %dmin: nudge steer %s",
CAR0107_IDLE_TIMEOUT_MS / 60000,
turn_left ? "left" : "right");
car0107_idle_nudge_steering(turn_left);
car0107_notify_control_activity();
}
my_zlog_info("car0107 idle monitor task exit");
}
void car0107_idle_startup(int device_id)
{
if (device_id != DEVICE_CAR0107) {
return;
}
if (car0107_idle_pool_init() != 0) {
return;
}
car0107_idle_lock();
if (thread_pool_add_task(s_idle_ctx.pool, car0107_idle_monitor_task, NULL) != 0) {
my_zlog_error("car0107 idle monitor task submit failed");
}
car0107_idle_unlock();
car0107_notify_control_activity();
my_zlog_info("car0107 idle monitor enabled: steer nudge every %dmin when idle",
CAR0107_IDLE_TIMEOUT_MS / 60000);
}
void car0107_idle_thread_close(void)
{
car0107_idle_lock();
s_idle_ctx.shutdown = true;
car0107_idle_unlock();
if (s_idle_ctx.pool) {
thread_pool_destroy(s_idle_ctx.pool);
s_idle_ctx.pool = NULL;
s_idle_ctx.pool_ready = false;
}
my_zlog_info("car0107 idle monitor thread pool closed");
}
#ifndef CAR0107_IDLE_H__
#define CAR0107_IDLE_H__
void car0107_idle_startup(int device_id);
void car0107_idle_thread_close(void);
#endif
......@@ -136,7 +136,7 @@ static const device_abnormal_close_t s_devcontrol_config[]= {
{
.device_id = DEVICE_CAR0107,
.device_abnormal_stop = car0107_middle_pwm,
.device_close = NULL,
.device_close = car0107_idle_thread_close,
.gpio_pin_pulled=pin_all_default,
.gpio_pwm_pulled=pwm_all_default
},
......
......@@ -10,6 +10,7 @@
#include "car0105_control.h"
#include "car0106_control.h"
#include "car0107_control.h"
#include "car0107_idle.h"
#include "ptz_common.h"
#include "tank0202_control.h"
#include "tank0203_control.h"
......
......@@ -2,6 +2,7 @@
#include "devcontrol_common.h"
#include "common.h"
#include "gpio_init.h"
#include "car0107_idle.h"
int g_device_delay_back_count =0;//设备计时,比如坦克打击倒退逻辑
......@@ -267,6 +268,9 @@ void device_init(int device_id) {
if (device_id == DEVICE_CAR0102) {
car0102_pin27_startup(device_id);
}
if (device_id == DEVICE_CAR0107) {
car0107_idle_startup(device_id);
}
my_zlog_debug("%s initialized successfully!", config->device_name);
......
......@@ -374,9 +374,9 @@ int audio_speaker_init() {
int audio_init(){
delay_s(10);
delay_s(5);
audio_wheat_init();
delay_s(3);
delay_s(1);
audio_speaker_init();
return 0;
......@@ -410,7 +410,7 @@ static const char *s_yundea_block =
*/
int audio_config_init() {
delay_s(20);//延迟30s
delay_s(12);
FILE *fp = fopen(CONFIG_FILE, "r");
if (!fp) {
......
......@@ -11,6 +11,8 @@
#include "go_deploy.h"
#include "tailscale_deploy.h"
#include "runtime_deps.h"
#include "wifi_config_agent.h"
#include "stream_debug_agent.h"
#include "webrtcpush_run.h"
#endif
\ No newline at end of file
......@@ -21,6 +21,8 @@ file(GLOB_RECURSE MODULES_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/tailscale_deploy/*.c
${CMAKE_CURRENT_SOURCE_DIR}/webrtcpush/*.c
${CMAKE_CURRENT_SOURCE_DIR}/runtime_deps/*.c
${CMAKE_CURRENT_SOURCE_DIR}/wifi_config/*.c
${CMAKE_CURRENT_SOURCE_DIR}/stream_debug/*.c
)
set(MODULES_SOURCES
......@@ -40,6 +42,8 @@ set(MODULES_INCLUDE_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/tailscale_deploy
${CMAKE_CURRENT_SOURCE_DIR}/webrtcpush
${CMAKE_CURRENT_SOURCE_DIR}/runtime_deps
${CMAKE_CURRENT_SOURCE_DIR}/wifi_config
${CMAKE_CURRENT_SOURCE_DIR}/stream_debug
${WEBRTCPUSH_GST_INCLUDE_DIRS}
${WEBRTCPUSH_JSON_INCLUDE_DIRS}
${WEBRTCPUSH_SOUP_INCLUDE_DIRS}
......
This diff is collapsed.
......@@ -7,8 +7,18 @@
int opencamsh();
void refresh_cam();//刷新摄像头函数
void refresh_cam(void);//刷新摄像头函数
bool is_browser_running();
void browser_begin_external_switch(void);
void browser_end_external_switch(void);
int browser_auto_restart_allowed(void);
/* 推流调试:仅浏览器 webrtc 模式可切换;effective_url 输出实际打开的完整网址 */
int browser_switch_stream_url(const char *url, char *effective_url, size_t effective_size);
/* 查询 chromium 运行状态与当前推流网址(url 缓冲区未运行时置空串) */
int browser_get_stream_url_info(char *url, size_t url_size, bool *running);
#endif
\ No newline at end of file
#include "stream_debug_agent.h"
#include "stream_debug_config.h"
#include "browser_open.h"
#include "webrtcpush_run.h"
#include "wifi_config_agent.h"
#include "http_config_mqtt.h"
#include "common.h"
static const char *stream_debug_current_mode(void)
{
if (webrtcpush_should_use_mpp()) {
return "c_lang";
}
return "webrtc";
}
static int stream_debug_send_json(int sock, const struct sockaddr_in *addr, const char *json)
{
if (!json || !addr || sock < 0) {
return -1;
}
return sendto(sock, json, strlen(json), 0,
(const struct sockaddr *)addr, sizeof(*addr)) >= 0 ? 0 : -1;
}
void stream_debug_handle_mode_query(int sock, const struct sockaddr_in *addr)
{
cJSON *root = cJSON_CreateObject();
const char *mode = stream_debug_current_mode();
char *payload;
if (!root) {
return;
}
cJSON_AddStringToObject(root, "cmd", "stream_mode_response");
cJSON_AddStringToObject(root, "mode", mode);
payload = cJSON_PrintUnformatted(root);
if (payload) {
stream_debug_send_json(sock, addr, payload);
my_zlog_info("推流调试: stream_mode_query -> mode=%s", mode);
free(payload);
}
cJSON_Delete(root);
}
static void stream_debug_send_url_result(int sock, const struct sockaddr_in *addr,
int success, const char *message,
const char *url)
{
cJSON *root = cJSON_CreateObject();
char *payload;
if (!root) {
return;
}
cJSON_AddStringToObject(root, "cmd", "stream_url_result");
cJSON_AddBoolToObject(root, "success", success ? 1 : 0);
if (message && message[0]) {
cJSON_AddStringToObject(root, "message", message);
}
if (url && url[0]) {
cJSON_AddStringToObject(root, "url", url);
}
payload = cJSON_PrintUnformatted(root);
if (payload) {
stream_debug_send_json(sock, addr, payload);
free(payload);
}
cJSON_Delete(root);
}
void stream_debug_handle_url_update(int sock, const struct sockaddr_in *addr, cJSON *root)
{
cJSON *url_item = cJSON_GetObjectItemCaseSensitive(root, "url");
const char *url;
char effective_url[STREAM_DEBUG_URL_MAX];
int rc;
if (strcmp(stream_debug_current_mode(), "webrtc") != 0) {
stream_debug_send_url_result(sock, addr, 0,
"当前为 C 语言推流,不支持切换网址,请修改设备配置",
NULL);
my_zlog_warn("推流调试: stream_url_update 拒绝(c_lang 模式)");
return;
}
if (!cJSON_IsString(url_item) || !url_item->valuestring || !url_item->valuestring[0]) {
stream_debug_send_url_result(sock, addr, 0, "缺少有效的 url 字段", NULL);
return;
}
url = url_item->valuestring;
my_zlog_info("推流调试: 收到 stream_url_update url=%s", url);
rc = browser_switch_stream_url(url, effective_url, sizeof(effective_url));
if (rc == 0) {
stream_debug_send_url_result(sock, addr, 1, "推流网址已切换", effective_url);
my_zlog_info("推流调试: 推流网址切换成功 -> %s", effective_url);
} else {
stream_debug_send_url_result(sock, addr, 0, "推流网址切换失败", NULL);
my_zlog_warn("推流调试: 推流网址切换失败");
}
wifi_config_agent_rebind_socket();
}
void stream_debug_handle_url_query(int sock, const struct sockaddr_in *addr)
{
cJSON *root = cJSON_CreateObject();
char url_buf[STREAM_DEBUG_URL_MAX];
bool running = false;
char *payload;
my_zlog_info("推流调试: 收到 stream_url_query");
if (!root) {
return;
}
cJSON_AddStringToObject(root, "cmd", "stream_url_response");
if (strcmp(stream_debug_current_mode(), "webrtc") != 0) {
cJSON_AddBoolToObject(root, "success", 0);
cJSON_AddBoolToObject(root, "running", 0);
cJSON_AddStringToObject(root, "message", "当前为 C 语言推流,不支持查询推流网址");
my_zlog_warn("推流调试: stream_url_query 拒绝(c_lang 模式)");
} else {
url_buf[0] = '\0';
(void)browser_get_stream_url_info(url_buf, sizeof(url_buf), &running);
cJSON_AddBoolToObject(root, "success", 1);
cJSON_AddBoolToObject(root, "running", running ? 1 : 0);
cJSON_AddStringToObject(root, "url", running ? url_buf : "");
cJSON_AddStringToObject(root, "message", running ? "当前推流网址" : "浏览器未启动");
my_zlog_info("推流调试: stream_url_query -> running=%d url=%s",
running ? 1 : 0, running ? url_buf : "");
}
payload = cJSON_PrintUnformatted(root);
if (payload) {
stream_debug_send_json(sock, addr, payload);
free(payload);
}
cJSON_Delete(root);
wifi_config_agent_rebind_socket();
}
#ifndef STREAM_DEBUG_AGENT_H__
#define STREAM_DEBUG_AGENT_H__
#include <netinet/in.h>
#include <cJSON.h>
void stream_debug_handle_mode_query(int sock, const struct sockaddr_in *addr);
void stream_debug_handle_url_update(int sock, const struct sockaddr_in *addr, cJSON *root);
void stream_debug_handle_url_query(int sock, const struct sockaddr_in *addr);
#endif
#ifndef STREAM_DEBUG_CONFIG_H__
#define STREAM_DEBUG_CONFIG_H__
#define STREAM_DEBUG_URL_MAX 512
#define STREAM_DEBUG_MESSAGE_MAX 256
#define STREAM_DEBUG_CHROMIUM_STOP_MS 1000
#endif
#include "audio_source.h"
#include "webrtcpush_config.h"
#include "webrtcpush_log.h"
#include <gst/gst.h>
#include <gst/app/gstappsink.h>
struct AudioSource {
GstElement *pipeline;
GstElement *appsink;
GstElement *enc;
guint8 *frame_buf; /* 缓存最新帧数据,避免 sample 生命周期问题 */
};
AudioSource *audio_source_start(const char *alsa_device, char **error_message)
{
AudioSource *src;
GstElement *pipe, *asrc, *conv, *resample, *caps_f, *enc, *sink;
GstCaps *caps;
GstStateChangeReturn ret;
if (!alsa_device || !alsa_device[0]) {
if (error_message)
*error_message = g_strdup("no ALSA device");
return NULL;
}
src = g_new0(AudioSource, 1);
pipe = gst_pipeline_new("audio-pipe");
if (!g_strcmp0(alsa_device, "test")) {
asrc = gst_element_factory_make("audiotestsrc", "asrc");
if (asrc)
g_object_set(asrc, "wave", 0, "freq", 440, NULL);
} else {
asrc = gst_element_factory_make("alsasrc", "asrc");
if (asrc)
g_object_set(asrc, "device", alsa_device, NULL);
}
conv = gst_element_factory_make("audioconvert", "conv");
resample = gst_element_factory_make("audioresample", "resample");
caps_f = gst_element_factory_make("capsfilter", "caps_f");
enc = gst_element_factory_make("opusenc", "enc");
sink = gst_element_factory_make("appsink", "sink");
if (!pipe || !asrc || !conv || !resample || !caps_f || !enc || !sink) {
if (error_message)
*error_message = g_strdup("failed to create audio GStreamer elements");
if (pipe)
gst_object_unref(pipe);
g_free(src);
return NULL;
}
/* Opus 要求 48000Hz;单声道足够车机麦 */
caps = gst_caps_new_simple("audio/x-raw",
"rate", G_TYPE_INT, WEBRTCPUSH_OPUS_CLOCKRATE,
"channels", G_TYPE_INT, WEBRTCPUSH_OPUS_CHANNELS,
"format", G_TYPE_STRING, "S16LE", NULL);
g_object_set(caps_f, "caps", caps, NULL);
gst_caps_unref(caps);
g_object_set(enc,
"bitrate", WEBRTCPUSH_OPUS_BITRATE,
"cbr", TRUE,
"framesize", 20, /* 20ms 帧 */
"inband-fec", TRUE,
NULL);
g_object_set(sink,
"emit-signals", FALSE,
"drop", FALSE,
"max-buffers", WEBRTCPUSH_AUDIO_QUEUE_DEPTH,
NULL);
gst_bin_add_many(GST_BIN(pipe), asrc, conv, resample, caps_f, enc, sink, NULL);
if (!gst_element_link_many(asrc, conv, resample, caps_f, enc, sink, NULL)) {
if (error_message)
*error_message = g_strdup("failed to link audio chain");
gst_object_unref(pipe);
g_free(src);
return NULL;
}
src->pipeline = pipe;
src->appsink = sink;
src->enc = enc;
ret = gst_element_set_state(pipe, GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE) {
if (error_message)
*error_message = g_strdup("audio pipeline failed to reach PLAYING");
gst_element_set_state(pipe, GST_STATE_NULL);
gst_object_unref(pipe);
g_free(src);
return NULL;
}
my_zlog_info("audio_source: started device=%s opus=%uch %uHz %ukbps",
alsa_device, WEBRTCPUSH_OPUS_CHANNELS, WEBRTCPUSH_OPUS_CLOCKRATE,
WEBRTCPUSH_OPUS_BITRATE / 1000);
return src;
}
void audio_source_stop(AudioSource *src)
{
if (!src)
return;
if (src->pipeline) {
gst_element_set_state(src->pipeline, GST_STATE_NULL);
gst_object_unref(src->pipeline);
}
g_free(src->frame_buf);
g_free(src);
}
gboolean audio_source_pull(AudioSource *src, const uint8_t **data, size_t *size,
guint64 *pts_ns, gint timeout_ms)
{
GstAppSink *appsink;
GstSample *sample;
GstBuffer *buffer;
GstMapInfo map;
if (!src || !src->appsink || !data || !size || timeout_ms < 1)
return FALSE;
appsink = GST_APP_SINK(src->appsink);
sample = gst_app_sink_try_pull_sample(appsink, (guint64)timeout_ms * GST_MSECOND);
if (!sample)
return FALSE;
buffer = gst_sample_get_buffer(sample);
if (!buffer || !gst_buffer_map(buffer, &map, GST_MAP_READ)) {
gst_sample_unref(sample);
return FALSE;
}
g_free(src->frame_buf);
src->frame_buf = g_memdup2(map.data, map.size);
*data = src->frame_buf;
*size = map.size;
if (pts_ns)
*pts_ns = GST_BUFFER_PTS(buffer);
gst_buffer_unmap(buffer, &map);
gst_sample_unref(sample);
return TRUE;
}
#ifndef AUDIO_SOURCE_H
#define AUDIO_SOURCE_H
#include <glib.h>
#include <stddef.h>
#include <stdint.h>
typedef struct AudioSource AudioSource;
/* alsa_device: plughw:X,Y | "test"(audiotestsrc 测试音) */
AudioSource *audio_source_start(const char *alsa_device, char **error_message);
void audio_source_stop(AudioSource *src);
/* 拉一帧 Opus payload;数据在下次 pull 前有效。timeout_ms:appsink 等待毫秒。 */
gboolean audio_source_pull(AudioSource *src, const uint8_t **data, size_t *size,
guint64 *pts_ns, gint timeout_ms);
#endif
This diff is collapsed.
......@@ -22,4 +22,9 @@ void mpp_h264_source_request_keyframe(MppH264Source *src);
gboolean mpp_h264_source_is_mpp_encoder(const MppH264Source *src);
const gchar *mpp_h264_source_get_sprop(const MppH264Source *src);
/* 管道无帧时尝试 NULL→PLAYING 恢复 */
gboolean mpp_h264_source_recover(MppH264Source *src);
#endif
This diff is collapsed.
......@@ -14,18 +14,43 @@
/* 正常固定 24fps;弱网以降码率为主,后续若启用动态帧率也不得低于 22fps。 */
#define WEBRTCPUSH_H264_FPS 24
#define WEBRTCPUSH_H264_MIN_FPS 22
#define WEBRTCPUSH_H264_GOP (WEBRTCPUSH_H264_FPS * 3)
#define WEBRTCPUSH_H264_GOP (WEBRTCPUSH_H264_FPS) /* 1s 一个 IDR */
/* 与 gst_webrtc_pipeline / jywy 浏览器推流对齐的码率策略 */
#define WEBRTCPUSH_INITIAL_BITRATE 1400000U /* 起播 1.4 Mbps */
#define WEBRTCPUSH_INITIAL_BITRATE 1800000U
#define WEBRTCPUSH_MIN_BITRATE 500000U
#define WEBRTCPUSH_MAX_BITRATE 3200000U
#define WEBRTCPUSH_REMB_UTIL_PERCENT 82U /* 链路容量扣除音频/RTP 余量 */
#define WEBRTCPUSH_BITRATE_RAMP_MS 1000U /* 每秒向目标码率逼近一档 */
#define WEBRTCPUSH_REMB_UTIL_PERCENT 85U
#define WEBRTCPUSH_REMB_DOWN_MIN_STEP 50000U /* 非急跌时 <50kbps 不调编码器 */
#define WEBRTCPUSH_BITRATE_RAMP_UP_MS 500U /* 升码更快恢复画质 */
#define WEBRTCPUSH_BITRATE_RAMP_DOWN_MS 1000U
#define WEBRTCPUSH_PACING_HEADROOM_PERCENT 108U
#define WEBRTCPUSH_PACING_INTERVAL_MS 5U
#define WEBRTCPUSH_PACING_HEADROOM_PERCENT 120U
#define WEBRTCPUSH_PACING_MAX_BITRATE 3750000U
#define WEBRTCPUSH_NACK_PACKETS 1024U
/* RTP 分片与 NACK(MTU=1200,留 SRTP/DTLS/FU 余量) */
#define WEBRTCPUSH_RTP_MAX_FRAGMENT 1050U
#define WEBRTCPUSH_NACK_PACKETS 512U
/* PLI/IDR 节流:避免频繁 force-key-unit 拉高瞬时码率 */
#define WEBRTCPUSH_PLI_IDR_THROTTLE_MS 200U
/* 周期性推流指标日志间隔 */
#define WEBRTCPUSH_STATS_LOG_INTERVAL_MS 8000U
/* 连续发送失败退避与上限 */
#define WEBRTCPUSH_SEND_FAIL_RESET 30U
/* H.264 Baseline@L3.1,兼容性最好 */
#define WEBRTCPUSH_H264_PROFILE_LEVEL_ID "42e01f"
/* 拉帧线程与发送线程之间的有界队列(leaky,满则丢最旧帧) */
#define WEBRTCPUSH_SEND_QUEUE_DEPTH 4U
/* 管道缓冲:运动场景需适度缓存,过低易 pull timeout / 糊屏 */
#define WEBRTCPUSH_MPP_PRE_ENC_BUFFERS 3 /* 编码前 leaky */
#define WEBRTCPUSH_MPP_POST_ENC_BUFFERS 2 /* 编码后保留 AU */
#define WEBRTCPUSH_APPSINK_MAX_BUFFERS 2
/* 视频采集:auto | /dev/videoN | test(videotestsrc 测试图案) */
#define WEBRTCPUSH_VIDEO_DEVICE "auto"
......@@ -36,6 +61,12 @@
*/
#define WEBRTCPUSH_ALSA_DEVICE "auto"
/* Opus 音频编码参数(上行麦克风推流) */
#define WEBRTCPUSH_OPUS_BITRATE 64000U
#define WEBRTCPUSH_OPUS_CLOCKRATE 48000U
#define WEBRTCPUSH_OPUS_CHANNELS 1
#define WEBRTCPUSH_AUDIO_QUEUE_DEPTH 8U
/*
* 设备侧 DataChannel(myDataChannel)与手机 createDataChannel('init') 争用 SCTP,
* 易触发 sctpenc association error 并导致管道闪断/进程崩溃。仅推流可不建。
......
......@@ -172,7 +172,7 @@ int webrtcpush_run_blocking(void)
s_app.prefer_mpp = TRUE;
s_app.device_offerer = FALSE;
s_app.verbose = WEBRTCPUSH_DEBUG ? TRUE : FALSE;
s_app.enable_audio = FALSE; /* 视频先行;音频后续 ALSA→Opus track */
setup_alsa_device(&s_app); /* enable_audio 由 ALSA 设备探测结果决定 */
s_app.loop = g_main_loop_new(NULL, FALSE);
......
This diff is collapsed.
#ifndef WIFI_CONFIG_AGENT_H__
#define WIFI_CONFIG_AGENT_H__
int wifi_config_agent_start(void);
void wifi_config_agent_stop(void);
void wifi_config_agent_rebind_socket(void);
#endif
#ifndef WIFI_CONFIG_CONFIG_H__
#define WIFI_CONFIG_CONFIG_H__
#define WIFI_CONFIG_UDP_PORT 18888
#define WIFI_CONFIG_RECV_BUF_SIZE 2048
#define WIFI_CONFIG_DEVICE_ID_MAX 32
#define WIFI_CONFIG_DEVICE_NAME_MAX 64
#define WIFI_CONFIG_MESSAGE_MAX 256
#define WIFI_CONFIG_DEVICE_NO_LEN 14
#endif
......@@ -9,4 +9,4 @@ file perms = 600
millisecond = "%d(%Y-%m-%d %H:%M:%S).%ms [%V] %m%n"
[rules]
my_log.* "/home/orangepi/car/master/log/log_2026-07-01.log"; millisecond
my_log.* "/home/orangepi/car/master/log/log_2026-07-02.log"; millisecond
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment