MayaFlux 0.1.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->shutdown();
154 }
155 }
156 m_subsystems.clear();
157}
158
160{
161 auto it = m_cross_access_permissions.find(from);
162 return it != m_cross_access_permissions.end() && it->second.count(to) > 0;
163}
164
169
170std::optional<std::span<const double>> SubsystemManager::read_cross_subsystem_buffer(
171 SubsystemType requesting_type,
172 SubsystemType target_type,
173 uint32_t channel)
174{
175 std::shared_lock lock(m_mutex);
176
177 if (m_subsystems.find(requesting_type) == m_subsystems.end()) {
178 return std::nullopt;
179 }
180
181 if (!is_cross_access_allowed(requesting_type, target_type)) {
182 return std::nullopt;
183 }
184
185 auto target_token = m_subsystems[target_type]->get_tokens();
186
187 try {
188 return m_buffer_manager->get_buffer_data(target_token.Buffer, channel);
189 } catch (...) {
190 return std::nullopt;
191 }
192}
193
195{
196 auto subsystem_it = m_subsystems.find(type);
197 if (subsystem_it == m_subsystems.end()) {
199 "Invalid subsystem type: Subsystem not found.");
200 return nullptr;
201 }
202
203 auto handle = subsystem_it->second->get_processing_context_handle();
204 if (!handle) {
206 "Invalid processing context handle: Handle is null.");
207 return nullptr;
208 }
209
210 return handle;
211}
212
213void SubsystemManager::register_process_hook(SubsystemType type, const std::string& name, ProcessHook hook, HookPosition position)
214{
215 auto handle = get_validated_handle(type);
216 if (!handle)
217 return;
218
219 if (!hook) {
221 "Invalid process hook: Hook cannot be null or invalid.");
222 return;
223 }
224
225 if (position == HookPosition::PRE_PROCESS) {
226 handle->pre_process_hooks[name] = std::move(hook);
227 } else {
228 handle->post_process_hooks[name] = std::move(hook);
229 }
230}
231
233{
234 auto handle = get_validated_handle(type);
235 if (!handle)
236 return;
237
238 if (handle->pre_process_hooks.erase(name) == 0) {
239 handle->post_process_hooks.erase(name);
240 }
241}
242
243bool SubsystemManager::has_process_hook(SubsystemType type, const std::string& name)
244{
245 auto handle = get_validated_handle(type);
246 if (!handle)
247 return false;
248
249 return handle->pre_process_hooks.contains(name) || handle->post_process_hooks.contains(name);
250}
251}
#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.
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 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.
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.