feat: 修复启动bash路径、将丢失连接时的视频稍微不堆积

This commit is contained in:
Mock
2026-04-10 11:49:38 +08:00
parent f443934ee4
commit 40cd68db3d
8 changed files with 93 additions and 6 deletions

View File

@@ -174,7 +174,7 @@ def test_kcp_idle_video_peers_survive_without_receive_loop() -> None:
port = _reserve_port() port = _reserve_port()
listen_addr = f'127.0.0.1:{port}' listen_addr = f'127.0.0.1:{port}'
sender_id = 'peer-b-video' sender_id = 'peer-b-video'
receiver_id = 'peer-a-video' receiver_id = 'pytest-kcp-video-idle-receiver'
with _run_server('kcpserver', listen_addr): with _run_server('kcpserver', listen_addr):
sender = _connect_with_retry(Session, transport='kcp', server_addr=listen_addr, peer_id=sender_id) sender = _connect_with_retry(Session, transport='kcp', server_addr=listen_addr, peer_id=sender_id)
@@ -194,6 +194,22 @@ def test_kcp_idle_video_peers_survive_without_receive_loop() -> None:
receiver.close() receiver.close()
def test_kcp_peer_a_video_stale_receiver_is_evicted() -> None:
port = _reserve_port()
listen_addr = f'127.0.0.1:{port}'
receiver_id = 'peer-a-video'
with _run_server('kcpserver', listen_addr):
receiver = _connect_with_retry(Session, transport='kcp', server_addr=listen_addr, peer_id=receiver_id)
try:
time.sleep(5.0)
with pytest.raises(OSError):
receiver.recv(timeout_ms=1000)
finally:
receiver.close()
def test_udp_session_close_interrupts_blocking_recv() -> None: def test_udp_session_close_interrupts_blocking_recv() -> None:
port = _reserve_port() port = _reserve_port()
listen_addr = f'127.0.0.1:{port}' listen_addr = f'127.0.0.1:{port}'

View File

@@ -17,6 +17,7 @@ The scripts assume:
- `robot-command-center` is a sibling directory next to it - `robot-command-center` is a sibling directory next to it
If your `robot-command-center` is elsewhere, set `ROBOT_COMMAND_CENTER_ROOT` in `robot-remote.env.local`. If your `robot-command-center` is elsewhere, set `ROBOT_COMMAND_CENTER_ROOT` in `robot-remote.env.local`.
`start-backend.sh` and `start-frontend.sh` need that repo; `start-ros-receiver.sh` and `start-b-side-omnid.sh` do not.
## Files ## Files

View File

