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
16#include <future>
17
18
19#ifdef MAYAFLUX_PLATFORM_WINDOWS
20#ifdef ERROR
21#undef ERROR
22#endif // ERROR
23
24#endif // MAYAFLUX_PLATFORM_WINDOWS
25
26
27namespace MayaFlux::Core {
28
30 std::shared_ptr<Nodes::NodeGraphManager> node_graph_manager,
31 std::shared_ptr<Buffers::BufferManager> buffer_manager,
32 std::shared_ptr<Vruta::TaskScheduler> task_scheduler,
33 std::shared_ptr<Core::WindowManager> window_manager,
34 std::shared_ptr<InputManager> input_manager)
35 : m_node_graph_manager(std::move(node_graph_manager))
36 , m_buffer_manager(std::move(buffer_manager))
37 , m_task_scheduler(std::move(task_scheduler))
38 , m_window_manager(std::move(window_manager))
39 , m_input_manager(std::move(input_manager))
40{
43 std::source_location::current(),
44 "SubsystemManager requires valid NodeGraphManager");
45 }
46 if (!m_buffer_manager) {
48 std::source_location::current(),
49 "SubsystemManager requires valid BufferManager");
50 }
51 if (!m_task_scheduler) {
53 std::source_location::current(),
54 "SubsystemManager requires valid TaskScheduler");
55 }
56 if (!m_window_manager) {
58 "No WindowManager provided - Graphics subsystems will be unavailable");
59 }
60 if (!m_input_manager) {
62 "No InputManager provided - Input subsystems will be unavailable");
63 }
64}
65
67{
68 create_subsystem_internal<AudioSubsystem>(SubsystemType::AUDIO, stream_info);
69}
70
72{
73 if (!m_window_manager) {
74 error<std::runtime_error>(
77 std::source_location::current(),
78 "Cannot create GraphicsSubsystem without a valid WindowManager");
79 }
80
81 create_subsystem_internal<GraphicsSubsystem>(SubsystemType::GRAPHICS, graphics_config);
82}
83
85{
86 if (!m_input_manager) {
87 error<std::runtime_error>(
90 std::source_location::current(),
91 "Cannot create InputSubsystem without a valid InputManager");
92 }
93
94 create_subsystem_internal<InputSubsystem>(SubsystemType::INPUT, input_config);
95}
96
98{
99 create_subsystem_internal<NetworkSubsystem>(SubsystemType::NETWORK, network_config);
100}
101
102void SubsystemManager::add_subsystem(SubsystemType type, const std::shared_ptr<ISubsystem>& subsystem)
103{
104 auto tokens = subsystem->get_tokens();
105 auto handle = std::make_unique<SubsystemProcessingHandle>(
111 tokens);
112
113 subsystem->initialize(*handle);
114 subsystem->register_callbacks();
115
116 m_subsystems[type] = subsystem;
117 m_handles[type] = std::move(handle);
118}
119
120std::shared_ptr<AudioSubsystem> SubsystemManager::get_audio_subsystem()
121{
122 if (auto subsystem = std::dynamic_pointer_cast<AudioSubsystem>(get_subsystem(SubsystemType::AUDIO))) {
123 return subsystem;
124 }
125 return nullptr;
126}
127
128std::shared_ptr<GraphicsSubsystem> SubsystemManager::get_graphics_subsystem()
129{
130 if (auto subsystem = std::dynamic_pointer_cast<GraphicsSubsystem>(get_subsystem(SubsystemType::GRAPHICS))) {
131 return subsystem;
132 }
133 return nullptr;
134}
135
136std::shared_ptr<InputSubsystem> SubsystemManager::get_input_subsystem()
137{
138 if (auto subsystem = std::dynamic_pointer_cast<InputSubsystem>(get_subsystem(SubsystemType::INPUT))) {
139 return subsystem;
140 }
141 return nullptr;
142}
143
144std::shared_ptr<NetworkSubsystem> SubsystemManager::get_network_subsystem()
145{
146 if (auto subsystem = std::dynamic_pointer_cast<NetworkSubsystem>(get_subsystem(SubsystemType::NETWORK))) {
147 return subsystem;
148 }
149 return nullptr;
150}
151
153{
154 for (auto& [token, subsystem] : m_subsystems) {
155 if (subsystem->is_ready()) {
156 subsystem->start();
157 }
158 }
159
160 for (auto& [token, subsystem] : m_subsystems) {
161 if (subsystem->is_ready())
162 subsystem->wait_until_running();
163 }
164}
165
167{
168 for (auto& [type, subsystem] : m_subsystems) {
169 if (subsystem->is_running()) {
170 subsystem->pause();
171 }
172 }
173}
174
176{
177 for (auto& [type, subsystem] : m_subsystems) {
178 if (subsystem->is_ready()) {
179 subsystem->resume();
180 }
181 }
182}
183
184std::shared_ptr<ISubsystem> SubsystemManager::get_subsystem(SubsystemType type)
185{
186 return has_subsystem(type) ? m_subsystems[type] : nullptr;
187}
188
190{
191 if (auto it = m_subsystems.find(type); it != m_subsystems.end()) {
192 it->second->shutdown();
193 m_subsystems.erase(it);
194 m_handles.erase(type);
195 m_cross_access_permissions.erase(type);
196 }
197}
198
199std::unordered_map<SubsystemType, std::pair<bool, bool>> SubsystemManager::query_subsystem_status() const
200{
201 std::unordered_map<SubsystemType, std::pair<bool, bool>> statuses;
202 for (const auto& [type, subsystem] : m_subsystems) {
203 if (subsystem == nullptr) {
204 statuses[type] = { false, false };
205 continue;
206 }
207 statuses[type] = { subsystem->is_ready(), subsystem->is_running() };
208 }
209 return statuses;
210}
211
213{
214 std::vector<std::future<void>> futures;
215 futures.reserve(m_subsystems.size());
216
217 for (auto& [type, subsystem] : m_subsystems) {
218 if (subsystem && subsystem->is_running()) {
219 futures.push_back(std::async(std::launch::async,
220 [&subsystem = subsystem]() { subsystem->stop(); }));
221 }
222 }
223
224 for (auto& f : futures)
225 f.wait();
226}
227
229{
230 if (auto audio = get_audio_subsystem()) {
231 audio->stop();
232 }
233}
234
236{
237 if (auto graphics = get_graphics_subsystem()) {
238 graphics->stop();
239 }
240}
241
243{
244 if (auto input = get_input_subsystem()) {
245 input->stop();
246 }
247}
248
250{
251 for (auto& [token, subsystem] : m_subsystems) {
252 if (subsystem && subsystem->is_ready()) {
253 subsystem->shutdown();
254 }
255 }
256 m_subsystems.clear();
257}
258
260{
261 auto it = m_cross_access_permissions.find(from);
262 return it != m_cross_access_permissions.end() && it->second.count(to) > 0;
263}
264
269
270std::optional<std::span<const double>> SubsystemManager::read_cross_subsystem_buffer(
271 SubsystemType requesting_type,
272 SubsystemType target_type,
273 uint32_t channel)
274{
275 std::shared_lock lock(m_mutex);
276
277 if (m_subsystems.find(requesting_type) == m_subsystems.end()) {
278 return std::nullopt;
279 }
280
281 if (!is_cross_access_allowed(requesting_type, target_type)) {
282 return std::nullopt;
283 }
284
285 auto target_token = m_subsystems[target_type]->get_tokens();
286
287 try {
288 return m_buffer_manager->get_buffer_data(target_token.Buffer, channel);
289 } catch (...) {
290 return std::nullopt;
291 }
292}
293
295{
296 auto subsystem_it = m_subsystems.find(type);
297 if (subsystem_it == m_subsystems.end()) {
299 "Invalid subsystem type: Subsystem not found.");
300 return nullptr;
301 }
302
303 auto handle = subsystem_it->second->get_processing_context_handle();
304 if (!handle) {
306 "Invalid processing context handle: Handle is null.");
307 return nullptr;
308 }
309
310 return handle;
311}
312
313void SubsystemManager::register_process_hook(SubsystemType type, const std::string& name, ProcessHook hook, HookPosition position)
314{
315 auto handle = get_validated_handle(type);
316 if (!handle)
317 return;
318
319 if (!hook) {
321 "Invalid process hook: Hook cannot be null or invalid.");
322 return;
323 }
324
325 if (position == HookPosition::PRE_PROCESS) {
326 handle->pre_process_hooks[name] = std::move(hook);
327 } else {
328 handle->post_process_hooks[name] = std::move(hook);
329 }
330}
331
333{
334 auto handle = get_validated_handle(type);
335 if (!handle)
336 return;
337
338 if (handle->pre_process_hooks.erase(name) == 0) {
339 handle->post_process_hooks.erase(name);
340 }
341}
342
343bool SubsystemManager::has_process_hook(SubsystemType type, const std::string& name)
344{
345 auto handle = get_validated_handle(type);
346 if (!handle)
347 return false;
348
349 return handle->pre_process_hooks.contains(name) || handle->post_process_hooks.contains(name);
350}
351
352}
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
Core::GlobalGraphicsConfig graphics
Definition Config.cpp:35
Core::GlobalInputConfig input
Definition Config.cpp:36
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.