CARLA
Loading...
Searching...
No Matches
Dispatcher.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma
2// de Barcelona (UAB).
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
8
9#include "carla/Exception.h"
10#include "carla/Logging.h"
12
13#include <exception>
14
15namespace carla {
16namespace streaming {
17namespace detail {
18
20 // Disconnect all the sessions from their streams, this should kill any
21 // session remaining since at this point the io_context should be already
22 // stopped.
23 for (auto &pair : _stream_map) {
24#ifndef LIBCARLA_NO_EXCEPTIONS
25 try {
26#endif // LIBCARLA_NO_EXCEPTIONS
27 auto stream_state = pair.second;
28 stream_state->ClearSessions();
29#ifndef LIBCARLA_NO_EXCEPTIONS
30 } catch (const std::exception &e) {
31 log_error("failed to clear sessions:", e.what());
32 }
33#endif // LIBCARLA_NO_EXCEPTIONS
34 }
35 }
36
38 std::scoped_lock<std::mutex> lock(_mutex);
39 ++_cached_token._token.stream_id; // id zero only happens in overflow.
41 std::shared_ptr<MultiStreamState> ptr;
42 auto search = _stream_map.find(_cached_token.get_stream_id());
43 if (search == _stream_map.end()) {
44 // creating new stream
45 ptr = std::make_shared<MultiStreamState>(_cached_token);
46 auto result = _stream_map.emplace(std::make_pair(_cached_token.get_stream_id(), ptr));
47 if (!result.second) {
48 throw_exception(std::runtime_error("failed to create stream!"));
49 }
51 ptr->EnableForROS();
52 }
53 log_debug("Stream created");
54 return carla::streaming::Stream(ptr);
55 } else {
56 // reusing existing stream
57 log_debug("Stream reused");
58 ptr = search->second;
59 return carla::streaming::Stream(ptr);
60 }
61 }
62
64 std::scoped_lock<std::mutex> lock(_mutex);
65 log_debug("Calling CloseStream for ", id);
66 auto search = _stream_map.find(id);
67 if (search != _stream_map.end()) {
68 auto stream_state = search->second;
69 if (stream_state) {
70 log_debug("Disconnecting all sessions (stream ", id, ")");
71 stream_state->ClearSessions();
72 }
73 _stream_map.erase(search);
74 }
75 }
76
77 std::optional<stream_id_type> Dispatcher::ResolveSessionStreamId(stream_id_type session_stream_id) const {
79 return session_stream_id;
80 }
81 auto alias = _stream_aliases.find(session_stream_id);
82 if (alias == _stream_aliases.end()) {
83 return std::nullopt;
84 }
85 return alias->second;
86 }
87
88 bool Dispatcher::RegisterSession(std::shared_ptr<Session> session) {
89 DEBUG_ASSERT(session != nullptr);
90 std::scoped_lock<std::mutex> lock(_mutex);
91 const auto stream_id = ResolveSessionStreamId(session->get_stream_id());
92 auto search = stream_id ? _stream_map.find(*stream_id) : _stream_map.end();
93 if (search != _stream_map.end()) {
94 auto stream_state = search->second;
95 if (stream_state) {
96 log_debug("Connecting session (stream ", session->get_stream_id(), ")");
97 _session_streams.insert_or_assign(session.get(), stream_state);
98 stream_state->ConnectSession(std::move(session));
99 log_debug("Current streams: ", _stream_map.size());
100 return true;
101 }
102 }
103 _session_streams.erase(session.get());
104 log_error("Invalid session: no stream available with id", session->get_stream_id());
105 return false;
106 }
107
108 void Dispatcher::DeregisterSession(std::shared_ptr<Session> session) {
109 DEBUG_ASSERT(session != nullptr);
110 std::scoped_lock<std::mutex> lock(_mutex);
111 log_debug("Calling DeregisterSession for ", session->get_stream_id());
112 // The stream the session joined, not a fresh lookup: an alias may have
113 // been retargeted to another stream since.
114 auto search = _session_streams.find(session.get());
115 if (search == _session_streams.end()) {
116 return;
117 }
118 auto stream_state = search->second.lock();
119 _session_streams.erase(search);
120 if (stream_state) {
121 log_debug("Disconnecting session (stream ", session->get_stream_id(), ")");
122 stream_state->DisconnectSession(session);
123 log_debug("Current streams: ", _stream_map.size());
124 }
125 }
126
128 std::scoped_lock<std::mutex> lock(_mutex);
129 log_debug("Searching sensor id: ", sensor_id);
130 auto search = _stream_map.find(sensor_id);
131 if (search != _stream_map.end()) {
132 log_debug("Found sensor id: ", sensor_id);
133 auto stream_state = search->second;
134 stream_state->ForceActive();
135 log_debug("Getting token from stream ", sensor_id, " on port ", stream_state->token().get_port());
136 return stream_state->token();
137 } else {
138 log_debug("Not Found sensor id, creating sensor stream: ", sensor_id);
139 token_type temp_token(_cached_token);
140 temp_token.set_stream_id(sensor_id);
141 auto ptr = std::make_shared<MultiStreamState>(temp_token);
142 auto result = _stream_map.emplace(std::make_pair(temp_token.get_stream_id(), ptr));
143 ptr->ForceActive();
144
146 ptr->EnableForROS();
147 }
148 if (!result.second) {
149 log_debug("Failed to create multistream for stream ", sensor_id, " on port ", temp_token.get_port());
150 }
151
152 log_debug("Created token from stream ", sensor_id, " on port ", temp_token.get_port());
153 return temp_token;
154 }
155 return token_type();
156 }
157
158 std::optional<token_type> Dispatcher::FindToken(stream_id_type stream_id) {
159 std::scoped_lock<std::mutex> lock(_mutex);
160 auto search = _stream_map.find(stream_id);
161 if (search == _stream_map.end()) {
162 return std::nullopt;
163 }
164 auto stream_state = search->second;
165 stream_state->ForceActive();
166 return stream_state->token();
167 }
168
170 std::scoped_lock<std::mutex> lock(_mutex);
172 }
173
175 std::scoped_lock<std::mutex> lock(_mutex);
176 _stream_aliases.insert_or_assign(alias, stream_id);
177 }
178
180 std::scoped_lock<std::mutex> lock(_mutex);
181 _stream_aliases.erase(alias);
182 }
183
184 std::optional<stream_id_type> Dispatcher::FindStreamAlias(stream_id_type alias) {
185 std::scoped_lock<std::mutex> lock(_mutex);
186 auto search = _stream_aliases.find(alias);
187 if (search == _stream_aliases.end()) {
188 return std::nullopt;
189 }
190 return search->second;
191 }
192
193} // namespace detail
194} // namespace streaming
195} // namespace carla
#define DEBUG_ASSERT(predicate)
Definition Debug.h:66
void SetSessionsUseStreamAliases(bool enabled)
When enabled, a session subscribes through an alias (see SetStreamAlias) and a stream id without an a...
void SetStreamAlias(stream_id_type alias, stream_id_type stream_id)
Routes sessions subscribing to alias to the local stream stream_id.
void DeregisterSession(std::shared_ptr< Session > session)
std::unordered_map< const Session *, std::weak_ptr< MultiStreamState > > _session_streams
Definition Dispatcher.h:112
std::optional< stream_id_type > ResolveSessionStreamId(stream_id_type session_stream_id) const
Stream a session subscribing to session_stream_id belongs to.
carla::streaming::Stream MakeStream()
std::optional< token_type > FindToken(stream_id_type stream_id)
Like GetToken(), but returns std::nullopt for an unknown stream_id instead of creating an empty strea...
bool RegisterSession(std::shared_ptr< Session > session)
std::optional< stream_id_type > FindStreamAlias(stream_id_type alias)
void CloseStream(carla::streaming::detail::stream_id_type id)
std::unordered_map< stream_id_type, stream_id_type > _stream_aliases
Definition Dispatcher.h:110
void RemoveStreamAlias(stream_id_type alias)
token_type GetToken(stream_id_type sensor_id)
Serializes a stream endpoint.
void set_stream_id(stream_id_type id)
detail::Stream< detail::MultiStreamState > Stream
A stream represents an unidirectional channel for sending data from server to client.
Definition Stream.h:19
This file contains definitions of common data structures used in traffic manager.
static void log_error(Args &&... args)
Definition Logging.h:110
void throw_exception(const ExceptionT &e)
Templated on the static type so the thrown object keeps its dynamic type: taking a const std::excepti...
Definition Exception.h:44
static void log_debug(Args &&... args)
Definition Logging.h:68