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
d92f8afb
Commit
d92f8afb
authored
Jul 06, 2026
by
957dd
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
加入了跟app的通信,网络配置那些优化
parent
6edd4759
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
487 additions
and
44 deletions
+487
-44
device_wifi_manager.c
app/device_change/device_wifi_manager.c
+144
-0
device_wifi_manager.h
app/device_change/device_wifi_manager.h
+16
-0
main
build/main
+0
-0
modules_common.h
include/modules_common.h
+2
-1
CMakeLists.txt
modules/CMakeLists.txt
+2
-2
device_debug_agent.c
modules/device_debug/device_debug_agent.c
+2
-2
device_debug_agent.h
modules/device_debug/device_debug_agent.h
+2
-2
device_debug_config.h
modules/device_debug/device_debug_config.h
+0
-0
device_diag.c
modules/device_debug/device_diag.c
+0
-0
device_diag.h
modules/device_debug/device_diag.h
+21
-0
runtime_deps.c
modules/runtime_deps/runtime_deps.c
+21
-1
audio_source.c
modules/webrtcpush/audio_source.c
+1
-1
mpp_h264_source.c
modules/webrtcpush/mpp_h264_source.c
+34
-12
rtc_client.c
modules/webrtcpush/rtc_client.c
+0
-0
webrtcpush_config.h
modules/webrtcpush/webrtcpush_config.h
+16
-13
wifi_config_agent.c
modules/wifi_config/wifi_config_agent.c
+172
-5
pacinghandler.hpp
third_party/libdatachannel/include/rtc/pacinghandler.hpp
+2
-0
rtc.h
third_party/libdatachannel/include/rtc/rtc.h
+4
-0
capi.cpp
third_party/libdatachannel/src/capi.cpp
+25
-0
pacinghandler.cpp
third_party/libdatachannel/src/pacinghandler.cpp
+22
-4
zlog.conf
zlog.conf
+1
-1
No files found.
app/device_change/device_wifi_manager.c
View file @
d92f8afb
...
@@ -885,3 +885,147 @@ void device_send_saved_wifi() {
...
@@ -885,3 +885,147 @@ void device_send_saved_wifi() {
}
}
cJSON_Delete
(
root
);
cJSON_Delete
(
root
);
}
}
/* ==================== App WiFi 管理 (UDP 18888) 实现 ==================== */
/* 从 .nmconnection 文件读取 psk= 字段。文件权限 root:root 600,
* 设备进程以 root 运行可直接读取。返回 0=成功, -1=失败/无密码 */
static
int
read_wifi_psk_from_profile
(
const
char
*
ssid
,
char
*
psk_out
,
size_t
psk_sz
)
{
char
filepath
[
512
];
FILE
*
fp
;
char
line
[
256
];
char
*
p
;
int
found
=
0
;
if
(
!
ssid
||
!
psk_out
||
psk_sz
==
0
)
return
-
1
;
psk_out
[
0
]
=
'\0'
;
/* 主路径:/etc/NetworkManager/system-connections/<ssid>.nmconnection */
snprintf
(
filepath
,
sizeof
(
filepath
),
"%s%s.nmconnection"
,
NM_CONN_DIR
,
ssid
);
fp
=
fopen
(
filepath
,
"r"
);
if
(
!
fp
)
return
-
1
;
while
(
fgets
(
line
,
sizeof
(
line
),
fp
))
{
trim_line
(
line
);
/* 匹配 psk= 开头(前面可能有空格) */
p
=
strchr
(
line
,
'p'
);
while
(
p
)
{
if
(
strncmp
(
p
,
"psk="
,
4
)
==
0
)
{
const
char
*
val
=
p
+
4
;
strncpy
(
psk_out
,
val
,
psk_sz
-
1
);
psk_out
[
psk_sz
-
1
]
=
'\0'
;
found
=
1
;
break
;
}
p
=
strchr
(
p
+
1
,
'p'
);
}
if
(
found
)
break
;
}
fclose
(
fp
);
return
found
?
0
:
-
1
;
}
/* 查询已保存 WiFi 列表,返回 cJSON 数组(调用方负责 cJSON_Delete) */
cJSON
*
app_wifi_list_query
(
void
)
{
saved_wifi_entry_t
entries
[
MAX_WIFI_ENTRIES
];
int
count
;
cJSON
*
list
;
int
active_idx
=
-
1
;
/* 刷新当前连接 SSID,确保 active 判断准确 */
get_current_wifi
();
count
=
collect_saved_wifi_entries
(
entries
,
MAX_WIFI_ENTRIES
);
if
(
count
<
0
)
count
=
0
;
list
=
cJSON_CreateArray
();
if
(
!
list
)
return
NULL
;
for
(
int
i
=
0
;
i
<
count
;
i
++
)
{
cJSON
*
item
=
cJSON_CreateObject
();
if
(
!
item
)
continue
;
cJSON_AddStringToObject
(
item
,
"ssid"
,
entries
[
i
].
ssid
);
/* password:从 .nmconnection 读取;默认 WiFi 用内置密码兜底 */
char
psk
[
WIFI_PSK_MAX_LENGTH
+
1
]
=
{
0
};
if
(
read_wifi_psk_from_profile
(
entries
[
i
].
ssid
,
psk
,
sizeof
(
psk
))
==
0
)
cJSON_AddStringToObject
(
item
,
"password"
,
psk
);
else
if
(
is_default_wifi_ssid
(
entries
[
i
].
ssid
))
cJSON_AddStringToObject
(
item
,
"password"
,
default_password
);
else
cJSON_AddStringToObject
(
item
,
"password"
,
""
);
/* active:wifi_profile_is_in_use 内部已综合判断 */
int
in_use
=
wifi_profile_is_in_use
(
entries
[
i
].
ssid
);
cJSON_AddBoolToObject
(
item
,
"active"
,
in_use
?
1
:
0
);
if
(
in_use
&&
active_idx
<
0
)
active_idx
=
i
;
/* protected:默认 WiFi (jking) 受保护 */
cJSON_AddBoolToObject
(
item
,
"protected"
,
is_default_wifi_ssid
(
entries
[
i
].
ssid
)
?
1
:
0
);
cJSON_AddItemToArray
(
list
,
item
);
}
(
void
)
active_idx
;
return
list
;
}
/* 切换当前连接到已保存的指定 SSID */
int
app_wifi_switch
(
const
char
*
ssid
)
{
saved_wifi_entry_t
entries
[
MAX_WIFI_ENTRIES
];
int
count
;
int
found
=
0
;
char
psk
[
WIFI_PSK_MAX_LENGTH
+
1
]
=
{
0
};
if
(
!
ssid
||
!
ssid
[
0
])
return
-
1
;
count
=
collect_saved_wifi_entries
(
entries
,
MAX_WIFI_ENTRIES
);
if
(
count
<
0
)
return
-
1
;
for
(
int
i
=
0
;
i
<
count
;
i
++
)
{
if
(
strcmp
(
entries
[
i
].
ssid
,
ssid
)
==
0
)
{
found
=
1
;
break
;
}
}
if
(
!
found
)
return
-
1
;
/* 读取已保存密码,无密码则空串连接(开放网络) */
if
(
read_wifi_psk_from_profile
(
ssid
,
psk
,
sizeof
(
psk
))
!=
0
&&
is_default_wifi_ssid
(
ssid
))
snprintf
(
psk
,
sizeof
(
psk
),
"%s"
,
default_password
);
/* 复用现有连接逻辑:已存在则直接 connect,无密码走无密码分支。
* 区分返回码:未找到返回 -1,连接失败返回 -2,便于 agent 给准确提示。 */
if
(
orange_pi_connect_wifi
(
ssid
,
psk
[
0
]
?
psk
:
NULL
)
==
0
)
return
0
;
my_zlog_error
(
"app_wifi_switch: WiFi 已保存但连接失败 SSID=%s"
,
ssid
);
return
-
2
;
}
/* 删除已保存的指定 SSID(受保护的 jking 不可删) */
int
app_wifi_delete
(
const
char
*
ssid
)
{
if
(
!
ssid
||
!
ssid
[
0
])
return
-
1
;
/* 受保护检查(与 device_wifi_delete_saved_profile 内部一致,提前返回便于 agent 区分原因) */
if
(
is_default_wifi_ssid
(
ssid
))
return
-
2
;
/* device_wifi_delete_saved_profile 内部还会检查是否在用,
* 在用的返回 -3。这里统一映射为 -1 失败,由 agent 组织 message。 */
int
rc
=
device_wifi_delete_saved_profile
(
ssid
);
if
(
rc
==
0
)
return
0
;
return
-
1
;
}
app/device_change/device_wifi_manager.h
View file @
d92f8afb
...
@@ -18,4 +18,19 @@ int orange_pi_save_wifi(const char *ssid, const char *password);
...
@@ -18,4 +18,19 @@ int orange_pi_save_wifi(const char *ssid, const char *password);
/* 保存并立即连接 WiFi(含满 10 个自动删最旧逻辑) */
/* 保存并立即连接 WiFi(含满 10 个自动删最旧逻辑) */
int
orange_pi_connect_wifi
(
const
char
*
ssid
,
const
char
*
password
);
int
orange_pi_connect_wifi
(
const
char
*
ssid
,
const
char
*
password
);
/* ===== App WiFi 管理 (UDP 18888) 接口 ===== */
/* 查询已保存 WiFi 列表,返回 cJSON 数组(调用方负责 cJSON_Delete):
* 每项含 ssid/password/active/protected 四字段。
* active/protected 由内部判断,password 从 .nmconnection 读取。 */
cJSON
*
app_wifi_list_query
(
void
);
/* 切换当前连接到已保存的指定 SSID。
* 返回 0=已发起切换(异步), -1=未找到/失败 */
int
app_wifi_switch
(
const
char
*
ssid
);
/* 删除已保存的指定 SSID(受保护的 jking 不可删)。
* 返回 0=成功, -1=未找到/失败, -2=受保护不可删 */
int
app_wifi_delete
(
const
char
*
ssid
);
#endif
#endif
\ No newline at end of file
build/main
View file @
d92f8afb
No preview for this file type
include/modules_common.h
View file @
d92f8afb
...
@@ -12,7 +12,7 @@
...
@@ -12,7 +12,7 @@
#include "tailscale_deploy.h"
#include "tailscale_deploy.h"
#include "runtime_deps.h"
#include "runtime_deps.h"
#include "wifi_config_agent.h"
#include "wifi_config_agent.h"
#include "
stream
_debug_agent.h"
#include "
device
_debug_agent.h"
#include "webrtcpush_run.h"
#include "webrtcpush_run.h"
#endif
#endif
\ No newline at end of file
modules/CMakeLists.txt
View file @
d92f8afb
...
@@ -22,7 +22,7 @@ file(GLOB_RECURSE MODULES_SOURCES
...
@@ -22,7 +22,7 @@ file(GLOB_RECURSE MODULES_SOURCES
${
CMAKE_CURRENT_SOURCE_DIR
}
/webrtcpush/*.c
${
CMAKE_CURRENT_SOURCE_DIR
}
/webrtcpush/*.c
${
CMAKE_CURRENT_SOURCE_DIR
}
/runtime_deps/*.c
${
CMAKE_CURRENT_SOURCE_DIR
}
/runtime_deps/*.c
${
CMAKE_CURRENT_SOURCE_DIR
}
/wifi_config/*.c
${
CMAKE_CURRENT_SOURCE_DIR
}
/wifi_config/*.c
${
CMAKE_CURRENT_SOURCE_DIR
}
/
stream
_debug/*.c
${
CMAKE_CURRENT_SOURCE_DIR
}
/
device
_debug/*.c
)
)
set
(
MODULES_SOURCES
set
(
MODULES_SOURCES
...
@@ -43,7 +43,7 @@ set(MODULES_INCLUDE_DIRS
...
@@ -43,7 +43,7 @@ set(MODULES_INCLUDE_DIRS
${
CMAKE_CURRENT_SOURCE_DIR
}
/webrtcpush
${
CMAKE_CURRENT_SOURCE_DIR
}
/webrtcpush
${
CMAKE_CURRENT_SOURCE_DIR
}
/runtime_deps
${
CMAKE_CURRENT_SOURCE_DIR
}
/runtime_deps
${
CMAKE_CURRENT_SOURCE_DIR
}
/wifi_config
${
CMAKE_CURRENT_SOURCE_DIR
}
/wifi_config
${
CMAKE_CURRENT_SOURCE_DIR
}
/
stream
_debug
${
CMAKE_CURRENT_SOURCE_DIR
}
/
device
_debug
${
WEBRTCPUSH_GST_INCLUDE_DIRS
}
${
WEBRTCPUSH_GST_INCLUDE_DIRS
}
${
WEBRTCPUSH_JSON_INCLUDE_DIRS
}
${
WEBRTCPUSH_JSON_INCLUDE_DIRS
}
${
WEBRTCPUSH_SOUP_INCLUDE_DIRS
}
${
WEBRTCPUSH_SOUP_INCLUDE_DIRS
}
...
...
modules/
stream_debug/stream
_debug_agent.c
→
modules/
device_debug/device
_debug_agent.c
View file @
d92f8afb
#include "
stream
_debug_agent.h"
#include "
device
_debug_agent.h"
#include "
stream
_debug_config.h"
#include "
device
_debug_config.h"
#include "browser_open.h"
#include "browser_open.h"
#include "webrtcpush_run.h"
#include "webrtcpush_run.h"
#include "wifi_config_agent.h"
#include "wifi_config_agent.h"
...
...
modules/
stream_debug/stream
_debug_agent.h
→
modules/
device_debug/device
_debug_agent.h
View file @
d92f8afb
#ifndef
STREAM
_DEBUG_AGENT_H__
#ifndef
DEVICE
_DEBUG_AGENT_H__
#define
STREAM
_DEBUG_AGENT_H__
#define
DEVICE
_DEBUG_AGENT_H__
#include <netinet/in.h>
#include <netinet/in.h>
#include <cJSON.h>
#include <cJSON.h>
...
...
modules/
stream_debug/stream
_debug_config.h
→
modules/
device_debug/device
_debug_config.h
View file @
d92f8afb
File moved
modules/device_debug/device_diag.c
0 → 100644
View file @
d92f8afb
This diff is collapsed.
Click to expand it.
modules/device_debug/device_diag.h
0 → 100644
View file @
d92f8afb
#ifndef DEVICE_DIAG_H__
#define DEVICE_DIAG_H__
#include <netinet/in.h>
#include <cJSON.h>
/* ===== 设备调试协议 v4(UDP 18888) ===== */
/* 简易自检:检测 USB 摄像头/麦克风/喇叭/浏览器状态,回 device_check_response */
void
device_diag_handle_check
(
int
sock
,
const
struct
sockaddr_in
*
addr
);
/* 浏览器控制:op="refresh" 刷新,op="reopen" 重开 */
void
device_diag_handle_browser_ctrl
(
int
sock
,
const
struct
sockaddr_in
*
addr
,
const
char
*
op
);
/* 日志获取:校验密码 fcrs666,启动 TCP 18889 传输线程,回 log_fetch_ready */
void
device_diag_handle_log_fetch
(
int
sock
,
const
struct
sockaddr_in
*
addr
,
cJSON
*
root
);
/* 判断是否为设备诊断 cmd(device_check / browser_refresh / browser_reopen / log_fetch) */
int
device_diag_is_cmd
(
const
char
*
cmd
);
#endif
modules/runtime_deps/runtime_deps.c
View file @
d92f8afb
...
@@ -45,6 +45,23 @@ static const GstNeed s_webrtc_gst_required[] = {
...
@@ -45,6 +45,23 @@ static const GstNeed s_webrtc_gst_required[] = {
static
gboolean
s_webrtc_push_ok
=
FALSE
;
static
gboolean
s_webrtc_push_ok
=
FALSE
;
static
gboolean
s_webrtc_push_disabled
=
FALSE
;
static
gboolean
s_webrtc_push_disabled
=
FALSE
;
/* GLib/GObject/GStreamer 日志重定向到 zlog
* 平台底层库(libsoup/libnice/GStreamer)的 INFO/MESSAGE/DEBUG 级别
* 通常是 WebSocket 心跳帧/消息分发等 3s 一次的常规事件,
* 下沉到 debug 后 release 发布版(LOG_PRODUCTION)自动屏蔽,
* 避免日志污染。ERROR/WARNING 保留。 */
static
void
glib_log_handler
(
const
gchar
*
log_domain
,
GLogLevelFlags
log_level
,
const
gchar
*
message
,
gpointer
user_data
)
{
(
void
)
user_data
;
if
(
log_level
&
G_LOG_LEVEL_ERROR
)
my_zlog_error
(
"glib/%s: %s"
,
log_domain
?
log_domain
:
"?"
,
message
?
message
:
"(null)"
);
else
if
(
log_level
&
(
G_LOG_LEVEL_CRITICAL
|
G_LOG_LEVEL_WARNING
))
my_zlog_warn
(
"glib/%s: %s"
,
log_domain
?
log_domain
:
"?"
,
message
?
message
:
"(null)"
);
else
my_zlog_debug
(
"glib/%s: %s"
,
log_domain
?
log_domain
:
"?"
,
message
?
message
:
"(null)"
);
}
static
const
char
*
s_chromium_bins
[]
=
{
static
const
char
*
s_chromium_bins
[]
=
{
"/usr/bin/chromium-browser"
,
"/usr/bin/chromium-browser"
,
"/usr/bin/chromium"
,
"/usr/bin/chromium"
,
...
@@ -283,8 +300,11 @@ static gboolean gst_check_required_plugins(void)
...
@@ -283,8 +300,11 @@ static gboolean gst_check_required_plugins(void)
static
int
ensure_gstreamer_plugins
(
void
)
static
int
ensure_gstreamer_plugins
(
void
)
{
{
if
(
!
gst_is_initialized
())
if
(
!
gst_is_initialized
())
{
gst_init
(
NULL
,
NULL
);
gst_init
(
NULL
,
NULL
);
/* 把 GLib/GObject/GStreamer 警告重定向到 zlog,避免污染终端 stderr */
g_log_set_default_handler
(
glib_log_handler
,
NULL
);
}
if
(
gst_check_required_plugins
())
{
if
(
gst_check_required_plugins
())
{
my_zlog_info
(
"runtime_deps: GStreamer plugins OK"
);
my_zlog_info
(
"runtime_deps: GStreamer plugins OK"
);
...
...
modules/webrtcpush/audio_source.c
View file @
d92f8afb
...
@@ -62,7 +62,7 @@ AudioSource *audio_source_start(const char *alsa_device, char **error_message)
...
@@ -62,7 +62,7 @@ AudioSource *audio_source_start(const char *alsa_device, char **error_message)
g_object_set
(
enc
,
g_object_set
(
enc
,
"bitrate"
,
WEBRTCPUSH_OPUS_BITRATE
,
"bitrate"
,
WEBRTCPUSH_OPUS_BITRATE
,
"
cbr"
,
TRUE
,
"
bitrate-type"
,
0
,
/* 0=cbr */
"framesize"
,
20
,
/* 20ms 帧 */
"framesize"
,
20
,
/* 20ms 帧 */
"inband-fec"
,
TRUE
,
"inband-fec"
,
TRUE
,
NULL
);
NULL
);
...
...
modules/webrtcpush/mpp_h264_source.c
View file @
d92f8afb
...
@@ -17,7 +17,7 @@
...
@@ -17,7 +17,7 @@
#define MPP_VIDEO_START_BPS WEBRTCPUSH_INITIAL_BITRATE
#define MPP_VIDEO_START_BPS WEBRTCPUSH_INITIAL_BITRATE
#define MPP_VIDEO_MIN_BPS WEBRTCPUSH_MIN_BITRATE
#define MPP_VIDEO_MIN_BPS WEBRTCPUSH_MIN_BITRATE
#define MPP_VIDEO_MAX_BPS WEBRTCPUSH_MAX_BITRATE
#define MPP_VIDEO_MAX_BPS WEBRTCPUSH_MAX_BITRATE
#define MPP_H264_PROFILE 66
/* Baseline
:板端 mpph264enc 最稳
*/
#define MPP_H264_PROFILE 66
/* Baseline
matches negotiated 42e01f
*/
#define WRTC_V4L2_CAP_VIDEO_CAPTURE (1u << 0)
#define WRTC_V4L2_CAP_VIDEO_CAPTURE (1u << 0)
#define WRTC_V4L2_CAP_VIDEO_CAPTURE_MPLANE (1u << 12)
#define WRTC_V4L2_CAP_VIDEO_CAPTURE_MPLANE (1u << 12)
...
@@ -35,6 +35,7 @@ struct MppH264Source {
...
@@ -35,6 +35,7 @@ struct MppH264Source {
GstElement
*
parse
;
GstElement
*
parse
;
GstElement
*
eq
;
GstElement
*
eq
;
GstElement
*
appsink
;
GstElement
*
appsink
;
GstElement
*
vsrc
;
/* v4l2src 指针,用于 recover 时更新设备 */
gboolean
use_mpp
;
gboolean
use_mpp
;
guint8
*
frame_buf
;
guint8
*
frame_buf
;
size_t
frame_size
;
size_t
frame_size
;
...
@@ -282,6 +283,8 @@ static void configure_v4l2_src(GstElement *src, gboolean compressed_mjpeg)
...
@@ -282,6 +283,8 @@ static void configure_v4l2_src(GstElement *src, gboolean compressed_mjpeg)
* mmap 兼容性最好,性能损失可接受(720p@24fps)。
* mmap 兼容性最好,性能损失可接受(720p@24fps)。
*/
*/
g_object_set
(
src
,
"io-mode"
,
2
,
NULL
);
g_object_set
(
src
,
"io-mode"
,
2
,
NULL
);
/* 减少内核 DQBUF 缓冲,降低采集延迟 */
g_object_set
(
src
,
"buffer-size"
,
1024
,
NULL
);
}
}
static
GstElement
*
make_h264_encoder
(
gboolean
prefer_mpp
,
gboolean
use_test
,
static
GstElement
*
make_h264_encoder
(
gboolean
prefer_mpp
,
gboolean
use_test
,
...
@@ -399,18 +402,21 @@ static void request_keyframe(MppH264Source *src)
...
@@ -399,18 +402,21 @@ static void request_keyframe(MppH264Source *src)
src
->
keyframe_req
++
;
src
->
keyframe_req
++
;
src
->
pending_idr
=
TRUE
;
src
->
pending_idr
=
TRUE
;
/*
兜底:直接向编码器发 force-key-unit,不依赖 enc_sink_probe 触发时机
*/
/*
直接向编码器 sink pad 发 force-key-unit(upstream event 标准发送方式)
*/
if
(
src
->
enc
)
{
if
(
src
->
enc
)
{
GstEvent
*
ev
=
gst_video_event_new_upstream_force_key_unit
(
GstPad
*
sink_pad
=
gst_element_get_static_pad
(
src
->
enc
,
"sink"
);
GST_CLOCK_TIME_NONE
,
TRUE
,
src
->
keyframe_req
);
if
(
sink_pad
)
{
if
(
!
gst_element_send_event
(
src
->
enc
,
ev
))
{
GstEvent
*
ev
=
gst_video_event_new_upstream_force_key_unit
(
GstPad
*
sink_pad
=
gst_element_get_static_pad
(
src
->
enc
,
"sink"
);
GST_CLOCK_TIME_NONE
,
TRUE
,
src
->
keyframe_req
);
if
(
sink_pad
)
{
gboolean
ok
=
gst_pad_send_event
(
sink_pad
,
ev
);
ev
=
gst_video_event_new_upstream_force_key_unit
(
gst_object_unref
(
sink_pad
);
GST_CLOCK_TIME_NONE
,
TRUE
,
src
->
keyframe_req
);
if
(
!
ok
)
gst_pad_send_event
(
sink_pad
,
ev
);
my_zlog_warn
(
"mpp_h264_source: force-key-unit send failed on sink pad"
);
gst_object_unref
(
sink_pad
);
}
else
{
}
/* fallback: element_send_event */
GstEvent
*
ev
=
gst_video_event_new_upstream_force_key_unit
(
GST_CLOCK_TIME_NONE
,
TRUE
,
src
->
keyframe_req
);
gst_element_send_event
(
src
->
enc
,
ev
);
}
}
}
}
my_zlog_info
(
"mpp_h264_source: IDR queued (%u)"
,
src
->
keyframe_req
);
my_zlog_info
(
"mpp_h264_source: IDR queued (%u)"
,
src
->
keyframe_req
);
...
@@ -690,6 +696,7 @@ MppH264Source *mpp_h264_source_start(const char *video_device, char **error_mess
...
@@ -690,6 +696,7 @@ MppH264Source *mpp_h264_source_start(const char *video_device, char **error_mess
}
}
}
}
src
->
vsrc
=
vsrc
;
src
->
pipeline
=
pipe
;
src
->
pipeline
=
pipe
;
src
->
enc
=
enc
;
src
->
enc
=
enc
;
src
->
parse
=
parse
;
src
->
parse
=
parse
;
...
@@ -881,6 +888,21 @@ gboolean mpp_h264_source_recover(MppH264Source *src)
...
@@ -881,6 +888,21 @@ gboolean mpp_h264_source_recover(MppH264Source *src)
src
->
pending_idr
=
FALSE
;
src
->
pending_idr
=
FALSE
;
src
->
pending_recover
=
FALSE
;
src
->
pending_recover
=
FALSE
;
gst_element_set_state
(
src
->
pipeline
,
GST_STATE_NULL
);
gst_element_set_state
(
src
->
pipeline
,
GST_STATE_NULL
);
/* 重新探测摄像头设备(USB 重枚举后可能从 video0 变成 video1/2) */
if
(
src
->
vsrc
)
{
gchar
*
new_dev
=
pick_v4l2_capture_device
();
if
(
new_dev
)
{
gchar
*
old_dev
=
NULL
;
g_object_get
(
src
->
vsrc
,
"device"
,
&
old_dev
,
NULL
);
if
(
!
old_dev
||
g_strcmp0
(
old_dev
,
new_dev
)
!=
0
)
{
g_object_set
(
src
->
vsrc
,
"device"
,
new_dev
,
NULL
);
my_zlog_warn
(
"mpp_h264_source: recover device changed %s -> %s"
,
old_dev
?
old_dev
:
"(null)"
,
new_dev
);
}
g_free
(
old_dev
);
g_free
(
new_dev
);
}
}
g_usleep
(
300000
);
g_usleep
(
300000
);
ret
=
gst_element_set_state
(
src
->
pipeline
,
GST_STATE_PLAYING
);
ret
=
gst_element_set_state
(
src
->
pipeline
,
GST_STATE_PLAYING
);
if
(
ret
==
GST_STATE_CHANGE_FAILURE
)
{
if
(
ret
==
GST_STATE_CHANGE_FAILURE
)
{
...
...
modules/webrtcpush/rtc_client.c
View file @
d92f8afb
This diff is collapsed.
Click to expand it.
modules/webrtcpush/webrtcpush_config.h
View file @
d92f8afb
...
@@ -7,26 +7,29 @@
...
@@ -7,26 +7,29 @@
* 1:走 libdatachannel 原生推流(摄像头 → MPP/x264 → libdatachannel)
* 1:走 libdatachannel 原生推流(摄像头 → MPP/x264 → libdatachannel)
*
*
* 原生分支:v4l2 采集 → mpph264enc(或 x264enc 回退)→ libdatachannel 发送。
* 原生分支:v4l2 采集 → mpph264enc(或 x264enc 回退)→ libdatachannel 发送。
* 音频尚未接入,视频跑通后再接 ALSA→Opus track。
*/
*/
#define WEBRTCPUSH_USE_MPP 1
#define WEBRTCPUSH_USE_MPP 1
/* 正常固定 24fps;弱网以降码率为主,后续若启用动态帧率也不得低于 22fps。 */
/* 正常固定 24fps;弱网以降码率为主,后续若启用动态帧率也不得低于 22fps。 */
#define WEBRTCPUSH_H264_FPS 24
#define WEBRTCPUSH_H264_FPS 24
#define WEBRTCPUSH_H264_MIN_FPS 22
#define WEBRTCPUSH_H264_MIN_FPS 22
#define WEBRTCPUSH_H264_GOP (WEBRTCPUSH_H264_FPS
)
/* 1s 一个
IDR */
#define WEBRTCPUSH_H264_GOP (WEBRTCPUSH_H264_FPS
* 3)
/* 3s; PLI still requests
IDR */
/* 与 gst_webrtc_pipeline / jywy 浏览器推流对齐的码率策略 */
/* 与 gst_webrtc_pipeline / jywy 浏览器推流对齐的码率策略 */
#define WEBRTCPUSH_INITIAL_BITRATE 1
8
00000U
#define WEBRTCPUSH_INITIAL_BITRATE 1
4
00000U
#define WEBRTCPUSH_MIN_BITRATE 500000U
#define WEBRTCPUSH_MIN_BITRATE 500000U
#define WEBRTCPUSH_MAX_BITRATE 3200000U
#define WEBRTCPUSH_MAX_BITRATE 3200000U
#define WEBRTCPUSH_REMB_UTIL_PERCENT 85U
#define WEBRTCPUSH_REMB_UTIL_PERCENT 80U
#define WEBRTCPUSH_REMB_DOWN_MIN_STEP 50000U
/* 非急跌时 <50kbps 不调编码器 */
#define WEBRTCPUSH_REMB_DOWN_MIN_STEP 100000U
#define WEBRTCPUSH_BITRATE_RAMP_UP_MS 500U
/* 升码更快恢复画质 */
#define WEBRTCPUSH_REMB_DOWN_CONFIRMATIONS 3U
#define WEBRTCPUSH_BITRATE_RAMP_DOWN_MS 1000U
#define WEBRTCPUSH_REMB_SEVERE_PERCENT 65U
#define WEBRTCPUSH_PACING_HEADROOM_PERCENT 108U
#define WEBRTCPUSH_BITRATE_RAMP_UP_MS 2500U
#define WEBRTCPUSH_BITRATE_RAMP_DOWN_MS 500U
#define WEBRTCPUSH_PACING_HEADROOM_PERCENT 125U
#define WEBRTCPUSH_PACING_INTERVAL_MS 5U
#define WEBRTCPUSH_PACING_INTERVAL_MS 5U
#define WEBRTCPUSH_PACING_MAX_BITRATE 3750000U
#define WEBRTCPUSH_PACING_MAX_BITRATE 4000000U
#define WEBRTCPUSH_PACING_MAX_QUEUE_MS 300U
#define WEBRTCPUSH_PACING_GUARD_COOLDOWN_MS 1000U
/* RTP 分片与 NACK(MTU=1200,留 SRTP/DTLS/FU 余量) */
/* RTP 分片与 NACK(MTU=1200,留 SRTP/DTLS/FU 余量) */
#define WEBRTCPUSH_RTP_MAX_FRAGMENT 1050U
#define WEBRTCPUSH_RTP_MAX_FRAGMENT 1050U
...
@@ -45,12 +48,12 @@
...
@@ -45,12 +48,12 @@
#define WEBRTCPUSH_H264_PROFILE_LEVEL_ID "42e01f"
#define WEBRTCPUSH_H264_PROFILE_LEVEL_ID "42e01f"
/* 拉帧线程与发送线程之间的有界队列(leaky,满则丢最旧帧) */
/* 拉帧线程与发送线程之间的有界队列(leaky,满则丢最旧帧) */
#define WEBRTCPUSH_SEND_QUEUE_DEPTH
4
U
#define WEBRTCPUSH_SEND_QUEUE_DEPTH
2
U
/* 管道缓冲:运动场景需适度缓存,过低易 pull timeout / 糊屏 */
/* 管道缓冲:运动场景需适度缓存,过低易 pull timeout / 糊屏 */
#define WEBRTCPUSH_MPP_PRE_ENC_BUFFERS
3
/* 编码前 leaky
*/
#define WEBRTCPUSH_MPP_PRE_ENC_BUFFERS
1
/* 编码前 leaky,低延迟
*/
#define WEBRTCPUSH_MPP_POST_ENC_BUFFERS
2
/* 编码后保留 AU */
#define WEBRTCPUSH_MPP_POST_ENC_BUFFERS
1
/* 编码后保留 AU */
#define WEBRTCPUSH_APPSINK_MAX_BUFFERS
2
#define WEBRTCPUSH_APPSINK_MAX_BUFFERS
1
/* 视频采集:auto | /dev/videoN | test(videotestsrc 测试图案) */
/* 视频采集:auto | /dev/videoN | test(videotestsrc 测试图案) */
#define WEBRTCPUSH_VIDEO_DEVICE "auto"
#define WEBRTCPUSH_VIDEO_DEVICE "auto"
...
...
modules/wifi_config/wifi_config_agent.c
View file @
d92f8afb
#include "wifi_config_agent.h"
#include "wifi_config_agent.h"
#include "wifi_config_config.h"
#include "wifi_config_config.h"
#include "stream_debug_agent.h"
#include "device_debug_agent.h"
#include "device_diag.h"
#include "device_identity.h"
#include "device_identity.h"
#include "device_fileopen.h"
#include "device_fileopen.h"
#include "device_wifi_manager.h"
#include "device_wifi_manager.h"
...
@@ -60,6 +61,12 @@ void wifi_config_agent_rebind_socket(void)
...
@@ -60,6 +61,12 @@ void wifi_config_agent_rebind_socket(void)
pthread_mutex_unlock
(
&
s_wifi_config_sock_mutex
);
pthread_mutex_unlock
(
&
s_wifi_config_sock_mutex
);
}
}
/* 设备诊断 cmd 转发判断(device_check / browser_refresh / browser_reopen / log_fetch) */
static
int
is_device_diag_cmd
(
const
char
*
cmd
)
{
return
device_diag_is_cmd
(
cmd
);
}
static
int
is_stream_debug_cmd
(
const
char
*
cmd
)
static
int
is_stream_debug_cmd
(
const
char
*
cmd
)
{
{
return
cmd
&&
(
strcmp
(
cmd
,
"stream_mode_query"
)
==
0
||
return
cmd
&&
(
strcmp
(
cmd
,
"stream_mode_query"
)
==
0
||
...
@@ -292,6 +299,31 @@ static void send_config_result(int sock, const struct sockaddr_in *addr, int suc
...
@@ -292,6 +299,31 @@ static void send_config_result(int sock, const struct sockaddr_in *addr, int suc
cJSON_Delete
(
root
);
cJSON_Delete
(
root
);
}
}
/* config_ack:设备收到 config 后立即回复,表示已收到即将执行 */
static
void
send_config_ack
(
int
sock
,
const
struct
sockaddr_in
*
addr
,
int
accepted
,
const
char
*
action
,
const
char
*
message
)
{
cJSON
*
root
=
cJSON_CreateObject
();
char
*
payload
;
if
(
!
root
)
return
;
cJSON_AddStringToObject
(
root
,
"cmd"
,
"config_ack"
);
cJSON_AddBoolToObject
(
root
,
"accepted"
,
accepted
?
1
:
0
);
if
(
action
&&
action
[
0
])
cJSON_AddStringToObject
(
root
,
"action"
,
action
);
if
(
message
&&
message
[
0
])
cJSON_AddStringToObject
(
root
,
"message"
,
message
);
payload
=
cJSON_PrintUnformatted
(
root
);
if
(
payload
)
{
send_json
(
sock
,
addr
,
payload
);
free
(
payload
);
}
cJSON_Delete
(
root
);
}
static
void
handle_discover
(
int
sock
,
const
struct
sockaddr_in
*
addr
)
static
void
handle_discover
(
int
sock
,
const
struct
sockaddr_in
*
addr
)
{
{
char
device_id
[
WIFI_CONFIG_DEVICE_ID_MAX
];
char
device_id
[
WIFI_CONFIG_DEVICE_ID_MAX
];
...
@@ -327,6 +359,7 @@ static void handle_config(int sock, const struct sockaddr_in *addr, cJSON *root)
...
@@ -327,6 +359,7 @@ static void handle_config(int sock, const struct sockaddr_in *addr, cJSON *root)
char
message
[
WIFI_CONFIG_MESSAGE_MAX
];
char
message
[
WIFI_CONFIG_MESSAGE_MAX
];
int
success
;
int
success
;
/* 参数校验:ssid 非法时仍用旧协议回 config_result,保持兼容 */
if
(
!
cJSON_IsString
(
ssid_item
)
||
!
ssid_item
->
valuestring
||
!
ssid_item
->
valuestring
[
0
])
{
if
(
!
cJSON_IsString
(
ssid_item
)
||
!
ssid_item
->
valuestring
||
!
ssid_item
->
valuestring
[
0
])
{
send_config_result
(
sock
,
addr
,
0
,
"缺少有效的 ssid 字段"
);
send_config_result
(
sock
,
addr
,
0
,
"缺少有效的 ssid 字段"
);
return
;
return
;
...
@@ -340,18 +373,138 @@ static void handle_config(int sock, const struct sockaddr_in *addr, cJSON *root)
...
@@ -340,18 +373,138 @@ static void handle_config(int sock, const struct sockaddr_in *addr, cJSON *root)
my_zlog_info
(
"WiFi配置助手: 收到配网请求 SSID=%s action=%s"
,
ssid
,
action
);
my_zlog_info
(
"WiFi配置助手: 收到配网请求 SSID=%s action=%s"
,
ssid
,
action
);
/* 新协议(v3):先立即回复 config_ack,表示已收到即将执行。
* 这样 action=connect 切换 WiFi 后,即使手机收不到最终结果,
* 也已通过 ack 知道设备收到了配置。 */
snprintf
(
message
,
sizeof
(
message
),
"%s"
,
strcmp
(
action
,
"connect"
)
==
0
?
"已收到配置,即将切换 WiFi"
:
"已收到配置,即将保存"
);
send_config_ack
(
sock
,
addr
,
1
,
action
,
message
);
if
(
strcmp
(
action
,
"save"
)
==
0
)
{
if
(
strcmp
(
action
,
"save"
)
==
0
)
{
/* save 模式:保存完成后回复 config_result(最终结果) */
success
=
orange_pi_save_wifi
(
ssid
,
password
)
==
0
;
success
=
orange_pi_save_wifi
(
ssid
,
password
)
==
0
;
snprintf
(
message
,
sizeof
(
message
),
"%s"
,
snprintf
(
message
,
sizeof
(
message
),
"%s"
,
success
?
"WiFi 配置已保存"
:
"WiFi 保存失败"
);
success
?
"WiFi 配置已保存"
:
"WiFi 保存失败"
);
my_zlog_info
(
"WiFi配置助手: 配网结果 success=%d, message=%s"
,
success
,
message
);
send_config_result
(
sock
,
addr
,
success
,
message
);
}
else
{
}
else
{
/* connect 模式:只回 config_ack 即可,切 WiFi 后手机收不到最终结果,
* 不再回复 config_result,避免无意义发送。 */
success
=
orange_pi_connect_wifi
(
ssid
,
password
)
==
0
;
success
=
orange_pi_connect_wifi
(
ssid
,
password
)
==
0
;
snprintf
(
message
,
sizeof
(
message
),
"%s"
,
my_zlog_info
(
"WiFi配置助手: connect 已执行 success=%d (不回 config_result)"
,
success
);
success
?
"WiFi 配置已保存并连接成功"
:
"WiFi 连接失败"
);
}
}
static
void
handle_wifi_list_query
(
int
sock
,
const
struct
sockaddr_in
*
addr
)
{
cJSON
*
root
=
cJSON_CreateObject
();
cJSON
*
list
;
char
*
payload
;
if
(
!
root
)
return
;
cJSON_AddStringToObject
(
root
,
"cmd"
,
"wifi_list_response"
);
list
=
app_wifi_list_query
();
if
(
!
list
)
list
=
cJSON_CreateArray
();
cJSON_AddItemToObject
(
root
,
"list"
,
list
);
payload
=
cJSON_PrintUnformatted
(
root
);
if
(
payload
)
{
send_json
(
sock
,
addr
,
payload
);
free
(
payload
);
}
cJSON_Delete
(
root
);
my_zlog_info
(
"WiFi配置助手: 应答 wifi_list_query"
);
}
static
void
handle_wifi_switch
(
int
sock
,
const
struct
sockaddr_in
*
addr
,
cJSON
*
root
)
{
cJSON
*
ssid_item
=
cJSON_GetObjectItemCaseSensitive
(
root
,
"ssid"
);
cJSON
*
resp
;
const
char
*
ssid
=
NULL
;
char
message
[
WIFI_CONFIG_MESSAGE_MAX
];
int
success
;
int
rc
;
char
*
payload
;
if
(
!
cJSON_IsString
(
ssid_item
)
||
!
ssid_item
->
valuestring
||
!
ssid_item
->
valuestring
[
0
])
{
resp
=
cJSON_CreateObject
();
cJSON_AddStringToObject
(
resp
,
"cmd"
,
"wifi_switch_result"
);
cJSON_AddBoolToObject
(
resp
,
"success"
,
0
);
cJSON_AddStringToObject
(
resp
,
"message"
,
"缺少有效的 ssid 字段"
);
payload
=
cJSON_PrintUnformatted
(
resp
);
if
(
payload
)
{
send_json
(
sock
,
addr
,
payload
);
free
(
payload
);
}
cJSON_Delete
(
resp
);
return
;
}
}
my_zlog_info
(
"WiFi配置助手: 配网结果 success=%d, message=%s"
,
success
,
message
);
ssid
=
ssid_item
->
valuestring
;
send_config_result
(
sock
,
addr
,
success
,
message
);
my_zlog_info
(
"WiFi配置助手: 收到 wifi_switch SSID=%s"
,
ssid
);
rc
=
app_wifi_switch
(
ssid
);
success
=
(
rc
==
0
);
if
(
rc
==
0
)
snprintf
(
message
,
sizeof
(
message
),
"WiFi 切换成功,正在连接 %s"
,
ssid
);
else
if
(
rc
==
-
1
)
snprintf
(
message
,
sizeof
(
message
),
"未找到已保存的 WiFi:%s"
,
ssid
);
else
/* rc == -2:已保存但连接失败 */
snprintf
(
message
,
sizeof
(
message
),
"WiFi 已保存但连接失败:%s(信号弱或不可达)"
,
ssid
);
resp
=
cJSON_CreateObject
();
cJSON_AddStringToObject
(
resp
,
"cmd"
,
"wifi_switch_result"
);
cJSON_AddBoolToObject
(
resp
,
"success"
,
success
?
1
:
0
);
cJSON_AddStringToObject
(
resp
,
"message"
,
message
);
payload
=
cJSON_PrintUnformatted
(
resp
);
if
(
payload
)
{
send_json
(
sock
,
addr
,
payload
);
free
(
payload
);
}
cJSON_Delete
(
resp
);
}
static
void
handle_wifi_delete
(
int
sock
,
const
struct
sockaddr_in
*
addr
,
cJSON
*
root
)
{
cJSON
*
ssid_item
=
cJSON_GetObjectItemCaseSensitive
(
root
,
"ssid"
);
cJSON
*
resp
;
const
char
*
ssid
=
NULL
;
char
message
[
WIFI_CONFIG_MESSAGE_MAX
];
int
success
;
int
rc
;
char
*
payload
;
if
(
!
cJSON_IsString
(
ssid_item
)
||
!
ssid_item
->
valuestring
||
!
ssid_item
->
valuestring
[
0
])
{
resp
=
cJSON_CreateObject
();
cJSON_AddStringToObject
(
resp
,
"cmd"
,
"wifi_delete_result"
);
cJSON_AddBoolToObject
(
resp
,
"success"
,
0
);
cJSON_AddStringToObject
(
resp
,
"message"
,
"缺少有效的 ssid 字段"
);
payload
=
cJSON_PrintUnformatted
(
resp
);
if
(
payload
)
{
send_json
(
sock
,
addr
,
payload
);
free
(
payload
);
}
cJSON_Delete
(
resp
);
return
;
}
ssid
=
ssid_item
->
valuestring
;
my_zlog_info
(
"WiFi配置助手: 收到 wifi_delete SSID=%s"
,
ssid
);
rc
=
app_wifi_delete
(
ssid
);
success
=
(
rc
==
0
);
if
(
rc
==
0
)
snprintf
(
message
,
sizeof
(
message
),
"已删除 WiFi:%s"
,
ssid
);
else
if
(
rc
==
-
2
)
snprintf
(
message
,
sizeof
(
message
),
"受保护的 WiFi 不可删除:%s"
,
ssid
);
else
snprintf
(
message
,
sizeof
(
message
),
"未找到或正在使用的 WiFi:%s"
,
ssid
);
resp
=
cJSON_CreateObject
();
cJSON_AddStringToObject
(
resp
,
"cmd"
,
"wifi_delete_result"
);
cJSON_AddBoolToObject
(
resp
,
"success"
,
success
?
1
:
0
);
cJSON_AddStringToObject
(
resp
,
"message"
,
message
);
payload
=
cJSON_PrintUnformatted
(
resp
);
if
(
payload
)
{
send_json
(
sock
,
addr
,
payload
);
free
(
payload
);
}
cJSON_Delete
(
resp
);
}
}
static
void
process_message
(
int
sock
,
const
char
*
buf
,
const
struct
sockaddr_in
*
addr
)
static
void
process_message
(
int
sock
,
const
char
*
buf
,
const
struct
sockaddr_in
*
addr
)
...
@@ -384,6 +537,20 @@ static void process_message(int sock, const char *buf, const struct sockaddr_in
...
@@ -384,6 +537,20 @@ static void process_message(int sock, const char *buf, const struct sockaddr_in
stream_debug_handle_url_update
(
sock
,
addr
,
root
);
stream_debug_handle_url_update
(
sock
,
addr
,
root
);
}
else
if
(
strcmp
(
cmd_item
->
valuestring
,
"stream_url_query"
)
==
0
)
{
}
else
if
(
strcmp
(
cmd_item
->
valuestring
,
"stream_url_query"
)
==
0
)
{
stream_debug_handle_url_query
(
sock
,
addr
);
stream_debug_handle_url_query
(
sock
,
addr
);
}
else
if
(
strcmp
(
cmd_item
->
valuestring
,
"wifi_list_query"
)
==
0
)
{
handle_wifi_list_query
(
sock
,
addr
);
}
else
if
(
strcmp
(
cmd_item
->
valuestring
,
"wifi_switch"
)
==
0
)
{
handle_wifi_switch
(
sock
,
addr
,
root
);
}
else
if
(
strcmp
(
cmd_item
->
valuestring
,
"wifi_delete"
)
==
0
)
{
handle_wifi_delete
(
sock
,
addr
,
root
);
}
else
if
(
strcmp
(
cmd_item
->
valuestring
,
"device_check"
)
==
0
)
{
device_diag_handle_check
(
sock
,
addr
);
}
else
if
(
strcmp
(
cmd_item
->
valuestring
,
"browser_refresh"
)
==
0
)
{
device_diag_handle_browser_ctrl
(
sock
,
addr
,
"refresh"
);
}
else
if
(
strcmp
(
cmd_item
->
valuestring
,
"browser_reopen"
)
==
0
)
{
device_diag_handle_browser_ctrl
(
sock
,
addr
,
"reopen"
);
}
else
if
(
strcmp
(
cmd_item
->
valuestring
,
"log_fetch"
)
==
0
)
{
device_diag_handle_log_fetch
(
sock
,
addr
,
root
);
}
}
cJSON_Delete
(
root
);
cJSON_Delete
(
root
);
...
...
third_party/libdatachannel/include/rtc/pacinghandler.hpp
View file @
d92f8afb
...
@@ -26,6 +26,7 @@ public:
...
@@ -26,6 +26,7 @@ public:
PacingHandler
(
double
bitsPerSecond
,
std
::
chrono
::
milliseconds
sendInterval
);
PacingHandler
(
double
bitsPerSecond
,
std
::
chrono
::
milliseconds
sendInterval
);
void
setBitrate
(
double
bitsPerSecond
);
void
setBitrate
(
double
bitsPerSecond
);
size_t
clear
();
size_t
clear
();
void
getQueueStats
(
size_t
&
packetCount
,
size_t
&
byteCount
);
void
outgoing
(
message_vector
&
messages
,
const
message_callback
&
send
)
override
;
void
outgoing
(
message_vector
&
messages
,
const
message_callback
&
send
)
override
;
...
@@ -40,6 +41,7 @@ private:
...
@@ -40,6 +41,7 @@ private:
std
::
mutex
mMutex
;
std
::
mutex
mMutex
;
std
::
queue
<
message_ptr
>
mRtpBuffer
;
std
::
queue
<
message_ptr
>
mRtpBuffer
;
size_t
mQueuedBytes
=
0
;
void
schedule
(
const
message_callback
&
send
);
void
schedule
(
const
message_callback
&
send
);
};
};
...
...
third_party/libdatachannel/include/rtc/rtc.h
View file @
d92f8afb
...
@@ -434,6 +434,10 @@ RTC_C_EXPORT int rtcSetPacingBitrate(int tr, unsigned int bitrate);
...
@@ -434,6 +434,10 @@ RTC_C_EXPORT int rtcSetPacingBitrate(int tr, unsigned int bitrate);
// Returns the number of dropped packets, or a negative RTC_ERR_* value.
// Returns the number of dropped packets, or a negative RTC_ERR_* value.
RTC_C_EXPORT
int
rtcClearPacingQueue
(
int
tr
);
RTC_C_EXPORT
int
rtcClearPacingQueue
(
int
tr
);
// Read the current pacing queue without modifying it.
RTC_C_EXPORT
int
rtcGetPacingQueueStats
(
int
tr
,
unsigned
int
*
packetCount
,
unsigned
int
*
byteCount
);
// Transform seconds to timestamp using track's clock rate, result is written to timestamp
// Transform seconds to timestamp using track's clock rate, result is written to timestamp
RTC_C_EXPORT
int
rtcTransformSecondsToTimestamp
(
int
id
,
double
seconds
,
uint32_t
*
timestamp
);
RTC_C_EXPORT
int
rtcTransformSecondsToTimestamp
(
int
id
,
double
seconds
,
uint32_t
*
timestamp
);
...
...
third_party/libdatachannel/src/capi.cpp
View file @
d92f8afb
...
@@ -1482,6 +1482,31 @@ int rtcClearPacingQueue(int tr) {
...
@@ -1482,6 +1482,31 @@ int rtcClearPacingQueue(int tr) {
});
});
}
}
int
rtcGetPacingQueueStats
(
int
tr
,
unsigned
int
*
packetCount
,
unsigned
int
*
byteCount
)
{
return
wrap
([
&
]
{
shared_ptr
<
PacingHandler
>
handler
;
{
std
::
lock_guard
lock
(
mutex
);
auto
it
=
pacingHandlerMap
.
find
(
tr
);
if
(
it
==
pacingHandlerMap
.
end
())
throw
std
::
invalid_argument
(
"Pacing handler does not exist"
);
handler
=
it
->
second
;
}
size_t
packets
=
0
;
size_t
bytes
=
0
;
handler
->
getQueueStats
(
packets
,
bytes
);
if
(
packetCount
)
*
packetCount
=
packets
>
std
::
numeric_limits
<
unsigned
int
>::
max
()
?
std
::
numeric_limits
<
unsigned
int
>::
max
()
:
static_cast
<
unsigned
int
>
(
packets
);
if
(
byteCount
)
*
byteCount
=
bytes
>
std
::
numeric_limits
<
unsigned
int
>::
max
()
?
std
::
numeric_limits
<
unsigned
int
>::
max
()
:
static_cast
<
unsigned
int
>
(
bytes
);
return
RTC_ERR_SUCCESS
;
});
}
int
rtcTransformSecondsToTimestamp
(
int
id
,
double
seconds
,
uint32_t
*
timestamp
)
{
int
rtcTransformSecondsToTimestamp
(
int
id
,
double
seconds
,
uint32_t
*
timestamp
)
{
return
wrap
([
&
]
{
return
wrap
([
&
]
{
auto
config
=
getRtpConfig
(
id
);
auto
config
=
getRtpConfig
(
id
);
...
...
third_party/libdatachannel/src/pacinghandler.cpp
View file @
d92f8afb
...
@@ -8,6 +8,7 @@
...
@@ -8,6 +8,7 @@
#if RTC_ENABLE_MEDIA
#if RTC_ENABLE_MEDIA
#include <algorithm>
#include <memory>
#include <memory>
#include "pacinghandler.hpp"
#include "pacinghandler.hpp"
...
@@ -29,10 +30,17 @@ size_t PacingHandler::clear() {
...
@@ -29,10 +30,17 @@ size_t PacingHandler::clear() {
const
size_t
count
=
mRtpBuffer
.
size
();
const
size_t
count
=
mRtpBuffer
.
size
();
while
(
!
mRtpBuffer
.
empty
())
while
(
!
mRtpBuffer
.
empty
())
mRtpBuffer
.
pop
();
mRtpBuffer
.
pop
();
mQueuedBytes
=
0
;
mBudget
=
0.
;
mBudget
=
0.
;
return
count
;
return
count
;
}
}
void
PacingHandler
::
getQueueStats
(
size_t
&
packetCount
,
size_t
&
byteCount
)
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
mMutex
);
packetCount
=
mRtpBuffer
.
size
();
byteCount
=
mQueuedBytes
;
}
void
PacingHandler
::
schedule
(
const
message_callback
&
send
)
{
void
PacingHandler
::
schedule
(
const
message_callback
&
send
)
{
if
(
mHaveScheduled
.
exchange
(
true
))
{
if
(
mHaveScheduled
.
exchange
(
true
))
{
return
;
return
;
...
@@ -44,21 +52,30 @@ void PacingHandler::schedule(const message_callback &send) {
...
@@ -44,21 +52,30 @@ void PacingHandler::schedule(const message_callback &send) {
const
std
::
lock_guard
<
std
::
mutex
>
lock
(
mMutex
);
const
std
::
lock_guard
<
std
::
mutex
>
lock
(
mMutex
);
mHaveScheduled
.
store
(
false
);
mHaveScheduled
.
store
(
false
);
// Update the budget and cap it
// Keep credit for short scheduler stalls. Capping at one interval
// permanently under-runs the configured bitrate whenever the worker
// wakes up late, which turns scheduler jitter into growing media delay.
const
double
bytesPerSecond
=
mBytesPerSecond
.
load
();
const
double
bytesPerSecond
=
mBytesPerSecond
.
load
();
const
auto
now
=
std
::
chrono
::
high_resolution_clock
::
now
();
auto
newBudget
=
auto
newBudget
=
std
::
chrono
::
duration
<
double
>
(
std
::
chrono
::
high_resolution_clock
::
now
()
-
mLastRun
)
std
::
chrono
::
duration
<
double
>
(
now
-
mLastRun
)
.
count
()
*
.
count
()
*
bytesPerSecond
;
bytesPerSecond
;
auto
maxBudget
=
std
::
chrono
::
duration
<
double
>
(
mSendInterval
).
count
()
*
bytesPerSecond
;
const
auto
catchUpWindow
=
std
::
max
(
mSendInterval
*
5
,
std
::
chrono
::
milliseconds
(
25
));
auto
maxBudget
=
std
::
chrono
::
duration
<
double
>
(
catchUpWindow
).
count
()
*
bytesPerSecond
;
mBudget
=
std
::
min
(
mBudget
+
newBudget
,
maxBudget
);
mBudget
=
std
::
min
(
mBudget
+
newBudget
,
maxBudget
);
mLastRun
=
std
::
chrono
::
high_resolution_clock
::
now
()
;
mLastRun
=
now
;
// Send packets while there is budget, allow a single partial packet over budget
// Send packets while there is budget, allow a single partial packet over budget
while
(
!
mRtpBuffer
.
empty
()
&&
mBudget
>
0
)
{
while
(
!
mRtpBuffer
.
empty
()
&&
mBudget
>
0
)
{
auto
size
=
int
(
mRtpBuffer
.
front
()
->
size
());
auto
size
=
int
(
mRtpBuffer
.
front
()
->
size
());
send
(
std
::
move
(
mRtpBuffer
.
front
()));
send
(
std
::
move
(
mRtpBuffer
.
front
()));
mRtpBuffer
.
pop
();
mRtpBuffer
.
pop
();
mQueuedBytes
=
mQueuedBytes
>=
static_cast
<
size_t
>
(
size
)
?
mQueuedBytes
-
static_cast
<
size_t
>
(
size
)
:
0
;
mBudget
-=
size
;
mBudget
-=
size
;
}
}
...
@@ -74,6 +91,7 @@ void PacingHandler::outgoing(message_vector &messages, const message_callback &s
...
@@ -74,6 +91,7 @@ void PacingHandler::outgoing(message_vector &messages, const message_callback &s
std
::
lock_guard
<
std
::
mutex
>
lock
(
mMutex
);
std
::
lock_guard
<
std
::
mutex
>
lock
(
mMutex
);
for
(
auto
&
m
:
messages
)
{
for
(
auto
&
m
:
messages
)
{
mQueuedBytes
+=
m
->
size
();
mRtpBuffer
.
push
(
std
::
move
(
m
));
mRtpBuffer
.
push
(
std
::
move
(
m
));
}
}
messages
.
clear
();
messages
.
clear
();
...
...
zlog.conf
View file @
d92f8afb
...
@@ -9,4 +9,4 @@ file perms = 600
...
@@ -9,4 +9,4 @@ file perms = 600
millisecond
=
"%d(%Y-%m-%d %H:%M:%S).%ms [%V] %m%n"
millisecond
=
"%d(%Y-%m-%d %H:%M:%S).%ms [%V] %m%n"
[
rules
]
[
rules
]
my_log
.*
"/home/orangepi/car/master/log/log_2026-07-0
2
.log"
;
millisecond
my_log
.*
"/home/orangepi/car/master/log/log_2026-07-0
6
.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