From d431f9d7906610fa544cf44b45fe1cd04b063638 Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Tue, 3 Mar 2015 21:28:07 +0100 Subject: [PATCH] [DEV] rework hw synchronisme to group interface and correct parsing of timestamp mode --- data/hardwareLinux.json | 9 +-- lutin_river.py | 1 + river/CircularBuffer.cpp | 9 ++- river/io/Group.cpp | 135 +++++++++++++++++++++++++++++++++++++ river/io/Group.h | 34 ++++++++++ river/io/Manager.cpp | 100 +++++++++++++++++++++------ river/io/Manager.h | 6 ++ river/io/Node.cpp | 39 ++++++----- river/io/Node.h | 16 ++++- river/io/NodeAEC.cpp | 8 ++- river/io/NodeAirTAudio.cpp | 15 +---- river/io/NodeAirTAudio.h | 2 + 12 files changed, 310 insertions(+), 64 deletions(-) create mode 100644 river/io/Group.cpp create mode 100644 river/io/Group.h diff --git a/data/hardwareLinux.json b/data/hardwareLinux.json index d2293bf..f15fc41 100644 --- a/data/hardwareLinux.json +++ b/data/hardwareLinux.json @@ -10,10 +10,10 @@ # name of the interface # name:"default", name:"hw:0,0", - timestamp-mode:"hardware", + timestamp-mode:"trigered", }, - # lik hardware ti the specified IO name : - hw-link:"speaker", + # Link 2 ios with the same time in low level (named group) : + group:"baseIOSynchrone", # frequency to open device frequency:48000, # mapping of the harware device (mapping is not get under) @@ -32,8 +32,9 @@ interface:"alsa", #name:"default", name:"hw:0,0", - timestamp-mode:"hardware", + timestamp-mode:"trigered", }, + group:"baseIOSynchrone", frequency:48000, channel-map:[ "front-left", "front-right", diff --git a/lutin_river.py b/lutin_river.py index 96bac4b..7527cf6 100644 --- a/lutin_river.py +++ b/lutin_river.py @@ -15,6 +15,7 @@ def create(target): 'river/Manager.cpp', 'river/Interface.cpp', 'river/CircularBuffer.cpp', + 'river/io/Group.cpp', 'river/io/Node.cpp', 'river/io/NodeAirTAudio.cpp', 'river/io/NodePortAudio.cpp', diff --git a/river/CircularBuffer.cpp b/river/CircularBuffer.cpp index cdd2273..a24ef9f 100644 --- a/river/CircularBuffer.cpp +++ b/river/CircularBuffer.cpp @@ -234,16 +234,18 @@ size_t river::CircularBuffer::read(void* _data, size_t _nbChunk, const std11::ch // return the number of element droped return nbElementDrop; } + void river::CircularBuffer::setReadPosition(const std11::chrono::system_clock::time_point& _time) { // Critical section (theoriquely protected by Mutex) size_t usedSizeBeforeEnd = getUsedSizeBeforEnd(); if (0 < m_size) { // check the time of the read : std11::chrono::nanoseconds deltaTime = _time - m_timeRead; - size_t nbSampleToRemove = m_frequency*deltaTime.count()/1000000000; + size_t nbSampleToRemove = int64_t(m_frequency)*int64_t(deltaTime.count())/1000000000LL; nbSampleToRemove = std::min(nbSampleToRemove, m_size); - RIVER_WARNING("Remove sample in the buffer " << nbSampleToRemove << " / " << m_size); - std11::chrono::nanoseconds updateTime((nbSampleToRemove*1000000000)/int64_t(m_frequency)); + RIVER_VERBOSE("Remove sample in the buffer " << nbSampleToRemove << " / " << m_size); + std11::chrono::nanoseconds updateTime((int64_t(nbSampleToRemove)*1000000000LL)/int64_t(m_frequency)); + RIVER_VERBOSE(" add time : " << updateTime.count() << "ns / " << deltaTime.count() << "ns"); if (usedSizeBeforeEnd >= nbSampleToRemove) { usedSizeBeforeEnd -= nbSampleToRemove; m_size -= nbSampleToRemove; @@ -260,6 +262,7 @@ void river::CircularBuffer::setReadPosition(const std11::chrono::system_clock::t } } + size_t river::CircularBuffer::getFreeSize() const { return m_capacity - m_size; } diff --git a/river/io/Group.cpp b/river/io/Group.cpp new file mode 100644 index 0000000..34e2fd1 --- /dev/null +++ b/river/io/Group.cpp @@ -0,0 +1,135 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2015, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#include +#include +#include "Node.h" +#include "NodeAEC.h" +#include "NodeAirTAudio.h" +#include "NodePortAudio.h" +#include "Node.h" + +#undef __class__ +#define __class__ "io::Group" + +void river::io::Group::createFrom(const ejson::Document& _obj, const std::string& _name) { + RIVER_INFO("Create Group[" << _name << "] (START) ___________________________"); + for (size_t iii=0; iii<_obj.size(); ++iii) { + const std11::shared_ptr tmpObject = _obj.getObject(_obj.getKey(iii)); + if (tmpObject == nullptr) { + continue; + } + std::string groupName = tmpObject->getStringValue("group", ""); + if (groupName == _name) { + RIVER_INFO("Add element in Group[" << _name << "]: " << _obj.getKey(iii)); + // get type : io + std::string ioType = tmpObject->getStringValue("io", "error"); + #ifdef __AIRTAUDIO_INFERFACE__ + if ( ioType == "input" + || ioType == "output") { + std11::shared_ptr tmp = river::io::NodeAirTAudio::create(_obj.getKey(iii), tmpObject); + tmp->setGroup(shared_from_this()); + m_list.push_back(tmp); + } + #endif + #ifdef __PORTAUDIO_INFERFACE__ + if ( ioType == "PAinput" + || ioType == "PAoutput") { + std11::shared_ptr tmp = river::io::NodePortAudio::create(_obj.getKey(iii), tmpObject); + tmp->setGroup(shared_from_this()); + m_list.push_back(tmp); + } + #endif + } + } + // Link all the IO together : (not needed if one device ... + // Note : The interlink work only for alsa (NOW) and with AirTAudio... + if(m_list.size() > 1) { + #ifdef __AIRTAUDIO_INFERFACE__ + std11::shared_ptr linkRef = std11::dynamic_pointer_cast(m_list[0]); + for (size_t iii=1; iii link = std11::dynamic_pointer_cast(m_list[iii]); + linkRef->m_adac.isMasterOf(link->m_adac); + } + } + #endif + } + /* + // manage Link Between Nodes : + if (m_link != nullptr) { + RIVER_INFO("******** START LINK ************"); + std11::shared_ptr link = std11::dynamic_pointer_cast(m_link); + if (link == nullptr) { + RIVER_ERROR("Can not link 2 Interface with not the same type (reserved for HW interface)"); + return; + } + link->m_adac.isMasterOf(m_adac); + // TODO : Add return ... + RIVER_INFO("******** LINK might be done ************"); + } + */ + RIVER_INFO("Create Group[" << _name << "] ( END ) ___________________________"); + RIVER_INFO("Group[" << _name << "] List elements : "); + for (size_t iii=0; iiigetName()); + } + } +} + + +std11::shared_ptr river::io::Group::getNode(const std::string& _name) { + for (size_t iii=0; iiigetName() == _name) { + return m_list[iii]; + } + } + } + return std11::shared_ptr(); +} + +void river::io::Group::start() { + RIVER_ERROR("request start "); + int32_t count = 0; + for (size_t iii=0; iiigetNumberOfInterface(); + } + } + RIVER_ERROR(" have " << count << " interfaces ..."); + if (count == 1) { + RIVER_ERROR("GROUP :::::::::::: START() [START]"); + for (size_t iii=0; iiistart(); + } + } + RIVER_ERROR("GROUP :::::::::::: START() [DONE]"); + } +} + +void river::io::Group::stop() { + RIVER_ERROR("request stop "); + int32_t count = 0; + for (size_t iii=0; iiigetNumberOfInterface(); + } + } + RIVER_ERROR(" have " << count << " interfaces ..."); + if (count == 0) { + RIVER_ERROR("GROUP :::::::::::: STOP() [START]"); + for (size_t iii=0; iiistop(); + } + } + RIVER_ERROR("GROUP :::::::::::: STOP() [DONE]"); + } +} + diff --git a/river/io/Group.h b/river/io/Group.h new file mode 100644 index 0000000..2e36b7c --- /dev/null +++ b/river/io/Group.h @@ -0,0 +1,34 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2015, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#ifndef __RIVER_IO_GROUP_H__ +#define __RIVER_IO_GROUP_H__ + +#include +#include +#include + +namespace river { + namespace io { + class Node; + class Manager; + class Group : public std11::enable_shared_from_this { + public: + Group() {} + ~Group() {} + private: + std::vector< std11::shared_ptr > m_list; + public: + void createFrom(const ejson::Document& _obj, const std::string& _name); + std11::shared_ptr getNode(const std::string& _name); + void start(); + void stop(); + }; + } +} + +#endif + diff --git a/river/io/Manager.cpp b/river/io/Manager.cpp index 1e18238..7de5b7c 100644 --- a/river/io/Manager.cpp +++ b/river/io/Manager.cpp @@ -11,6 +11,9 @@ #include "NodeAirTAudio.h" #include "NodePortAudio.h" #include +#include +#include +#include #undef __class__ #define __class__ "io::Manager" @@ -84,40 +87,74 @@ std11::shared_ptr river::io::Manager::getInstance() { std11::shared_ptr river::io::Manager::getNode(const std::string& _name) { RIVER_WARNING("Get node : " << _name); + // search in the standalone list : for (size_t iii=0; iii tmppp = m_list[iii].lock(); if ( tmppp != nullptr && _name == tmppp->getName()) { - RIVER_WARNING(" find it ... "); + RIVER_WARNING(" find it ... in standalone"); return tmppp; } } + // search in the group list: + { + for (std::map >::iterator it(m_listGroup.begin()); + it != m_listGroup.end(); + ++it) { + if (it->second != nullptr) { + std11::shared_ptr node = it->second->getNode(_name); + if (node != nullptr) { + RIVER_WARNING(" find it ... in group: " << it->first); + return node; + } + } + } + } RIVER_WARNING("Create a new one : " << _name); // check if the node can be open : const std11::shared_ptr tmpObject = m_config.getObject(_name); if (tmpObject != nullptr) { + //Check if it is in a group: + std::string groupName = tmpObject->getStringValue("group", ""); // get type : io std::string ioType = tmpObject->getStringValue("io", "error"); - #ifdef __AIRTAUDIO_INFERFACE__ - if ( ioType == "input" - || ioType == "output") { - std11::shared_ptr tmp = river::io::NodeAirTAudio::create(_name, tmpObject); - m_list.push_back(tmp); - return tmp; - } else - #endif - #ifdef __PORTAUDIO_INFERFACE__ - if ( ioType == "PAinput" - || ioType == "PAoutput") { - std11::shared_ptr tmp = river::io::NodePortAudio::create(_name, tmpObject); - m_list.push_back(tmp); - return tmp; - } else - #endif - if (ioType == "aec") { - std11::shared_ptr tmp = river::io::NodeAEC::create(_name, tmpObject); - m_list.push_back(tmp); - return tmp; + if ( groupName != "" + && ( ioType == "input" + || ioType == "output" + || ioType == "PAinput" + || ioType == "PAoutput") ) { + std11::shared_ptr tmpGroup = getGroup(groupName); + if (tmpGroup == nullptr) { + RIVER_WARNING("Can not get group ... '" << groupName << "'"); + return std11::shared_ptr(); + } + return tmpGroup->getNode(_name); + } else { + if (groupName != "") { + RIVER_WARNING("Group is only availlable for Hardware interface ... '" << _name << "'"); + } + // TODO : Create a standalone group for every single element ==> simplify understanding ... but not for virtual interface ... + #ifdef __AIRTAUDIO_INFERFACE__ + if ( ioType == "input" + || ioType == "output") { + std11::shared_ptr tmp = river::io::NodeAirTAudio::create(_name, tmpObject); + m_list.push_back(tmp); + return tmp; + } + #endif + #ifdef __PORTAUDIO_INFERFACE__ + if ( ioType == "PAinput" + || ioType == "PAoutput") { + std11::shared_ptr tmp = river::io::NodePortAudio::create(_name, tmpObject); + m_list.push_back(tmp); + return tmp; + } + #endif + if (ioType == "aec") { + std11::shared_ptr tmp = river::io::NodeAEC::create(_name, tmpObject); + m_list.push_back(tmp); + return tmp; + } } } RIVER_ERROR("Can not create the interface : '" << _name << "' the node is not DEFINED in the configuration file availlable : " << m_config.getKeys()); @@ -196,3 +233,24 @@ void river::io::Manager::generateDot(const std::string& _filename) { node.fileClose(); RIVER_INFO("Generate the DOT files: " << node << " (DONE)"); } + +std11::shared_ptr river::io::Manager::getGroup(const std::string& _name) { + std11::shared_ptr out; + std::map >::iterator it = m_listGroup.find(_name); + if (it == m_listGroup.end()) { + RIVER_INFO("Create a new group: " << _name << " (START)"); + out = std11::make_shared(); + if (out != nullptr) { + out->createFrom(m_config, _name); + std::pair > plop(std::string(_name), out); + m_listGroup.insert(plop); + RIVER_INFO("Create a new group: " << _name << " ( END )"); + } else { + RIVER_ERROR("Can not create new group: " << _name << " ( END )"); + } + } else { + out = it->second; + } + + return out; +} \ No newline at end of file diff --git a/river/io/Manager.h b/river/io/Manager.h index 7af0224..8adf84b 100644 --- a/river/io/Manager.h +++ b/river/io/Manager.h @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -18,6 +19,7 @@ #include