rosotacom-dev 2.5.dev47__tar.gz → 2.5.dev49__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/PKG-INFO +1 -1
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/forensics-report.md +7 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/rfcs/0003-metric-backbone.md +11 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/session-configuration.md +29 -7
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview.py +36 -6
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview_core.py +44 -15
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/session/content/base/session_plugin_base.yaml +66 -4
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/session/creation/generate_session_files.py +72 -7
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom_dev.egg-info/PKG-INFO +1 -1
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom_dev.egg-info/scm_version.json +2 -2
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_session_pipeline.py +73 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_status_overview_observer.py +75 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_transit.py +38 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.devcontainer/devcontainer.json.template +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.devcontainer/re_generate_devcontainer_json.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/CODEOWNERS +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/ISSUE_TEMPLATE/documentation-audit.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/ISSUE_TEMPLATE/implementation-cleanup.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/ISSUE_TEMPLATE/quality-workflow.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/ISSUE_TEMPLATE/redesign.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/ISSUE_TEMPLATE/release-process.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/ISSUE_TEMPLATE/repository-diagnosis.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/ISSUE_TEMPLATE/test-ci-audit.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/ISSUE_TEMPLATE/work-item.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/actions/setup-just/action.yml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/dependabot.yml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/workflows/benchmark-calibrate.yml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/workflows/benchmark-gate.yml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/workflows/dev-release.yml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/workflows/image-scan.yml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/workflows/nightly-e2e.yml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/workflows/pr-lightweight.yml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/workflows/pr-merge-gate.yml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.github/workflows/release.yml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/.pre-commit-config.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/AGENTS.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/CONCURRENCY.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/CONTRIBUTING.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/DEVELOPMENT_PRINCIPLES.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/MANIFEST.in +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/README.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/budgets.jsonl +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/calibration/README.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/calibration/capacity-size-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/calibration/probe-loss-gop-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/calibration/probe-loss-nominal-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/calibration/probe-loss-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/calibration/probe-loss-tight-fastdds.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/calibration/probe-loss-tight-zenoh.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/codecov.yml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/deployment-configuration.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/benchmark-ab.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/benchmark-bag-as-load.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/ci.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/ffmpeg-keyframes.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/findings/README.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/findings/cyclone-spdp-discovery-bursts.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/findings/delay-alone-no-loss.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/findings/head-of-line-irregularity.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/findings/jitter-loss-bandwidth-latency.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/findings/lighter-message-loss.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/findings/reorder-becomes-reader-loss.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/findings/repro/reorder_drop_repro.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/findings/zero-loss-boundaries-18kb-20hz.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/geo-link-map.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/github-repository-settings.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/link-bandwidth.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/link-trace.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/owner-runbook.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/performance-bands.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/playbooks/README.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/quality-model.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/release-notes/TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/release-notes/v2.1.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/release-notes/v2.2.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/release-notes/v2.3.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/release-notes/v2.4.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/release.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/rfcs/0001-expectation-driven-test-suite.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/rfcs/0002-expectation-concepts.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/rfcs/0004-network-profiles.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/rfcs/0005-benchmark-genres-and-ci.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/rfcs/0006-dynamic-qos.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/rfcs/0007-regression-gate.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/rfcs/README.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/testing.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/docs/work-items.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/install.sh +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/justfile +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/media/control_center.png +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/media/echo_test.png +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/media/forensics-report-example.png +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/media/host.png +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/media/vehicle.png +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/pyproject.toml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/requirements.txt +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/__init__.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/__main__.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/anonymize.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/benched_set.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/benchmark.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/benchmark_delta.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/cli.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/deployment.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/forensics.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/geomap.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/image_cache.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/netem_dist.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/plots.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/py.typed +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/benched-set.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/.gitignore +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/README.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/__init__.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/bags/8_drop_reference/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/deployment.example.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/dist/field-20260817.dist +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/profiles.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scenarios/2_native_chatter/scenario-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_a.sh +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_b.sh +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/wait_for_echo_topic.sh +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/10_restamp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/11_trickle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/12_content_integrity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/13_link_latency/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/14_remote_assist_anonymized/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/15_remote_assist_anonymized_costmap/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/16_remote_assist_anonymized_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/17_synthetic_camera_quality/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/1_heartbeat/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/1_heartbeat_status/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/2_native_chatter/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/3_comp_occ_grid/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/4_comp_occ_grid_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/5_sized_payload/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/6_sized_payload_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/7_latched_static/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/8_drop/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/9_throttle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/bench_1_1_capacity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/bench_1_2_load_sweep/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/bench_1_3_ramp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/bench_1_4_recovery/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/examples/sessions/bench_1_5_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ros2docker.json.example +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/.vscode/c_cpp_properties.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/.vscode/settings.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_initial_peer_list.xml.template +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v2.xml.template +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v3.xml.template +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v4.xml.template +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v5.xml.template +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ota_configs/cyclonedds_local_participants.xml.template +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ota_configs/fastdds_unicast.xml.template +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ota_configs/get_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ota_configs/utils.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ota_configs/zenoh.json5.template +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/.gitkeep +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_cpp/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_cpp/COLCON_IGNORE +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_cpp/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_cpp/package.xml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_cpp/src/hz_monitor.cpp +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_compressor.cpp +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_decompressor.cpp +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_msgs/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_msgs/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/CompressedData.msg +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/EchoHeartbeat.msg +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/OtaStamped.msg +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/SizedPayload.msg +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_msgs/package.xml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/__init__.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/base_bridge_relay.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_in.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_out.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/ffmpeg_flags.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/heartbeat_echo.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/hz_monitor.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_bandwidth_reducer.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_pixel_capper.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/lanelet_saver.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/latch_relay.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/costmap_remapper.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/marker_remapper.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/speed_test.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/tf_remapper.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/traffic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/wifi_network_analysis_1.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_trace.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/local_global_frame_bridge.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/localization_map_split_reduce_saver.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/msg_transform.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pair_management.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer_core.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pub_sub_pair.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/qos.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_in.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_out.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/restamp.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/sized_publisher.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency_core.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/tf_map_to_cart_saver.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_resolution.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/trickle.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_compressor.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_decompressor.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/package.xml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/resource/com_py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/setup.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/test/test_copyright.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/test/test_flake8.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/ros2src/com_py/test/test_pep257.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/session/content/network/up_connectivity.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/session/content/network/wifi_network_analysis_2.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/session/creation/anonymize_bag.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/session/creation/catmux_log_setup.sh +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/session/creation/create_session_yaml.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/session/creation/run_session.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/session/creation/run_session_in_external_terminal.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/resources/ws/session/creation/strip_ansi.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/status_eval.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/transit.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom/video_quality.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom_dev.egg-info/SOURCES.txt +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom_dev.egg-info/dependency_links.txt +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom_dev.egg-info/entry_points.txt +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom_dev.egg-info/requires.txt +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom_dev.egg-info/scm_file_list.json +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/src/rosotacom_dev.egg-info/top_level.txt +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/terminology.md +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/contract/test_benched_set_registry.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/contract/test_findings.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/contract/test_markdown_links.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/contract/test_ota_source_bundle.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/contract/test_package_metadata.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/contract/test_packaged_resources.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/contract/test_profile_covers_generated_commands.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/contract/test_pytest_policy.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/contract/test_readme_examples.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/contract/test_security_maintenance_config.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/contract/test_session_configuration_doc.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/contract/test_session_template_substitution.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/contract/test_workflow_contracts.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/e2e/conftest.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/e2e/test_anonymize_e2e.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/e2e/test_benchmark_ab.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/e2e/test_benchmark_capacity.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/e2e/test_benchmark_replay.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/e2e/test_parallel_smoke.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/e2e/test_smoke.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/e2e/test_timeline_stepping.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/e2e/test_video_quality_e2e.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/sessions/generate_rmw_matrix.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-local_zenoh-ros2dds-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota-tuned/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/sessions/rmw_matrix/1_heartbeat_fastdds/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/sessions/rmw_matrix/1_heartbeat_zen-endpoints/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_anonymize.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_benched_set.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_benchmark_delta.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_catmux_pane_logging.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_cli.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_concurrency.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_deployment.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_ffmpeg_flags.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_field_profiles.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_forensics.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_geomap.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_image_cache.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_link_trace.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_netem_dist.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_playout_pacer.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_plots.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_qos_fallback_logging.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_relay_optional_parameters.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_status_eval.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_status_overview.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev47 → rosotacom_dev-2.5.dev49}/tests/unit/test_video_quality.py +0 -0
|
@@ -93,6 +93,13 @@ delivered below it; `unknown` without sender-side records. `min_offered_hz` /
|
|
|
93
93
|
rate — they never enter the delivered view, where the cross-peer join would
|
|
94
94
|
upgrade receiver-inferred lost rows to delivered.
|
|
95
95
|
|
|
96
|
+
The sending peer's status overview emits those rows itself for every wrapped
|
|
97
|
+
stream (stage `com_out`, status `sent`, sequence gaps in its own observation as
|
|
98
|
+
`unobserved` — see RFC 0003): record on both machines and place both peers'
|
|
99
|
+
`logs/<peer>/status/` under one instance directory before running the report,
|
|
100
|
+
and the `unknown` verdicts disappear. Recordings made before the sender-side
|
|
101
|
+
rows existed stay `unknown` for their outbound streams.
|
|
102
|
+
|
|
96
103
|
Events across streams and kinds are grouped into **incidents** when their
|
|
97
104
|
windows touch (merge gap defaults to one bin): one degradation moment, several
|
|
98
105
|
lenses on it.
|
|
@@ -56,6 +56,17 @@ Every metric on the wishlist is a projection of one recorded object per message:
|
|
|
56
56
|
inter_arrival / jitter — receiver-local regularity
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
+
The **sending peer** records its own view of the same message at `com_out`
|
|
60
|
+
(`direction: outbound`): `t_wrap` plus `t_com_out` (both its own clock, so
|
|
61
|
+
`sections.wrap_to_com_out_ms` is the relay hop, and there is no θ). Its status
|
|
62
|
+
values are deliberately different — `sent` for an observed message,
|
|
63
|
+
`unobserved` for a gap in its own observation (the local best-effort observer
|
|
64
|
+
missed it; the link cannot lose a message before the link) — so the offline
|
|
65
|
+
join, which ranks only `lost < reordered < delivered`, can enrich a receiver
|
|
66
|
+
row with sender timestamps but a sender row can never overwrite a receiver's
|
|
67
|
+
`lost` verdict. This is what lets the forensics report classify a rate collapse
|
|
68
|
+
as `source` vs `link`: offered (sender `t_wrap` bins) against delivered.
|
|
69
|
+
|
|
59
70
|
**Why `epoch` is part of the key.** `universal_ota_wrapper` counts per topic
|
|
60
71
|
from zero, so a peer that restarts inside an instance replays sequence numbers
|
|
61
72
|
the receiver has already seen. The receiver detects the restart from the
|
|
@@ -568,13 +568,39 @@ number being reported.
|
|
|
568
568
|
- `bit_rate` (int)
|
|
569
569
|
- `encoder_av_options` (string)
|
|
570
570
|
|
|
571
|
-
#### Receiver-side playout pacing
|
|
571
|
+
#### Receiver-side playout pacing
|
|
572
572
|
|
|
573
573
|
A receiver that hands every packet to the decoder the moment it arrives turns
|
|
574
574
|
network delay jitter into display stutter. `com_py playout_pacer` re-times a
|
|
575
575
|
received packet stream to `stamp + budget` (budget adaptive above the fastest
|
|
576
576
|
observed path, clock-offset-proof; late packets pass through immediately, order
|
|
577
|
-
always preserved — the decoder chain sees every packet)
|
|
577
|
+
always preserved — the decoder chain sees every packet). On the 2026-08-17 CCNG
|
|
578
|
+
field trace this removes ~95 % of delay-caused >200 ms display gaps at ~100 ms
|
|
579
|
+
median added age (adaptive mode).
|
|
580
|
+
|
|
581
|
+
Declaratively, add a `playout` block to the transport:
|
|
582
|
+
|
|
583
|
+
```yaml
|
|
584
|
+
transport:
|
|
585
|
+
type: "ffmpeg"
|
|
586
|
+
gop_size: 3
|
|
587
|
+
remote_republish: compressed
|
|
588
|
+
playout: # receiver-side; requires remote_republish
|
|
589
|
+
adaptive: true # default true; false uses target_ms as a fixed budget
|
|
590
|
+
target_ms: 350 # fixed budget when adaptive: false
|
|
591
|
+
min_ms: 100 # adaptive clamp above the observed delay floor
|
|
592
|
+
max_ms: 800
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
The receiving peer then runs the pacer in its own `PACE` window against the
|
|
596
|
+
arrived encoded stream, and the reverse republish decodes `<encoded>/paced`
|
|
597
|
+
instead of the raw arrival — the delivered topic name is unchanged, which is
|
|
598
|
+
why `playout` requires `remote_republish`: without a republish the pacer's
|
|
599
|
+
`/paced` suffix would rename what the receiving application subscribes to.
|
|
600
|
+
The sender's own preview decode (`local_republish`) is never paced — it reads
|
|
601
|
+
the local copy of what was just encoded, so there is no jitter to absorb.
|
|
602
|
+
|
|
603
|
+
The node also runs standalone against any packet stream:
|
|
578
604
|
|
|
579
605
|
```bash
|
|
580
606
|
ros2 run com_py playout_pacer --ros-args \
|
|
@@ -583,11 +609,7 @@ ros2 run com_py playout_pacer --ros-args \
|
|
|
583
609
|
```
|
|
584
610
|
|
|
585
611
|
It republishes on `<topic>/paced` plus `.../paced/budget_ms` and
|
|
586
|
-
`.../paced/queue_depth` debug topics
|
|
587
|
-
decoder) at the paced name. On the 2026-08-17 CCNG field trace this removes
|
|
588
|
-
~95 % of delay-caused >200 ms display gaps at ~100 ms median added age
|
|
589
|
-
(adaptive mode). Declarative wiring as a `transport.playout` block is tracked
|
|
590
|
-
in issue #284.
|
|
612
|
+
`.../paced/queue_depth` debug topics.
|
|
591
613
|
|
|
592
614
|
`type: foxglove` supports (CompressedVideo):
|
|
593
615
|
- `gop_size` (int)
|
|
@@ -253,6 +253,22 @@ class StageObserver(Node):
|
|
|
253
253
|
),
|
|
254
254
|
None,
|
|
255
255
|
)
|
|
256
|
+
com_out = next(
|
|
257
|
+
(
|
|
258
|
+
context
|
|
259
|
+
for context in contexts
|
|
260
|
+
if context.get("stage") == "com_out"
|
|
261
|
+
and context.get("direction") == "outbound"
|
|
262
|
+
),
|
|
263
|
+
None,
|
|
264
|
+
)
|
|
265
|
+
keyframe: Optional[bool] = None
|
|
266
|
+
if com_in is not None or com_out is not None:
|
|
267
|
+
try:
|
|
268
|
+
if msg.msg_type == FFMPEG_PACKET_TYPE:
|
|
269
|
+
keyframe = parse_keyframe_flag(bytes(msg.serialized_msg))
|
|
270
|
+
except Exception:
|
|
271
|
+
keyframe = None
|
|
256
272
|
if com_in is not None:
|
|
257
273
|
seq = int(msg.seq)
|
|
258
274
|
t_wrap_s = _stamp_seconds(msg.header.stamp)
|
|
@@ -262,12 +278,6 @@ class StageObserver(Node):
|
|
|
262
278
|
clock_offset_s = estimate["offset_s"]
|
|
263
279
|
rtt_s = estimate["rtt_s"]
|
|
264
280
|
delay_s = now_ros_s + clock_offset_s - t_wrap_s
|
|
265
|
-
keyframe: Optional[bool] = None
|
|
266
|
-
try:
|
|
267
|
-
if msg.msg_type == FFMPEG_PACKET_TYPE:
|
|
268
|
-
keyframe = parse_keyframe_flag(bytes(msg.serialized_msg))
|
|
269
|
-
except Exception:
|
|
270
|
-
keyframe = None
|
|
271
281
|
transit = {
|
|
272
282
|
"peer": com_in.get("peer"),
|
|
273
283
|
"source": com_in.get("source"),
|
|
@@ -279,6 +289,26 @@ class StageObserver(Node):
|
|
|
279
289
|
"t_com_in": now_ros_s,
|
|
280
290
|
"keyframe": keyframe,
|
|
281
291
|
}
|
|
292
|
+
elif com_out is not None:
|
|
293
|
+
# The sending peer's own view of the same message: what the
|
|
294
|
+
# source handed to the link, before any OTA hop. The wrapper
|
|
295
|
+
# stamped `t_wrap` on THIS machine, so no peer offset applies
|
|
296
|
+
# (same rule as the generic local-stage branch below) and the
|
|
297
|
+
# delay is the wrap->com_out relay hop, not an OTA number.
|
|
298
|
+
seq = int(msg.seq)
|
|
299
|
+
t_wrap_s = _stamp_seconds(msg.header.stamp)
|
|
300
|
+
delay_s = now_ros_s - t_wrap_s
|
|
301
|
+
transit = {
|
|
302
|
+
"peer": com_out.get("peer"),
|
|
303
|
+
"source": com_out.get("source"),
|
|
304
|
+
"target": com_out.get("target"),
|
|
305
|
+
"topic": com_out.get("base"),
|
|
306
|
+
"direction": com_out.get("direction"),
|
|
307
|
+
"stage": com_out.get("stage"),
|
|
308
|
+
"t_wrap": t_wrap_s,
|
|
309
|
+
"t_com_out": now_ros_s,
|
|
310
|
+
"keyframe": keyframe,
|
|
311
|
+
}
|
|
282
312
|
else:
|
|
283
313
|
header = getattr(msg, "header", None)
|
|
284
314
|
stamp = getattr(header, "stamp", None) if header is not None else None
|
|
@@ -451,6 +451,15 @@ class StageObservation:
|
|
|
451
451
|
self.sequence_events.append((now, expected_delta, missing, reordered, missing))
|
|
452
452
|
|
|
453
453
|
if transit is not None and seq is not None:
|
|
454
|
+
# A sender-side com_out row observes its own machine's wrapper:
|
|
455
|
+
# a sequence gap there means the local observer missed the
|
|
456
|
+
# message, not that the link lost it, and an observed message
|
|
457
|
+
# was *sent*, not delivered. The distinct status values also
|
|
458
|
+
# keep the offline join honest: `join_transit_records` ranks
|
|
459
|
+
# only lost < reordered < delivered, so a sender row can never
|
|
460
|
+
# overwrite the receiving side's `lost` verdict for the same
|
|
461
|
+
# (source, topic, epoch, seq).
|
|
462
|
+
outbound = transit.get("direction") == "outbound"
|
|
454
463
|
common = {
|
|
455
464
|
"kind": "transit",
|
|
456
465
|
"peer": transit.get("peer"),
|
|
@@ -465,16 +474,21 @@ class StageObservation:
|
|
|
465
474
|
"epoch": self.epoch,
|
|
466
475
|
}
|
|
467
476
|
if missing_start is not None:
|
|
477
|
+
gap_time_field = "t_com_out" if outbound else "t_com_in"
|
|
468
478
|
for missing_seq in range(missing_start, int(seq)):
|
|
469
479
|
self.transit_records.append(
|
|
470
480
|
{
|
|
471
481
|
**common,
|
|
472
482
|
"seq": missing_seq,
|
|
473
|
-
"status": "lost",
|
|
483
|
+
"status": "unobserved" if outbound else "lost",
|
|
474
484
|
"t_wrap": None,
|
|
475
|
-
|
|
485
|
+
gap_time_field: None,
|
|
476
486
|
"clock_offset_ms": None,
|
|
477
|
-
"sections":
|
|
487
|
+
"sections": (
|
|
488
|
+
{"wrap_to_com_out_ms": None}
|
|
489
|
+
if outbound
|
|
490
|
+
else {"ota_hop_ms": None}
|
|
491
|
+
),
|
|
478
492
|
"size_bytes": None,
|
|
479
493
|
"inter_arrival_ms": None,
|
|
480
494
|
"jitter_ms": None,
|
|
@@ -493,27 +507,42 @@ class StageObservation:
|
|
|
493
507
|
if inter_arrival_s is not None:
|
|
494
508
|
self.last_inter_arrival_s = inter_arrival_s
|
|
495
509
|
self.last_transit_recv_wall = wall
|
|
510
|
+
if outbound:
|
|
511
|
+
# Same clock on both ends of this hop, so there is no
|
|
512
|
+
# corrected/uncorrected pair and no OTA section: the only
|
|
513
|
+
# honest number is the wrap->com_out relay hop.
|
|
514
|
+
status = "sent"
|
|
515
|
+
time_fields = {"t_com_out": transit.get("t_com_out")}
|
|
516
|
+
sections: Dict[str, Any] = {
|
|
517
|
+
"wrap_to_com_out_ms": (
|
|
518
|
+
round(delay_s * 1000.0, 3) if delay_s is not None else None
|
|
519
|
+
),
|
|
520
|
+
}
|
|
521
|
+
else:
|
|
522
|
+
status = sequence_status
|
|
523
|
+
time_fields = {"t_com_in": transit.get("t_com_in")}
|
|
524
|
+
sections = {
|
|
525
|
+
"ota_hop_ms": (
|
|
526
|
+
round(delay_s * 1000.0, 3) if delay_s is not None else None
|
|
527
|
+
),
|
|
528
|
+
"ota_hop_uncorrected_ms": (
|
|
529
|
+
round(raw_delay_s * 1000.0, 3)
|
|
530
|
+
if raw_delay_s is not None
|
|
531
|
+
else None
|
|
532
|
+
),
|
|
533
|
+
}
|
|
496
534
|
row = {
|
|
497
535
|
**common,
|
|
498
536
|
"seq": int(seq),
|
|
499
|
-
"status":
|
|
537
|
+
"status": status,
|
|
500
538
|
"t_wrap": transit.get("t_wrap"),
|
|
501
|
-
|
|
539
|
+
**time_fields,
|
|
502
540
|
"clock_offset_ms": (
|
|
503
541
|
round(clock_offset_s * 1000.0, 3)
|
|
504
542
|
if clock_offset_s is not None
|
|
505
543
|
else None
|
|
506
544
|
),
|
|
507
|
-
"sections":
|
|
508
|
-
"ota_hop_ms": (
|
|
509
|
-
round(delay_s * 1000.0, 3) if delay_s is not None else None
|
|
510
|
-
),
|
|
511
|
-
"ota_hop_uncorrected_ms": (
|
|
512
|
-
round(raw_delay_s * 1000.0, 3)
|
|
513
|
-
if raw_delay_s is not None
|
|
514
|
-
else None
|
|
515
|
-
),
|
|
516
|
-
},
|
|
545
|
+
"sections": sections,
|
|
517
546
|
"size_bytes": size,
|
|
518
547
|
"inter_arrival_ms": (
|
|
519
548
|
round(inter_arrival_s * 1000.0, 3)
|
|
@@ -232,15 +232,49 @@ parameters:
|
|
|
232
232
|
irt_1_topic: # e.g. /sensors/camera/front_wide/image_color
|
|
233
233
|
irt_1_transport: # e.g. raw
|
|
234
234
|
irt_1_out_transport: compressed # e.g. raw, compressed – determines the output remap format
|
|
235
|
+
irt_1_paced: # "true" -> decode reads ${irt_1_topic}/paced (playout pacer, PACE window)
|
|
235
236
|
irt_2_topic: # e.g. /sensors/front_camera/image_raw/compressed
|
|
236
237
|
irt_2_transport: # e.g. raw
|
|
237
238
|
irt_2_out_transport: compressed # e.g. raw, compressed – determines the output remap format
|
|
239
|
+
irt_2_paced: # "true" -> decode reads ${irt_2_topic}/paced
|
|
238
240
|
irt_3_topic: # e.g. /sensor/front_camera/image_color/compressed
|
|
239
241
|
irt_3_transport: # e.g. raw
|
|
240
242
|
irt_3_out_transport: compressed # e.g. raw, compressed – determines the output remap format
|
|
243
|
+
irt_3_paced: # "true" -> decode reads ${irt_3_topic}/paced
|
|
241
244
|
irt_4_topic: # e.g. /sensor/front_camera/image_color/compressed
|
|
242
245
|
irt_4_transport: # e.g. raw
|
|
243
246
|
irt_4_out_transport: compressed # e.g. raw, compressed – determines the output remap format
|
|
247
|
+
irt_4_paced: # "true" -> decode reads ${irt_4_topic}/paced
|
|
248
|
+
|
|
249
|
+
# Receiver-side playout pacing (transport.playout in the session definition):
|
|
250
|
+
# re-times the arrived encoded stream on '<topic>/paced' so the decode sees a
|
|
251
|
+
# steady cadence instead of the network's delay jitter. Never reorders, never
|
|
252
|
+
# drops; late packets pass through immediately.
|
|
253
|
+
pace: false
|
|
254
|
+
pace_1_topic: # the arrived encoded stream, e.g. /camera/image/ffmpeg
|
|
255
|
+
pace_1_msg_type: # e.g. ffmpeg_image_transport_msgs/msg/FFMPEGPacket
|
|
256
|
+
pace_1_adaptive: # "true" | "false"
|
|
257
|
+
pace_1_target_ms: # fixed budget when adaptive is "false"
|
|
258
|
+
pace_1_min_ms: # adaptive clamp above the observed delay floor
|
|
259
|
+
pace_1_max_ms:
|
|
260
|
+
pace_2_topic:
|
|
261
|
+
pace_2_msg_type:
|
|
262
|
+
pace_2_adaptive:
|
|
263
|
+
pace_2_target_ms:
|
|
264
|
+
pace_2_min_ms:
|
|
265
|
+
pace_2_max_ms:
|
|
266
|
+
pace_3_topic:
|
|
267
|
+
pace_3_msg_type:
|
|
268
|
+
pace_3_adaptive:
|
|
269
|
+
pace_3_target_ms:
|
|
270
|
+
pace_3_min_ms:
|
|
271
|
+
pace_3_max_ms:
|
|
272
|
+
pace_4_topic:
|
|
273
|
+
pace_4_msg_type:
|
|
274
|
+
pace_4_adaptive:
|
|
275
|
+
pace_4_target_ms:
|
|
276
|
+
pace_4_min_ms:
|
|
277
|
+
pace_4_max_ms:
|
|
244
278
|
|
|
245
279
|
common:
|
|
246
280
|
before_commands:
|
|
@@ -623,6 +657,30 @@ windows:
|
|
|
623
657
|
- args+=(--remap "${in_remap}:=${it_4_topic}" --remap "out/${it_4_transport}:=${it_4_topic}/${outgoing_suffix}")
|
|
624
658
|
- echo ${args[@]}
|
|
625
659
|
- ${args[@]}
|
|
660
|
+
- name: PACE
|
|
661
|
+
if: pace
|
|
662
|
+
layout: even-vertical
|
|
663
|
+
splits:
|
|
664
|
+
- commands:
|
|
665
|
+
- if [ '${pace_1_topic}' = "None" ]; then exit; fi
|
|
666
|
+
- args=(ros2 run com_py playout_pacer --ros-args -p topic:=${pace_1_topic} -p msg_type:=${pace_1_msg_type} -p adaptive:=${pace_1_adaptive} -p target_ms:=${pace_1_target_ms} -p min_ms:=${pace_1_min_ms} -p max_ms:=${pace_1_max_ms} -p qos_config_file:='${qos_config_file}')
|
|
667
|
+
- echo ${args[@]}
|
|
668
|
+
- ${args[@]}
|
|
669
|
+
- commands:
|
|
670
|
+
- if [ '${pace_2_topic}' = "None" ]; then exit; fi
|
|
671
|
+
- args=(ros2 run com_py playout_pacer --ros-args -p topic:=${pace_2_topic} -p msg_type:=${pace_2_msg_type} -p adaptive:=${pace_2_adaptive} -p target_ms:=${pace_2_target_ms} -p min_ms:=${pace_2_min_ms} -p max_ms:=${pace_2_max_ms} -p qos_config_file:='${qos_config_file}')
|
|
672
|
+
- echo ${args[@]}
|
|
673
|
+
- ${args[@]}
|
|
674
|
+
- commands:
|
|
675
|
+
- if [ '${pace_3_topic}' = "None" ]; then exit; fi
|
|
676
|
+
- args=(ros2 run com_py playout_pacer --ros-args -p topic:=${pace_3_topic} -p msg_type:=${pace_3_msg_type} -p adaptive:=${pace_3_adaptive} -p target_ms:=${pace_3_target_ms} -p min_ms:=${pace_3_min_ms} -p max_ms:=${pace_3_max_ms} -p qos_config_file:='${qos_config_file}')
|
|
677
|
+
- echo ${args[@]}
|
|
678
|
+
- ${args[@]}
|
|
679
|
+
- commands:
|
|
680
|
+
- if [ '${pace_4_topic}' = "None" ]; then exit; fi
|
|
681
|
+
- args=(ros2 run com_py playout_pacer --ros-args -p topic:=${pace_4_topic} -p msg_type:=${pace_4_msg_type} -p adaptive:=${pace_4_adaptive} -p target_ms:=${pace_4_target_ms} -p min_ms:=${pace_4_min_ms} -p max_ms:=${pace_4_max_ms} -p qos_config_file:='${qos_config_file}')
|
|
682
|
+
- echo ${args[@]}
|
|
683
|
+
- ${args[@]}
|
|
626
684
|
- name: IRT
|
|
627
685
|
if: irt
|
|
628
686
|
layout: even-vertical
|
|
@@ -630,28 +688,32 @@ windows:
|
|
|
630
688
|
- commands:
|
|
631
689
|
- if [ '${irt_1_topic}' = "None" ]; then exit; fi
|
|
632
690
|
- if [[ "${irt_1_out_transport}" == "raw" ]]; then out_remap="out"; else out_remap="out/${irt_1_out_transport}"; fi
|
|
691
|
+
- if [[ "${irt_1_paced}" != "None" ]]; then irt_in_topic="${irt_1_topic}/paced"; else irt_in_topic="${irt_1_topic}"; fi
|
|
633
692
|
- args=(ros2 run image_transport republish --ros-args -r __node:=irt_republish1 -p in_transport:=${irt_1_transport} -p out_transport:=${irt_1_out_transport}
|
|
634
|
-
--remap in/${irt_1_transport}:=${
|
|
693
|
+
--remap in/${irt_1_transport}:=${irt_in_topic} --remap ${out_remap}:=${irt_1_topic}/${irt_1_out_transport})
|
|
635
694
|
- echo ${args[@]}
|
|
636
695
|
- ${args[@]}
|
|
637
696
|
- commands:
|
|
638
697
|
- if [ '${irt_2_topic}' = "None" ]; then exit; fi
|
|
639
698
|
- if [[ "${irt_2_out_transport}" == "raw" ]]; then out_remap="out"; else out_remap="out/${irt_2_out_transport}"; fi
|
|
699
|
+
- if [[ "${irt_2_paced}" != "None" ]]; then irt_in_topic="${irt_2_topic}/paced"; else irt_in_topic="${irt_2_topic}"; fi
|
|
640
700
|
- args=(ros2 run image_transport republish --ros-args -r __node:=irt_republish2 -p in_transport:=${irt_2_transport} -p out_transport:=${irt_2_out_transport}
|
|
641
|
-
--remap in/${irt_2_transport}:=${
|
|
701
|
+
--remap in/${irt_2_transport}:=${irt_in_topic} --remap ${out_remap}:=${irt_2_topic}/${irt_2_out_transport})
|
|
642
702
|
- echo ${args[@]}
|
|
643
703
|
- ${args[@]}
|
|
644
704
|
- commands:
|
|
645
705
|
- if [ '${irt_3_topic}' = "None" ]; then exit; fi
|
|
646
706
|
- if [[ "${irt_3_out_transport}" == "raw" ]]; then out_remap="out"; else out_remap="out/${irt_3_out_transport}"; fi
|
|
707
|
+
- if [[ "${irt_3_paced}" != "None" ]]; then irt_in_topic="${irt_3_topic}/paced"; else irt_in_topic="${irt_3_topic}"; fi
|
|
647
708
|
- args=(ros2 run image_transport republish --ros-args -r __node:=irt_republish3 -p in_transport:=${irt_3_transport} -p out_transport:=${irt_3_out_transport}
|
|
648
|
-
--remap in/${irt_3_transport}:=${
|
|
709
|
+
--remap in/${irt_3_transport}:=${irt_in_topic} --remap ${out_remap}:=${irt_3_topic}/${irt_3_out_transport})
|
|
649
710
|
- echo ${args[@]}
|
|
650
711
|
- ${args[@]}
|
|
651
712
|
- commands:
|
|
652
713
|
- if [ '${irt_4_topic}' = "None" ]; then exit; fi
|
|
653
714
|
- if [[ "${irt_4_out_transport}" == "raw" ]]; then out_remap="out"; else out_remap="out/${irt_4_out_transport}"; fi
|
|
715
|
+
- if [[ "${irt_4_paced}" != "None" ]]; then irt_in_topic="${irt_4_topic}/paced"; else irt_in_topic="${irt_4_topic}"; fi
|
|
654
716
|
- args=(ros2 run image_transport republish --ros-args -r __node:=irt_republish4 -p in_transport:=${irt_4_transport} -p out_transport:=${irt_4_out_transport}
|
|
655
|
-
--remap in/${irt_4_transport}:=${
|
|
717
|
+
--remap in/${irt_4_transport}:=${irt_in_topic} --remap ${out_remap}:=${irt_4_topic}/${irt_4_out_transport})
|
|
656
718
|
- echo ${args[@]}
|
|
657
719
|
- ${args[@]}
|
|
@@ -92,6 +92,13 @@ class TransportSpec:
|
|
|
92
92
|
#: image_transport itself, or one that only forwards or records packets,
|
|
93
93
|
#: does not want a second copy of every frame.
|
|
94
94
|
remote_republish: Optional[str] = None
|
|
95
|
+
#: Receiver-side playout pacing (issue #284): re-time the arrived packet
|
|
96
|
+
#: stream to smooth network delay jitter before the reverse republish
|
|
97
|
+
#: decodes it. Keys: adaptive / target_ms / min_ms / max_ms (validated in
|
|
98
|
+
#: the parser; defaults live in the playout_pacer node). Requires
|
|
99
|
+
#: `remote_republish`, because the pacer publishes on `<encoded>/paced`
|
|
100
|
+
#: and only the republish remap keeps the delivered topic name unchanged.
|
|
101
|
+
playout: Optional[Dict[str, Any]] = None
|
|
95
102
|
|
|
96
103
|
|
|
97
104
|
@dataclass
|
|
@@ -1692,12 +1699,45 @@ def _compute_pipeline(
|
|
|
1692
1699
|
)
|
|
1693
1700
|
return str(value)
|
|
1694
1701
|
|
|
1695
|
-
|
|
1702
|
+
remote_republish = _republish("remote_republish")
|
|
1703
|
+
|
|
1704
|
+
playout: Optional[Dict[str, Any]] = None
|
|
1705
|
+
playout_cfg = t.get("playout")
|
|
1706
|
+
if playout_cfg is not None:
|
|
1707
|
+
if not isinstance(playout_cfg, dict):
|
|
1708
|
+
raise ValueError(f"transport.playout must be a mapping for topic '{entry.base}'")
|
|
1709
|
+
allowed = {"adaptive", "target_ms", "min_ms", "max_ms"}
|
|
1710
|
+
unknown = sorted(set(playout_cfg) - allowed)
|
|
1711
|
+
if unknown:
|
|
1712
|
+
raise ValueError(
|
|
1713
|
+
f"transport.playout for topic '{entry.base}' has unknown keys {unknown}; "
|
|
1714
|
+
f"allowed: {sorted(allowed)}"
|
|
1715
|
+
)
|
|
1716
|
+
if remote_republish is None:
|
|
1717
|
+
raise ValueError(
|
|
1718
|
+
f"transport.playout for topic '{entry.base}' requires remote_republish: "
|
|
1719
|
+
"the pacer publishes on '<encoded>/paced', and only the reverse republish's "
|
|
1720
|
+
"input remap keeps the delivered topic name unchanged. Without a republish "
|
|
1721
|
+
"the receiver would have to subscribe a renamed topic."
|
|
1722
|
+
)
|
|
1723
|
+
for key in ("target_ms", "min_ms", "max_ms"):
|
|
1724
|
+
if key in playout_cfg and (not isinstance(playout_cfg[key], (int, float)) or playout_cfg[key] <= 0):
|
|
1725
|
+
raise ValueError(f"transport.playout.{key} must be a positive number for topic '{entry.base}'")
|
|
1726
|
+
min_ms = float(playout_cfg.get("min_ms", 100.0))
|
|
1727
|
+
max_ms = float(playout_cfg.get("max_ms", 800.0))
|
|
1728
|
+
if max_ms < min_ms:
|
|
1729
|
+
raise ValueError(f"transport.playout.max_ms must be >= min_ms for topic '{entry.base}'")
|
|
1730
|
+
if "adaptive" in playout_cfg and not isinstance(playout_cfg["adaptive"], bool):
|
|
1731
|
+
raise ValueError(f"transport.playout.adaptive must be a boolean for topic '{entry.base}'")
|
|
1732
|
+
playout = dict(playout_cfg)
|
|
1733
|
+
|
|
1734
|
+
params = {k: v for k, v in t.items() if k not in ("type", "playout", *republish_keys)}
|
|
1696
1735
|
transport = TransportSpec(
|
|
1697
1736
|
type=ttype,
|
|
1698
1737
|
params=params,
|
|
1699
1738
|
local_republish=_republish("local_republish"),
|
|
1700
|
-
remote_republish=
|
|
1739
|
+
remote_republish=remote_republish,
|
|
1740
|
+
playout=playout,
|
|
1701
1741
|
)
|
|
1702
1742
|
|
|
1703
1743
|
topic = entry.base
|
|
@@ -3201,21 +3241,46 @@ def func(
|
|
|
3201
3241
|
# it encoded and (b) the decode of what arrived. Both run on *this* peer;
|
|
3202
3242
|
# what differs is which copy they decode and which transport the session
|
|
3203
3243
|
# asked each of them to publish in.
|
|
3204
|
-
|
|
3244
|
+
# The sender's own preview decode is never paced: it reads the local
|
|
3245
|
+
# copy of what it just encoded, so there is no network jitter to
|
|
3246
|
+
# absorb. Playout pacing exists on the receiving side only.
|
|
3247
|
+
irt_all: List[Tuple[str, str, str, Optional[Dict[str, Any]]]] = []
|
|
3205
3248
|
for t, tspec in irt_items_local:
|
|
3206
3249
|
assert tspec is not None
|
|
3207
|
-
irt_all.append((t, tspec.type, str(tspec.local_republish)))
|
|
3208
|
-
irt_all.extend(
|
|
3250
|
+
irt_all.append((t, tspec.type, str(tspec.local_republish), None))
|
|
3251
|
+
irt_all.extend(
|
|
3252
|
+
(topic, tspec.type, str(tspec.remote_republish), tspec.playout) for topic, tspec in irt_items_remote
|
|
3253
|
+
)
|
|
3209
3254
|
_assert_max("irt", irt_all, 4)
|
|
3210
3255
|
if irt_all:
|
|
3211
3256
|
items2 = [("irt", True)]
|
|
3212
|
-
for i, (topic, _ttype, _out_transport) in enumerate(irt_all, 1):
|
|
3257
|
+
for i, (topic, _ttype, _out_transport, _playout) in enumerate(irt_all, 1):
|
|
3213
3258
|
items2.append((f"irt_{i}_topic", topic))
|
|
3214
|
-
for i, (_topic, ttype, out_transport) in enumerate(irt_all, 1):
|
|
3259
|
+
for i, (_topic, ttype, out_transport, playout) in enumerate(irt_all, 1):
|
|
3215
3260
|
items2.append((f"irt_{i}_transport", ttype))
|
|
3216
3261
|
items2.append((f"irt_{i}_out_transport", out_transport))
|
|
3262
|
+
if playout is not None:
|
|
3263
|
+
# Points the decode's input remap at '<topic>/paced'; the
|
|
3264
|
+
# pacer itself runs in the PACE window below.
|
|
3265
|
+
items2.append((f"irt_{i}_paced", "true"))
|
|
3217
3266
|
blocks.append(PluginBlock("irt", items2))
|
|
3218
3267
|
|
|
3268
|
+
paced_entries = [
|
|
3269
|
+
(i, topic, ttype, playout)
|
|
3270
|
+
for i, (topic, ttype, _out_transport, playout) in enumerate(irt_all, 1)
|
|
3271
|
+
if playout is not None
|
|
3272
|
+
]
|
|
3273
|
+
if paced_entries:
|
|
3274
|
+
items_pace: List[Tuple[str, Any]] = [("pace", True)]
|
|
3275
|
+
for i, topic, ttype, playout in paced_entries:
|
|
3276
|
+
items_pace.append((f"pace_{i}_topic", topic))
|
|
3277
|
+
items_pace.append((f"pace_{i}_msg_type", TRANSPORT_OUTPUT_TYPES[ttype]))
|
|
3278
|
+
items_pace.append((f"pace_{i}_adaptive", "true" if playout.get("adaptive", True) else "false"))
|
|
3279
|
+
items_pace.append((f"pace_{i}_target_ms", float(playout.get("target_ms", 350.0))))
|
|
3280
|
+
items_pace.append((f"pace_{i}_min_ms", float(playout.get("min_ms", 100.0))))
|
|
3281
|
+
items_pace.append((f"pace_{i}_max_ms", float(playout.get("max_ms", 800.0))))
|
|
3282
|
+
blocks.append(PluginBlock("pace", items_pace))
|
|
3283
|
+
|
|
3219
3284
|
if nor_items:
|
|
3220
3285
|
items2 = [("nor", True)]
|
|
3221
3286
|
nor_prefix = f"/{peer_name[remote]}" if bool(inbound_cfg.get("keep_source_prefix", False)) else ""
|
|
@@ -233,3 +233,76 @@ def test_generated_peer_files_wire_the_wrapped_camera(tmp_path: Path) -> None:
|
|
|
233
233
|
# ... and what the application finally reads is the decoded image.
|
|
234
234
|
assert stages["native_in"]["topic"] == "/camera/image/ffmpeg/raw"
|
|
235
235
|
assert stages["native_in"]["type"] == "sensor_msgs/msg/Image"
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
# ---------------------------------------------------------------------------
|
|
239
|
+
# receiver-side playout pacing (transport.playout, issue #284)
|
|
240
|
+
# ---------------------------------------------------------------------------
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def test_playout_requires_a_receiver_republish() -> None:
|
|
244
|
+
"""Without a reverse republish the pacer would rename the delivered topic."""
|
|
245
|
+
with pytest.raises(ValueError, match="requires remote_republish"):
|
|
246
|
+
_pipeline({"transport": {"type": "ffmpeg", "playout": {"min_ms": 100}}})
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def test_playout_rejects_unknown_keys_and_bad_numbers() -> None:
|
|
250
|
+
with pytest.raises(ValueError, match="unknown keys"):
|
|
251
|
+
_pipeline(_ffmpeg(playout={"budget_ms": 350}))
|
|
252
|
+
with pytest.raises(ValueError, match="positive number"):
|
|
253
|
+
_pipeline(_ffmpeg(playout={"target_ms": -1}))
|
|
254
|
+
with pytest.raises(ValueError, match="max_ms must be >= min_ms"):
|
|
255
|
+
_pipeline(_ffmpeg(playout={"min_ms": 500, "max_ms": 100}))
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def test_playout_never_leaks_into_encoder_params() -> None:
|
|
259
|
+
_entry, pipe = _pipeline(_ffmpeg(gop_size=3, playout={"min_ms": 100, "max_ms": 800}))
|
|
260
|
+
tspec = pipe["transport"]
|
|
261
|
+
assert tspec.playout == {"min_ms": 100, "max_ms": 800}
|
|
262
|
+
assert "playout" not in tspec.params
|
|
263
|
+
assert tspec.params["gop_size"] == 3
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def test_playout_does_not_rename_the_delivered_topic() -> None:
|
|
267
|
+
"""The pacer sits between unwrapper and decode; what the application reads keeps its name."""
|
|
268
|
+
_entry, plain = _pipeline(_ffmpeg())
|
|
269
|
+
_entry, paced = _pipeline(_ffmpeg(playout={}))
|
|
270
|
+
assert generator._delivered_topic(paced, paced["final"]) == generator._delivered_topic(plain, plain["final"])
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def test_generated_peer_files_wire_the_pacer(tmp_path: Path) -> None:
|
|
274
|
+
processing = {
|
|
275
|
+
"transport": {
|
|
276
|
+
"type": "ffmpeg",
|
|
277
|
+
"gop_size": 3,
|
|
278
|
+
"remote_republish": "compressed",
|
|
279
|
+
"playout": {"adaptive": True, "min_ms": 120, "max_ms": 600},
|
|
280
|
+
},
|
|
281
|
+
"use_ota_wrapper": True,
|
|
282
|
+
}
|
|
283
|
+
generator.func(
|
|
284
|
+
session_config_obj=_camera_cfg(processing),
|
|
285
|
+
output_dir=str(tmp_path),
|
|
286
|
+
force=True,
|
|
287
|
+
peer_addresses={"a": "127.0.0.1", "b": "127.0.0.2"},
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
receiver = (tmp_path / "a" / "plugin.yaml").read_text(encoding="utf-8")
|
|
291
|
+
# The pacer runs on the receiving peer against the arrived encoded stream...
|
|
292
|
+
assert "pace_1_topic: /camera/image/ffmpeg" in receiver
|
|
293
|
+
assert "pace_1_msg_type: ffmpeg_image_transport_msgs/msg/FFMPEGPacket" in receiver
|
|
294
|
+
assert (
|
|
295
|
+
"pace_1_adaptive: 'true'" in receiver
|
|
296
|
+
or 'pace_1_adaptive: "true"' in receiver
|
|
297
|
+
or "pace_1_adaptive: true" in receiver
|
|
298
|
+
)
|
|
299
|
+
assert "pace_1_min_ms: 120.0" in receiver
|
|
300
|
+
assert "pace_1_max_ms: 600.0" in receiver
|
|
301
|
+
# ...and the decode reads the paced copy.
|
|
302
|
+
assert "irt_1_paced" in receiver
|
|
303
|
+
|
|
304
|
+
# The sender has no pacer: its preview (if any) reads its own encode, and
|
|
305
|
+
# this session declares no local_republish at all.
|
|
306
|
+
sender = (tmp_path / "b" / "plugin.yaml").read_text(encoding="utf-8")
|
|
307
|
+
assert "pace" not in sender or "pace_1_topic" not in sender
|
|
308
|
+
assert "irt_1_paced" not in sender
|