mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-12 10:49:59 +01:00
Fixed Session load recursion, allow higher level of imbrication
Recursive load of SessionFile in a Session is now detected by filename and prevented. Deeper level of integration of sessionfile inside session is thus possible (set to 3). Sessions now have an id, allowing to reference them by id in the logs. Terminology is clarified between level and recursion.
This commit is contained in:
10
Session.cpp
10
Session.cpp
@@ -42,9 +42,13 @@ SessionNote::SessionNote(const std::string &t, bool l, int s): label(std::to_str
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Session::Session() : active_(true), activation_threshold_(MIXING_MIN_THRESHOLD),
|
Session::Session(uint64_t id) : id_(id), active_(true), activation_threshold_(MIXING_MIN_THRESHOLD),
|
||||||
filename_(""), failedSource_(nullptr), thumbnail_(nullptr)
|
filename_(""), failedSource_(nullptr), thumbnail_(nullptr)
|
||||||
{
|
{
|
||||||
|
// create unique id
|
||||||
|
if (id_ == 0)
|
||||||
|
id_ = BaseToolkit::uniqueId();
|
||||||
|
|
||||||
config_[View::RENDERING] = new Group;
|
config_[View::RENDERING] = new Group;
|
||||||
config_[View::RENDERING]->scale_ = glm::vec3(0.f);
|
config_[View::RENDERING]->scale_ = glm::vec3(0.f);
|
||||||
|
|
||||||
@@ -669,10 +673,10 @@ void Session::validate (SourceList &sources)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Session *Session::load(const std::string& filename, uint recursion)
|
Session *Session::load(const std::string& filename, uint level)
|
||||||
{
|
{
|
||||||
// create session
|
// create session
|
||||||
SessionCreator creator(recursion);
|
SessionCreator creator(level);
|
||||||
creator.load(filename);
|
creator.load(filename);
|
||||||
|
|
||||||
// return created session
|
// return created session
|
||||||
|
|||||||
@@ -38,10 +38,13 @@ class Session
|
|||||||
friend class RenderSource;
|
friend class RenderSource;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Session();
|
Session(uint64_t id = 0);
|
||||||
~Session();
|
~Session();
|
||||||
|
|
||||||
static Session *load(const std::string& filename, uint recursion = 0);
|
// Get unique id
|
||||||
|
inline uint64_t id () const { return id_; }
|
||||||
|
|
||||||
|
static Session *load(const std::string& filename, uint level = 0);
|
||||||
static std::string save(const std::string& filename, Session *session, const std::string& snapshot_name = "");
|
static std::string save(const std::string& filename, Session *session, const std::string& snapshot_name = "");
|
||||||
|
|
||||||
// add given source into the session
|
// add given source into the session
|
||||||
@@ -169,6 +172,7 @@ public:
|
|||||||
Metronome::Synchronicity inputSynchrony(uint input);
|
Metronome::Synchronicity inputSynchrony(uint input);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
uint64_t id_;
|
||||||
bool active_;
|
bool active_;
|
||||||
float activation_threshold_;
|
float activation_threshold_;
|
||||||
RenderView render_;
|
RenderView render_;
|
||||||
|
|||||||
@@ -94,25 +94,34 @@ SessionInformation SessionCreator::info(const std::string& filename)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionCreator::SessionCreator(int recursion): SessionLoader(nullptr, recursion)
|
SessionCreator::SessionCreator(uint level): SessionLoader(nullptr, level)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionCreator::load(const std::string& filename)
|
void SessionCreator::load(const std::string& filename)
|
||||||
{
|
{
|
||||||
|
// avoid imbricated sessions at too many depth
|
||||||
|
if (level_ > MAX_SESSION_LEVEL) {
|
||||||
|
Log::Warning("Too many imbricated sessions detected! Interrupting loading at depth %d.\n", MAX_SESSION_LEVEL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load XML document
|
||||||
XMLError eResult = xmlDoc_.LoadFile(filename.c_str());
|
XMLError eResult = xmlDoc_.LoadFile(filename.c_str());
|
||||||
if ( XMLResultError(eResult)){
|
if ( XMLResultError(eResult)){
|
||||||
Log::Warning("%s could not be opened.\n%s", filename.c_str(), xmlDoc_.ErrorStr());
|
Log::Warning("%s could not be opened.\n%s", filename.c_str(), xmlDoc_.ErrorStr());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check header
|
||||||
XMLElement *header = xmlDoc_.FirstChildElement(APP_NAME);
|
XMLElement *header = xmlDoc_.FirstChildElement(APP_NAME);
|
||||||
if (header == nullptr) {
|
if (header == nullptr) {
|
||||||
Log::Warning("%s is not a %s session file.", filename.c_str(), APP_NAME);
|
Log::Warning("%s is not a %s file.", filename.c_str(), APP_NAME);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check version
|
||||||
int version_major = -1, version_minor = -1;
|
int version_major = -1, version_minor = -1;
|
||||||
header->QueryIntAttribute("major", &version_major);
|
header->QueryIntAttribute("major", &version_major);
|
||||||
header->QueryIntAttribute("minor", &version_minor);
|
header->QueryIntAttribute("minor", &version_minor);
|
||||||
@@ -124,15 +133,28 @@ void SessionCreator::load(const std::string& filename)
|
|||||||
// return;
|
// return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check content
|
||||||
|
XMLElement *sessionNode = xmlDoc_.FirstChildElement("Session");
|
||||||
|
if (sessionNode == nullptr) {
|
||||||
|
Log::Warning("%s is not a %s session file.", filename.c_str(), APP_NAME);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read id of session
|
||||||
|
uint64_t id__ = 0;
|
||||||
|
sessionNode->QueryUnsigned64Attribute("id", &id__);
|
||||||
|
|
||||||
// session file seems legit, create a session
|
// session file seems legit, create a session
|
||||||
session_ = new Session;
|
session_ = new Session(id__);
|
||||||
|
|
||||||
|
// set filename and current path
|
||||||
|
sessionFilePath_ = SystemToolkit::path_filename(filename);
|
||||||
|
session_->setFilename( filename );
|
||||||
|
|
||||||
// load views config (includes resolution of session rendering)
|
// load views config (includes resolution of session rendering)
|
||||||
loadConfig( xmlDoc_.FirstChildElement("Views") );
|
loadConfig( xmlDoc_.FirstChildElement("Views") );
|
||||||
|
|
||||||
// ready to read sources
|
// ready to read sources
|
||||||
sessionFilePath_ = SystemToolkit::path_filename(filename);
|
|
||||||
XMLElement *sessionNode = xmlDoc_.FirstChildElement("Session");
|
|
||||||
SessionLoader::load( sessionNode );
|
SessionLoader::load( sessionNode );
|
||||||
|
|
||||||
// load snapshots
|
// load snapshots
|
||||||
@@ -157,7 +179,9 @@ void SessionCreator::load(const std::string& filename)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// all good
|
// all good
|
||||||
session_->setFilename(filename);
|
Log::Info("Session %s Opened '%s' (%d sources)", std::to_string(session_->id()).c_str(),
|
||||||
|
filename.c_str(), session_->numSource());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -295,21 +319,13 @@ void SessionCreator::loadPlayGroups(tinyxml2::XMLElement *playgroupNode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionLoader::SessionLoader(): Visitor(),
|
SessionLoader::SessionLoader(Session *session, uint level): Visitor(),
|
||||||
session_(nullptr), xmlCurrent_(nullptr), recursion_(0)
|
session_(session), xmlCurrent_(nullptr), level_(level)
|
||||||
{
|
{
|
||||||
// impose C locale
|
// impose C locale
|
||||||
setlocale(LC_ALL, "C");
|
setlocale(LC_ALL, "C");
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionLoader::SessionLoader(Session *session, int recursion): Visitor(),
|
|
||||||
session_(session), xmlCurrent_(nullptr), recursion_(recursion)
|
|
||||||
{
|
|
||||||
// impose C locale
|
|
||||||
setlocale(LC_ALL, "C");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::map< uint64_t, Source* > SessionLoader::getSources() const
|
std::map< uint64_t, Source* > SessionLoader::getSources() const
|
||||||
{
|
{
|
||||||
return sources_id_;
|
return sources_id_;
|
||||||
@@ -345,16 +361,12 @@ void SessionLoader::load(XMLElement *sessionNode)
|
|||||||
{
|
{
|
||||||
sources_id_.clear();
|
sources_id_.clear();
|
||||||
|
|
||||||
if (recursion_ > MAX_SESSION_LEVEL) {
|
|
||||||
Log::Warning("Recursive or imbricated sessions detected! Interrupting loading after %d iterations.\n", MAX_SESSION_LEVEL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sessionNode != nullptr && session_ != nullptr)
|
if (sessionNode != nullptr && session_ != nullptr)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// session attributes
|
// session attributes
|
||||||
//
|
//
|
||||||
|
// read and set activation threshold
|
||||||
float t = MIXING_MIN_THRESHOLD;
|
float t = MIXING_MIN_THRESHOLD;
|
||||||
sessionNode->QueryFloatAttribute("activationThreshold", &t);
|
sessionNode->QueryFloatAttribute("activationThreshold", &t);
|
||||||
session_->setActivationThreshold(t);
|
session_->setActivationThreshold(t);
|
||||||
@@ -411,6 +423,9 @@ void SessionLoader::load(XMLElement *sessionNode)
|
|||||||
else if ( std::string(pType) == "SrtReceiverSource") {
|
else if ( std::string(pType) == "SrtReceiverSource") {
|
||||||
load_source = new SrtReceiverSource(id_xml_);
|
load_source = new SrtReceiverSource(id_xml_);
|
||||||
}
|
}
|
||||||
|
else if ( std::string(pType) != "CloneSource") {
|
||||||
|
Log::Info("Unknown source type '%s' ignored.", pType);
|
||||||
|
}
|
||||||
|
|
||||||
// skip failed (including clones)
|
// skip failed (including clones)
|
||||||
if (!load_source)
|
if (!load_source)
|
||||||
@@ -764,7 +779,7 @@ void SessionLoader::visit(MediaPlayer &n)
|
|||||||
XMLElement* mediaplayerNode = xmlCurrent_->FirstChildElement("MediaPlayer");
|
XMLElement* mediaplayerNode = xmlCurrent_->FirstChildElement("MediaPlayer");
|
||||||
|
|
||||||
if (mediaplayerNode) {
|
if (mediaplayerNode) {
|
||||||
uint64_t id__ = -1;
|
uint64_t id__ = 0;
|
||||||
mediaplayerNode->QueryUnsigned64Attribute("id", &id__);
|
mediaplayerNode->QueryUnsigned64Attribute("id", &id__);
|
||||||
|
|
||||||
// timeline
|
// timeline
|
||||||
@@ -1004,17 +1019,28 @@ void SessionLoader::visit (SessionFileSource& s)
|
|||||||
const char * text = pathNode->GetText();
|
const char * text = pathNode->GetText();
|
||||||
if (text) {
|
if (text) {
|
||||||
std::string path(text);
|
std::string path(text);
|
||||||
// load only new files
|
|
||||||
if ( path != s.path() ) {
|
|
||||||
if ( !SystemToolkit::file_exists(path) ){
|
if ( !SystemToolkit::file_exists(path) ){
|
||||||
const char * relative;
|
const char * relative;
|
||||||
if ( pathNode->QueryStringAttribute("relative", &relative) == XML_SUCCESS) {
|
if ( pathNode->QueryStringAttribute("relative", &relative) == XML_SUCCESS) {
|
||||||
std::string rel = SystemToolkit::path_absolute_from_path(std::string( relative ), sessionFilePath_);
|
std::string rel = SystemToolkit::path_absolute_from_path(std::string( relative ), sessionFilePath_);
|
||||||
Log::Info("File %s not found; Trying %s instead.", path.c_str(), rel.c_str());
|
Log::Info("File '%s' not found; Trying '%s' instead.", path.c_str(), rel.c_str());
|
||||||
path = rel;
|
path = rel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.load(path, recursion_ + 1);
|
// load only if session source s is new
|
||||||
|
if ( path != s.path() ) {
|
||||||
|
// level of session imbrication
|
||||||
|
uint l = level_;
|
||||||
|
if ( path == session_->filename() && l < MAX_SESSION_LEVEL) {
|
||||||
|
// prevent recursive load by reaching maximum level of inclusion immediately
|
||||||
|
l += MAX_SESSION_LEVEL;
|
||||||
|
Log::Warning("Prevending recursive inclusion of Session '%s' into itself.", path.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// normal increment level of inclusion
|
||||||
|
++l;
|
||||||
|
// launch session loader at incremented level
|
||||||
|
s.load(path, l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1032,7 +1058,7 @@ void SessionLoader::visit (SessionGroupSource& s)
|
|||||||
// only parse if newly created
|
// only parse if newly created
|
||||||
if (s.session()->empty()) {
|
if (s.session()->empty()) {
|
||||||
// load session inside group
|
// load session inside group
|
||||||
SessionLoader grouploader( s.session(), recursion_ + 1 );
|
SessionLoader grouploader( s.session(), level_ + 1 );
|
||||||
grouploader.load( sessionGroupNode );
|
grouploader.load( sessionGroupNode );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef SESSIONCREATOR_H
|
#ifndef SESSIONCREATOR_H
|
||||||
#define SESSIONCREATOR_H
|
#define SESSIONCREATOR_H
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <tinyxml2.h>
|
#include <tinyxml2.h>
|
||||||
|
|
||||||
@@ -13,11 +14,9 @@ class FrameBufferImage;
|
|||||||
|
|
||||||
class SessionLoader : public Visitor {
|
class SessionLoader : public Visitor {
|
||||||
|
|
||||||
SessionLoader();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SessionLoader(Session *session, int recursion = 0);
|
SessionLoader(Session *session = nullptr, uint level = 0);
|
||||||
inline Session *session() const { return session_; }
|
inline Session *session() const { return session_; }
|
||||||
|
|
||||||
void load(tinyxml2::XMLElement *sessionNode);
|
void load(tinyxml2::XMLElement *sessionNode);
|
||||||
@@ -84,8 +83,8 @@ protected:
|
|||||||
std::string sessionFilePath_;
|
std::string sessionFilePath_;
|
||||||
// parsing current xml
|
// parsing current xml
|
||||||
tinyxml2::XMLElement *xmlCurrent_;
|
tinyxml2::XMLElement *xmlCurrent_;
|
||||||
// level of loading recursion
|
// level of loading imbricated sessions and recursion
|
||||||
int recursion_;
|
uint level_;
|
||||||
// map of correspondance from xml source id (key) to new source pointer (value)
|
// map of correspondance from xml source id (key) to new source pointer (value)
|
||||||
std::map< uint64_t, Source* > sources_id_;
|
std::map< uint64_t, Source* > sources_id_;
|
||||||
// list of groups (lists of xml source id)
|
// list of groups (lists of xml source id)
|
||||||
@@ -115,7 +114,7 @@ class SessionCreator : public SessionLoader {
|
|||||||
void loadInputCallbacks(tinyxml2::XMLElement *inputsNode);
|
void loadInputCallbacks(tinyxml2::XMLElement *inputsNode);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SessionCreator(int recursion = 0);
|
SessionCreator(uint level = 0);
|
||||||
|
|
||||||
void load(const std::string& filename);
|
void load(const std::string& filename);
|
||||||
|
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ SessionFileSource::SessionFileSource(uint64_t id) : SessionSource(id), path_("")
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionFileSource::load(const std::string &p, uint recursion)
|
void SessionFileSource::load(const std::string &p, uint level)
|
||||||
{
|
{
|
||||||
path_ = p;
|
path_ = p;
|
||||||
|
|
||||||
@@ -192,7 +192,7 @@ void SessionFileSource::load(const std::string &p, uint recursion)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// launch a thread to load the session file
|
// launch a thread to load the session file
|
||||||
sessionLoader_ = std::async(std::launch::async, Session::load, path_, recursion);
|
sessionLoader_ = std::async(std::launch::async, Session::load, path_, level);
|
||||||
Log::Notify("Opening %s", p.c_str());
|
Log::Notify("Opening %s", p.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +229,7 @@ void SessionFileSource::init()
|
|||||||
// done init
|
// done init
|
||||||
wait_for_sources_ = false;
|
wait_for_sources_ = false;
|
||||||
initialized_ = true;
|
initialized_ = true;
|
||||||
Log::Info("Source Session %s loaded %d sources.", path_.c_str(), session_->numSource());
|
Log::Info("Source '%s' linked to Session %s.", name().c_str(), std::to_string(session_->id()).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( !failed_ ) {
|
else if ( !failed_ ) {
|
||||||
@@ -254,7 +254,7 @@ void SessionFileSource::init()
|
|||||||
wait_for_sources_ = true;
|
wait_for_sources_ = true;
|
||||||
else {
|
else {
|
||||||
initialized_ = true;
|
initialized_ = true;
|
||||||
Log::Info("New Session created (%d x %d).", renderbuffer->width(), renderbuffer->height());
|
Log::Info("Source '%s' linked to new Session %s.", name().c_str(), std::to_string(session_->id()).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public:
|
|||||||
void render() override;
|
void render() override;
|
||||||
|
|
||||||
// SessionFile Source specific interface
|
// SessionFile Source specific interface
|
||||||
void load(const std::string &p = "", uint recursion = 0);
|
void load(const std::string &p = "", uint level = 0);
|
||||||
|
|
||||||
inline std::string path() const { return path_; }
|
inline std::string path() const { return path_; }
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ bool SessionVisitor::saveSession(const std::string& filename, Session *session)
|
|||||||
(*iter)->accept(sv);
|
(*iter)->accept(sv);
|
||||||
|
|
||||||
// save session attributes
|
// save session attributes
|
||||||
|
sessionNode->SetAttribute("id", session->id());
|
||||||
sessionNode->SetAttribute("activationThreshold", session->activationThreshold());
|
sessionNode->SetAttribute("activationThreshold", session->activationThreshold());
|
||||||
|
|
||||||
// save the thumbnail
|
// save the thumbnail
|
||||||
@@ -664,6 +665,7 @@ void SessionVisitor::visit (SessionGroupSource& s)
|
|||||||
Session *se = s.session();
|
Session *se = s.session();
|
||||||
if (se) {
|
if (se) {
|
||||||
XMLElement *sessionNode = xmlDoc_->NewElement("Session");
|
XMLElement *sessionNode = xmlDoc_->NewElement("Session");
|
||||||
|
sessionNode->SetAttribute("id", se->id());
|
||||||
xmlCurrent_->InsertEndChild(sessionNode);
|
xmlCurrent_->InsertEndChild(sessionNode);
|
||||||
|
|
||||||
for (auto iter = se->begin(); iter != se->end(); ++iter){
|
for (auto iter = se->begin(); iter != se->end(); ++iter){
|
||||||
|
|||||||
Reference in New Issue
Block a user