MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Engine.cpp
Go to the documentation of this file.
1#include "Engine.hpp"
2
11
14
16
17#ifdef MAYAFLUX_PLATFORM_MACOS
18#include <CoreFoundation/CoreFoundation.h>
19#include <csignal>
20#include <future>
21#include <unistd.h>
22#endif
23
24#ifdef MAYAFLUX_PLATFORM_WINDOWS
26#endif
27
28#ifdef MAYAFLUX_PLATFORM_LINUX
29#include <csignal>
30#include <pthread.h>
31#endif
32
33namespace MayaFlux::Core {
34
35//-------------------------------------------------------------------------
36// Initialization and Lifecycle
37//-------------------------------------------------------------------------
38
40 : m_stochastic_engine(new Kinesis::Stochastic::Stochastic(Kinesis::Stochastic::Algorithm::UNIFORM))
41{
42}
43
45{
46 End();
47}
48
49Engine::Engine(Engine&& other) noexcept
50 : m_stream_info(other.m_stream_info)
51 , m_graphics_config(other.m_graphics_config)
52 , m_is_paused(other.m_is_paused)
53 , m_is_initialized(other.m_is_initialized)
54 , m_should_shutdown(other.m_should_shutdown.load())
55 , m_scheduler(std::move(other.m_scheduler))
56 , m_node_graph_manager(std::move(other.m_node_graph_manager))
57 , m_buffer_manager(std::move(other.m_buffer_manager))
58 , m_subsystem_manager(std::move(other.m_subsystem_manager))
59 , m_window_manager(std::move(other.m_window_manager))
60 , m_event_manager(std::move(other.m_event_manager))
61 , m_input_manager(std::move(other.m_input_manager))
62 , m_io_manager(std::move(other.m_io_manager))
63 , m_stochastic_engine(std::move(other.m_stochastic_engine))
64{
65 other.m_is_initialized = false;
66 other.m_is_paused = false;
67}
68
70{
71 if (this != &other) {
72 End();
73
74 m_stream_info = other.m_stream_info;
75 m_graphics_config = other.m_graphics_config;
76
77 m_subsystem_manager = std::move(other.m_subsystem_manager);
78 m_node_graph_manager = std::move(other.m_node_graph_manager);
79 m_buffer_manager = std::move(other.m_buffer_manager);
80 m_scheduler = std::move(other.m_scheduler);
81 m_window_manager = std::move(other.m_window_manager);
82 m_event_manager = std::move(other.m_event_manager);
83 m_input_manager = std::move(other.m_input_manager);
84 m_io_manager = std::move(other.m_io_manager);
85 m_stochastic_engine = std::move(other.m_stochastic_engine);
86
87 m_is_initialized = other.m_is_initialized;
88 m_is_paused = other.m_is_paused;
89 m_should_shutdown = other.m_should_shutdown.load();
90
91 other.m_is_initialized = false;
92 other.m_is_paused = false;
93 }
94 return *this;
95}
96
101
102void Engine::Init(const GlobalStreamInfo& streamInfo)
103{
105}
106
107void Engine::Init(const GlobalStreamInfo& streamInfo, const GlobalGraphicsConfig& graphics_config, const GlobalInputConfig& input_config, const GlobalNetworkConfig& network_config)
108{
110 m_stream_info = streamInfo;
111 m_graphics_config = graphics_config;
112 m_input_config = input_config;
113 m_network_config = network_config;
114
115 m_scheduler = std::make_shared<Vruta::TaskScheduler>(m_stream_info.sample_rate);
116 m_event_manager = std::make_shared<Vruta::EventManager>();
117 m_input_manager = std::make_shared<InputManager>();
118
119 m_buffer_manager = std::make_shared<Buffers::BufferManager>(
123
124 m_node_graph_manager = std::make_shared<Nodes::NodeGraphManager>(
126
127 m_node_graph_manager->set_node_config(m_node_config);
128
129 m_io_manager = std::make_shared<IO::IOManager>(
131
133 m_window_manager = std::make_shared<WindowManager>(m_graphics_config);
134 } else {
135 MF_WARN(Journal::Component::Core, Journal::Context::Init, "No windowing backend selected - running in audio-only mode");
136 }
137
138 m_subsystem_manager = std::make_shared<SubsystemManager>(
140
141 m_subsystem_manager->create_audio_subsystem(m_stream_info);
142
143 m_subsystem_manager->create_graphics_subsystem(m_graphics_config);
144
145 m_subsystem_manager->create_network_subsystem(m_network_config);
146
147 m_subsystem_manager->create_input_subsystem(m_input_config);
148
149 m_buffer_manager->initialize_buffer_service();
150
151 m_is_initialized = true;
152
154}
155
165
167{
169 return;
170 }
171
172 m_subsystem_manager->pause_all_subsystems();
173 m_is_paused = true;
174}
175
177{
178 if (!m_is_paused || !m_is_initialized) {
179 return;
180 }
181
182 m_subsystem_manager->resume_all_subsystems();
183 m_is_paused = false;
184}
185
187{
189 return false;
190 }
191
192 if (m_is_initialized) {
193 auto status = m_subsystem_manager->query_subsystem_status();
194 for (const auto& [type, readiness] : status) {
195 const auto& [is_ready, is_running] = readiness;
196 if (is_ready && is_running) {
197 return true;
198 }
199 }
200 }
201 return false;
202}
203
205{
206#ifdef MAYAFLUX_PLATFORM_MACOS
207 run_macos_event_loop();
208#elif defined(MAYAFLUX_PLATFORM_WINDOWS)
209 static HANDLE s_shutdown_event = CreateEventW(nullptr, TRUE, FALSE, nullptr);
210 if (!s_shutdown_event) {
212 "Failed to create shutdown event (GetLastError={}), cannot await Ctrl-C", GetLastError());
213 return;
214 }
215 ResetEvent(s_shutdown_event);
216
217 SetConsoleCtrlHandler([](DWORD type) -> BOOL {
218 if (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT || type == CTRL_CLOSE_EVENT) {
219 SetEvent(s_shutdown_event);
220 return TRUE;
221 }
222 return FALSE;
223 },
224 TRUE);
225
226 WaitForSingleObject(s_shutdown_event, INFINITE);
227#else
228 static std::atomic<bool> s_signal_received { false };
229 s_signal_received.store(false, std::memory_order_relaxed);
230
231 sigset_t block_mask, orig_mask;
232 sigemptyset(&block_mask);
233 sigaddset(&block_mask, SIGINT);
234 sigaddset(&block_mask, SIGTERM);
235 pthread_sigmask(SIG_BLOCK, &block_mask, &orig_mask);
236
237 struct sigaction sa {};
238 sigemptyset(&sa.sa_mask);
239 sa.sa_handler = [](int) { s_signal_received.store(true, std::memory_order_release); };
240 sigaction(SIGINT, &sa, nullptr);
241 sigaction(SIGTERM, &sa, nullptr);
242
243 while (!s_signal_received.load(std::memory_order_acquire)) {
244 sigsuspend(&orig_mask);
245 }
246
247 pthread_sigmask(SIG_SETMASK, &orig_mask, nullptr);
248#endif
249
250 m_should_shutdown.store(true, std::memory_order_release);
251
253 "Shutdown requested, awaiting all subsystem termination ......");
254}
255
257{
258 m_should_shutdown.store(true, std::memory_order_release);
259
260#ifdef MAYAFLUX_PLATFORM_MACOS
261 CFRunLoopStop(CFRunLoopGetMain());
262#endif
263}
264
266{
267 return m_should_shutdown.load(std::memory_order_acquire);
268}
269
270#ifdef MAYAFLUX_PLATFORM_MACOS
271void Engine::run_macos_event_loop()
272{
273 CFRunLoopRef runLoop = CFRunLoopGetMain();
274
275 signal(SIGINT, SIG_IGN);
276 signal(SIGTERM, SIG_IGN);
277
278 dispatch_source_t sigintSource = dispatch_source_create(
279 DISPATCH_SOURCE_TYPE_SIGNAL,
280 SIGINT,
281 0,
282 dispatch_get_main_queue());
283
284 dispatch_source_t sigtermSource = dispatch_source_create(
285 DISPATCH_SOURCE_TYPE_SIGNAL,
286 SIGTERM,
287 0,
288 dispatch_get_main_queue());
289
290 dispatch_source_set_event_handler(sigintSource, ^{
292 });
293
294 dispatch_source_set_event_handler(sigtermSource, ^{
296 });
297
298 dispatch_resume(sigintSource);
299 dispatch_resume(sigtermSource);
300
301 double timeout_seconds = 1.0 / static_cast<double>(m_graphics_config.target_frame_rate);
302
304 "Main thread event loop running (polling at {}fps)",
306
307 while (!is_shutdown_requested()) {
308 CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeout_seconds, false);
309 }
310
311 dispatch_source_cancel(sigintSource);
312 dispatch_release(sigintSource);
313 dispatch_source_cancel(sigtermSource);
314 dispatch_release(sigtermSource);
315
317 "Main thread event loop exiting");
318}
319#endif
320
322{
323 if (!m_subsystem_manager) {
324 return;
325 }
326
327#ifdef MAYAFLUX_PLATFORM_MACOS
328 if (CFRunLoopGetCurrent() == CFRunLoopGetMain()) {
329 auto stopped = std::async(std::launch::async, [this]() {
330 m_subsystem_manager->stop();
331 });
332 while (stopped.wait_for(std::chrono::milliseconds(0)) != std::future_status::ready) {
333 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.01, false);
334 }
335 stopped.get();
336 return;
337 }
338#endif
339
340 m_subsystem_manager->stop();
341}
342
344{
345 if (!m_is_initialized)
346 return;
347
349
351
352 if (m_event_manager) {
353 m_event_manager->terminate_all_events();
354 }
355
357 m_node_graph_manager->terminate_active_processing();
358 }
359
360 if (m_io_manager) {
361 m_io_manager->stop();
362 }
363
365
366 if (m_io_manager) {
367 m_io_manager->shutdown();
368 }
369
370 if (m_scheduler) {
371 m_scheduler->terminate_all_tasks();
372 }
373
374 if (m_buffer_manager) {
375 m_buffer_manager->terminate_active_buffers();
376 m_buffer_manager.reset();
377 }
378
379 if (m_window_manager) {
380 m_window_manager->set_terminate();
381 auto windows = m_window_manager->get_windows();
382 for (auto& window : windows) {
383 m_window_manager->destroy_window(window, true);
384 }
385 m_window_manager.reset();
386 }
387
389 m_node_graph_manager.reset();
390 }
391
393 m_subsystem_manager->shutdown();
394 }
395
396 m_is_initialized = false;
397 m_is_paused = false;
398}
399
401{
403 return m_node_graph_manager->get_node_config();
404 }
405
406 return m_node_config;
407}
408
410{
411 m_node_config = config;
413 m_node_graph_manager->set_node_config(config);
414 }
415}
416
417} // namespace MayaFlux::Core
#define MF_INFO(comp, ctx,...)
#define MF_LOG(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
Factory free functions for the Forma surface system.
std::weak_ptr< Core::Window > window
Definition Picker.cpp:23
vk::PhysicalDeviceType type
Definition VKDevice.cpp:126
void Init()
Initializes all system components and prepares for processing.
Definition Engine.cpp:97
std::shared_ptr< SubsystemManager > m_subsystem_manager
Definition Engine.hpp:402
void await_shutdown()
Blocks until shutdown is requested (main thread event loop)
Definition Engine.cpp:204
std::shared_ptr< IO::IOManager > m_io_manager
IO manager for video/audio loading and dispatch.
Definition Engine.hpp:406
GlobalNetworkConfig m_network_config
Network configuration.
Definition Engine.hpp:387
GlobalGraphicsConfig m_graphics_config
Graphics/windowing configuration.
Definition Engine.hpp:385
void request_shutdown()
Request shutdown from any thread.
Definition Engine.cpp:256
void Resume()
Resumes processing from paused state.
Definition Engine.cpp:176
void stop_subsystems()
Stops subsystems while servicing required main thread work on macOS.
Definition Engine.cpp:321
std::shared_ptr< Vruta::EventManager > m_event_manager
Event manager.
Definition Engine.hpp:404
std::shared_ptr< Buffers::BufferManager > m_buffer_manager
Buffer manager.
Definition Engine.hpp:401
void set_node_config(const Nodes::NodeConfig &config)
Sets the node processing configuration.
Definition Engine.cpp:409
GlobalStreamInfo m_stream_info
Stream configuration.
Definition Engine.hpp:384
bool is_running() const
Checks if the coordinated processing system is currently active.
Definition Engine.cpp:186
void Start()
Starts the coordinated processing of all subsystems.
Definition Engine.cpp:156
Nodes::NodeConfig & get_node_config()
Gets the current node processing configuration.
Definition Engine.cpp:400
std::atomic< bool > m_should_shutdown
Definition Engine.hpp:393
void Pause()
Pauses all processing while maintaining system state.
Definition Engine.cpp:166
bool m_is_paused
Pause state flag.
Definition Engine.hpp:390
std::shared_ptr< WindowManager > m_window_manager
Window manager (Windowing subsystem)
Definition Engine.hpp:403
Engine()
Constructs a new Engine instance.
Definition Engine.cpp:39
std::shared_ptr< Vruta::TaskScheduler > m_scheduler
Task scheduler.
Definition Engine.hpp:399
std::shared_ptr< InputManager > m_input_manager
Input manager (HID/MIDI/etc.)
Definition Engine.hpp:405
Nodes::NodeConfig m_node_config
Node processing configuration.
Definition Engine.hpp:388
~Engine()
Destroys the Engine instance and cleans up resources.
Definition Engine.cpp:44
bool is_shutdown_requested() const
Check if shutdown has been requested.
Definition Engine.cpp:265
void End()
Stops all processing and performs clean shutdown.
Definition Engine.cpp:343
std::shared_ptr< Nodes::NodeGraphManager > m_node_graph_manager
Node graph manager.
Definition Engine.hpp:400
Engine & operator=(const Engine &)=delete
GlobalInputConfig m_input_config
Input configuration.
Definition Engine.hpp:386
Central lifecycle manager and component orchestrator for the MayaFlux processing system.
Definition Engine.hpp:80
@ Init
Engine/subsystem initialization.
@ Runtime
General runtime operations (default fallback)
@ Core
Core engine, backend, subsystems.
void shutdown()
Release stored references.
Definition Forma.cpp:58
bool initialize(std::shared_ptr< Nodes::NodeGraphManager > node_graph_manager, std::shared_ptr< Buffers::BufferManager > buffer_manager, std::shared_ptr< Vruta::TaskScheduler > scheduler, std::shared_ptr< Vruta::EventManager > event_manager, std::shared_ptr< Core::WindowManager > window_manager)
Store engine-level references for use by all subsequent Forma calls.
Definition Forma.cpp:46
bool initialize()
Initialize Portal::System.
Definition System.cpp:27
void shutdown()
Shutdown Portal::System and release all resources.
Definition System.cpp:69
constexpr std::string_view enum_to_string(EnumType value) noexcept
Universal enum to string converter using magic_enum (original case)
void End()
Stops and cleans up the default engine.
Definition Core.cpp:156
@ NONE
No windowing (offscreen rendering only)
uint32_t target_frame_rate
Target frame rate for visual processing (Hz)
WindowingBackend windowing_backend
Selected windowing backend.
Configuration for the InputSubsystem.
Configuration for the NetworkSubsystem.
uint32_t channels
Number of discrete channels in this set.
bool enabled
Whether this channel set is active in the stream.
uint32_t buffer_size
Number of samples per processing block.
ChannelConfig input
Configuration for input signal channels (disabled by default)
uint32_t sample_rate
Number of samples processed per second (Hz)
ChannelConfig output
Configuration for output signal channels.
Comprehensive configuration for digital audio stream processing.
Configuration settings for individual audio nodes.
Definition NodeSpec.hpp:29