MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
SubsystemManager.cpp
Go to the documentation of this file.
3
5
7
9
11
13
15
16namespace MayaFlux::Core {
17
19 std::shared_ptr<Nodes::NodeGraphManager> node_graph_manager,
20 std::shared_ptr<Buffers::BufferManager> buffer_manager,
21 std::shared_ptr<Vruta::TaskScheduler> task_scheduler,
22 std::shared_ptr<Core::WindowManager> window_manager,
23 std::shared_ptr<InputManager> input_manager)
24 : m_node_graph_manager(std::move(node_graph_manager))
25 , m_buffer_manager(std::move(buffer_manager))
26 , m_task_scheduler(std::move(task_scheduler))
27 , m_window_manager(std::move(window_manager))
28 , m_input_manager(std::move(input_manager))
29{
32 std::source_location::current(),
33 "SubsystemManager requires valid NodeGraphManager");
34 }
35 if (!m_buffer_manager) {
37 std::source_location::current(),
38 "SubsystemManager requires valid BufferManager");
39 }
40 if (!m_task_scheduler) {
42 std::source_location::current(),
43 "SubsystemManager requires valid TaskScheduler");
44 }
45 if (!m_window_manager) {
47 "No WindowManager provided - Graphics subsystems will be unavailable");
48 }
49 if (!m_input_manager) {
51 "No InputManager provided - Input subsystems will be unavailable");
52 }
53}
54
56{
57 create_subsystem_internal<AudioSubsystem>(SubsystemType::AUDIO, stream_info);
58}
59
61{
62 if (!m_window_manager) {
63 error<std::runtime_error>(
66 std::source_location::current(),
67 "Cannot create GraphicsSubsystem without a valid WindowManager");
68 }
69
70 create_subsystem_internal<GraphicsSubsystem>(SubsystemType::GRAPHICS, graphics_config);
71}
72
74{
75 if (!m_input_manager) {
76 error<std::runtime_error>(
79 std::source_location::current(),
80 "Cannot create InputSubsystem without a valid InputManager");
81 }
82
83 create_subsystem_internal<InputSubsystem>(SubsystemType::INPUT, input_config);
84}
85
87{
88 create_subsystem_internal<NetworkSubsystem>(SubsystemType::NETWORK, network_config);
89}
90
91void SubsystemManager::add_subsystem(SubsystemType type, const std::shared_ptr<ISubsystem>& subsystem)
92{
93 auto tokens = subsystem->get_tokens();
94 auto handle = std::make_unique<SubsystemProcessingHandle>(
100 tokens);
101
102 subsystem->initialize(*handle);
103 subsystem->register_callbacks();
104
105 m_subsystems[type] = subsystem;
106 m_handles[type] = std::move(handle);
107}
108
109std::shared_ptr<AudioSubsystem> SubsystemManager::get_audio_subsystem()
110{
111 if (auto subsystem = std::dynamic_pointer_cast<AudioSubsystem>(get_subsystem(SubsystemType::AUDIO))) {
112 return subsystem;
113 }
114 return nullptr;
115}
116
117std::shared_ptr<GraphicsSubsystem> SubsystemManager::get_graphics_subsystem()
118{
119 if (auto subsystem = std::dynamic_pointer_cast<GraphicsSubsystem>(get_subsystem(SubsystemType::GRAPHICS))) {
120 return subsystem;
121 }
122 return nullptr;
123}
124
125std::shared_ptr<InputSubsystem> SubsystemManager::get_input_subsystem()
126{
127 if (auto subsystem = std::dynamic_pointer_cast<InputSubsystem>(get_subsystem(SubsystemType::INPUT))) {
128 return subsystem;
129 }
130 return nullptr;
131}
132
133std::shared_ptr<NetworkSubsystem> SubsystemManager::get_network_subsystem()
134{
135 if (auto subsystem = std::dynamic_pointer_cast<NetworkSubsystem>(get_subsystem(SubsystemType::NETWORK))) {
136 return subsystem;
137 }
138 return nullptr;
139}
140
142{
143 for (auto& [token, subsystem] : m_subsystems) {
144 if (subsystem->is_ready()) {
145 subsystem->start();
146 }
147 }
148}
149
151{
152 for (auto& [type, subsystem] : m_subsystems) {
153 if (subsystem->is_running()) {
154 subsystem->pause();
155 }
156 }
157}
158
160{
161 for (auto& [type, subsystem] : m_subsystems) {
162 if (subsystem->is_ready()) {
163 subsystem->resume();
164 }
165 }
166}
167
168std::shared_ptr<ISubsystem> SubsystemManager::get_subsystem(SubsystemType type)
169{
170 return has_subsystem(type) ? m_subsystems[type] : nullptr;
171}
172
174{
175 if (auto it = m_subsystems.find(type); it != m_subsystems.end()) {
176 it->second->shutdown();
177 m_subsystems.erase(it);
178 m_handles.erase(type);
179 m_cross_access_permissions.erase(type);
180 }
181}
182
183std::unordered_map<SubsystemType, std::pair<bool, bool>> SubsystemManager::query_subsystem_status() const
184{
185 std::unordered_map<SubsystemType, std::pair<bool, bool>> statuses;
186 for (const auto& [type, subsystem] : m_subsystems) {
187 if (subsystem == nullptr) {
188 statuses[type] = { false, false };
189 continue;
190 }
191 statuses[type] = { subsystem->is_ready(), subsystem->is_running() };
192 }
193 return statuses;
194}
195
197{
198 for (auto& [token, subsystem] : m_subsystems) {
199 if (subsystem && subsystem->is_running()) {
200 subsystem->stop();
201 }
202 }
203}
204
206{
207 if (auto audio = get_audio_subsystem()) {
208 audio->stop();
209 }
210}
211
213{
214 if (auto graphics = get_graphics_subsystem()) {
215 graphics->stop();
216 }
217}
218
220{
221 if (auto input = get_input_subsystem()) {
222 input->stop();
223 }
224}
225
227{
228 for (auto& [token, subsystem] : m_subsystems) {
229 if (subsystem && subsystem->is_ready()) {
230 subsystem->shutdown();
231 }
232 }
233 m_subsystems.clear();
234}
235
237{
238 auto it = m_cross_access_permissions.find(from);
239 return it != m_cross_access_permissions.end() && it->second.count(to) > 0;
240}
241
246
247std::optional<std::span<const double>> SubsystemManager::read_cross_subsystem_buffer(
248 SubsystemType requesting_type,
249 SubsystemType target_type,
250 uint32_t channel)
251{
252 std::shared_lock lock(m_mutex);
253
254 if (m_subsystems.find(requesting_type) == m_subsystems.end()) {
255 return std::nullopt;
256 }
257
258 if (!is_cross_access_allowed(requesting_type, target_type)) {
259 return std::nullopt;
260 }
261
262 auto target_token = m_subsystems[target_type]->get_tokens();
263
264 try {
265 return m_buffer_manager->get_buffer_data(target_token.Buffer, channel);
266 } catch (...) {
267 return std::nullopt;
268 }
269}
270
272{
273 auto subsystem_it = m_subsystems.find(type);
274 if (subsystem_it == m_subsystems.end()) {
276 "Invalid subsystem type: Subsystem not found.");
277 return nullptr;
278 }
279
280 auto handle = subsystem_it->second->get_processing_context_handle();
281 if (!handle) {
283 "Invalid processing context handle: Handle is null.");
284 return nullptr;
285 }
286
287 return handle;
288}
289
291{
292 auto handle = get_validated_handle(type);
293 if (!handle)
294 return;
295
296 if (!hook) {
298 "Invalid process hook: Hook cannot be null or invalid.");
299 return;
300 }
301
303 handle->pre_process_hooks[name] = std::move(hook);
304 } else {
305 handle->post_process_hooks[name] = std::move(hook);
306 }
307}
308
310{
311 auto handle = get_validated_handle(type);
312 if (!handle)
313 return;
314
315 if (handle->pre_process_hooks.erase(name) == 0) {
316 handle->post_process_hooks.erase(name);
317 }
318}
319
320bool SubsystemManager::has_process_hook(SubsystemType type, const std::string& name)
321{
322 auto handle = get_validated_handle(type);
323 if (!handle)
324 return false;
325
326 return handle->pre_process_hooks.contains(name) || handle->post_process_hooks.contains(name);
327}
328
329}
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
glm::vec3 position
uint32_t channel
std::shared_ptr< Buffers::BufferManager > m_buffer_manager
void unregister_process_hook(SubsystemType type, const std::string &name)
Remove a previously registered processing hook.
bool has_process_hook(SubsystemType type, const std::string &name)
Check if a processing hook exists.
void stop()
Stop all subsystems.
void stop_input_subsystem()
Stop the input subsystem.
std::shared_ptr< Nodes::NodeGraphManager > m_node_graph_manager
void pause_all_subsystems()
Pause all subsystems.
std::shared_ptr< Vruta::TaskScheduler > m_task_scheduler
void create_graphics_subsystem(const GlobalGraphicsConfig &graphics_config)
Create and register the graphics subsystem.
void resume_all_subsystems()
Resume all paused subsystems.
std::unordered_map< SubsystemType, std::unordered_set< SubsystemType > > m_cross_access_permissions
void register_process_hook(SubsystemType type, const std::string &name, ProcessHook hook, HookPosition position=HookPosition::POST_PROCESS)
Register a processing hook for a specific subsystem.
bool has_subsystem(SubsystemType type) const
Check if a subsystem type exists.
void allow_cross_access(SubsystemType from, SubsystemType to)
Configure cross-subsystem data access permissions.
std::shared_ptr< AudioSubsystem > get_audio_subsystem()
Get typed access to the audio subsystem.
void stop_graphics_subsystem()
Stop the graphics subsystem.
void add_subsystem(SubsystemType type, const std::shared_ptr< ISubsystem > &subsystem)
Register a subsystem instance with the manager.
std::shared_ptr< ISubsystem > get_subsystem(SubsystemType type)
Get access to a specific subsystem by type.
void create_network_subsystem(const GlobalNetworkConfig &network_config)
Create and register the network subsystem.
void start_all_subsystems()
Start all registered subsystems in coordination.
std::shared_ptr< InputSubsystem > get_input_subsystem()
Get typed access to the input subsystem.
std::shared_ptr< Core::WindowManager > m_window_manager
bool is_cross_access_allowed(SubsystemType from, SubsystemType to) const
void shutdown()
Shutdown all subsystems in proper order.
void stop_audio_subsystem()
Stop the audio subsystem.
std::shared_ptr< NetworkSubsystem > get_network_subsystem()
Get typed access to the network subsystem.
std::unordered_map< SubsystemType, std::pair< bool, bool > > query_subsystem_status() const
Query operational status of all subsystems.
std::unordered_map< SubsystemType, std::unique_ptr< SubsystemProcessingHandle > > m_handles
void remove_subsystem(SubsystemType type)
Remove and shutdown a subsystem.
SubsystemProcessingHandle * get_validated_handle(SubsystemType type) const
Get processing handle with validation.
std::unordered_map< SubsystemType, std::shared_ptr< ISubsystem > > m_subsystems
std::optional< std::span< const double > > read_cross_subsystem_buffer(SubsystemType requesting_type, SubsystemType target_type, uint32_t channel)
Read data from another subsystem's buffers.
std::shared_ptr< GraphicsSubsystem > get_graphics_subsystem()
Get typed access to the graphics subsystem.
std::shared_mutex m_mutex
Thread safety for subsystem operations.
std::shared_ptr< InputManager > m_input_manager
void create_audio_subsystem(GlobalStreamInfo &stream_info)
Create and register the audio subsystem.
void create_input_subsystem(GlobalInputConfig &input_config)
Create and register the input subsystem.
SubsystemManager(std::shared_ptr< Nodes::NodeGraphManager > node_graph_manager, std::shared_ptr< Buffers::BufferManager > buffer_manager, std::shared_ptr< Vruta::TaskScheduler > task_scheduler, std::shared_ptr< Core::WindowManager > window_manager=nullptr, std::shared_ptr< InputManager > input_manager=nullptr)
Constructs SubsystemManager with required processing managers.
Unified interface combining buffer and node processing for subsystems.
std::function< void(unsigned int num_frames)> ProcessHook
Function type for process hooks that can be registered with the engine.
HookPosition
Defines the position in the processing cycle where a hook should be executed.
@ PRE_PROCESS
Execute hook before any audio processing occurs.
@ Init
Engine/subsystem initialization.
@ Runtime
General runtime operations (default fallback)
@ Core
Core engine, backend, subsystems.
Configuration for the InputSubsystem.
Configuration for the NetworkSubsystem.
Comprehensive configuration for digital audio stream processing.