3434#include < exception>
3535#include < functional>
3636#include < mutex>
37+ #include < optional>
3738#include < string>
3839#include < vector>
3940
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
89164ImageTransportStreamerBase::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
103178ImageTransportStreamerBase::~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