diff --git a/data/hardwareNao.json b/data/hardwareNao.json new file mode 100644 index 0000000..eae1268 --- /dev/null +++ b/data/hardwareNao.json @@ -0,0 +1,135 @@ +{ + speaker:{ + io:"output", + map-on:{ + interface:"alsa", + name:"AD1989A_outputs", + timestamp-mode:"trigered", + }, + frequency:48000, + channel-map:[ + "front-left", "front-right", + ], + type:"int16", + nb-chunk:6000, + volume-name:"MASTER", + mux-demux-type:"int16-on-int32", + }, + microphone:{ + io:"input", + map-on:{ + interface:"alsa", + name:"AD1989A_inputs", + timestamp-mode:"trigered", + }, + frequency:48000, + channel-map:[ + "front-left", "front-right" + , "rear-left", "rear-right" + ], + type:"int16", + nb-chunk:6000, + mux-demux-type:"int16", + }, + speakerGroup:{ + io:"output", + map-on:{ + interface:"alsa", + name:"hw:0,0", + timestamp-mode:"trigered", + }, + group:"baseIOSynchrone", + frequency:48000, + channel-map:[ + "front-left", "front-right", + ], + type:"int16", + nb-chunk:1024, + volume-name:"MASTER", + mux-demux-type:"int16-on-int32", + }, + microphone-front:{ + io:"input", + map-on:{ + interface:"alsa", + name:"hw:0,0,0", + timestamp-mode:"trigered", + }, + group:"baseIOSynchrone", + frequency:48000, + channel-map:[ + "front-left", "front-right" + ], + type:"int16", + nb-chunk:1024, + mux-demux-type:"int16", + }, + microphone-rear:{ + io:"input", + map-on:{ + interface:"alsa", + name:"hw:0,0,1", + timestamp-mode:"trigered", + }, + group:"baseIOSynchrone", + frequency:48000, + channel-map:[ + "rear-left", "rear-right" + ], + type:"int16", + nb-chunk:1024, + mux-demux-type:"int16", + }, + # virtual Nodes : + microphone-clean:{ + io:"aec", + # connect in input mode + map-on-microphone:{ + # generic virtual definition + io:"input", + map-on:"microphone-muxed", + resampling-type:"speexdsp", + resampling-option:"quality=10" + }, + # connect in feedback mode + map-on-feedback:{ + io:"feedback", + map-on:"speaker", + resampling-type:"speexdsp", + resampling-option:"quality=10", + }, + #classical format configuration: + frequency:16000, + channel-map:[ + "front-left", "front-right", "rear-left", "rear-right" + ], + type:"int16", + # AEC algo definition + algo:"river-remover", + algo-mode:"cutter", + feedback-delay:10000, # in nanosecond + mux-demux-type:"int16", + }, + microphone-muxed:{ + io:"muxer", + map-on-input-1:{ + # generic virtual definition + io:"input", + map-on:"microphone-front", + resampling-type:"speexdsp", + resampling-option:"quality=10" + }, + map-on-input-2:{ + io:"input", + map-on:"microphone-rear", + resampling-type:"speexdsp", + resampling-option:"quality=10", + }, + frequency:48000, + channel-map:[ + "front-left", "front-right", "rear-left", "rear-right" + ], + type:"int16", + mux-demux-type:"int16", + }, +} diff --git a/data/virtual.json b/data/virtual.json deleted file mode 100644 index eba6eee..0000000 --- a/data/virtual.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - # name of the virtual interface - microphone:{ - # input or output - io:"input", - # name of the harware device - map-on:"microphone", - # name of the resampler - resampling-type:"speexdsp", - # some option to the resampler - resampling-option:"quality=10" - }, - speaker:{ - io:"output", - map-on:"speaker", - resampling-type:"speexdsp", - resampling-option:"quality=10" - }, - feedback:{ - # note : Feedback is plugged on an output not an input - io:"feedback", - map-on:"speaker", - resampling-type:"speexdsp", - resampling-option:"quality=10" - }, - microphone-clean:{ - io:"input", - map-on:"microphone-clean", - resampling-type:"speexdsp", - resampling-option:"quality=10" - }, - microphone-muxed:{ - io:"input", - map-on:"microphone-muxed", - resampling-type:"speexdsp", - resampling-option:"quality=10" - }, -} \ No newline at end of file diff --git a/lutin_river.py b/lutin_river.py index 549a0f7..3505dea 100644 --- a/lutin_river.py +++ b/lutin_river.py @@ -12,6 +12,7 @@ def create(target): myModule.add_src_file([ 'river/debug.cpp', + 'river/river.cpp', 'river/Manager.cpp', 'river/Interface.cpp', 'river/CircularBuffer.cpp', diff --git a/lutin_river_test.py b/lutin_river_test.py index f92d696..f5f5e30 100644 --- a/lutin_river_test.py +++ b/lutin_river_test.py @@ -28,7 +28,6 @@ def create(target): else: debug.warning("unknow target for AIRTAudio : " + target.name); - myModule.copy_file('data/virtual.json', 'virtual.json') myModule.add_module_depend(['river', 'gtest', 'etk']) # add the currrent module at the diff --git a/river/Interface.cpp b/river/Interface.cpp index 83e3c97..168f5e8 100644 --- a/river/Interface.cpp +++ b/river/Interface.cpp @@ -18,26 +18,23 @@ river::Interface::Interface(void) : m_node(), - m_name(""), - m_volume(0.0f) { + m_name("") { static uint32_t uid = 0; m_uid = uid++; } -bool river::Interface::init(const std::string& _name, - float _freq, +bool river::Interface::init(float _freq, const std::vector& _map, audio::format _format, const std11::shared_ptr& _node, const std11::shared_ptr& _config) { std::vector map(_map); - m_name = _name; m_node = _node; - m_volume = 0.0f; m_config = _config; m_mode = river::modeInterface_unknow; std::string type = m_config->getStringValue("io", "error"); + m_name = _node->getName() + "__" + (_node->isInput()==true?"input":"output") + "__" + type; if (type == "output") { m_mode = river::modeInterface_output; } else if (type == "input") { @@ -97,14 +94,13 @@ bool river::Interface::init(const std::string& _name, return true; } -std11::shared_ptr river::Interface::create(const std::string& _name, - float _freq, - const std::vector& _map, - audio::format _format, - const std11::shared_ptr& _node, - const std11::shared_ptr& _config) { +std11::shared_ptr river::Interface::create(float _freq, + const std::vector& _map, + audio::format _format, + const std11::shared_ptr& _node, + const std11::shared_ptr& _config) { std11::shared_ptr out = std11::shared_ptr(new river::Interface()); - out->init(_name, _freq, _map, _format, _node, _config); + out->init(_freq, _map, _format, _node, _config); return out; } diff --git a/river/Interface.h b/river/Interface.h index 74636c0..15f23b4 100644 --- a/river/Interface.h +++ b/river/Interface.h @@ -48,24 +48,21 @@ namespace river { * @brief Constructor */ Interface(); - bool init(const std::string& _name, - float _freq, + bool init(float _freq, const std::vector& _map, audio::format _format, const std11::shared_ptr& _node, const std11::shared_ptr& _config); + static std11::shared_ptr create(float _freq, + const std::vector& _map, + audio::format _format, + const std11::shared_ptr& _node, + const std11::shared_ptr& _config); public: /** * @brief Destructor */ virtual ~Interface(); - static std11::shared_ptr create(const std::string& _name, - float _freq, - const std::vector& _map, - audio::format _format, - const std11::shared_ptr& _node, - const std11::shared_ptr& _config); - protected: mutable std11::recursive_mutex m_mutex; std11::shared_ptr m_config; @@ -94,6 +91,9 @@ namespace river { virtual std::string getName() { return m_name; }; + virtual void setName(const std::string& _name) { + m_name = _name; + }; /** * @brief set the read/write mode enable. */ @@ -206,7 +206,6 @@ namespace river { virtual void systemNewInputData(std11::chrono::system_clock::time_point _time, const void* _data, size_t _nbChunk); virtual void systemNeedOutputData(std11::chrono::system_clock::time_point _time, void* _data, size_t _nbChunk, size_t _chunkSize); virtual void systemVolumeChange(); - float m_volume; //!< Local channel Volume public: virtual void generateDot(etk::FSNode& _node, const std::string& _nameIO, bool _isLink=true); virtual std::string getDotNodeName() const; diff --git a/river/Manager.cpp b/river/Manager.cpp index 8737d1f..8241d6a 100644 --- a/river/Manager.cpp +++ b/river/Manager.cpp @@ -11,27 +11,11 @@ #include "io/Manager.h" #include "io/Node.h" #include "debug.h" +#include #undef __class__ #define __class__ "Manager" -static std::string basicAutoConfig = - "{\n" - " microphone:{\n" - " io:'input',\n" - " map-on:'microphone',\n" - " resampling-type:'speexdsp',\n" - " resampling-option:'quality=10'\n" - " },\n" - " speaker:{\n" - " io:'output',\n" - " map-on:'speaker',\n" - " resampling-type:'speexdsp',\n" - " resampling-option:'quality=10'\n" - " }\n" - "}\n"; - - std11::shared_ptr river::Manager::create(const std::string& _applicationUniqueId) { return std11::shared_ptr(new river::Manager(_applicationUniqueId)); } @@ -39,11 +23,7 @@ std11::shared_ptr river::Manager::create(const std::string& _app river::Manager::Manager(const std::string& _applicationUniqueId) : m_applicationUniqueId(_applicationUniqueId), m_listOpenInterface() { - // TODO : Maybe create a single interface property (and all get the same ...) - if (m_config.load("DATA:virtual.json") == false) { - RIVER_WARNING("you must set a basic configuration file for virtual configuration: DATA:virtual.json (load default interface)"); - m_config.parse(basicAutoConfig); - } + } river::Manager::~Manager() { @@ -51,114 +31,166 @@ river::Manager::~Manager() { } -std::vector > river::Manager::getListStreamInput() { - std::vector > output; - std::vector keys = m_config.getKeys(); - for (size_t iii=0; iii tmppp = m_config.getObject(keys[iii]); - if (tmppp != nullptr) { - std::string type = tmppp->getStringValue("io", "error"); - if ( type == "input" - || type == "feedback") { - output.push_back(std::make_pair(std::string(keys[iii]), std::string("---"))); - } - } +std::vector river::Manager::getListStreamInput() { + std::vector output; + std11::shared_ptr manager = river::io::Manager::getInstance(); + if (manager == nullptr) { + RIVER_ERROR("Unable to load harware IO manager ... "); + } else { + output = manager->getListStreamInput(); } return output; } -std::vector > river::Manager::getListStreamOutput() { - std::vector > output; - std::vector keys = m_config.getKeys(); - for (size_t iii=0; iii tmppp = m_config.getObject(keys[iii]); - if (tmppp != nullptr) { - std::string type = tmppp->getStringValue("io", "error"); - if (type == "output") { - output.push_back(std::make_pair(std::string(keys[iii]), std::string("---"))); - } - } +std::vector river::Manager::getListStreamOutput() { + std::vector output; + std11::shared_ptr manager = river::io::Manager::getInstance(); + if (manager == nullptr) { + RIVER_ERROR("Unable to load harware IO manager ... "); + } else { + output = manager->getListStreamOutput(); } return output; } +std::vector river::Manager::getListStreamVirtual() { + std::vector output; + std11::shared_ptr manager = river::io::Manager::getInstance(); + if (manager == nullptr) { + RIVER_ERROR("Unable to load harware IO manager ... "); + } else { + output = manager->getListStreamVirtual(); + } + return output; +} + +std::vector river::Manager::getListStream() { + std::vector output; + std11::shared_ptr manager = river::io::Manager::getInstance(); + if (manager == nullptr) { + RIVER_ERROR("Unable to load harware IO manager ... "); + } else { + output = manager->getListStream(); + } + return output; +} bool river::Manager::setVolume(const std::string& _volumeName, float _valuedB) { - return river::io::Manager::getInstance()->setVolume(_volumeName, _valuedB); + std11::shared_ptr manager = river::io::Manager::getInstance(); + if (manager == nullptr) { + RIVER_ERROR("Unable to load harware IO manager ... "); + return false; + } + return manager->setVolume(_volumeName, _valuedB); } float river::Manager::getVolume(const std::string& _volumeName) const { - return river::io::Manager::getInstance()->getVolume(_volumeName); + std11::shared_ptr manager = river::io::Manager::getInstance(); + if (manager == nullptr) { + RIVER_ERROR("Unable to load harware IO manager ... "); + return false; + } + return manager->getVolume(_volumeName); } std::pair river::Manager::getVolumeRange(const std::string& _volumeName) const { - return river::io::Manager::getInstance()->getVolumeRange(_volumeName); + std11::shared_ptr manager = river::io::Manager::getInstance(); + if (manager == nullptr) { + RIVER_ERROR("Unable to load harware IO manager ... "); + return std::make_pair(0.0f,0.0f); + } + return manager->getVolumeRange(_volumeName); } std11::shared_ptr river::Manager::createOutput(float _freq, - const std::vector& _map, - audio::format _format, - const std::string& _streamName, - const std::string& _name) { - // check if the output exist - const std11::shared_ptr tmppp = m_config.getObject(_streamName); - if (tmppp == nullptr) { - RIVER_ERROR("can not open a non existance virtual input: '" << _streamName << "' not present in : " << m_config.getKeys()); - return std11::shared_ptr(); - } - // check if it is an Output: - std::string type = tmppp->getStringValue("io", "error"); - if (type != "output") { - RIVER_ERROR("can not open in output a virtual interface: '" << _streamName << "' configured has : " << type); - return std11::shared_ptr(); - } - std::string mapOn = tmppp->getStringValue("map-on", ""); - if (mapOn == "") { - RIVER_ERROR("can not open in output a virtual interface: '" << _streamName << "' No 'map-on' element in json file ... "); - return std11::shared_ptr(); - } + const std::vector& _map, + audio::format _format, + const std::string& _streamName, + const std::string& _options) { // get global hardware interface: std11::shared_ptr manager = river::io::Manager::getInstance(); + if (manager == nullptr) { + RIVER_ERROR("Unable to load harware IO manager ... "); + return std11::shared_ptr(); + } // get the output or input channel : - std11::shared_ptr node = manager->getNode(mapOn); + std11::shared_ptr node = manager->getNode(_streamName); + if (node == nullptr) { + RIVER_ERROR("Can not get the Requested stream '" << _streamName << "' ==> not listed in : " << manager->getListStream()); + return std11::shared_ptr(); + } + if (node->isOutput() != true) { + RIVER_ERROR("Can not Connect output on other thing than output ... for stream '" << _streamName << "'");; + return std11::shared_ptr(); + } // create user iterface: std11::shared_ptr interface; - interface = river::Interface::create(_name, _freq, _map, _format, node, tmppp); + std11::shared_ptr tmpOption = ejson::Object::create(_options); + tmpOption->addString("io", "output"); + interface = river::Interface::create(_freq, _map, _format, node, tmpOption); // store it in a list (needed to apply some parameters). m_listOpenInterface.push_back(interface); return interface; } std11::shared_ptr river::Manager::createInput(float _freq, - const std::vector& _map, - audio::format _format, - const std::string& _streamName, - const std::string& _name) { - // check if the output exist - const std11::shared_ptr tmppp = m_config.getObject(_streamName); - if (tmppp == nullptr) { - RIVER_ERROR("can not open a non existance virtual interface: '" << _streamName << "' not present in : " << m_config.getKeys()); - return std11::shared_ptr(); - } - // check if it is an Output: - std::string type = tmppp->getStringValue("io", "error"); - if ( type != "input" - && type != "feedback") { - RIVER_ERROR("can not open in output a virtual interface: '" << _streamName << "' configured has : " << type); - return std11::shared_ptr(); - } - std::string mapOn = tmppp->getStringValue("map-on", ""); - if (mapOn == "") { - RIVER_ERROR("can not open in output a virtual interface: '" << _streamName << "' No 'map-on' element in json file ... "); - return std11::shared_ptr(); - } + const std::vector& _map, + audio::format _format, + const std::string& _streamName, + const std::string& _options) { // get global hardware interface: std11::shared_ptr manager = river::io::Manager::getInstance(); + if (manager == nullptr) { + RIVER_ERROR("Unable to load harware IO manager ... "); + return std11::shared_ptr(); + } // get the output or input channel : - std11::shared_ptr node = manager->getNode(mapOn); + std11::shared_ptr node = manager->getNode(_streamName); + if (node == nullptr) { + RIVER_ERROR("Can not get the Requested stream '" << _streamName << "' ==> not listed in : " << manager->getListStream()); + return std11::shared_ptr(); + } + if (node->isInput() != true) { + RIVER_ERROR("Can not Connect input on other thing than input ... for stream '" << _streamName << "'");; + return std11::shared_ptr(); + } // create user iterface: std11::shared_ptr interface; - interface = river::Interface::create(_name, _freq, _map, _format, node, tmppp); + std11::shared_ptr tmpOption = ejson::Object::create(_options); + tmpOption->addString("io", "input"); + interface = river::Interface::create(_freq, _map, _format, node, tmpOption); + // store it in a list (needed to apply some parameters). + m_listOpenInterface.push_back(interface); + return interface; +} + + +std11::shared_ptr river::Manager::createFeedback(float _freq, + const std::vector& _map, + audio::format _format, + const std::string& _streamName, + const std::string& _options) { + // get global hardware interface: + std11::shared_ptr manager = river::io::Manager::getInstance(); + if (manager == nullptr) { + RIVER_ERROR("Unable to load harware IO manager ... "); + return std11::shared_ptr(); + } + // get the output or input channel : + std11::shared_ptr node = manager->getNode(_streamName); + if (node == nullptr) { + RIVER_ERROR("Can not get the Requested stream '" << _streamName << "' ==> not listed in : " << manager->getListStream()); + return std11::shared_ptr(); + } + if (node->isOutput() != true) { + RIVER_ERROR("Can not Connect feedback on other thing than output ... for stream '" << _streamName << "'");; + return std11::shared_ptr(); + } + // create user iterface: + std11::shared_ptr interface; + std11::shared_ptr tmpOption = ejson::Object::create(_options); + tmpOption->addString("io", "feedback"); + interface = river::Interface::create(_freq, _map, _format, node, tmpOption); // store it in a list (needed to apply some parameters). m_listOpenInterface.push_back(interface); return interface; diff --git a/river/Manager.h b/river/Manager.h index 7833c02..393f115 100644 --- a/river/Manager.h +++ b/river/Manager.h @@ -21,7 +21,6 @@ namespace river { */ class Manager { private: - ejson::Document m_config; // virtual configuration const std::string& m_applicationUniqueId; //!< name of the application that open the Audio Interface. std::vector > m_listOpenInterface; //!< List of all open Stream. protected: @@ -37,15 +36,25 @@ namespace river { virtual ~Manager(); public: /** - * @brief Get all input audio stream description. - * @return a list of all availlables input stream (name + description) + * @brief Get all input audio stream. + * @return a list of all availlables input stream name */ - virtual std::vector > getListStreamInput(); + std::vector getListStreamInput(); /** - * @brief Get all output audio stream description. - * @return a list of all availlables output stream (name + description) + * @brief Get all output audio stream. + * @return a list of all availlables output stream name */ - virtual std::vector > getListStreamOutput(); + std::vector getListStreamOutput(); + /** + * @brief Get all audio virtual stream. + * @return a list of all availlables virtual stream name + */ + std::vector getListStreamVirtual(); + /** + * @brief Get all audio stream. + * @return a list of all availlables stream name + */ + std::vector getListStream(); /** * @brief Set a volume for a specific group @@ -75,30 +84,44 @@ namespace river { * @brief Create output Interface * @param[in] _freq Frequency to open Interface [8,16,22,32,48] kHz * @param[in] _map ChannelMap of the Output - * @param[in] _format Sample Format to open the stream [int8_t] + * @param[in] _format Sample Format to open the stream [int8_t, int16_t, ...] * @param[in] _streamName Stream name to open: "" or "default" open current selected output - * @param[in] _name Name of this interface + * @param[in] _options Json option to configure default resampling and many other things. * @return a pointer on the interface */ - virtual std11::shared_ptr createOutput(float _freq, - const std::vector& _map, - audio::format _format, - const std::string& _streamName = "", - const std::string& _name = ""); + virtual std11::shared_ptr createOutput(float _freq = 48000, + const std::vector& _map = std::vector(), + audio::format _format = audio::format_int16, + const std::string& _streamName = "", + const std::string& _options = ""); /** * @brief Create input Interface * @param[in] _freq Frequency to open Interface [8,16,22,32,48] kHz * @param[in] _map ChannelMap of the Output - * @param[in] _format Sample Format to open the stream [int8_t] + * @param[in] _format Sample Format to open the stream [int8_t, int16_t, ...] * @param[in] _streamName Stream name to open: "" or "default" open current selected input - * @param[in] _name Name of this interface + * @param[in] _options Json option to configure default resampling and many other things. * @return a pointer on the interface */ - virtual std11::shared_ptr createInput(float _freq, - const std::vector& _map, - audio::format _format, - const std::string& _streamName = "", - const std::string& _name = ""); + virtual std11::shared_ptr createInput(float _freq = 48000, + const std::vector& _map = std::vector(), + audio::format _format = audio::format_int16, + const std::string& _streamName = "", + const std::string& _options = ""); + /** + * @brief Create input Feedback Interface + * @param[in] _freq Frequency to open Interface [8,16,22,32,48] kHz + * @param[in] _map ChannelMap of the Output + * @param[in] _format Sample Format to open the stream [int8_t, int16_t, ...] + * @param[in] _streamName Stream name to open: "" or "default" open current selected input + * @param[in] _options Json option to configure default resampling and many other things. + * @return a pointer on the interface + */ + virtual std11::shared_ptr createFeedback(float _freq = 48000, + const std::vector& _map = std::vector(), + audio::format _format = audio::format_int16, + const std::string& _streamName = "", + const std::string& _options = ""); /** * @brief Generate the dot file corresponding at all the actif nodes. * @param[in] _filename Name of the file to write data. diff --git a/river/io/Manager.cpp b/river/io/Manager.cpp index ec45567..1cf66a6 100644 --- a/river/io/Manager.cpp +++ b/river/io/Manager.cpp @@ -57,19 +57,27 @@ static std::string basicAutoConfig = river::io::Manager::Manager() { - if (m_config.load("DATA:hardware.json") == false) { - RIVER_WARNING("you must set a basic configuration file for harware configuration: DATA:hardware.json (load default interface)"); - m_config.parse(basicAutoConfig); - } - // TODO : Load virtual.json and check if all is correct ... - #ifdef __PORTAUDIO_INFERFACE__ PaError err = Pa_Initialize(); if(err != paNoError) { RIVER_WARNING("Can not initialize portaudio : " << Pa_GetErrorText(err)); } #endif -}; +} + +void river::io::Manager::init(const std::string _filename) { + std11::unique_lock lock(m_mutex); + if (_filename == "") { + RIVER_INFO("Load default config"); + m_config.parse(basicAutoConfig); + } else if (m_config.load(_filename) == false) { + RIVER_ERROR("you must set a basic configuration file for harware configuration: '" << _filename << "'"); + } +} +void river::io::Manager::unInit() { + std11::unique_lock lock(m_mutex); + +} river::io::Manager::~Manager() { #ifdef __PORTAUDIO_INFERFACE__ @@ -80,12 +88,85 @@ river::io::Manager::~Manager() { #endif }; - std11::shared_ptr river::io::Manager::getInstance() { + if (river::isInit() == false) { + return std11::shared_ptr(); + } static std11::shared_ptr manager(new Manager()); return manager; } + +std::vector river::io::Manager::getListStreamInput() { + std11::unique_lock lock(m_mutex); + std::vector output; + std::vector keys = m_config.getKeys(); + for (size_t iii=0; iii tmppp = m_config.getObject(keys[iii]); + if (tmppp != nullptr) { + std::string type = tmppp->getStringValue("io", "error"); + if ( type == "input" + || type == "PAinput") { + output.push_back(keys[iii]); + } + } + } + return output; +} + +std::vector river::io::Manager::getListStreamOutput() { + std11::unique_lock lock(m_mutex); + std::vector output; + std::vector keys = m_config.getKeys(); + for (size_t iii=0; iii tmppp = m_config.getObject(keys[iii]); + if (tmppp != nullptr) { + std::string type = tmppp->getStringValue("io", "error"); + if ( type == "output" + || type == "PAoutput") { + output.push_back(keys[iii]); + } + } + } + return output; +} + +std::vector river::io::Manager::getListStreamVirtual() { + std11::unique_lock lock(m_mutex); + std::vector output; + std::vector keys = m_config.getKeys(); + for (size_t iii=0; iii tmppp = m_config.getObject(keys[iii]); + if (tmppp != nullptr) { + std::string type = tmppp->getStringValue("io", "error"); + if ( type != "input" + && type != "PAinput" + && type != "output" + && type != "PAoutput" + && type != "error") { + output.push_back(keys[iii]); + } + } + } + return output; +} + +std::vector river::io::Manager::getListStream() { + std11::unique_lock lock(m_mutex); + std::vector output; + std::vector keys = m_config.getKeys(); + for (size_t iii=0; iii tmppp = m_config.getObject(keys[iii]); + if (tmppp != nullptr) { + std::string type = tmppp->getStringValue("io", "error"); + if (type != "error") { + output.push_back(keys[iii]); + } + } + } + return output; +} + std11::shared_ptr river::io::Manager::getNode(const std::string& _name) { std11::unique_lock lock(m_mutex); RIVER_WARNING("Get node : " << _name); diff --git a/river/io/Manager.h b/river/io/Manager.h index dea73aa..e6d849b 100644 --- a/river/io/Manager.h +++ b/river/io/Manager.h @@ -38,7 +38,9 @@ namespace river { /** * @brief Destructor */ - virtual ~Manager(); + ~Manager(); + void init(); + void unInit(); private: ejson::Document m_config; // harware configuration std::vector > m_listKeepAlive; //!< list of all Node that might be keep alive sone time @@ -49,6 +51,26 @@ namespace river { std::vector > m_volumeGroup; public: std11::shared_ptr getVolumeGroup(const std::string& _name); + /** + * @brief Get all input audio stream. + * @return a list of all availlables input stream name + */ + std::vector getListStreamInput(); + /** + * @brief Get all output audio stream. + * @return a list of all availlables output stream name + */ + std::vector getListStreamOutput(); + /** + * @brief Get all audio virtual stream. + * @return a list of all availlables virtual stream name + */ + std::vector getListStreamVirtual(); + /** + * @brief Get all audio stream. + * @return a list of all availlables stream name + */ + std::vector getListStream(); /** * @brief Set a volume for a specific group @@ -58,26 +80,26 @@ namespace river { * @return false An error occured * @example : setVolume("MASTER", -3.0f); */ - virtual bool setVolume(const std::string& _volumeName, float _valuedB); + bool setVolume(const std::string& _volumeName, float _valuedB); /** * @brief Get a volume value * @param[in] _volumeName Name of the volume (MASTER, MATER_BT ...) * @return The Volume value in dB. * @example ret = getVolume("MASTER"); can return something like ret = -3.0f */ - virtual float getVolume(const std::string& _volumeName); + float getVolume(const std::string& _volumeName); /** * @brief Get a parameter value * @param[in] _volumeName Name of the volume (MASTER, MATER_BT ...) * @return The requested value Range. * @example ret = getVolumeRange("MASTER"); can return something like ret=(-120.0f,0.0f) */ - virtual std::pair getVolumeRange(const std::string& _volumeName) const; + std::pair getVolumeRange(const std::string& _volumeName) const; /** * @brief Generate the dot file corresponding at the actif nodes. * @param[in] _filename Name of the file to write data. */ - virtual void generateDot(const std::string& _filename); + void generateDot(const std::string& _filename); private: std::map > m_listGroup; //!< List of all groups std11::shared_ptr getGroup(const std::string& _name); diff --git a/river/io/NodeAEC.cpp b/river/io/NodeAEC.cpp index 8852251..5535535 100644 --- a/river/io/NodeAEC.cpp +++ b/river/io/NodeAEC.cpp @@ -13,90 +13,15 @@ #undef __class__ #define __class__ "io::NodeAEC" -#if 0 -int32_t river::io::NodeAEC::airtAudioCallback(void* _outputBuffer, - void* _inputBuffer, - uint32_t _nbChunk, - const std11::chrono::system_clock::time_point& _time, - airtaudio::status _status) { - std11::unique_lock lock(m_mutex); - //RIVER_INFO("Time=" << _time); - /* - for (int32_t iii=0; iii<400; ++iii) { - RIVER_VERBOSE("dummy=" << uint64_t(dummy[iii])); - } - */ - if (_outputBuffer != nullptr) { - RIVER_VERBOSE("data Output size request :" << _nbChunk << " [BEGIN] status=" << _status << " nbIO=" << m_list.size()); - std::vector output; - RIVER_VERBOSE("resize=" << _nbChunk*m_process.getInputConfig().getMap().size()); - output.resize(_nbChunk*m_process.getInputConfig().getMap().size(), 0); - const int32_t* outputTmp = nullptr; - std::vector outputTmp2; - RIVER_VERBOSE("resize=" << sizeof(int32_t)*m_process.getInputConfig().getMap().size()*_nbChunk); - outputTmp2.resize(sizeof(int32_t)*m_process.getInputConfig().getMap().size()*_nbChunk, 0); - for (auto &it : m_list) { - if (it == nullptr) { - continue; - } - if (it->getMode() != river::modeInterface_output) { - continue; - } - RIVER_VERBOSE(" IO name="<< it->getName()); - // clear datas ... - memset(&outputTmp2[0], 0, sizeof(int32_t)*m_process.getInputConfig().getMap().size()*_nbChunk); - RIVER_VERBOSE(" request Data="<< _nbChunk); - it->systemNeedOutputData(_time, &outputTmp2[0], _nbChunk, sizeof(int32_t)*m_process.getInputConfig().getMap().size()); - RIVER_VERBOSE(" Mix it ..."); - outputTmp = reinterpret_cast(&outputTmp2[0]); - // Add data to the output tmp buffer : - for (size_t kkk=0; kkkgetMode() != river::modeInterface_feedback) { - continue; - } - RIVER_VERBOSE(" IO name="<< it->getName() << " (feedback)"); - it->systemNewInputData(_time, _outputBuffer, _nbChunk); - } - RIVER_VERBOSE("data Output size request :" << _nbChunk << " [ END ]"); - } - if (_inputBuffer != nullptr) { - RIVER_VERBOSE("data Input size request :" << _nbChunk << " [BEGIN] status=" << _status << " nbIO=" << m_list.size()); - int16_t* inputBuffer = static_cast(_inputBuffer); - for (auto &it : m_list) { - if (it == nullptr) { - continue; - } - if (it->getMode() != river::modeInterface_input) { - continue; - } - RIVER_INFO(" IO name="<< it->getName()); - it->systemNewInputData(_time, inputBuffer, _nbChunk); - } - RIVER_VERBOSE("data Input size request :" << _nbChunk << " [ END ]"); - } - return 0; -} -#endif - std11::shared_ptr river::io::NodeAEC::create(const std::string& _name, const std11::shared_ptr& _config) { return std11::shared_ptr(new river::io::NodeAEC(_name, _config)); } std11::shared_ptr river::io::NodeAEC::createInput(float _freq, - const std::vector& _map, - audio::format _format, - const std::string& _objectName, - const std::string& _name) { + const std::vector& _map, + audio::format _format, + const std::string& _objectName, + const std::string& _name) { // check if the output exist const std11::shared_ptr tmppp = m_config->getObject(_objectName); if (tmppp == nullptr) { @@ -119,7 +44,10 @@ std11::shared_ptr river::io::NodeAEC::createInput(float _freq, std11::shared_ptr node = manager->getNode(streamName); // create user iterface: std11::shared_ptr interface; - interface = river::Interface::create(_name, _freq, _map, _format, node, tmppp); + interface = river::Interface::create(_freq, _map, _format, node, tmppp); + if (interface != nullptr) { + interface->setName(_name); + } return interface; } diff --git a/river/io/NodeMuxer.cpp b/river/io/NodeMuxer.cpp index 253188b..d6b96b8 100644 --- a/river/io/NodeMuxer.cpp +++ b/river/io/NodeMuxer.cpp @@ -44,7 +44,10 @@ std11::shared_ptr river::io::NodeMuxer::createInput(float _fre std11::shared_ptr node = manager->getNode(streamName); // create user iterface: std11::shared_ptr interface; - interface = river::Interface::create(_name, _freq, _map, _format, node, tmppp); + interface = river::Interface::create(_freq, _map, _format, node, tmppp); + if (interface != nullptr) { + interface->setName(_name); + } return interface; } diff --git a/river/river.cpp b/river/river.cpp new file mode 100644 index 0000000..d632686 --- /dev/null +++ b/river/river.cpp @@ -0,0 +1,38 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2015, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#iclude +#iclude +#include + +static bool river_isInit = false; +static std::string river_configFile = ""; + + + +void river::init(const std::string& _filename) { + if (river_isInit == false) { + river_isInit = true; + river_configFile = _filename; + RIVER_INFO("init RIVER :" << river_configFile); + std11::shared_ptr mng = river::io::Manager::getInstance(); + mng->init(river_configFile); + } +} + +void river::unInit() { + if (river_isInit == true) { + river_isInit = false; + RIVER_INFO("un-init RIVER :" << river_configFile); + std11::shared_ptr mng = river::io::Manager::getInstance(); + mng->unInit(); + } +} + +bool river::isInit() { + return river_isInit; +} + diff --git a/river/river.h b/river/river.h new file mode 100644 index 0000000..cc4913e --- /dev/null +++ b/river/river.h @@ -0,0 +1,33 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2015, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#ifndef __RIVER_H__ +#define __RIVER_H__ + +#include + +namespace river { + /** + * @brief Initialize the River Library + * @param[in] _filename Name of the configuration file (if "" ==> default config file) + */ + void init(const std::string& _filename); + /** + * @brief Un-initialize the River Library + * @note this close all stream of all interfaces. + * @note really good for test. + */ + void unInit(); + /** + * @brief Get the status of initialisation + * @return true River is init + * @return false River is NOT init + */ + bool isInit(); +} + +#endif + diff --git a/test/testEchoDelay.h b/test/testEchoDelay.h index e4443f9..36e65dc 100644 --- a/test/testEchoDelay.h +++ b/test/testEchoDelay.h @@ -45,8 +45,6 @@ namespace river_test_echo_delay { m_gain(-40) { //Set stereo output: std::vector channelMap; - channelMap.push_back(audio::channel_frontLeft); - channelMap.push_back(audio::channel_frontRight); m_interfaceOut = m_manager->createOutput(48000, channelMap, audio::format_int16, @@ -345,6 +343,9 @@ namespace river_test_echo_delay { m_interfaceOut->start(); m_interfaceIn->start(); //m_interfaceFB->start(); + while (m_estimateVolumeInput == true) { + usleep(10000); + } usleep(10000000); //m_interfaceFB->stop(); m_interfaceIn->stop(); diff --git a/test/testMuxer.h b/test/testMuxer.h index 9ce91ac..3ce3fc8 100644 --- a/test/testMuxer.h +++ b/test/testMuxer.h @@ -41,7 +41,7 @@ namespace river_test_muxer { std11::placeholders::_5, std11::placeholders::_6)); m_interfaceOut->addVolumeGroup("FLOW"); - m_interfaceOut->setParameter("volume", "FLOW", "-6dB"); + //m_interfaceOut->setParameter("volume", "FLOW", "-6dB"); //Set stereo output: m_interfaceIn = m_manager->createInput(48000, @@ -71,7 +71,7 @@ namespace river_test_muxer { double baseCycle = 2.0*M_PI/(double)48000 * 440; for (int32_t iii=0; iii<_nbChunk; iii++) { for (int32_t jjj=0; jjj<_map.size(); jjj++) { - data[_map.size()*iii+jjj] = sin(m_phase) * 30000; + data[_map.size()*iii+jjj] = sin(m_phase) * 7000; } m_phase += baseCycle; if (m_phase >= 2*M_PI) { diff --git a/test/testRecordCallback.h b/test/testRecordCallback.h index d5de46a..a608106 100644 --- a/test/testRecordCallback.h +++ b/test/testRecordCallback.h @@ -7,6 +7,8 @@ #ifndef __RIVER_TEST_RECORD_CALLBACK_H__ #define __RIVER_TEST_RECORD_CALLBACK_H__ +#include + #undef __class__ #define __class__ "test_record_callback" @@ -20,8 +22,6 @@ namespace river_test_record_callback { m_manager(_manager) { //Set stereo output: std::vector channelMap; - channelMap.push_back(audio::channel_frontLeft); - channelMap.push_back(audio::channel_frontRight); m_interface = m_manager->createInput(48000, channelMap, audio::format_int16, @@ -46,6 +46,7 @@ namespace river_test_record_callback { if (_format != audio::format_int16) { APPL_ERROR("call wrong type ... (need int16_t)"); } + RIVER_SAVE_FILE_MACRO(int16_t, "REC_INPUT.raw", _data, _nbChunk * _map.size()); const int16_t* data = static_cast(_data); int64_t value = 0; for (size_t iii=0; iii<_nbChunk*_map.size(); ++iii) { @@ -57,9 +58,7 @@ namespace river_test_record_callback { void run() { m_interface->start(); // wait 2 second ... - usleep(2000000); - - + usleep(20000000); m_interface->stop(); } };