@@ -19,6 +19,12 @@ is_robot_command_center_root() {
[[ -f "${dir}/backend/config/asgi.py" && -f "${dir}/frontend/package.json" ]] [[ -f "${dir}/backend/config/asgi.py" && -f "${dir}/frontend/package.json" ]]
} }
require_robot_command_center_root() {
if ! is_robot_command_center_root "${ROBOT_COMMAND_CENTER_ROOT}"; then
die "ROBOT_COMMAND_CENTER_ROOT must point to the robot-command-center repo root. Current value: ${ROBOT_COMMAND_CENTER_ROOT}. Set it in ${SCRIPT_DIR}/robot-remote.env.local if needed."
fi
}
export OMNISOCKETGO_ROOT="${OMNISOCKETGO_ROOT:-${DEFAULT_OMNISOCKETGO_ROOT}}" export OMNISOCKETGO_ROOT="${OMNISOCKETGO_ROOT:-${DEFAULT_OMNISOCKETGO_ROOT}}"
ENV_FILES=( ENV_FILES=(
@@ -42,10 +48,6 @@ if ! is_omnisocketgo_root "${OMNISOCKETGO_ROOT}"; then
die "OMNISOCKETGO_ROOT must point to the OmniSocketGo repo root. Current value: ${OMNISOCKETGO_ROOT}" die "OMNISOCKETGO_ROOT must point to the OmniSocketGo repo root. Current value: ${OMNISOCKETGO_ROOT}"
fi fi
if ! is_robot_command_center_root "${ROBOT_COMMAND_CENTER_ROOT}"; then
die "ROBOT_COMMAND_CENTER_ROOT must point to the robot-command-center repo root. Current value: ${ROBOT_COMMAND_CENTER_ROOT}. Set it in ${SCRIPT_DIR}/robot-remote.env.local if needed."
fi
export BACKEND_DIR="${BACKEND_DIR:-${ROBOT_COMMAND_CENTER_ROOT}/backend}" export BACKEND_DIR="${BACKEND_DIR:-${ROBOT_COMMAND_CENTER_ROOT}/backend}"
export FRONTEND_DIR="${FRONTEND_DIR:-${ROBOT_COMMAND_CENTER_ROOT}/frontend}" export FRONTEND_DIR="${FRONTEND_DIR:-${ROBOT_COMMAND_CENTER_ROOT}/frontend}"
export ROS_CONTROL_PY_DIR="${ROS_CONTROL_PY_DIR:-${OMNISOCKETGO_ROOT}/ros-control-py}" export ROS_CONTROL_PY_DIR="${ROS_CONTROL_PY_DIR:-${OMNISOCKETGO_ROOT}/ros-control-py}"

View File

@@ -4,6 +4,7 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091 # shellcheck disable=SC1091
source "${SCRIPT_DIR}/load-env.sh" source "${SCRIPT_DIR}/load-env.sh"
require_robot_command_center_root
if [[ ! -d "${PYTHON_VENV_PATH}" ]]; then if [[ ! -d "${PYTHON_VENV_PATH}" ]]; then
"${PYTHON3_BIN}" -m venv "${PYTHON_VENV_PATH}" "${PYTHON3_BIN}" -m venv "${PYTHON_VENV_PATH}"

View File

@@ -4,6 +4,7 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091 # shellcheck disable=SC1091
source "${SCRIPT_DIR}/load-env.sh" source "${SCRIPT_DIR}/load-env.sh"
require_robot_command_center_root
cd "${FRONTEND_DIR}" cd "${FRONTEND_DIR}"
exec npm run dev -- --host "${FRONTEND_HOST}" --port "${FRONTEND_PORT}" exec npm run dev -- --host "${FRONTEND_HOST}" --port "${FRONTEND_PORT}"

View File

@@ -113,11 +113,17 @@ static int kcp_hub_peer_is_telemetry(const char *peer_id) {
return kcp_hub_peer_id_has_suffix(peer_id, "-telemetry"); return kcp_hub_peer_id_has_suffix(peer_id, "-telemetry");
} }
static int kcp_hub_peer_is_video_receiver(const char *peer_id) {
return peer_id != NULL && strcmp(peer_id, "peer-a-video") == 0;
}
static int kcp_hub_peer_uses_server_lease(const char *peer_id) { static int kcp_hub_peer_uses_server_lease(const char *peer_id) {
if (peer_id == NULL || peer_id[0] == '\0') { if (peer_id == NULL || peer_id[0] == '\0') {
return 0; return 0;
} }
return kcp_hub_peer_id_has_suffix(peer_id, "-ctrl") || kcp_hub_peer_is_telemetry(peer_id); return kcp_hub_peer_id_has_suffix(peer_id, "-ctrl")
|| kcp_hub_peer_is_telemetry(peer_id)
|| kcp_hub_peer_is_video_receiver(peer_id);
} }
static const char *kcp_hub_peer_node_id(const char *peer_id) { static const char *kcp_hub_peer_node_id(const char *peer_id) {

View File

@@ -566,6 +566,32 @@ static int video_sender_init(video_sender_t *sender, const video_pipeline_config
return 0; return 0;
} }
static int video_sender_drain_pending_messages(video_sender_t *sender) {
if (sender == NULL || sender->client == NULL) {
errno = EINVAL;
return -1;
}
for (;;) {
message_t msg;
int rc;
protocol_message_init(&msg);
rc = kcp_client_receive_timed(sender->client, &msg, 1);
if (rc == 1) {
protocol_message_clear(&msg);
return 0;
}
if (rc != 0) {
protocol_message_clear(&msg);
return -1;
}
// Drain unread server errors so an offline receiver cannot back up the reverse KCP stream.
protocol_message_clear(&msg);
}
}
static int video_sender_send_packet(video_sender_t *sender, const AVPacket *encoded_pkt, uint64_t timestamp) { static int video_sender_send_packet(video_sender_t *sender, const AVPacket *encoded_pkt, uint64_t timestamp) {
uint8_t *payload; uint8_t *payload;
size_t payload_len; size_t payload_len;
@@ -585,6 +611,10 @@ static int video_sender_send_packet(video_sender_t *sender, const AVPacket *enco
memcpy(payload, encoded_pkt->data, (size_t) encoded_pkt->size); memcpy(payload, encoded_pkt->data, (size_t) encoded_pkt->size);
memcpy(payload + encoded_pkt->size, &timestamp, sizeof(timestamp)); memcpy(payload + encoded_pkt->size, &timestamp, sizeof(timestamp));
rc = kcp_client_send_binary(sender->client, sender->target_peer, payload, payload_len); rc = kcp_client_send_binary(sender->client, sender->target_peer, payload, payload_len);
if (rc != 0) {
return rc;
}
rc = video_sender_drain_pending_messages(sender);
return rc; return rc;
} }

View File

@@ -566,6 +566,32 @@ static int video_sender_init(video_sender_t *sender, const video_pipeline_config
return 0; return 0;
} }
static int video_sender_drain_pending_messages(video_sender_t *sender) {
if (sender == NULL || sender->client == NULL) {
errno = EINVAL;
return -1;
}
for (;;) {
message_t msg;
int rc;
protocol_message_init(&msg);
rc = kcp_client_receive_timed(sender->client, &msg, 1);
if (rc == 1) {
protocol_message_clear(&msg);
return 0;
}
if (rc != 0) {
protocol_message_clear(&msg);
return -1;
}
// Drain unread server errors so an offline receiver cannot back up the reverse KCP stream.
protocol_message_clear(&msg);
}
}
static int video_sender_send_packet(video_sender_t *sender, const AVPacket *encoded_pkt, uint64_t timestamp) { static int video_sender_send_packet(video_sender_t *sender, const AVPacket *encoded_pkt, uint64_t timestamp) {
uint8_t *payload; uint8_t *payload;
size_t payload_len; size_t payload_len;
@@ -585,6 +611,10 @@ static int video_sender_send_packet(video_sender_t *sender, const AVPacket *enco
memcpy(payload, encoded_pkt->data, (size_t) encoded_pkt->size); memcpy(payload, encoded_pkt->data, (size_t) encoded_pkt->size);
memcpy(payload + encoded_pkt->size, &timestamp, sizeof(timestamp)); memcpy(payload + encoded_pkt->size, &timestamp, sizeof(timestamp));
rc = kcp_client_send_binary(sender->client, sender->target_peer, payload, payload_len); rc = kcp_client_send_binary(sender->client, sender->target_peer, payload, payload_len);
if (rc != 0) {
return rc;
}
rc = video_sender_drain_pending_messages(sender);
return rc; return rc;
} }