MayaFlux 0.3.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
14namespace MayaFlux::Core {
15
17 std::shared_ptr<Nodes::NodeGraphManager> node_graph_manager,
18 std::shared_ptr<Buffers::BufferManager> buffer_manager,
19 std::shared_ptr<Vruta::TaskScheduler> task_scheduler,
20 std::shared_ptr<Core::WindowManager> window_manager,
21 std::shared_ptr<InputManager> input_manager)
22 : m_node_graph_manager(std::move(node_graph_manager))
23 , m_buffer_manager(std::move(buffer_manager))
24 , m_task_scheduler(std::move(task_scheduler))
25 , m_window_manager(std::move(window_manager))
26 , m_input_manager(std::move(input_manager))
27{
30 std::source_location::current(),
31 "SubsystemManager requires valid NodeGraphManager");
32 }
33 if (!m_buffer_manager) {
35 std::source_location::current(),
36 "SubsystemManager requires valid BufferManager");
37 }
38 if (!m_task_scheduler) {
40 std::source_location::current(),
41 "SubsystemManager requires valid TaskScheduler");
42 }
43 if (!m_window_manager) {
45 "No WindowManager provided - Graphics subsystems will be unavailable");
46 }
47 if (!m_input_manager) {
49 "No InputManager provided - Input subsystems will be unavailable");
50 }
51}
52
54{
55 create_subsystem_internal<AudioSubsystem>(SubsystemType::AUDIO, stream_info);
56}
57
59{
60 if (!m_window_manager) {
61 error<std::runtime_error>(
64 std::source_location::current(),
65 "Cannot create GraphicsSubsystem without a valid WindowManager");
66 }
67
68 create_subsystem_internal<GraphicsSubsystem>(SubsystemType::GRAPHICS, graphics_config);
69}
70
72{
73 if (!m_input_manager) {
74 error<std::runtime_error>(
77 std::source_location::current(),
78 "Cannot create InputSubsystem without a valid InputManager");
79 }
80
81 create_subsystem_internal<InputSubsystem>(SubsystemType::INPUT, input_config);
82}
83
84void SubsystemManager::add_subsystem(SubsystemType type, const std::shared_ptr<ISubsystem>& subsystem)
85{
86 auto tokens = subsystem->get_tokens();
87 auto handle = std::make_unique<SubsystemProcessingHandle>(
93 tokens);
94
95 subsystem->initialize(*handle);
96 subsystem->register_callbacks();
97
98 m_subsystems[type] = subsystem;
99 m_handles[type] = std::move(handle);
100}
101
102std::shared_ptr<AudioSubsystem> SubsystemManager::get_audio_subsystem()
103{
104 if (auto subsystem = std::dynamic_pointer_cast<AudioSubsystem>(get_subsystem(SubsystemType::AUDIO))) {
105 return subsystem;
106 }
107 return nullptr;
108}
109
110std::shared_ptr<GraphicsSubsystem> SubsystemManager::get_graphics_subsystem()
111{
112 if (auto subsystem = std::dynamic_pointer_cast<GraphicsSubsystem>(get_subsystem(SubsystemType::GRAPHICS))) {
113 return subsystem;
114 }
115 return nullptr;
116}
117
118std::shared_ptr<InputSubsystem> SubsystemManager::get_input_subsystem()
119{
120 if (auto subsystem = std::dynamic_pointer_cast<InputSubsystem>(get_subsystem(SubsystemType::INPUT))) {
121 return subsystem;
122 }
123 return nullptr;
124}
125
127{
128 for (auto& [token, subsystem] : m_subsystems) {
129 if (subsystem->is_ready()) {
130 subsystem->start();
131 }
132 }
133}
134
136{
137 for (auto& [type, subsystem] : m_subsystems) {
138 if (subsystem->is_running()) {
139 subsystem->pause();
140 }
141 }
142}
143
145{
146 for (auto& [type, subsystem] : m_subsystems) {
147 if (subsystem->is_ready()) {
148 subsystem->resume();
149 }
150 }
151}
152
153std::shared_ptr<ISubsystem> SubsystemManager::get_subsystem(SubsystemType type)
154{
155 return has_subsystem(type) ? m_subsystems[type] : nullptr;
156}
157
159{
160 if (auto it = m_subsystems.find(type); it != m_subsystems.end()) {
161 it->second->shutdown();
162 m_subsystems.erase(it);
163 m_handles.erase(type);
164 m_cross_access_permissions.erase(type);
165 }
166}
167
168std::unordered_map<SubsystemType, std::pair<bool, bool>> SubsystemManager::query_subsystem_status() const
169{
170 std::unordered_map<SubsystemType, std::pair<bool, bool>> statuses;
171 for (const auto& [type, subsystem] : m_subsystems) {
172 if (subsystem == nullptr) {
173 statuses[type] = { false, false };
174 continue;
175 }
176 statuses[type] = { subsystem->is_ready(), subsystem->is_running() };
177 }
178 return statuses;
179}
180
182{
183 for (auto& [token, subsystem] : m_subsystems) {
184 if (subsystem && subsystem->is_running()) {
185 subsystem->stop();
186 }
187 }
188}
189
191{
192 if (auto audio = get_audio_subsystem()) {
193 audio->stop();
194 }
195}
196
198{
199 if (auto graphics = get_graphics_subsystem()) {
200 graphics->stop();
201 }
202}
203
205{
206 if (auto input = get_input_subsystem()) {
207 input->stop();
208 }
209}
210
212{
213 for (auto& [token, subsystem] : m_subsystems) {
214 if (subsystem && subsystem->is_ready()) {
215 subsystem->shutdown();
216 }
217 }
218 m_subsystems.clear();
219}
220
222{
223 auto it = m_cross_access_permissions.find(from);
224 return it != m_cross_access_permissions.end() && it->second.count(to) > 0;
225}
226
231
232std::optional<std::span<const double>> SubsystemManager::read_cross_subsystem_buffer(
233 SubsystemType requesting_type,
234 SubsystemType target_type,
235 uint32_t channel)
236{
237 std::shared_lock lock(m_mutex);
238
239 if (m_subsystems.find(requesting_type) == m_subsystems.end()) {
240 return std::nullopt;
241 }
242
243 if (!is_cross_access_allowed(requesting_type, target_type)) {
244 return std::nullopt;
245 }
246
247 auto target_token = m_subsystems[target_type]->get_tokens();
248
249 try {
250 return m_buffer_manager->get_buffer_data(target_token.Buffer, channel);
251 } catch (...) {
252 return std::nullopt;
253 }
254}
255
257{
258 auto subsystem_it = m_subsystems.find(type);
259 if (subsystem_it == m_subsystems.end()) {
261 "Invalid subsystem type: Subsystem not found.");
262 return nullptr;
263 }
264
265 auto handle = subsystem_it->second->get_processing_context_handle();
266 if (!handle) {
268 "Invalid processing context handle: Handle is null.");
269 return nullptr;
270 }
271
272 return handle;
273}
274
275void SubsystemManager::register_process_hook(SubsystemType type, const std::string& name, ProcessHook hook, HookPosition position)
276{
277 auto handle = get_validated_handle(type);
278 if (!handle)
279 return;
280
281 if (!hook) {
283 "Invalid process hook: Hook cannot be null or invalid.");
284 return;
285 }
286
287 if (position == HookPosition::PRE_PROCESS) {
288 handle->pre_process_hooks[name] = std::move(hook);
289 } else {
290 handle->post_process_hooks[name] = std::move(hook);
291 }
292}
293
295{
296 auto handle = get_validated_handle(type);
297 if (!handle)
298 return;
299
300 if (handle->pre_process_hooks.erase(name) == 0) {
301 handle->post_process_hooks.erase(name);
302 }
303}
304
305bool SubsystemManager::has_process_hook(SubsystemType type, const std::string& name)
306{
307 auto handle = get_validated_handle(type);
308 if (!handle)
309 return false;
310
311 return handle->pre_process_hooks.contains(name) || handle->post_process_hooks.contains(name);
312}
313
314}
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
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 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::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.
Comprehensive configuration for digital audio stream processing.