MayaFlux 0.2.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
SubsystemManager.cpp
Go to the documentation of this file.
3
5
7
9
10namespace MayaFlux::Core {
11
13 std::shared_ptr<Nodes::NodeGraphManager> node_graph_manager,
14 std::shared_ptr<Buffers::BufferManager> buffer_manager,
15 std::shared_ptr<Vruta::TaskScheduler> task_scheduler,
16 std::shared_ptr<Core::WindowManager> window_manager)
17 : m_node_graph_manager(std::move(node_graph_manager))
18 , m_buffer_manager(std::move(buffer_manager))
19 , m_task_scheduler(std::move(task_scheduler))
20 , m_window_manager(std::move(window_manager))
21{
24 std::source_location::current(),
25 "SubsystemManager requires valid NodeGraphManager");
26 }
27 if (!m_buffer_manager) {
29 std::source_location::current(),
30 "SubsystemManager requires valid BufferManager");
31 }
32 if (!m_task_scheduler) {
34 std::source_location::current(),
35 "SubsystemManager requires valid TaskScheduler");
36 }
37 if (!m_window_manager) {
39 "No WindowManager provided - Graphics subsystems will be unavailable");
40 }
41}
42
44{
45 create_subsystem_internal<AudioSubsystem>(SubsystemType::AUDIO, stream_info, backend_type);
46}
47
49{
50 if (!m_window_manager) {
51 error<std::runtime_error>(
54 std::source_location::current(),
55 "Cannot create GraphicsSubsystem without a valid WindowManager");
56 }
57
58 create_subsystem_internal<GraphicsSubsystem>(SubsystemType::GRAPHICS, graphics_config);
59}
60
61void SubsystemManager::add_subsystem(SubsystemType type, const std::shared_ptr<ISubsystem>& subsystem)
62{
63 auto tokens = subsystem->get_tokens();
64 auto handle = std::make_unique<SubsystemProcessingHandle>(
69 tokens);
70
71 subsystem->initialize(*handle);
72 subsystem->register_callbacks();
73
74 m_subsystems[type] = subsystem;
75 m_handles[type] = std::move(handle);
76}
77
78std::shared_ptr<AudioSubsystem> SubsystemManager::get_audio_subsystem()
79{
80 if (auto subsystem = std::dynamic_pointer_cast<AudioSubsystem>(get_subsystem(SubsystemType::AUDIO))) {
81 return subsystem;
82 }
83 return nullptr;
84}
85
86std::shared_ptr<GraphicsSubsystem> SubsystemManager::get_graphics_subsystem()
87{
88 if (auto subsystem = std::dynamic_pointer_cast<GraphicsSubsystem>(get_subsystem(SubsystemType::GRAPHICS))) {
89 return subsystem;
90 }
91 return nullptr;
92}
93
95{
96 for (auto& [token, subsystem] : m_subsystems) {
97 if (subsystem->is_ready()) {
98 subsystem->start();
99 }
100 }
101}
102
104{
105 for (auto& [type, subsystem] : m_subsystems) {
106 if (subsystem->is_running()) {
107 subsystem->pause();
108 }
109 }
110}
111
113{
114 for (auto& [type, subsystem] : m_subsystems) {
115 if (subsystem->is_ready()) {
116 subsystem->resume();
117 }
118 }
119}
120
121std::shared_ptr<ISubsystem> SubsystemManager::get_subsystem(SubsystemType type)
122{
123 return has_subsystem(type) ? m_subsystems[type] : nullptr;
124}
125
127{
128 if (auto it = m_subsystems.find(type); it != m_subsystems.end()) {
129 it->second->shutdown();
130 m_subsystems.erase(it);
131 m_handles.erase(type);
132 m_cross_access_permissions.erase(type);
133 }
134}
135
136std::unordered_map<SubsystemType, std::pair<bool, bool>> SubsystemManager::query_subsystem_status() const
137{
138 std::unordered_map<SubsystemType, std::pair<bool, bool>> statuses;
139 for (const auto& [type, subsystem] : m_subsystems) {
140 if (subsystem == nullptr) {
141 statuses[type] = { false, false };
142 continue;
143 }
144 statuses[type] = { subsystem->is_ready(), subsystem->is_running() };
145 }
146 return statuses;
147}
148
150{
151 for (auto& [token, subsystem] : m_subsystems) {
152 if (subsystem && subsystem->is_running()) {
153 subsystem->stop();
154 }
155 }
156}
157
159{
160 if (auto audio = get_audio_subsystem()) {
161 audio->stop();
162 }
163}
164
166{
167 if (auto graphics = get_graphics_subsystem()) {
168 graphics->stop();
169 }
170}
171
173{
174 for (auto& [token, subsystem] : m_subsystems) {
175 if (subsystem && subsystem->is_ready()) {
176 subsystem->shutdown();
177 }
178 }
179 m_subsystems.clear();
180}
181
183{
184 auto it = m_cross_access_permissions.find(from);
185 return it != m_cross_access_permissions.end() && it->second.count(to) > 0;
186}
187
192
193std::optional<std::span<const double>> SubsystemManager::read_cross_subsystem_buffer(
194 SubsystemType requesting_type,
195 SubsystemType target_type,
196 uint32_t channel)
197{
198 std::shared_lock lock(m_mutex);
199
200 if (m_subsystems.find(requesting_type) == m_subsystems.end()) {
201 return std::nullopt;
202 }
203
204 if (!is_cross_access_allowed(requesting_type, target_type)) {
205 return std::nullopt;
206 }
207
208 auto target_token = m_subsystems[target_type]->get_tokens();
209
210 try {
211 return m_buffer_manager->get_buffer_data(target_token.Buffer, channel);
212 } catch (...) {
213 return std::nullopt;
214 }
215}
216
218{
219 auto subsystem_it = m_subsystems.find(type);
220 if (subsystem_it == m_subsystems.end()) {
222 "Invalid subsystem type: Subsystem not found.");
223 return nullptr;
224 }
225
226 auto handle = subsystem_it->second->get_processing_context_handle();
227 if (!handle) {
229 "Invalid processing context handle: Handle is null.");
230 return nullptr;
231 }
232
233 return handle;
234}
235
236void SubsystemManager::register_process_hook(SubsystemType type, const std::string& name, ProcessHook hook, HookPosition position)
237{
238 auto handle = get_validated_handle(type);
239 if (!handle)
240 return;
241
242 if (!hook) {
244 "Invalid process hook: Hook cannot be null or invalid.");
245 return;
246 }
247
248 if (position == HookPosition::PRE_PROCESS) {
249 handle->pre_process_hooks[name] = std::move(hook);
250 } else {
251 handle->post_process_hooks[name] = std::move(hook);
252 }
253}
254
256{
257 auto handle = get_validated_handle(type);
258 if (!handle)
259 return;
260
261 if (handle->pre_process_hooks.erase(name) == 0) {
262 handle->post_process_hooks.erase(name);
263 }
264}
265
266bool SubsystemManager::has_process_hook(SubsystemType type, const std::string& name)
267{
268 auto handle = get_validated_handle(type);
269 if (!handle)
270 return false;
271
272 return handle->pre_process_hooks.contains(name) || handle->post_process_hooks.contains(name);
273}
274
275}
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
static MayaFlux::Nodes::ProcessingToken token
Definition Timers.cpp:8
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.
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.
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)
Constructs SubsystemManager with required processing managers.
void start_all_subsystems()
Start all registered subsystems in coordination.
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.
void create_audio_subsystem(GlobalStreamInfo &stream_info, Utils::AudioBackendType backend_type)
Create and register the audio subsystem.
std::shared_mutex m_mutex
Thread safety for subsystem operations.
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.
Comprehensive configuration for digital audio stream processing.