Skip to content

Commit 21782a5

Browse files
kineticsystemclaude
authored andcommitted
Fixed issue with first visualization mask not being received by the UI
Web Video Server subscriber now automatically detects publisher QoS when no qos_profile query parameter is specified (defaults to "auto"). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 4b5f4e3 commit 21782a5

1 file changed

Lines changed: 78 additions & 13 deletions

File tree

src/streamers/image_transport_streamer.cpp

Lines changed: 78 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <exception>
3535
#include <functional>
3636
#include <mutex>
37+
#include <optional>
3738
#include <string>
3839
#include <vector>
3940

@@ -55,7 +56,9 @@
5556
#include "image_transport/transport_hints.hpp"
5657
#include "rclcpp/node.hpp"
5758
#include "rclcpp/logging.hpp"
59+
#include "rclcpp/qos.hpp"
5860
#include "rmw/qos_profiles.h"
61+
#include "rmw/types.h"
5962
#include "sensor_msgs/msg/image.hpp"
6063

6164
#include "web_video_server/streamer.hpp"
@@ -84,6 +87,78 @@ std::vector<std::string> get_image_topics(rclcpp::Node & node)
8487
return result;
8588
}
8689

90+
std::optional<rmw_qos_profile_t> detect_publisher_qos(
91+
const rclcpp::Node::SharedPtr & node,
92+
const rclcpp::Logger & logger,
93+
const std::string & topic)
94+
{
95+
RCLCPP_INFO(logger, "Attempting to auto-detect QoS for topic: %s", topic.c_str());
96+
97+
const auto topic_endpoint_info_array = node->get_publishers_info_by_topic(topic);
98+
if (topic_endpoint_info_array.empty()) {
99+
RCLCPP_WARN(logger, "No publishers found for topic: %s", topic.c_str());
100+
return std::nullopt;
101+
}
102+
103+
// Use the first publisher's QoS as reference.
104+
const auto & endpoint_info = topic_endpoint_info_array.front();
105+
const auto qos_profile = endpoint_info.qos_profile();
106+
107+
const std::string reliability =
108+
(qos_profile.reliability() == rclcpp::ReliabilityPolicy::Reliable) ? "RELIABLE" : "BEST_EFFORT";
109+
const std::string durability =
110+
(qos_profile.durability() == rclcpp::DurabilityPolicy::TransientLocal) ?
111+
"TRANSIENT_LOCAL" : "VOLATILE";
112+
113+
RCLCPP_INFO(
114+
logger, "Detected QoS - Reliability: %s, Durability: %s, History depth: %zu",
115+
reliability.c_str(), durability.c_str(), qos_profile.depth());
116+
117+
// Convert rclcpp QoS to rmw QoS profile.
118+
auto rmw_qos = rmw_qos_profile_default;
119+
rmw_qos.reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT;
120+
rmw_qos.durability = RMW_QOS_POLICY_DURABILITY_VOLATILE;
121+
rmw_qos.history = RMW_QOS_POLICY_HISTORY_KEEP_LAST;
122+
rmw_qos.depth = qos_profile.depth();
123+
124+
if (qos_profile.reliability() == rclcpp::ReliabilityPolicy::Reliable) {
125+
rmw_qos.reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
126+
}
127+
if (qos_profile.durability() == rclcpp::DurabilityPolicy::TransientLocal) {
128+
rmw_qos.durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
129+
}
130+
131+
return rmw_qos;
132+
}
133+
134+
std::optional<rmw_qos_profile_t> get_qos_profile(
135+
const rclcpp::Node::SharedPtr & node,
136+
const rclcpp::Logger & logger,
137+
const std::string & profile_name,
138+
const std::string & topic)
139+
{
140+
if (profile_name == "auto") {
141+
auto qos_profile = detect_publisher_qos(node, logger, topic);
142+
if (!qos_profile) {
143+
RCLCPP_WARN(
144+
logger, "Could not auto-detect QoS for topic %s. Using default profile.", topic.c_str());
145+
return rmw_qos_profile_default;
146+
}
147+
RCLCPP_INFO(logger, "Using auto-detected QoS profile for topic %s", topic.c_str());
148+
return qos_profile;
149+
}
150+
151+
RCLCPP_INFO(
152+
logger, "Using specified QoS profile %s for topic %s", profile_name.c_str(), topic.c_str());
153+
auto qos_profile = web_video_server::get_qos_profile_from_name(profile_name);
154+
if (!qos_profile) {
155+
RCLCPP_ERROR(
156+
logger, "Invalid QoS profile %s specified. Using default profile.", profile_name.c_str());
157+
return rmw_qos_profile_default;
158+
}
159+
return qos_profile;
160+
}
161+
87162
} // namespace
88163

89164
ImageTransportStreamerBase::ImageTransportStreamerBase(
@@ -97,7 +172,7 @@ ImageTransportStreamerBase::ImageTransportStreamerBase(
97172
output_height_ = request.get_query_param_value_or_default<int>("height", -1);
98173
invert_ = request.has_query_param("invert");
99174
default_transport_ = request.get_query_param_value_or_default("default_transport", "raw");
100-
qos_profile_name_ = request.get_query_param_value_or_default("qos_profile", "default");
175+
qos_profile_name_ = request.get_query_param_value_or_default("qos_profile", "auto");
101176
}
102177

103178
ImageTransportStreamerBase::~ImageTransportStreamerBase()
@@ -133,18 +208,8 @@ void ImageTransportStreamerBase::start()
133208
}
134209
}
135210

136-
// Get QoS profile from query parameter
137-
RCLCPP_INFO(
138-
logger_, "Streaming topic %s with QoS profile %s", topic_.c_str(),
139-
qos_profile_name_.c_str());
140-
auto qos_profile = get_qos_profile_from_name(qos_profile_name_);
141-
if (!qos_profile) {
142-
qos_profile = rmw_qos_profile_default;
143-
RCLCPP_ERROR(
144-
logger_,
145-
"Invalid QoS profile %s specified. Using default profile.",
146-
qos_profile_name_.c_str());
147-
}
211+
// Get QoS profile based on user selection or auto-detect.
212+
const auto qos_profile = get_qos_profile(node, logger_, qos_profile_name_, topic_);
148213

149214
// Create subscriber
150215
image_sub_ = image_transport::create_subscription(

0 commit comments

Comments
 (0)