Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
car-controlserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wenzhongjian
car-controlserver
Commits
7f0fd331
Commit
7f0fd331
authored
Jul 02, 2026
by
957dd
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
第三次未改完提交
parent
2eb47ff8
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
31 changed files
with
654 additions
and
16 deletions
+654
-16
device_wifi_manager.c
app/device_change/device_wifi_manager.c
+35
-0
device_wifi_manager.h
app/device_change/device_wifi_manager.h
+7
-0
main.c
app/main/main.c
+7
-0
pthread_open.c
app/main/pthread_open.c
+12
-3
main
build/main
+0
-0
car0107_control.c
drivers/devicecontrol/car/car0107_control.c
+0
-0
car0107_control.h
drivers/devicecontrol/car/car0107_control.h
+5
-0
car0107_idle.c
drivers/devicecontrol/car/car0107_idle.c
+154
-0
car0107_idle.h
drivers/devicecontrol/car/car0107_idle.h
+7
-0
devcontrol_common.c
drivers/devicecontrol/common/devcontrol_common.c
+1
-1
devcontrol_common.h
drivers/devicecontrol/common/devcontrol_common.h
+1
-0
device_init.c
drivers/gpio/device_init.c
+4
-0
audioplay.c
drivers/sensors/audioplay.c
+3
-3
modules_common.h
include/modules_common.h
+3
-0
CMakeLists.txt
modules/CMakeLists.txt
+4
-0
browser_open.c
modules/browser/browser_open.c
+0
-0
browser_open.h
modules/browser/browser_open.h
+12
-1
stream_debug_agent.c
modules/stream_debug/stream_debug_agent.c
+150
-0
stream_debug_agent.h
modules/stream_debug/stream_debug_agent.h
+11
-0
stream_debug_config.h
modules/stream_debug/stream_debug_config.h
+8
-0
audio_source.c
modules/webrtcpush/audio_source.c
+149
-0
audio_source.h
modules/webrtcpush/audio_source.h
+18
-0
mpp_h264_source.c
modules/webrtcpush/mpp_h264_source.c
+0
-0
mpp_h264_source.h
modules/webrtcpush/mpp_h264_source.h
+5
-0
rtc_client.c
modules/webrtcpush/rtc_client.c
+0
-0
webrtcpush_config.h
modules/webrtcpush/webrtcpush_config.h
+37
-6
webrtcpush_run.c
modules/webrtcpush/webrtcpush_run.c
+1
-1
wifi_config_agent.c
modules/wifi_config/wifi_config_agent.c
+0
-0
wifi_config_agent.h
modules/wifi_config/wifi_config_agent.h
+8
-0
wifi_config_config.h
modules/wifi_config/wifi_config_config.h
+11
-0
zlog.conf
zlog.conf
+1
-1
No files found.
app/device_change/device_wifi_manager.c
View file @
7f0fd331
...
...
@@ -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
)
...
...
app/device_change/device_wifi_manager.h
View file @
7f0fd331
...
...
@@ -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
app/main/main.c
View file @
7f0fd331
...
...
@@ -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
();
// 销毁自控的线程
...
...
app/main/pthread_open.c
View file @
7f0fd331
...
...
@@ -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
();
}
...
...
build/main
View file @
7f0fd331
No preview for this file type
drivers/devicecontrol/car/car0107_control.c
View file @
7f0fd331
This diff is collapsed.
Click to expand it.
drivers/devicecontrol/car/car0107_control.h
View file @
7f0fd331
...
...
@@ -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
drivers/devicecontrol/car/car0107_idle.c
0 → 100644
View file @
7f0fd331
#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"
);
}
drivers/devicecontrol/car/car0107_idle.h
0 → 100644
View file @
7f0fd331
#ifndef CAR0107_IDLE_H__
#define CAR0107_IDLE_H__
void
car0107_idle_startup
(
int
device_id
);
void
car0107_idle_thread_close
(
void
);
#endif
drivers/devicecontrol/common/devcontrol_common.c
View file @
7f0fd331
...
...
@@ -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
},
...
...
drivers/devicecontrol/common/devcontrol_common.h
View file @
7f0fd331
...
...
@@ -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"
...
...
drivers/gpio/device_init.c
View file @
7f0fd331
...
...
@@ -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
);
...
...
drivers/sensors/audioplay.c
View file @
7f0fd331
...
...
@@ -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
)
{
...
...
include/modules_common.h
View file @
7f0fd331
...
...
@@ -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
modules/CMakeLists.txt
View file @
7f0fd331
...
...
@@ -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
}
...
...
modules/browser/browser_open.c
View file @
7f0fd331
This diff is collapsed.
Click to expand it.
modules/browser/browser_open.h
View file @
7f0fd331
...
...
@@ -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
modules/stream_debug/stream_debug_agent.c
0 → 100644
View file @
7f0fd331
#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
();
}
modules/stream_debug/stream_debug_agent.h
0 → 100644
View file @
7f0fd331
#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
modules/stream_debug/stream_debug_config.h
0 → 100644
View file @
7f0fd331
#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
modules/webrtcpush/audio_source.c
0 → 100644
View file @
7f0fd331
#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
;
}
modules/webrtcpush/audio_source.h
0 → 100644
View file @
7f0fd331
#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
modules/webrtcpush/mpp_h264_source.c
View file @
7f0fd331
This diff is collapsed.
Click to expand it.
modules/webrtcpush/mpp_h264_source.h
View file @
7f0fd331
...
...
@@ -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
modules/webrtcpush/rtc_client.c
View file @
7f0fd331
This diff is collapsed.
Click to expand it.
modules/webrtcpush/webrtcpush_config.h
View file @
7f0fd331
...
...
@@ -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 1
400000U
/* 起播 1.4 Mbps */
#define WEBRTCPUSH_INITIAL_BITRATE 1
800000U
#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 并导致管道闪断/进程崩溃。仅推流可不建。
...
...
modules/webrtcpush/webrtcpush_run.c
View file @
7f0fd331
...
...
@@ -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
*/
s
etup_alsa_device
(
&
s_app
);
/* enable_audio 由 ALSA 设备探测结果决定
*/
s_app
.
loop
=
g_main_loop_new
(
NULL
,
FALSE
);
...
...
modules/wifi_config/wifi_config_agent.c
0 → 100644
View file @
7f0fd331
This diff is collapsed.
Click to expand it.
modules/wifi_config/wifi_config_agent.h
0 → 100644
View file @
7f0fd331
#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
modules/wifi_config/wifi_config_config.h
0 → 100644
View file @
7f0fd331
#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
zlog.conf
View file @
7f0fd331
...
...
@@ -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-0
1
.log"
;
millisecond
my_log
.*
"/home/orangepi/car/master/log/log_2026-07-0
2
.log"
;
millisecond
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment