[DEV] add muxer interface
This commit is contained in:
parent
92cbf5191b
commit
a7b6ddce90
@ -103,5 +103,31 @@
|
|||||||
algo-mode:"cutter",
|
algo-mode:"cutter",
|
||||||
feedback-delay:10000, # in nanosecond
|
feedback-delay:10000, # in nanosecond
|
||||||
mux-demux-type:"int16",
|
mux-demux-type:"int16",
|
||||||
}
|
},
|
||||||
|
# virtual Nodes :
|
||||||
|
microphone-muxed:{
|
||||||
|
io:"muxer",
|
||||||
|
# connect in input mode
|
||||||
|
map-on-input-1:{
|
||||||
|
# generic virtual definition
|
||||||
|
io:"input",
|
||||||
|
map-on:"microphone",
|
||||||
|
resampling-type:"speexdsp",
|
||||||
|
resampling-option:"quality=10"
|
||||||
|
},
|
||||||
|
# connect in feedback mode
|
||||||
|
map-on-input-2:{
|
||||||
|
io:"feedback",
|
||||||
|
map-on:"speaker",
|
||||||
|
resampling-type:"speexdsp",
|
||||||
|
resampling-option:"quality=10",
|
||||||
|
},
|
||||||
|
#classical format configuration:
|
||||||
|
frequency:48000,
|
||||||
|
channel-map:[
|
||||||
|
"front-left", "front-right", "rear-left", "rear-right"
|
||||||
|
],
|
||||||
|
type:"int16",
|
||||||
|
mux-demux-type:"int16",
|
||||||
|
},
|
||||||
}
|
}
|
@ -29,4 +29,10 @@
|
|||||||
resampling-type:"speexdsp",
|
resampling-type:"speexdsp",
|
||||||
resampling-option:"quality=10"
|
resampling-option:"quality=10"
|
||||||
},
|
},
|
||||||
|
microphone-muxed:{
|
||||||
|
io:"input",
|
||||||
|
map-on:"microphone-muxed",
|
||||||
|
resampling-type:"speexdsp",
|
||||||
|
resampling-option:"quality=10"
|
||||||
|
},
|
||||||
}
|
}
|
@ -20,6 +20,7 @@ def create(target):
|
|||||||
'river/io/NodeAirTAudio.cpp',
|
'river/io/NodeAirTAudio.cpp',
|
||||||
'river/io/NodePortAudio.cpp',
|
'river/io/NodePortAudio.cpp',
|
||||||
'river/io/NodeAEC.cpp',
|
'river/io/NodeAEC.cpp',
|
||||||
|
'river/io/NodeMuxer.cpp',
|
||||||
'river/io/Manager.cpp'
|
'river/io/Manager.cpp'
|
||||||
])
|
])
|
||||||
myModule.add_optionnal_module_depend('airtaudio', "__AIRTAUDIO_INFERFACE__")
|
myModule.add_optionnal_module_depend('airtaudio', "__AIRTAUDIO_INFERFACE__")
|
||||||
|
@ -31,6 +31,7 @@ bool river::Interface::init(const std::string& _name,
|
|||||||
audio::format _format,
|
audio::format _format,
|
||||||
const std11::shared_ptr<river::io::Node>& _node,
|
const std11::shared_ptr<river::io::Node>& _node,
|
||||||
const std11::shared_ptr<const ejson::Object>& _config) {
|
const std11::shared_ptr<const ejson::Object>& _config) {
|
||||||
|
std::vector<audio::channel> map(_map);
|
||||||
m_name = _name;
|
m_name = _name;
|
||||||
m_node = _node;
|
m_node = _node;
|
||||||
m_volume = 0.0f;
|
m_volume = 0.0f;
|
||||||
@ -46,6 +47,13 @@ bool river::Interface::init(const std::string& _name,
|
|||||||
}
|
}
|
||||||
// register interface to be notify from the volume change.
|
// register interface to be notify from the volume change.
|
||||||
m_node->registerAsRemote(shared_from_this());
|
m_node->registerAsRemote(shared_from_this());
|
||||||
|
|
||||||
|
if (map.size() == 0) {
|
||||||
|
RIVER_INFO("Select auto map system ...");
|
||||||
|
map = m_node->getInterfaceFormat().getMap();
|
||||||
|
RIVER_INFO(" ==> " << map);
|
||||||
|
}
|
||||||
|
|
||||||
// Create convertion interface
|
// Create convertion interface
|
||||||
if ( m_node->isInput() == true
|
if ( m_node->isInput() == true
|
||||||
&& m_mode == river::modeInterface_input) {
|
&& m_mode == river::modeInterface_input) {
|
||||||
@ -61,10 +69,10 @@ bool river::Interface::init(const std::string& _name,
|
|||||||
RIVER_INFO(" add volume for node");
|
RIVER_INFO(" add volume for node");
|
||||||
algo->addVolumeStage(tmpVolume);
|
algo->addVolumeStage(tmpVolume);
|
||||||
}
|
}
|
||||||
m_process.setOutputConfig(drain::IOFormatInterface(_map, _format, _freq));
|
m_process.setOutputConfig(drain::IOFormatInterface(map, _format, _freq));
|
||||||
} else if ( m_node->isOutput() == true
|
} else if ( m_node->isOutput() == true
|
||||||
&& m_mode == river::modeInterface_output) {
|
&& m_mode == river::modeInterface_output) {
|
||||||
m_process.setInputConfig(drain::IOFormatInterface(_map, _format, _freq));
|
m_process.setInputConfig(drain::IOFormatInterface(map, _format, _freq));
|
||||||
// add all time the volume stage :
|
// add all time the volume stage :
|
||||||
std11::shared_ptr<drain::Volume> algo = drain::Volume::create();
|
std11::shared_ptr<drain::Volume> algo = drain::Volume::create();
|
||||||
//algo->setOutputFormat(m_node->getInterfaceFormat());
|
//algo->setOutputFormat(m_node->getInterfaceFormat());
|
||||||
@ -88,7 +96,7 @@ bool river::Interface::init(const std::string& _name,
|
|||||||
m_process.pushBack(algo);
|
m_process.pushBack(algo);
|
||||||
*/
|
*/
|
||||||
// note : feedback has no volume stage ...
|
// note : feedback has no volume stage ...
|
||||||
m_process.setOutputConfig(drain::IOFormatInterface(_map, _format, _freq));
|
m_process.setOutputConfig(drain::IOFormatInterface(map, _format, _freq));
|
||||||
} else {
|
} else {
|
||||||
RIVER_ERROR("Can not link virtual interface with type : " << m_mode << " to a hardware interface " << (m_node->isInput()==true?"input":"output"));
|
RIVER_ERROR("Can not link virtual interface with type : " << m_mode << " to a hardware interface " << (m_node->isInput()==true?"input":"output"));
|
||||||
return false;
|
return false;
|
||||||
|
@ -27,6 +27,7 @@ namespace river {
|
|||||||
class Node;
|
class Node;
|
||||||
class NodeAirTAudio;
|
class NodeAirTAudio;
|
||||||
class NodeAEC;
|
class NodeAEC;
|
||||||
|
class NodeMuxer;
|
||||||
}
|
}
|
||||||
enum modeInterface {
|
enum modeInterface {
|
||||||
modeInterface_unknow,
|
modeInterface_unknow,
|
||||||
@ -38,6 +39,7 @@ namespace river {
|
|||||||
friend class io::Node;
|
friend class io::Node;
|
||||||
friend class io::NodeAirTAudio;
|
friend class io::NodeAirTAudio;
|
||||||
friend class io::NodeAEC;
|
friend class io::NodeAEC;
|
||||||
|
friend class io::NodeMuxer;
|
||||||
friend class Manager;
|
friend class Manager;
|
||||||
protected:
|
protected:
|
||||||
uint32_t m_uid; //!< unique ID for interface
|
uint32_t m_uid; //!< unique ID for interface
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <river/debug.h>
|
#include <river/debug.h>
|
||||||
#include "Node.h"
|
#include "Node.h"
|
||||||
#include "NodeAEC.h"
|
#include "NodeAEC.h"
|
||||||
|
#include "NodeMuxer.h"
|
||||||
#include "NodeAirTAudio.h"
|
#include "NodeAirTAudio.h"
|
||||||
#include "NodePortAudio.h"
|
#include "NodePortAudio.h"
|
||||||
#include <etk/os/FSNode.h>
|
#include <etk/os/FSNode.h>
|
||||||
@ -156,6 +157,11 @@ std11::shared_ptr<river::io::Node> river::io::Manager::getNode(const std::string
|
|||||||
m_list.push_back(tmp);
|
m_list.push_back(tmp);
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
if (ioType == "muxer") {
|
||||||
|
std11::shared_ptr<river::io::Node> tmp = river::io::NodeMuxer::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());
|
RIVER_ERROR("Can not create the interface : '" << _name << "' the node is not DEFINED in the configuration file availlable : " << m_config.getKeys());
|
||||||
|
@ -37,7 +37,8 @@ river::io::Node::Node(const std::string& _name, const std11::shared_ptr<const ej
|
|||||||
std::string interfaceType = m_config->getStringValue("io");
|
std::string interfaceType = m_config->getStringValue("io");
|
||||||
if ( interfaceType == "input"
|
if ( interfaceType == "input"
|
||||||
|| interfaceType == "PAinput"
|
|| interfaceType == "PAinput"
|
||||||
|| interfaceType == "aec") {
|
|| interfaceType == "aec"
|
||||||
|
|| interfaceType == "muxer") {
|
||||||
m_isInput = true;
|
m_isInput = true;
|
||||||
} else {
|
} else {
|
||||||
m_isInput = false;
|
m_isInput = false;
|
||||||
|
314
river/io/NodeMuxer.cpp
Normal file
314
river/io/NodeMuxer.cpp
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||||
|
* @license APACHE v2.0 (see license file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <river/io/NodeMuxer.h>
|
||||||
|
#include <river/debug.h>
|
||||||
|
#include <etk/types.h>
|
||||||
|
#include <etk/memory.h>
|
||||||
|
#include <etk/functional.h>
|
||||||
|
|
||||||
|
#undef __class__
|
||||||
|
#define __class__ "io::NodeMuxer"
|
||||||
|
|
||||||
|
std11::shared_ptr<river::io::NodeMuxer> river::io::NodeMuxer::create(const std::string& _name, const std11::shared_ptr<const ejson::Object>& _config) {
|
||||||
|
return std11::shared_ptr<river::io::NodeMuxer>(new river::io::NodeMuxer(_name, _config));
|
||||||
|
}
|
||||||
|
|
||||||
|
std11::shared_ptr<river::Interface> river::io::NodeMuxer::createInput(float _freq,
|
||||||
|
const std::vector<audio::channel>& _map,
|
||||||
|
audio::format _format,
|
||||||
|
const std::string& _objectName,
|
||||||
|
const std::string& _name) {
|
||||||
|
// check if the output exist
|
||||||
|
const std11::shared_ptr<const ejson::Object> tmppp = m_config->getObject(_objectName);
|
||||||
|
if (tmppp == nullptr) {
|
||||||
|
RIVER_ERROR("can not open a non existance virtual interface: '" << _objectName << "' not present in : " << m_config->getKeys());
|
||||||
|
return std11::shared_ptr<river::Interface>();
|
||||||
|
}
|
||||||
|
std::string streamName = tmppp->getStringValue("map-on", "error");
|
||||||
|
|
||||||
|
|
||||||
|
// 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<river::Interface>();
|
||||||
|
}
|
||||||
|
// get global hardware interface:
|
||||||
|
std11::shared_ptr<river::io::Manager> manager = river::io::Manager::getInstance();
|
||||||
|
// get the output or input channel :
|
||||||
|
std11::shared_ptr<river::io::Node> node = manager->getNode(streamName);
|
||||||
|
// create user iterface:
|
||||||
|
std11::shared_ptr<river::Interface> interface;
|
||||||
|
interface = river::Interface::create(_name, _freq, _map, _format, node, tmppp);
|
||||||
|
return interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
river::io::NodeMuxer::NodeMuxer(const std::string& _name, const std11::shared_ptr<const ejson::Object>& _config) :
|
||||||
|
Node(_name, _config) {
|
||||||
|
drain::IOFormatInterface interfaceFormat = getInterfaceFormat();
|
||||||
|
drain::IOFormatInterface hardwareFormat = getHarwareFormat();
|
||||||
|
m_sampleTime = std11::chrono::nanoseconds(1000000000/int64_t(hardwareFormat.getFrequency()));
|
||||||
|
/**
|
||||||
|
# connect in input mode
|
||||||
|
map-on-input-1:{
|
||||||
|
# generic virtual definition
|
||||||
|
io:"input",
|
||||||
|
map-on:"microphone",
|
||||||
|
resampling-type:"speexdsp",
|
||||||
|
resampling-option:"quality=10"
|
||||||
|
},
|
||||||
|
# connect in feedback mode
|
||||||
|
map-on-input-2:{
|
||||||
|
io:"feedback",
|
||||||
|
map-on:"speaker",
|
||||||
|
resampling-type:"speexdsp",
|
||||||
|
resampling-option:"quality=10",
|
||||||
|
},
|
||||||
|
# AEC algo definition
|
||||||
|
algo:"river-remover",
|
||||||
|
algo-mode:"cutter",
|
||||||
|
*/
|
||||||
|
RIVER_INFO("Create IN 1 : ");
|
||||||
|
m_interfaceInput1 = createInput(hardwareFormat.getFrequency(),
|
||||||
|
std::vector<audio::channel>(),
|
||||||
|
hardwareFormat.getFormat(),
|
||||||
|
"map-on-input-1",
|
||||||
|
_name + "-muxer-in1");
|
||||||
|
if (m_interfaceInput1 == nullptr) {
|
||||||
|
RIVER_ERROR("Can not opne virtual device ... map-on-input-1 in " << _name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_mapInput1 = m_interfaceInput1->getInterfaceFormat().getMap();
|
||||||
|
|
||||||
|
RIVER_INFO("Create IN 2 : ");
|
||||||
|
m_interfaceInput2 = createInput(hardwareFormat.getFrequency(),
|
||||||
|
std::vector<audio::channel>(),
|
||||||
|
hardwareFormat.getFormat(),
|
||||||
|
"map-on-input-2",
|
||||||
|
_name + "-muxer-in2");
|
||||||
|
if (m_interfaceInput2 == nullptr) {
|
||||||
|
RIVER_ERROR("Can not opne virtual device ... map-on-input-2 in " << _name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_mapInput2 = m_interfaceInput1->getInterfaceFormat().getMap();
|
||||||
|
|
||||||
|
// set callback mode ...
|
||||||
|
m_interfaceInput1->setInputCallback(std11::bind(&river::io::NodeMuxer::onDataReceivedFeedBack,
|
||||||
|
this,
|
||||||
|
std11::placeholders::_1,
|
||||||
|
std11::placeholders::_2,
|
||||||
|
std11::placeholders::_3,
|
||||||
|
std11::placeholders::_4,
|
||||||
|
std11::placeholders::_5,
|
||||||
|
std11::placeholders::_6));
|
||||||
|
// set callback mode ...
|
||||||
|
m_interfaceInput2->setInputCallback(std11::bind(&river::io::NodeMuxer::onDataReceivedMicrophone,
|
||||||
|
this,
|
||||||
|
std11::placeholders::_1,
|
||||||
|
std11::placeholders::_2,
|
||||||
|
std11::placeholders::_3,
|
||||||
|
std11::placeholders::_4,
|
||||||
|
std11::placeholders::_5,
|
||||||
|
std11::placeholders::_6));
|
||||||
|
|
||||||
|
m_bufferInput1.setCapacity(std11::chrono::milliseconds(1000),
|
||||||
|
audio::getFormatBytes(hardwareFormat.getFormat())*m_mapInput1.size(),
|
||||||
|
hardwareFormat.getFrequency());
|
||||||
|
m_bufferInput2.setCapacity(std11::chrono::milliseconds(1000),
|
||||||
|
audio::getFormatBytes(hardwareFormat.getFormat())*m_mapInput2.size(),
|
||||||
|
hardwareFormat.getFrequency());
|
||||||
|
|
||||||
|
m_process.updateInterAlgo();
|
||||||
|
}
|
||||||
|
|
||||||
|
river::io::NodeMuxer::~NodeMuxer() {
|
||||||
|
RIVER_INFO("close input stream");
|
||||||
|
stop();
|
||||||
|
m_interfaceInput1.reset();
|
||||||
|
m_interfaceInput2.reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
void river::io::NodeMuxer::start() {
|
||||||
|
std11::unique_lock<std11::mutex> lock(m_mutex);
|
||||||
|
RIVER_INFO("Start stream : '" << m_name << "' mode=" << (m_isInput?"input":"output") );
|
||||||
|
if (m_interfaceInput1 != nullptr) {
|
||||||
|
RIVER_INFO("Start FEEDBACK : ");
|
||||||
|
m_interfaceInput1->start();
|
||||||
|
}
|
||||||
|
if (m_interfaceInput2 != nullptr) {
|
||||||
|
RIVER_INFO("Start Microphone : ");
|
||||||
|
m_interfaceInput2->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void river::io::NodeMuxer::stop() {
|
||||||
|
std11::unique_lock<std11::mutex> lock(m_mutex);
|
||||||
|
if (m_interfaceInput1 != nullptr) {
|
||||||
|
m_interfaceInput1->stop();
|
||||||
|
}
|
||||||
|
if (m_interfaceInput2 != nullptr) {
|
||||||
|
m_interfaceInput2->stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void river::io::NodeMuxer::onDataReceivedMicrophone(const void* _data,
|
||||||
|
const std11::chrono::system_clock::time_point& _time,
|
||||||
|
size_t _nbChunk,
|
||||||
|
enum audio::format _format,
|
||||||
|
uint32_t _frequency,
|
||||||
|
const std::vector<audio::channel>& _map) {
|
||||||
|
RIVER_DEBUG("Microphone Time=" << _time << " _nbChunk=" << _nbChunk << " _map=" << _map << " _format=" << _format << " freq=" << _frequency);
|
||||||
|
RIVER_DEBUG(" next=" << _time + std11::chrono::nanoseconds(_nbChunk*1000000000LL/int64_t(_frequency)) );
|
||||||
|
if (_format != audio::format_int16) {
|
||||||
|
RIVER_ERROR("call wrong type ... (need int16_t)");
|
||||||
|
}
|
||||||
|
// push data synchronize
|
||||||
|
std11::unique_lock<std11::mutex> lock(m_mutex);
|
||||||
|
m_bufferInput1.write(_data, _nbChunk, _time);
|
||||||
|
//RIVER_SAVE_FILE_MACRO(int16_t, "REC_Microphone.raw", _data, _nbChunk*_map.size());
|
||||||
|
process();
|
||||||
|
}
|
||||||
|
|
||||||
|
void river::io::NodeMuxer::onDataReceivedFeedBack(const void* _data,
|
||||||
|
const std11::chrono::system_clock::time_point& _time,
|
||||||
|
size_t _nbChunk,
|
||||||
|
enum audio::format _format,
|
||||||
|
uint32_t _frequency,
|
||||||
|
const std::vector<audio::channel>& _map) {
|
||||||
|
RIVER_DEBUG("FeedBack Time=" << _time << " _nbChunk=" << _nbChunk << " _map=" << _map << " _format=" << _format << " freq=" << _frequency);
|
||||||
|
RIVER_DEBUG(" next=" << _time + std11::chrono::nanoseconds(_nbChunk*1000000000LL/int64_t(_frequency)) );
|
||||||
|
if (_format != audio::format_int16) {
|
||||||
|
RIVER_ERROR("call wrong type ... (need int16_t)");
|
||||||
|
}
|
||||||
|
// push data synchronize
|
||||||
|
std11::unique_lock<std11::mutex> lock(m_mutex);
|
||||||
|
m_bufferInput2.write(_data, _nbChunk, _time);
|
||||||
|
//RIVER_SAVE_FILE_MACRO(int16_t, "REC_FeedBack.raw", _data, _nbChunk*_map.size());
|
||||||
|
process();
|
||||||
|
}
|
||||||
|
|
||||||
|
void river::io::NodeMuxer::process() {
|
||||||
|
if (m_bufferInput1.getSize() <= 256) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (m_bufferInput2.getSize() <= 256) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std11::chrono::system_clock::time_point in1Time = m_bufferInput1.getReadTimeStamp();
|
||||||
|
std11::chrono::system_clock::time_point in2Time = m_bufferInput2.getReadTimeStamp();
|
||||||
|
std11::chrono::nanoseconds delta;
|
||||||
|
if (in1Time < in2Time) {
|
||||||
|
delta = in2Time - in1Time;
|
||||||
|
} else {
|
||||||
|
delta = in1Time - in2Time;
|
||||||
|
}
|
||||||
|
|
||||||
|
RIVER_INFO("check delta " << delta.count() << " > " << m_sampleTime.count());
|
||||||
|
if (delta > m_sampleTime) {
|
||||||
|
// Synchronize if possible
|
||||||
|
if (in1Time < in2Time) {
|
||||||
|
RIVER_INFO("in1Time < in2Time : Change Microphone time start " << in2Time);
|
||||||
|
RIVER_INFO(" old time stamp=" << m_bufferInput1.getReadTimeStamp());
|
||||||
|
m_bufferInput1.setReadPosition(in2Time);
|
||||||
|
RIVER_INFO(" new time stamp=" << m_bufferInput1.getReadTimeStamp());
|
||||||
|
}
|
||||||
|
if (in1Time > in2Time) {
|
||||||
|
RIVER_INFO("in1Time > in2Time : Change FeedBack time start " << in1Time);
|
||||||
|
RIVER_INFO(" old time stamp=" << m_bufferInput2.getReadTimeStamp());
|
||||||
|
m_bufferInput2.setReadPosition(in1Time);
|
||||||
|
RIVER_INFO(" new time stamp=" << m_bufferInput2.getReadTimeStamp());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check if enought time after synchronisation ...
|
||||||
|
if (m_bufferInput1.getSize() <= 256) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (m_bufferInput2.getSize() <= 256) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
in1Time = m_bufferInput1.getReadTimeStamp();
|
||||||
|
in2Time = m_bufferInput2.getReadTimeStamp();
|
||||||
|
|
||||||
|
if (in1Time-in2Time > m_sampleTime) {
|
||||||
|
RIVER_ERROR("Can not synchronize flow ... : " << in1Time << " != " << in2Time << " delta = " << (in1Time-in2Time).count()/1000 << " µs");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> dataIn1;
|
||||||
|
std::vector<uint8_t> dataIn2;
|
||||||
|
dataIn1.resize(256*sizeof(int16_t)*m_mapInput1.size(), 0);
|
||||||
|
dataIn2.resize(256*sizeof(int16_t)*m_mapInput2.size(), 0);
|
||||||
|
while (true) {
|
||||||
|
in1Time = m_bufferInput1.getReadTimeStamp();
|
||||||
|
in2Time = m_bufferInput2.getReadTimeStamp();
|
||||||
|
RIVER_INFO(" process 256 samples ... in1Time=" << in1Time << " in2Time=" << in2Time << " delta = " << (in1Time-in2Time).count());
|
||||||
|
m_bufferInput1.read(&dataIn1[0], 256);
|
||||||
|
m_bufferInput2.read(&dataIn2[0], 256);
|
||||||
|
RIVER_SAVE_FILE_MACRO(int16_t, "REC_INPUT1.raw", &dataIn1[0], 256 * m_mapInput1.size());
|
||||||
|
RIVER_SAVE_FILE_MACRO(int16_t, "REC_INPUT2.raw", &dataIn2[0], 256 * m_mapInput2.size());
|
||||||
|
// if threaded : send event / otherwise, process ...
|
||||||
|
processMuxer(&dataIn1[0], &dataIn2[0], 256, in1Time);
|
||||||
|
if ( m_bufferInput1.getSize() <= 256
|
||||||
|
|| m_bufferInput2.getSize() <= 256) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void river::io::NodeMuxer::processMuxer(void* _dataIn1, void* _dataIn2, uint32_t _nbChunk, const std11::chrono::system_clock::time_point& _time) {
|
||||||
|
RIVER_INFO("must Mux data : " << m_mapInput1 << " + " << m_mapInput2 << " ==> " << getInterfaceFormat().getMap());
|
||||||
|
//newInput(_dataIn1, _nbChunk, _time);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void river::io::NodeMuxer::generateDot(etk::FSNode& _node) {
|
||||||
|
_node << "subgraph clusterNode_" << m_uid << " {\n";
|
||||||
|
_node << " color=blue;\n";
|
||||||
|
_node << " label=\"[" << m_uid << "] IO::Node : " << m_name << "\";\n";
|
||||||
|
|
||||||
|
_node << " node [shape=box];\n";
|
||||||
|
// TODO : Create a structure ...
|
||||||
|
_node << " NODE_" << m_uid << "_HW_AEC [ label=\"AEC\" ];\n";
|
||||||
|
_node << " subgraph clusterNode_" << m_uid << "_process {\n";
|
||||||
|
_node << " label=\"Drain::Process\";\n";
|
||||||
|
_node << " node [shape=ellipse];\n";
|
||||||
|
_node << " node_ALGO_" << m_uid << "_in [ label=\"format=xxx\n freq=yyy\n channelMap={left,right}\" ];\n";
|
||||||
|
_node << " node_ALGO_" << m_uid << "_out [ label=\"format=xxx\n freq=yyy\n channelMap={left,right}\" ];\n";
|
||||||
|
|
||||||
|
_node << " }\n";
|
||||||
|
_node << " node [shape=square];\n";
|
||||||
|
_node << " NODE_" << m_uid << "_demuxer [ label=\"DEMUXER\n format=xxx\" ];\n";
|
||||||
|
// Link all nodes :
|
||||||
|
_node << " NODE_" << m_uid << "_HW_AEC -> node_ALGO_" << m_uid << "_in;\n";
|
||||||
|
_node << " node_ALGO_" << m_uid << "_in -> node_ALGO_" << m_uid << "_out;\n";
|
||||||
|
_node << " node_ALGO_" << m_uid << "_out -> NODE_" << m_uid << "_demuxer;\n";
|
||||||
|
_node << "}\n";
|
||||||
|
if (m_interfaceInput2 != nullptr) {
|
||||||
|
_node << " API_" << m_interfaceInput2->m_uid << "_input -> NODE_" << m_uid << "_HW_AEC;\n";
|
||||||
|
}
|
||||||
|
if (m_interfaceInput1 != nullptr) {
|
||||||
|
_node << " API_" << m_interfaceInput1->m_uid << "_feedback -> NODE_" << m_uid << "_HW_AEC;\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t iii=0; iii<m_list.size(); ++iii) {
|
||||||
|
if (m_list[iii] != nullptr) {
|
||||||
|
if (m_list[iii]->getMode() == modeInterface_input) {
|
||||||
|
m_list[iii]->generateDot(_node, "NODE_" + etk::to_string(m_uid) + "_demuxer");
|
||||||
|
} else if (m_list[iii]->getMode() == modeInterface_output) {
|
||||||
|
m_list[iii]->generateDot(_node, "NODE_" + etk::to_string(m_uid) + "_muxer");
|
||||||
|
} else if (m_list[iii]->getMode() == modeInterface_feedback) {
|
||||||
|
m_list[iii]->generateDot(_node, "NODE_" + etk::to_string(m_uid) + "_demuxer");
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
66
river/io/NodeMuxer.h
Normal file
66
river/io/NodeMuxer.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||||
|
* @license APACHE v2.0 (see license file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __RIVER_IO_NODE_MUXER_H__
|
||||||
|
#define __RIVER_IO_NODE_MUXER_H__
|
||||||
|
|
||||||
|
#include <river/io/Node.h>
|
||||||
|
#include <river/Interface.h>
|
||||||
|
#include <river/CircularBuffer.h>
|
||||||
|
|
||||||
|
namespace river {
|
||||||
|
namespace io {
|
||||||
|
class Manager;
|
||||||
|
class NodeMuxer : public Node {
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* @brief Constructor
|
||||||
|
*/
|
||||||
|
NodeMuxer(const std::string& _name, const std11::shared_ptr<const ejson::Object>& _config);
|
||||||
|
public:
|
||||||
|
static std11::shared_ptr<NodeMuxer> create(const std::string& _name, const std11::shared_ptr<const ejson::Object>& _config);
|
||||||
|
/**
|
||||||
|
* @brief Destructor
|
||||||
|
*/
|
||||||
|
virtual ~NodeMuxer();
|
||||||
|
protected:
|
||||||
|
virtual void start();
|
||||||
|
virtual void stop();
|
||||||
|
std11::shared_ptr<river::Interface> m_interfaceInput1;
|
||||||
|
std11::shared_ptr<river::Interface> m_interfaceInput2;
|
||||||
|
std11::shared_ptr<river::Interface> createInput(float _freq,
|
||||||
|
const std::vector<audio::channel>& _map,
|
||||||
|
audio::format _format,
|
||||||
|
const std::string& _streamName,
|
||||||
|
const std::string& _name);
|
||||||
|
void onDataReceivedMicrophone(const void* _data,
|
||||||
|
const std11::chrono::system_clock::time_point& _time,
|
||||||
|
size_t _nbChunk,
|
||||||
|
enum audio::format _format,
|
||||||
|
uint32_t _frequency,
|
||||||
|
const std::vector<audio::channel>& _map);
|
||||||
|
void onDataReceivedFeedBack(const void* _data,
|
||||||
|
const std11::chrono::system_clock::time_point& _time,
|
||||||
|
size_t _nbChunk,
|
||||||
|
enum audio::format _format,
|
||||||
|
uint32_t _frequency,
|
||||||
|
const std::vector<audio::channel>& _map);
|
||||||
|
std::vector<audio::channel> m_mapInput1;
|
||||||
|
std::vector<audio::channel> m_mapInput2;
|
||||||
|
river::CircularBuffer m_bufferInput1;
|
||||||
|
river::CircularBuffer m_bufferInput2;
|
||||||
|
std11::chrono::nanoseconds m_sampleTime; //!< represent the sample time at the specify frequency.
|
||||||
|
void process();
|
||||||
|
void processMuxer(void* _dataMic, void* _dataFB, uint32_t _nbChunk, const std11::chrono::system_clock::time_point& _time);
|
||||||
|
std::vector<uint8_t> m_data;
|
||||||
|
public:
|
||||||
|
virtual void generateDot(etk::FSNode& _node);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -269,8 +269,8 @@ namespace river_test_echo_delay {
|
|||||||
if ( valueMax > m_volumeInputMax
|
if ( valueMax > m_volumeInputMax
|
||||||
&& valueMin < m_volumeInputMin
|
&& valueMin < m_volumeInputMin
|
||||||
&& ( m_gain == 0.0
|
&& ( m_gain == 0.0
|
||||||
|| ( valueMax > INT16_MAX/2
|
|| ( valueMax > INT16_MAX*2/3
|
||||||
&& valueMin < INT16_MIN/2
|
&& valueMin < INT16_MIN*2/3
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
@ -7,11 +7,62 @@
|
|||||||
#ifndef __RIVER_TEST_MUXER_H__
|
#ifndef __RIVER_TEST_MUXER_H__
|
||||||
#define __RIVER_TEST_MUXER_H__
|
#define __RIVER_TEST_MUXER_H__
|
||||||
|
|
||||||
|
#include <river/debug.h>
|
||||||
|
|
||||||
#undef __class__
|
#undef __class__
|
||||||
#define __class__ "test_muxer"
|
#define __class__ "test_muxer"
|
||||||
|
|
||||||
namespace river_test_muxer {
|
namespace river_test_muxer {
|
||||||
|
class TestClass {
|
||||||
|
private:
|
||||||
|
std11::shared_ptr<river::Manager> m_manager;
|
||||||
|
std11::shared_ptr<river::Interface> m_interfaceIn;
|
||||||
|
public:
|
||||||
|
TestClass(std11::shared_ptr<river::Manager> _manager) :
|
||||||
|
m_manager(_manager) {
|
||||||
|
//Set stereo output:
|
||||||
|
m_interfaceIn = m_manager->createInput(48000,
|
||||||
|
std::vector<audio::channel>(),
|
||||||
|
audio::format_int16,
|
||||||
|
"microphone-muxed",
|
||||||
|
"microphone-muxed-local-name");
|
||||||
|
// set callback mode ...
|
||||||
|
m_interfaceIn->setInputCallback(std11::bind(&TestClass::onDataReceived,
|
||||||
|
this,
|
||||||
|
std11::placeholders::_1,
|
||||||
|
std11::placeholders::_2,
|
||||||
|
std11::placeholders::_3,
|
||||||
|
std11::placeholders::_4,
|
||||||
|
std11::placeholders::_5,
|
||||||
|
std11::placeholders::_6));
|
||||||
|
m_manager->generateDotAll("activeProcess.dot");
|
||||||
|
}
|
||||||
|
void onDataReceived(const void* _data,
|
||||||
|
const std11::chrono::system_clock::time_point& _time,
|
||||||
|
size_t _nbChunk,
|
||||||
|
enum audio::format _format,
|
||||||
|
uint32_t _frequency,
|
||||||
|
const std::vector<audio::channel>& _map) {
|
||||||
|
if (_format != audio::format_int16) {
|
||||||
|
APPL_ERROR("call wrong type ... (need int16_t)");
|
||||||
|
}
|
||||||
|
RIVER_SAVE_FILE_MACRO(int16_t, "REC_MicrophoneMuxed.raw", _data, _nbChunk*_map.size());
|
||||||
|
}
|
||||||
|
void run() {
|
||||||
|
m_interfaceIn->start();
|
||||||
|
usleep(10000000);
|
||||||
|
m_interfaceIn->stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(TestMuxer, testMuxing) {
|
||||||
|
std11::shared_ptr<river::Manager> manager;
|
||||||
|
manager = river::Manager::create("testApplication");
|
||||||
|
std11::shared_ptr<TestClass> process = std11::make_shared<TestClass>(manager);
|
||||||
|
process->run();
|
||||||
|
process.reset();
|
||||||
|
usleep(500000);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef __class__
|
#undef __class__
|
||||||
|
Loading…
x
Reference in New Issue
Block a user