Commit 2eb47ff8 authored by 957dd's avatar 957dd

未修改完第二次保存提交

parent edadce9a
......@@ -4,6 +4,9 @@ deviceback
Deviceld.txt
main
# 本地日报/笔记,不提交
docs/
# CMake / build 输出(默认全部忽略)
build/*
build/.ninja_*
......
......@@ -95,9 +95,4 @@ target_compile_options(main PRIVATE ${WEBRTCPUSH_CFLAGS})
# 安装规则
install(TARGETS main DESTINATION bin)
# carstart.service 使用 /home/orangepi/car/master/main
add_custom_command(TARGET main POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:main> ${CMAKE_SOURCE_DIR}/main
COMMENT "Copy main to project root for carstart.service"
)
enable_testing()
......@@ -8,7 +8,8 @@ static char s_wifi_last_password[SSID_MAX_LEN]= {0} ;
//获取当前连接wifi
void get_current_wifi() {
//显示已连接代码
g_current_ssid[0] = '\0';
FILE *fp = popen("nmcli -t -f ACTIVE,SSID dev wifi", "r");
if (!fp) {
my_zlog_error("{\"error\": \"无法执行扫描命令\"}");
......@@ -413,7 +414,7 @@ void connect_wifi_jking() {
if(system("sudo reboot")!=0){//重启香橙派
my_zlog_error("reboot fail");
}
my_zlog_debug("重启成功");
my_zlog_info("重启成功");
}
}
......@@ -500,7 +501,7 @@ void wifi_change_recmqtt(cJSON *body){
if(system("sudo reboot")!=0){//重启香橙派
my_zlog_error("reboot fail");
}
my_zlog_debug("重启成功");
my_zlog_info("重启成功");
}
if(ret == 0){
if(can_access_internet()==0){
......@@ -508,7 +509,7 @@ void wifi_change_recmqtt(cJSON *body){
my_zlog_debug("ssid:%S",g_current_ssid);
if(system("sudo reboot")!=0){//重启香橙派
my_zlog_error("reboot fail");
my_zlog_debug("重启成功");
my_zlog_info("重启成功");
}else {
delete_wifi_conf();
if(change_wifi_connect(default_SSID,default_password)==0) delete_wifi_by_ssid(g_current_ssid);
......@@ -528,7 +529,7 @@ void wifi_change_recmqtt(cJSON *body){
if(system("sudo reboot")!=0){//重启香橙派
my_zlog_error("reboot fail");
}
my_zlog_debug("重启成功");
my_zlog_info("重启成功");
}
}
......
This diff is collapsed.
......@@ -211,7 +211,11 @@ void *thread_open_browser(void *arg)
while (1) {
if (webrtcpush_should_use_mpp()) {
my_zlog_info("WEBRTCPUSH: libdatachannel native push mode");
(void)system("pkill chromium");
{
int pkill_rc = system("pkill chromium");
if (pkill_rc == -1)
my_zlog_warn("pkill chromium: system() failed");
}
delay_s(2);
while (s_webrtc_index == 1 && webrtcpush_should_use_mpp()) {
if (webrtcpush_is_running()) {
......
No preview for this file type
......@@ -303,7 +303,7 @@ int hardware_iic_config_init(){
}else if(res ==0){
delay_ms(200);
int ret=system("sudo reboot");//重启香橙派
if(ret==0) my_zlog_debug("重启成功");
if(ret==0) my_zlog_info("重启成功");
return 1;
}
}
......@@ -8,6 +8,7 @@
#include <stdio.h>
#include <strings.h>
#include <unistd.h>
#include <sys/wait.h>
#define AUDIO_USB_ALSA_DEVICE "hw:2,0"
......@@ -260,6 +261,31 @@ void audioplay_cycle(){
}
}
static void trim_line(char *s)
{
if (!s)
return;
s[strcspn(s, "\r\n")] = '\0';
}
static int pulse_pactl_exit_code(int status)
{
if (status == -1)
return -1;
if (WIFEXITED(status))
return WEXITSTATUS(status);
return -1;
}
static int pulse_output_means_already_loaded(const char *output)
{
if (!output || !output[0])
return 0;
return strstr(output, "already loaded") != NULL ||
strstr(output, "Already loaded") != NULL ||
strstr(output, "Module exists") != NULL;
}
static int pulse_module_exists(const char *module_name, const char *device)
{
FILE *fp = popen("pactl list modules short 2>/dev/null", "r");
......@@ -283,23 +309,58 @@ static int pulse_module_exists(const char *module_name, const char *device)
static int pulse_load_alsa_module(const char *module_name, const char *label)
{
char cmd[192];
char cmd[256];
char output[512];
char line[256];
if (pulse_module_exists(module_name, AUDIO_USB_ALSA_DEVICE)) {
my_zlog_debug("%s 已注册 (%s %s),跳过", label, module_name, AUDIO_USB_ALSA_DEVICE);
my_zlog_info("%s 已注册,跳过 (%s device=%s)",
label, module_name, AUDIO_USB_ALSA_DEVICE);
return 0;
}
snprintf(cmd, sizeof(cmd),
"pactl load-module %s device=%s >/dev/null 2>&1",
snprintf(cmd, sizeof(cmd), "pactl load-module %s device=%s 2>&1",
module_name, AUDIO_USB_ALSA_DEVICE);
int rc = system(cmd);
if (rc == 0) {
my_zlog_debug("%s 注册成功", label);
FILE *fp = popen(cmd, "r");
if (!fp) {
my_zlog_warn("%s 注册失败: 无法执行 pactl (%s)", label, strerror(errno));
return -1;
}
output[0] = '\0';
while (fgets(line, sizeof(line), fp) != NULL) {
trim_line(line);
if (!line[0])
continue;
if (output[0]) {
strncat(output, "; ", sizeof(output) - strlen(output) - 1);
}
strncat(output, line, sizeof(output) - strlen(output) - 1);
}
int status = pclose(fp);
int exit_code = pulse_pactl_exit_code(status);
if (exit_code == 0) {
my_zlog_info("%s 注册成功 (%s device=%s)%s%s",
label, module_name, AUDIO_USB_ALSA_DEVICE,
output[0] ? ", pactl: " : "", output[0] ? output : "");
return 0;
}
if (pulse_output_means_already_loaded(output) ||
pulse_module_exists(module_name, AUDIO_USB_ALSA_DEVICE)) {
my_zlog_info("%s 已注册,跳过 (%s device=%s)%s%s",
label, module_name, AUDIO_USB_ALSA_DEVICE,
output[0] ? ": " : "", output[0] ? output : "");
return 0;
}
my_zlog_warn("%s 注册失败,返回状态码: %d", label, rc);
my_zlog_warn("%s 注册失败 (%s device=%s): exit=%d%s%s",
label, module_name, AUDIO_USB_ALSA_DEVICE, exit_code,
output[0] ? ", pactl: " : ", pactl 无输出",
output[0] ? output : "");
return -1;
}
......
find_package(PkgConfig REQUIRED)
pkg_check_modules(WEBRTCPUSH_GST REQUIRED
gstreamer-1.0>=1.18
gstreamer-app-1.0
gstreamer-webrtc-1.0
gstreamer-sdp-1.0
gstreamer-video-1.0
......
......@@ -429,9 +429,11 @@ int device_message_receive(cJSON *json)
my_zlog_debug("删除已保存wifi");
break;
case 2011:
int res = system("sudo reboot"); // 重启香橙派
{
int res = system("sudo reboot");
if (res == 0)
my_zlog_info("重启成功");
}
break;
case 2012:
refresh_cam();
......
......@@ -9,6 +9,7 @@ mqttclient g_clients_t[MAX_SERVERS];
static char s_uuid_mqtt_topic_id[MAX_SERVERS][56];
static bool s_mosquitto_lib_inited = false;
static pthread_mutex_t s_mqtt_publish_mutex = PTHREAD_MUTEX_INITIALIZER;
// struct mosquitto *mosq;
// 新增:用于向其他MQTT服务器发送通知的函数
......@@ -47,6 +48,7 @@ int mqtt_publish_to_all(const char *topic, const char *payload, int qos)
return 0;
}
pthread_mutex_lock(&s_mqtt_publish_mutex);
for (int i = 0; i < total_count; i++) {
if (!g_clients_t[i].mosq || g_clients_t[i].permanently_failed) {
continue;
......@@ -55,6 +57,7 @@ int mqtt_publish_to_all(const char *topic, const char *payload, int qos)
sent_count++;
}
}
pthread_mutex_unlock(&s_mqtt_publish_mutex);
return sent_count;
}
......
......@@ -345,14 +345,9 @@ static int ensure_webrtc_stack(void)
static int ensure_libdatachannel_stack(void)
{
/* libdatachannel and its ICE/SRTP dependencies are linked into main. */
if (access(WEBRTCPUSH_H264_FILE, R_OK) != 0) {
my_zlog_error("runtime_deps: H264 test file is not readable: %s",
WEBRTCPUSH_H264_FILE);
if (ensure_webrtc_stack() != 0)
return -1;
}
my_zlog_info("runtime_deps: libdatachannel native sender ready, H264=%s",
WEBRTCPUSH_H264_FILE);
my_zlog_info("runtime_deps: libdatachannel native sender ready (MPP live encode)");
return 0;
}
......
This diff is collapsed.
#ifndef MPP_H264_SOURCE_H
#define MPP_H264_SOURCE_H
#include <glib.h>
#include <stddef.h>
#include <stdint.h>
typedef struct MppH264Source MppH264Source;
/* video_device: "auto" | /dev/videoN | "test" (videotestsrc) */
MppH264Source *mpp_h264_source_start(const char *video_device, char **error_message);
void mpp_h264_source_stop(MppH264Source *src);
/* 拉一帧 Annex-B AU;数据在下次 pull 前有效。timeout_ms:appsink 等待毫秒。 */
gboolean mpp_h264_source_pull(MppH264Source *src, gboolean force_idr,
const uint8_t **data, size_t *size,
gboolean *is_idr, guint64 *pts_ns,
gint timeout_ms);
void mpp_h264_source_set_bitrate(MppH264Source *src, guint bitrate_bps);
void mpp_h264_source_request_keyframe(MppH264Source *src);
gboolean mpp_h264_source_is_mpp_encoder(const MppH264Source *src);
#endif
This diff is collapsed.
......@@ -4,32 +4,36 @@
/*
* WEBRTCPUSH_USE_MPP — 推流方式(与 Chromium 浏览器互斥,共用 thread_open_browser 线程)
* 0:走 Chromium 浏览器推流(opencamsh,原有逻辑)
* 1:走 libdatachannel 原生推流,不打开浏览器
* 1:走 libdatachannel 原生推流(摄像头 → MPP/x264 → libdatachannel)
*
* WEBRTCPUSH_USE_MPP 是历史配置名。第一阶段原生分支从本地 Annex-B
* H.264 文件发送;验证通路后,只替换输入为 MPP 实时编码,入口仍是这一条
* 原生分支:v4l2 采集 → mpph264enc(或 x264enc 回退)→ libdatachannel 发送。
* 音频尚未接入,视频跑通后再接 ALSA→Opus track
*/
#define WEBRTCPUSH_USE_MPP 1
/* libdatachannel 第一阶段:720p Annex-B 测试流。 */
#define WEBRTCPUSH_H264_FILE PROJECT_ROOT_DIR "/testdata/rtc_test_720p.h264"
#define WEBRTCPUSH_H264_FPS 25
/* 正常固定 24fps;弱网以降码率为主,后续若启用动态帧率也不得低于 22fps。 */
#define WEBRTCPUSH_H264_FPS 24
#define WEBRTCPUSH_H264_MIN_FPS 22
#define WEBRTCPUSH_H264_GOP (WEBRTCPUSH_H264_FPS * 3)
/* REMB 慢升快降,最高码率按当前要求限制为 3.2 Mbps。 */
#define WEBRTCPUSH_INITIAL_BITRATE 1000000U
#define WEBRTCPUSH_MIN_BITRATE 250000U
/* 与 gst_webrtc_pipeline / jywy 浏览器推流对齐的码率策略 */
#define WEBRTCPUSH_INITIAL_BITRATE 1400000U /* 起播 1.4 Mbps */
#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_PACING_INTERVAL_MS 5U
#define WEBRTCPUSH_PACING_HEADROOM_PERCENT 120U
#define WEBRTCPUSH_PACING_MAX_BITRATE 3750000U
#define WEBRTCPUSH_NACK_PACKETS 1024U
/* 视频采集:auto | /dev/video0 | test(测试图案) */
/* 视频采集:auto | /dev/videoN | test(videotestsrc 测试图案) */
#define WEBRTCPUSH_VIDEO_DEVICE "auto"
/*
* 麦克风采集(仅上行推流到手机,与车机喇叭播放 audioplay/tts 无关)。
* 留空表示不推音频;hw:X,Y 运行时会转为 plughw:X,Y,并优先经 Pulse 的 input 源采集。
*/
/* auto:读 /proc/asound/pcm 选第一个 capture;hw:X,Y 固定卡号 */
#define WEBRTCPUSH_ALSA_DEVICE "auto"
/*
......@@ -41,10 +45,6 @@
/* WebRTC 信令 WebSocket 主机(路径 /websocket?dev=设备号) */
#define WEBRTCPUSH_SIGNAL_HOST "signal.yd-ss.com"
/*
* 1:g_print / 关键步骤打 INFO(Release 下也可见);0:走 my_zlog_debug
* 编译 Debug:cmake -DCMAKE_BUILD_TYPE=Debug ..
*/
#define WEBRTCPUSH_DEBUG 0
#endif
......@@ -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; /* Phase 1 validates the H.264 transport first. */
s_app.enable_audio = FALSE; /* 视频先行;音频后续 ALSA→Opus track */
s_app.loop = g_main_loop_new(NULL, FALSE);
......@@ -198,9 +198,10 @@ int webrtcpush_run_blocking(void)
}
s_running = TRUE;
my_zlog_info("webrtcpush libdatachannel started dev=%s file=%s fps=%d bitrate=%u..%u",
my_zlog_info("webrtcpush libdatachannel started dev=%s device=%s fps=%d bitrate=%u..%u",
s_app.dev_room ? s_app.dev_room : "?",
WEBRTCPUSH_H264_FILE, WEBRTCPUSH_H264_FPS,
s_app.video_device ? s_app.video_device : WEBRTCPUSH_VIDEO_DEVICE,
WEBRTCPUSH_H264_FPS,
WEBRTCPUSH_INITIAL_BITRATE, WEBRTCPUSH_MAX_BITRATE);
g_main_loop_run(s_app.loop);
......
{"head":{"message_type":2008},"body":{"wifi_ssid":"test_wifi_01","wifi_password":"pass0001"}}
{"head":{"message_type":2008},"body":{"wifi_ssid":"test_wifi_02","wifi_password":"pass0002"}}
{"head":{"message_type":2008},"body":{"wifi_ssid":"test_wifi_03","wifi_password":"pass0003"}}
{"head":{"message_type":2008},"body":{"wifi_ssid":"test_wifi_04","wifi_password":"pass0004"}}
{"head":{"message_type":2008},"body":{"wifi_ssid":"test_wifi_05","wifi_password":"pass0005"}}
{"head":{"message_type":2008},"body":{"wifi_ssid":"test_wifi_06","wifi_password":"pass0006"}}
{"head":{"message_type":2008},"body":{"wifi_ssid":"test_wifi_07","wifi_password":"pass0007"}}
{"head":{"message_type":2008},"body":{"wifi_ssid":"test_wifi_08","wifi_password":"pass0008"}}
{"head":{"message_type":2008},"body":{"wifi_ssid":"test_wifi_09","wifi_password":"pass0009"}}
{"head":{"message_type":2008},"body":{"wifi_ssid":"test_wifi_10","wifi_password":"pass0010"}}
{"head":{"message_type":2008},"body":{"wifi_ssid":"test_wifi_11","wifi_password":"pass0011"}}
......@@ -25,6 +25,7 @@ class RTC_CPP_EXPORT PacingHandler : public MediaHandler {
public:
PacingHandler(double bitsPerSecond, std::chrono::milliseconds sendInterval);
void setBitrate(double bitsPerSecond);
size_t clear();
void outgoing(message_vector &messages, const message_callback &send) override;
......
......@@ -430,6 +430,10 @@ RTC_C_EXPORT int rtcChainPacingHandler(int tr, unsigned int bitrate,
// Update a previously chained pacing handler without rebuilding the track
RTC_C_EXPORT int rtcSetPacingBitrate(int tr, unsigned int bitrate);
// Drop queued RTP packets before resynchronizing with a fresh key frame.
// Returns the number of dropped packets, or a negative RTC_ERR_* value.
RTC_C_EXPORT int rtcClearPacingQueue(int tr);
// 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);
......
......@@ -23,6 +23,7 @@ public:
static const size_t DefaultMaxSize = 512;
RtcpNackResponder(size_t maxSize = DefaultMaxSize);
void clear();
void incoming(message_vector &messages, const message_callback &send) override;
void outgoing(message_vector &messages, const message_callback &send) override;
......@@ -64,6 +65,9 @@ private:
/// Stores packet
/// @param packet Packet
void store(message_ptr packet);
/// Drops all packets retained for retransmission.
void clear();
};
const shared_ptr<Storage> mStorage;
......
......@@ -14,6 +14,7 @@
#include <algorithm>
#include <chrono>
#include <exception>
#include <limits>
#include <mutex>
#include <type_traits>
#include <unordered_map>
......@@ -32,6 +33,7 @@ std::unordered_map<int, shared_ptr<Track>> trackMap;
std::unordered_map<int, shared_ptr<RtcpSrReporter>> rtcpSrReporterMap;
std::unordered_map<int, shared_ptr<RtpPacketizationConfig>> rtpConfigMap;
std::unordered_map<int, shared_ptr<PacingHandler>> pacingHandlerMap;
std::unordered_map<int, shared_ptr<RtcpNackResponder>> rtcpNackResponderMap;
#endif
#if RTC_ENABLE_WEBSOCKET
std::unordered_map<int, shared_ptr<WebSocket>> webSocketMap;
......@@ -122,6 +124,7 @@ void eraseTrack(int tr) {
rtcpSrReporterMap.erase(tr);
rtpConfigMap.erase(tr);
pacingHandlerMap.erase(tr);
rtcpNackResponderMap.erase(tr);
#endif
userPointerMap.erase(tr);
}
......@@ -133,10 +136,12 @@ size_t eraseAll() {
trackMap.clear();
peerConnectionMap.clear();
#if RTC_ENABLE_MEDIA
count += rtcpSrReporterMap.size() + rtpConfigMap.size() + pacingHandlerMap.size();
count += rtcpSrReporterMap.size() + rtpConfigMap.size() + pacingHandlerMap.size() +
rtcpNackResponderMap.size();
rtcpSrReporterMap.clear();
rtpConfigMap.clear();
pacingHandlerMap.clear();
rtcpNackResponderMap.clear();
#endif
#if RTC_ENABLE_WEBSOCKET
count += webSocketMap.size() + webSocketServerMap.size();
......@@ -172,6 +177,7 @@ void eraseChannel(int id) {
rtcpSrReporterMap.erase(id);
rtpConfigMap.erase(id);
pacingHandlerMap.erase(id);
rtcpNackResponderMap.erase(id);
#endif
return;
}
......@@ -1388,6 +1394,10 @@ int rtcChainRtcpNackResponder(int tr, unsigned int maxStoredPacketsCount) {
auto track = getTrack(tr);
auto responder = std::make_shared<RtcpNackResponder>(maxStoredPacketsCount);
track->chainMediaHandler(responder);
{
std::lock_guard lock(mutex);
rtcpNackResponderMap[tr] = responder;
}
return RTC_ERR_SUCCESS;
});
}
......@@ -1449,6 +1459,29 @@ int rtcSetPacingBitrate(int tr, unsigned int bitrate) {
});
}
int rtcClearPacingQueue(int tr) {
return wrap([&] {
shared_ptr<PacingHandler> handler;
shared_ptr<RtcpNackResponder> nackResponder;
{
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;
if (auto nackIt = rtcpNackResponderMap.find(tr);
nackIt != rtcpNackResponderMap.end())
nackResponder = nackIt->second;
}
const size_t count = handler->clear();
if (nackResponder)
nackResponder->clear();
return count > static_cast<size_t>(std::numeric_limits<int>::max())
? std::numeric_limits<int>::max()
: static_cast<int>(count);
});
}
int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp) {
return wrap([&] {
auto config = getRtpConfig(id);
......
......@@ -24,6 +24,15 @@ void PacingHandler::setBitrate(double bitsPerSecond) {
mBytesPerSecond.store(bitsPerSecond / 8);
}
size_t PacingHandler::clear() {
std::lock_guard<std::mutex> lock(mMutex);
const size_t count = mRtpBuffer.size();
while (!mRtpBuffer.empty())
mRtpBuffer.pop();
mBudget = 0.;
return count;
}
void PacingHandler::schedule(const message_callback &send) {
if (mHaveScheduled.exchange(true)) {
return;
......
......@@ -20,6 +20,8 @@ namespace rtc {
RtcpNackResponder::RtcpNackResponder(size_t maxSize)
: mStorage(std::make_shared<Storage>(maxSize)) {}
void RtcpNackResponder::clear() { mStorage->clear(); }
void RtcpNackResponder::incoming(message_vector &messages, const message_callback &send) {
for (const auto &message : messages) {
if (message->type != Message::Control)
......@@ -108,6 +110,13 @@ void RtcpNackResponder::Storage::store(message_ptr packet) {
}
}
void RtcpNackResponder::Storage::clear() {
std::lock_guard lock(mutex);
storage.clear();
oldest.reset();
newest.reset();
}
} // namespace rtc
#endif /* RTC_ENABLE_MEDIA */
......@@ -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-06-30.log"; millisecond
my_log.* "/home/orangepi/car/master/log/log_2026-07-01.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