/** @file * @author Edouard DUPIN * @copyright 2015, Edouard DUPIN, all right reserved * @license APACHE v2.0 (see license file) */ #include "Interface.h" #include #include #include #include #include #include airtio::Interface::Interface(void) : m_name(""), m_node(nullptr), m_freq(8000), m_map(), m_format(airtalgo::format_int16), m_volume(0.0f) { } bool airtio::Interface::init(const std::string& _name, float _freq, const std::vector& _map, airtalgo::format _format, const std::shared_ptr& _node) { m_name = _name; m_node = _node; m_freq = _freq; m_map = _map; m_format = _format; m_volume = 0.0f; return true; } std::shared_ptr airtio::Interface::create(const std::string& _name, float _freq, const std::vector& _map, airtalgo::format _format, const std::shared_ptr& _node) { std::shared_ptr out = std::make_shared(new airtio::Interface()); out->init(_name, _freq, _map, _format, _node); return out; } void airtio::Interface::init() { // Create convertion interface if (m_node->isInput() == true) { if (m_map != m_node->getMap()) { std::shared_ptr algo = boost::make_shared(); algo->setInputFormat(airtalgo::IOFormatInterface(m_node->getMap(), m_node->getFormat(), m_node->getFrequency())); algo->setOutputFormat(airtalgo::IOFormatInterface(m_map, m_node->getFormat(), m_node->getFrequency())); m_listAlgo.push_back(algo); std::cout << "[INFO] convert " << m_node->getMap() << " -> " << m_map << std::endl; } if (m_freq != m_node->getFrequency()) { std::shared_ptr algo = boost::make_shared(); algo->setInputFormat(airtalgo::IOFormatInterface(m_map, m_node->getFormat(), m_node->getFrequency())); algo->setOutputFormat(airtalgo::IOFormatInterface(m_map, m_node->getFormat(), m_freq)); m_listAlgo.push_back(algo); std::cout << "[INFO] convert " << m_node->getFrequency() << " -> " << m_freq << std::endl; } if (m_format != m_node->getFormat()) { std::shared_ptr algo = boost::make_shared(); algo->setInputFormat(airtalgo::IOFormatInterface(m_map, m_node->getFormat(), m_freq)); algo->setOutputFormat(airtalgo::IOFormatInterface(m_map, m_format, m_freq)); m_listAlgo.push_back(algo); std::cout << "[INFO] convert " << m_node->getFormat() << " -> " << m_format << std::endl; } // by default we add a read node if (true) { std::shared_ptr algo = boost::make_shared(); algo->setInputFormat(airtalgo::IOFormatInterface(m_map, m_format, m_freq)); algo->setOutputFormat(airtalgo::IOFormatInterface(m_map, m_format, m_freq)); m_listAlgo.push_back(algo); std::cout << "[INFO] add default read node ..." << std::endl; } } else { // by default we add a write node: if (true) { std::shared_ptr algo = boost::make_shared(); algo->setInputFormat(airtalgo::IOFormatInterface(m_map, m_format, m_freq)); algo->setOutputFormat(airtalgo::IOFormatInterface(m_map, m_format, m_freq)); m_listAlgo.push_back(algo); std::cout << "[INFO] add default write node ..." << std::endl; } if (m_format != m_node->getFormat()) { std::shared_ptr algo = boost::make_shared(); algo->setInputFormat(airtalgo::IOFormatInterface(m_map, m_format, m_freq)); algo->setOutputFormat(airtalgo::IOFormatInterface(m_map, m_node->getFormat(), m_freq)); m_listAlgo.push_back(algo); std::cout << "[INFO] convert " << m_format << " -> " << m_node->getFormat() << std::endl; } if (m_freq != m_node->getFrequency()) { std::shared_ptr algo = boost::make_shared(); algo->setInputFormat(airtalgo::IOFormatInterface(m_map, m_node->getFormat(), m_freq)); algo->setOutputFormat(airtalgo::IOFormatInterface(m_map, m_node->getFormat(), m_node->getFrequency())); m_listAlgo.push_back(algo); std::cout << "[INFO] convert " << m_freq << " -> " << m_node->getFrequency() << std::endl; } if (m_map != m_node->getMap()) { std::shared_ptr algo = boost::make_shared(); algo->setInputFormat(airtalgo::IOFormatInterface(m_map, m_node->getFormat(), m_node->getFrequency())); algo->setOutputFormat(airtalgo::IOFormatInterface(m_node->getMap(), m_node->getFormat(), m_node->getFrequency())); m_listAlgo.push_back(algo); std::cout << "[INFO] convert " << m_map << " -> " << m_node->getMap() << std::endl; } } //m_node->interfaceAdd(shared_from_this()); } airtio::Interface::~Interface() { std::unique_lock lock(m_mutex); //m_node->interfaceRemove(shared_from_this()); } void airtio::Interface::setWriteCallbackInt16(size_t _chunkSize, writeNeedDataFunction_int16_t _function) { std::unique_lock lock(m_mutex); if (m_listAlgo.size() <= 0) { return; } std::shared_ptr algo = boost::dynamic_pointer_cast(m_listAlgo[0]); if (algo == nullptr) { return; } algo->setCallback(_function); } void airtio::Interface::setOutputCallback(size_t _chunkSize, airtalgo::needDataFunction _function, enum airtalgo::formatDataType _dataType) { std::unique_lock lock(m_mutex); if (m_listAlgo.size() > 0) { std::shared_ptr algoEP = boost::dynamic_pointer_cast(m_listAlgo[0]); if (algoEP != nullptr) { m_listAlgo.erase(m_listAlgo.begin()); } } std::shared_ptr algo = boost::make_shared(_function, _dataType); std::cout << "[INFO] set property: " << m_map << " " << m_format << " " << m_freq <setInputFormat(airtalgo::IOFormatInterface(m_map, m_format, m_freq)); algo->setOutputFormat(airtalgo::IOFormatInterface(m_map, m_format, m_freq)); m_listAlgo.insert(m_listAlgo.begin(), algo); } void airtio::Interface::setInputCallback(size_t _chunkSize, airtalgo::haveNewDataFunction _function, enum airtalgo::formatDataType _dataType) { std::unique_lock lock(m_mutex); if (m_listAlgo.size() > 0) { std::shared_ptr algoEP = boost::dynamic_pointer_cast(m_listAlgo[m_listAlgo.size()-1]); if (algoEP != nullptr) { m_listAlgo.erase(m_listAlgo.begin()+m_listAlgo.size()-1); } } std::shared_ptr algo = boost::make_shared(_function, _dataType); algo->setInputFormat(airtalgo::IOFormatInterface(m_map, m_format, m_freq)); algo->setOutputFormat(airtalgo::IOFormatInterface(m_map, m_format, m_freq)); m_listAlgo.push_back(algo); } void airtio::Interface::start(const std::chrono::system_clock::time_point& _time) { std::unique_lock lock(m_mutex); m_node->interfaceAdd(shared_from_this()); } void airtio::Interface::stop(bool _fast, bool _abort) { std::unique_lock lock(m_mutex); m_node->interfaceRemove(shared_from_this()); } void airtio::Interface::abort() { std::unique_lock lock(m_mutex); // TODO :... } void airtio::Interface::setVolume(float _gainDB) { std::unique_lock lock(m_mutex); // TODO :... } float airtio::Interface::getVolume() const { std::unique_lock lock(m_mutex); // TODO :... return 0; } std::pair airtio::Interface::getVolumeRange() const { std::unique_lock lock(m_mutex); return std::make_pair(-120.0f, 0.0f); } void airtio::Interface::write(const std::vector& _value) { write(&_value[0], _value.size()); } void airtio::Interface::write(const int16_t* _value, size_t _nbChunk) { std::unique_lock lock(m_mutex); std::shared_ptr algo = boost::dynamic_pointer_cast(m_listAlgo[0]); if (algo == nullptr) { return; } algo->write(_value, _nbChunk); } // TODO : add API aCCess mutex for Read and write... std::vector airtio::Interface::read(size_t _nbChunk) { // TODO :... std::vector data; /* data.resize(_nbChunk*m_map.size(), 0); m_mutex.lock(); int32_t nbChunkBuffer = m_circularBuffer.size() / m_map.size(); m_mutex.unlock(); while (nbChunkBuffer < _nbChunk) { usleep(1000); nbChunkBuffer = m_circularBuffer.size() / m_map.size(); } m_mutex.lock(); for (size_t iii = 0; iii lock(m_mutex); // TODO :... } size_t airtio::Interface::size() const { std::unique_lock lock(m_mutex); // TODO :... return 0; } void airtio::Interface::setBufferSize(size_t _nbChunk) { std::unique_lock lock(m_mutex); // TODO :... } void airtio::Interface::setBufferSize(const std::chrono::duration& _time) { std::unique_lock lock(m_mutex); // TODO :... } void airtio::Interface::clearInternalBuffer() { std::unique_lock lock(m_mutex); // TODO :... } std::chrono::system_clock::time_point airtio::Interface::getCurrentTime() const { std::unique_lock lock(m_mutex); // TODO :... return std::chrono::system_clock::time_point(); return std::chrono::system_clock::now(); } void airtio::Interface::setMasterVolume(float _gainDB) { std::unique_lock lock(m_mutex); //m_volumeMaster = _gainDB; // TODO :... } bool airtio::Interface::process(std::chrono::system_clock::time_point& _time, void* _input, size_t _inputNbChunk, void*& _output, size_t& _outputNbChunk) { if (m_listAlgo.size() == 0) { _output = _input; _outputNbChunk = _inputNbChunk; return true; } for (size_t iii=0; iiiprocess(_time, _input, _inputNbChunk, _output, _outputNbChunk); _input = _output; _inputNbChunk = _outputNbChunk; } } return true; } void airtio::Interface::systemNewInputData(std::chrono::system_clock::time_point _time, void* _data, int32_t _nbChunk) { void* out = nullptr; size_t nbChunkOut; //std::cout << " Interface DIRECT " << std::endl; process(_time, _data, _nbChunk, out, nbChunkOut); } void airtio::Interface::systemNeedOutputData(std::chrono::system_clock::time_point _time, void* _data, int32_t _nbChunk, size_t _chunkSize) { // TODO : while enought data or fhush data: memset(_data, 0, _nbChunk*_chunkSize); //std::cout << " Interface DIRECT " << std::endl; while(m_data.size()<_nbChunk*_chunkSize) { void* in = nullptr; size_t nbChunkIn = _nbChunk - m_data.size()/_chunkSize; void* out = nullptr; size_t nbChunkOut; if (nbChunkIn < 128) { nbChunkIn = 128; } // TODO : maybe remove this for input data ... for (int32_t iii=m_listAlgo.size()-1; iii >=0; --iii) { if (m_listAlgo[iii] != nullptr) { nbChunkIn = m_listAlgo[iii]->needInputData(nbChunkIn); } } if (nbChunkIn < 32) { nbChunkIn = 32; } //nbChunkIn *= 4; // get data from the upstream //std::cout << " * request " << nbChunkIn << " chunk" << std::endl; process(_time, in, nbChunkIn, out, nbChunkOut); //std::cout << " * get " << nbChunkOut << " chunk" << std::endl; if (nbChunkOut > 0) { size_t position = m_data.size(); m_data.resize(m_data.size() + nbChunkOut*_chunkSize); memcpy(&m_data[position], out, nbChunkOut*_chunkSize); } else { // TODO : ERROR ... break; } } if (m_data.size()>=_nbChunk*_chunkSize) { //std::cout << " * copy needed data" << std::endl; memcpy(_data, &m_data[0], _nbChunk*_chunkSize); m_data.erase(m_data.begin(), m_data.begin()+_nbChunk*_chunkSize); } else { //std::cout << " * soft underflow" << std::endl; // ERROR m_data.clear(); } /* process(_time, in, nbChunkIn, out, nbChunkOut); if (nbChunkIn!=nbChunkOut) { std::cout << " wrong size : request=" << _nbChunk << " get=" << nbChunkOut << std::endl; return; } memcpy(_data, out, _nbChunk*_chunkSize); */ }