22 #include "MSContext.hpp" 26 #ifdef AP_CPU_PROFILER 27 #include <gperftools/profiler.h> 30 #include <qapplication.h> 40 #include "MSElement.hpp" 41 #include "MSHeart.hpp" 42 #include "MSSessionStorage.hpp" 56 static MSHeart* HeartSingleton =
nullptr;
58 static QCoreApplication* App =
nullptr;
60 static QMap<QString, TimerData> Timers;
62 static QTime* PauseTimer =
nullptr;
64 static bool MalfunctionStatus =
false;
67 static void MSSignalHandler(
int signal_id)
69 bool LastHeartBeat =
false;
76 #if defined(__unix__) && !defined(__ANDROID__) 77 MCGenerateBacktrace();
82 #if defined(__unix__) && !defined(__ANDROID__) 83 MCGenerateBacktrace();
88 #if defined(__unix__) && !defined(__ANDROID__) 89 MCGenerateBacktrace();
94 #if defined(__unix__) && !defined(__ANDROID__) 95 MCGenerateBacktrace();
101 #if defined(__unix__) && !defined(__ANDROID__) 102 MCGenerateBacktrace();
104 LastHeartBeat =
true;
106 #if defined(__MINGW32__) || defined(__MINGW64__) 109 LastHeartBeat =
true;
114 #if defined(__unix__) && !defined(__ANDROID__) 115 MCGenerateBacktrace();
124 signal(SIGFPE, SIG_DFL);
125 signal(SIGSEGV, SIG_DFL);
126 signal(SIGILL, SIG_DFL);
127 signal(SIGINT, SIG_DFL);
128 signal(SIGTERM, SIG_DFL);
129 #if defined(__MINGW32__) || defined(__MINGW64__) 130 signal(SIGBREAK, SIG_DFL);
132 signal(SIGABRT, SIG_DFL);
134 MalfunctionStatus =
true;
136 if (LastHeartBeat && HeartSingleton && HeartSingleton->IsBeatingActive())
138 MC_NPRINT(
"Request to stop the heart beating...\n");
139 HeartSingleton->StopBeating();
144 if (SessionStorageSingleton && !SessionStorageSingleton->
GetRecordPath().isEmpty())
146 MC_NPRINT(
"Try to close the streams in the recorded sessions...\n");
147 SessionStorageSingleton->
Finalize();
151 if (!HeartSingleton || !HeartSingleton->IsBeatingActive())
158 QStringList MSContext::CmdArgumentMsgs = QStringList() <<
159 "ca_ArgumentNotFound" <<
160 "ca_ArgumentFound" <<
161 "ca_ArgumentFoundWithParameter";
164 DefaultDebugItems(
""), SessionPrepared(false), SessionRuntimeTimerName(
"SessionRuntime")
168 MC_ERROR(
"Only one MSContext instance can be created!");
172 qsrand(QDateTime::currentDateTimeUtc().toTime_t());
173 srand(QDateTime::currentDateTimeUtc().toTime_t());
175 if (graphical_context)
177 QApplication* QtContext =
new QApplication(argc, argv);
179 boost::scoped_ptr<QFont> AppFont(
new QFont(
"Courier New", 10));
181 QtContext->setFont(*AppFont);
184 App =
new QCoreApplication(argc, argv);
186 #if defined(__MINGW32__) || defined(__MINGW64__) 188 App->addLibraryPath(QDir::currentPath());
195 HeartSingleton =
new MSHeart();
196 connect(HeartSingleton, SIGNAL(BeatBegin(
int)),
this, SIGNAL(
NewHeartBeat(
int)), Qt::QueuedConnection);
197 connect(HeartSingleton, SIGNAL(Finished()),
this, SLOT(
HeartFinished()), Qt::QueuedConnection);
198 connect(
this, SIGNAL(
Stop()), HeartSingleton, SLOT(StopBeating()), Qt::QueuedConnection);
202 SessionStorageSingleton->connect(SessionStorageSingleton, SIGNAL(EndOfDatabase()),
204 SessionStorageSingleton->connect(HeartSingleton, SIGNAL(StorageForCurrentBeat(
int)),
205 SessionStorageSingleton, SLOT(BeatEnd(
int)));
213 signal(SIGFPE, MSSignalHandler);
214 signal(SIGSEGV, MSSignalHandler);
215 signal(SIGILL, MSSignalHandler);
216 signal(SIGINT, MSSignalHandler);
217 signal(SIGTERM, MSSignalHandler);
218 #if defined(__MINGW32__) || defined(__MINGW64__) 219 signal(SIGBREAK, MSSignalHandler);
221 signal(SIGABRT, MSSignalHandler);
236 if (SessionStorageSingleton)
238 SessionStorageSingleton->disconnect();
239 delete SessionStorageSingleton;
240 SessionStorageSingleton =
nullptr;
245 HeartSingleton->disconnect();
246 delete HeartSingleton;
247 HeartSingleton =
nullptr;
252 #ifdef AP_CPU_PROFILER 272 MC_ERROR(
"MSContext instance can not be created by MSContext::GetInstance()");
310 if (HeartSingleton->IsBeatingActive())
318 QDateTime CurrentDate = QDateTime::currentDateTime();
321 TempStr +=
"/sessions/";
322 TempStr += CurrentDate.toString(
"yyyy-MM-dd_hh.mm.ss");
330 return HeartSingleton->GetMaxBeats();
336 HeartSingleton->SetMaxBeats(max_beats);
348 return HeartSingleton->GetCurrentBeat();
366 return HeartSingleton->IsBeatFinished();
372 return MalfunctionStatus;
381 Result.Parameter =
nullptr;
404 MC_NPRINT(
"\nCommon options for libmindsession applications:\n" 406 " -c, --colordebug STRING Colorized debug mode, for the specified\n" 407 " classes/functions.\n" 408 " -d, --debug [STRING] Debug mode, optional argument: Only the specified\n" 409 " classes/functions are debugged, separated by commas.\n" 410 #ifdef AP_CPU_PROFILER
411 " -P, --profiling Run with processor profiler\n" 413 " -b, --beatlimit INT The beat limit for the heart\n" 414 " -h, --help Print this text\n\n");
444 #ifdef AP_CPU_PROFILER 445 ProfilerStart(
"./cpu_profiler.perf");
465 MC_NPRINT(
"Session run-time: %d ms (heart beats: %d, %.2f ms/beat)\n", RunTime,
466 HeartSingleton->GetCurrentBeat(), (float)RunTime / HeartSingleton->GetCurrentBeat());
468 for (
auto iter = Timers.begin(); iter != Timers.end(); ++iter)
472 MC_NPRINT(
"%s: %d ms (%.2f %%)\n", iter.value().Description.toAscii().data(),
473 iter.value().Time, (float)iter.value().Time*100 / RunTime);
496 MC_WARNING(
"A session has been prepared. Only sink elements can be registered.");
499 if (element.
GetType() != MS::Sink && element.
GetType() != MS::SinkGui && HeartSingleton->IsBeatingActive())
501 MC_WARNING(
"The heart beating is active. Only sink elements can be registered.");
509 connect(
this, SIGNAL(
Stop()), &element, SLOT(
Stop()));
512 if (HeartSingleton->IsBeatingActive())
514 HeartSingleton->RequestElementRegistration(element);
524 MC_WARNING(
"A session has been prepared. Only sink elements can be unregistered.");
527 if (element.
GetType() != MS::Sink && element.
GetType() != MS::SinkGui && HeartSingleton->IsBeatingActive())
529 MC_WARNING(
"The heart beating is active. Only sink elements can be unregistered.");
538 if (HeartSingleton->IsElementRegistered(element))
540 HeartSingleton->UnregisterElement(element);
542 disconnect(
this, SIGNAL(
Stop()), &element, SLOT(
Stop()));
549 HeartSingleton->SetBeatDurationLimit(new_limit);
557 MC_LOG(
"A session has been prepared already!");
588 MC_WARNING(
"There is no ongoing session to stop!");
592 SessionStorageSingleton->
Finalize();
611 HeartSingleton->StartBeating();
614 for (
auto iter = Timers.begin(); iter != Timers.end(); ++iter)
616 iter.value().Time = 0;
617 iter.value().Timer.restart();
626 HeartSingleton->StopBeating();
632 HeartSingleton->PauseBeating();
639 HeartSingleton->ResumeBeating();
651 if (description.isEmpty())
656 if (Timers.contains(
id))
658 MC_WARNING(
"A timer is already registered with the id %s.",
id.toAscii().data());
663 NewTimer.Description = description;
665 Timers[id] = NewTimer;
676 if (!Timers.contains(
id))
678 MC_WARNING(
"No timer is registered with this id %s.",
id.toAscii().data());
683 MC_WARNING(
"Timers are paused. Can't start a new timer.");
686 Timers[id].Timer.restart();
697 if (!Timers.contains(
id))
699 MC_WARNING(
"No timer is registered with this id %s.",
id.toAscii().data());
704 MC_WARNING(
"Timers are paused. Can't stop a timer.");
707 Timers[id].Time += Timers[id].Timer.elapsed();
708 Timers[id].Timer = QTime();
719 if (!Timers.contains(
id))
721 MC_WARNING(
"No timer is registered with this id %s.",
id.toAscii().data());
726 MC_WARNING(
"Timers are paused. Can't restart a new timer.");
730 Timers[id].Timer = QTime();
741 if (!Timers.contains(
id))
743 MC_WARNING(
"No timer is registered with this id %s.",
id.toAscii().data());
748 return Timers[id].Time;
750 if (Timers[
id].Timer.isValid())
752 Timers[id].Time += Timers[id].Timer.elapsed();
753 Timers[id].Timer = QTime();
754 Timers[id].Timer.start();
756 return Timers[id].Time;
767 PauseTimer =
new QTime();
776 MC_WARNING(
"Timers have not been paused yet.");
779 int PauseTime = PauseTimer->elapsed();
782 PauseTimer =
nullptr;
783 for (
auto iter = Timers.begin(); iter != Timers.end(); ++iter)
785 if (iter.value().Timer.isValid())
787 iter.value().Time += iter.value().Timer.elapsed()-PauseTime;
788 iter.value().Timer = QTime();
789 iter.value().Timer.start();
int GetPlayedHeartBeats() const
Get the number of the played heart beats.
int GetCurrentBeat() const
Get the current beat ID.
Load or store the source elements' output of a session.
void PreparePlay()
Prepare the play of a recorded session.
static void RegisterTimer(const QString &id, const QString &description)
Register a timer.
QString GenerateRecordPath()
Generate a record path.
void FindMindSessionArgs()
Find libmindsession specific command line arguments.
Creates a context for an application.
void HeartFinished()
Listen to the end of the heart.
Interface class to handle new types in the storage.
static void PauseTimers()
Pause the timers.
int GetElementID() const
Get the element ID.
void ResetTimers()
Reset the internal timers.
bool IsPaused() const
Whenever the context is paused.
void SetRecordPath(const QString &record_path)
Set the path of the record directory.
QString GetDefaultDebugItems() const
Get default active debug items.
void SetPlaybackPath(const QString &path)
Set the playback path.
QString DefaultDebugItems
Default active debugged items.
static MSSessionStorage * GetInstance()
Get a static instance of the class.
Basic ancestor class of the elements.
bool IsMalfunctionHappened() const
Whenever a malfunction happened in the context.
static void ResumeTimers()
Resume the timers.
#define MC_ERROR(...)
Error macro.
static void StartTimer(const QString &id)
Start a timer.
bool SessionPrepared
The heart beating is prepared.
#define MC_WARNING(...)
Warning macro.
virtual void StartHeartBeating()
Start the heart beating.
bool IsBeatingFinished() const
Whenever the heart beating is finished.
void PlayedSessionFinished()
The played session is finished.
virtual void StopHeartBeating()
Stop the heart beating.
QString GetRecordPath() const
Get the path of the record directory.
virtual void Resume()
Resume the context.
static void SetDebugStatus(bool new_status, bool global=false)
Set debug status.
bool CPUProfiling
CPU profiling.
ArgSearchResult FindArgument(const QString &arg, const QString &long_arg)
Find an argument.
void UnregisterElement(MSElement &element)
Unregister an element.
#define MC_NPRINT(...)
Print macro with normal letters without colors.
static int GetTimerElapsedTime(const QString &id)
Get the elapsed time of a timer.
void NewHeartBeat(int beat_id)
New heart beat.
void RegisterSessionStorage(MSSessionStorageInterface &storage)
Register a session storage.
int GetPlayedBeats() const
Get the played beats.
T MCRandComplex(const T &min, const T &max)
Get a random number generated with an advanced algorithm.
static void ResetTimer(const QString &id)
Reset a timer.
void SetMaxBeats(int max_beats)
Set the limit of the beats.
virtual bool PrepareSession()
Prepare a session.
#define MC_BPRINT(color,...)
Print macro with bold letters.
#define MC_DIR_SEPARATOR
Directory separator macro.
void HeartStopped()
The heart has been stopped.
QString GetPlaybackPath() const
Get the playback path.
bool HasRegisteredElements() const
Has registered elements.
void SetPlaybackPath(const QString &play_path)
Set the path of the play directory.
static void SetNewSeed(int seed=(int) time(nullptr))
Set a new global random seed based on the system time.
virtual void FinishSession()
Finish a session.
void Finalize()
Finalize the storage operations.
void SetBeatDurationLimit(int new_limit)
Set the beat duration limit.
QString GetPlaybackPath() const
Get the path of the play directory.
QList< MSElement * > RegElements
Elements to be registered by the heart beat.
~MSContext()
Class destructor.
void RegisterStorage(MSSessionStorageInterface &storage)
Register a session storage.
MS::ElementType GetType() const
Get the type of the element.
void Stop()
Stop the activities in the context.
QStringList ProgramArguments
Command line arguments.
QString MSGetBasePath()
Get the base path.
MSContext(int &argc, char **argv, bool graphical_context=false)
Class constructor.
void SetDefaultDebugItems(const QString &items)
Set default active debug items.
virtual void Pause()
Pause the context.
static void SetDebugFilter(const std::string &new_filter)
Set debug filter.
#define MC_LOG(...)
Debug macro.
static void StopTimer(const QString &id)
Stop a timer.
QString GetRecordPath() const
Get the record path.
void RegisterElement(MSElement &element)
Register a new element.
void RegisterElement(MSElement &object)
Register an element.
void SetRecordPath(const QString &record_path)
Set the record path.
void PrepareRecord()
Prepare the record of a new session.
static MSContext * GetInstance()
Get a static instance of the class.
int GetMaxBeats() const
Get the limit of the beats.
const QString SessionRuntimeTimerName
Session runtime timer name.
static void SetDebugColorFilters(const std::string &new_color_filters)
Set debug color filters.