[DEV] work on the stream of AEC

This commit is contained in:
Edouard DUPIN 2015-03-23 22:46:21 +01:00
parent 3f6d736454
commit 58da3cf125
6 changed files with 256 additions and 51 deletions

View File

@ -19,7 +19,7 @@ static std11::mutex g_mutex;
static std::vector<std11::weak_ptr<river::Manager> > g_listOfAllManager;
std11::shared_ptr<river::Manager> river::Manager::create(const std::string& _applicationUniqueId) {
std11::unique_lock<std11:mutex> lock(g_mutex);
std11::unique_lock<std11::mutex> lock(g_mutex);
for (size_t iii=0; iii<g_listOfAllManager.size() ; ++iii) {
std11::shared_ptr<river::Manager> tmp = g_listOfAllManager[iii].lock();
if (tmp == nullptr) {

View File

@ -30,7 +30,7 @@ std11::shared_ptr<river::Interface> river::io::NodeAEC::createInput(float _freq,
}
std::string streamName = tmppp->getStringValue("map-on", "error");
m_nbChunk = m_config->getNumberValue("nb-chunk", 1024);
// check if it is an Output:
std::string type = tmppp->getStringValue("io", "error");
if ( type != "input"
@ -197,8 +197,8 @@ void river::io::NodeAEC::onDataReceivedFeedBack(const void* _data,
}
void river::io::NodeAEC::process() {
if ( m_bufferMicrophone.getSize() <= 256
|| m_bufferFeedBack.getSize() <= 256) {
if ( m_bufferMicrophone.getSize() <= m_nbChunk
|| m_bufferFeedBack.getSize() <= m_nbChunk) {
return;
}
std11::chrono::system_clock::time_point MicTime = m_bufferMicrophone.getReadTimeStamp();
@ -227,10 +227,8 @@ void river::io::NodeAEC::process() {
}
}
// check if enought time after synchronisation ...
if (m_bufferMicrophone.getSize() <= 256) {
return;
}
if (m_bufferFeedBack.getSize() <= 256) {
if ( m_bufferMicrophone.getSize() <= m_nbChunk
|| m_bufferFeedBack.getSize() <= m_nbChunk) {
return;
}
@ -243,22 +241,20 @@ void river::io::NodeAEC::process() {
}
std::vector<uint8_t> dataMic;
std::vector<uint8_t> dataFB;
dataMic.resize(256*sizeof(int16_t)*2, 0);
dataFB.resize(256*sizeof(int16_t), 0);
dataMic.resize(m_nbChunk*sizeof(int16_t)*2, 0);
dataFB.resize(m_nbChunk*sizeof(int16_t), 0);
while (true) {
MicTime = m_bufferMicrophone.getReadTimeStamp();
fbTime = m_bufferFeedBack.getReadTimeStamp();
RIVER_INFO(" process 256 samples ... micTime=" << MicTime << " fbTime=" << fbTime << " delta = " << (MicTime-fbTime).count());
m_bufferMicrophone.read(&dataMic[0], 256);
m_bufferFeedBack.read(&dataFB[0], 256);
RIVER_SAVE_FILE_MACRO(int16_t, "REC_Microphone_sync.raw", &dataMic[0], 256*2);
RIVER_SAVE_FILE_MACRO(int16_t, "REC_FeedBack_sync.raw", &dataFB[0], 256);
m_bufferMicrophone.read(&dataMic[0], m_nbChunk);
m_bufferFeedBack.read(&dataFB[0], m_nbChunk);
RIVER_SAVE_FILE_MACRO(int16_t, "REC_Microphone_sync.raw", &dataMic[0], m_nbChunk*2);
RIVER_SAVE_FILE_MACRO(int16_t, "REC_FeedBack_sync.raw", &dataFB[0], m_nbChunk);
// if threaded : send event / otherwise, process ...
//processAEC(&dataMic[0], &dataFB[0], 256, _time);
if (m_bufferMicrophone.getSize() <= 256) {
return;
}
if (m_bufferFeedBack.getSize() <= 256) {
processAEC(&dataMic[0], &dataFB[0], m_nbChunk, MicTime);
if ( m_bufferMicrophone.getSize() <= m_nbChunk
|| m_bufferFeedBack.getSize() <= m_nbChunk) {
return;
}
}
@ -274,27 +270,15 @@ void river::io::NodeAEC::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=" << etk::to_string(m_process.getInputConfig().getFormat())
<< "\\n freq=" << m_process.getInputConfig().getFrequency()
<< "\\n channelMap=" << etk::to_string(m_process.getInputConfig().getMap()) << "\" ];\n";
_node << " node_ALGO_" << m_uid << "_out [ label=\"format=" << etk::to_string(m_process.getOutputConfig().getFormat())
<< "\\n freq=" << m_process.getOutputConfig().getFrequency()
<< "\\n channelMap=" << etk::to_string(m_process.getOutputConfig().getMap()) << "\" ];\n";
_node << " }\n";
_node << " NODE_" << m_uid << "_HW_AEC [ label=\"AEC\\n channelMap=" << etk::to_string(getInterfaceFormat().getMap()) << "\" ];\n";
std::string nameIn;
std::string nameOut;
m_process.generateDot(_node, 3, m_uid, nameIn, nameOut, false);
_node << " node [shape=square];\n";
_node << " NODE_" << m_uid << "_demuxer [ label=\"DEMUXER\\n format=" << etk::to_string(m_process.getOutputConfig().getFormat()) << "\" ];\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 << " NODE_" << m_uid << "_HW_AEC -> " << nameIn << ";\n";
_node << " " << nameOut << " -> NODE_" << m_uid << "_demuxer;\n";
_node << " }\n";
if (m_interfaceMicrophone != nullptr) {
_node << " " << m_interfaceMicrophone->getDotNodeName() << " -> NODE_" << m_uid << "_HW_AEC;\n";
@ -302,15 +286,29 @@ void river::io::NodeAEC::generateDot(etk::FSNode& _node) {
if (m_interfaceFeedBack != nullptr) {
_node << " " << m_interfaceFeedBack->getDotNodeName() << " -> NODE_" << m_uid << "_HW_AEC;\n";
}
_node << " \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");
for (size_t iii=0; iii< m_listAvaillable.size(); ++iii) {
if (m_listAvaillable[iii].expired() == true) {
continue;
}
std11::shared_ptr<river::Interface> element = m_listAvaillable[iii].lock();
if (element == nullptr) {
continue;
}
bool isLink = false;
for (size_t jjj=0; jjj<m_list.size(); ++jjj) {
if (element == m_list[jjj]) {
isLink = true;
}
}
if (element != nullptr) {
if (element->getMode() == modeInterface_input) {
element->generateDot(_node, "NODE_" + etk::to_string(m_uid) + "_demuxer", isLink);
} else if (element->getMode() == modeInterface_output) {
element->generateDot(_node, "NODE_" + etk::to_string(m_uid) + "_muxer", isLink);
} else if (element->getMode() == modeInterface_feedback) {
element->generateDot(_node, "NODE_" + etk::to_string(m_uid) + "_demuxer", isLink);
} else {
}

View File

@ -89,6 +89,8 @@ namespace river {
void processAEC(void* _dataMic, void* _dataFB, uint32_t _nbChunk, const std11::chrono::system_clock::time_point& _time);
public:
virtual void generateDot(etk::FSNode& _node);
private:
int32_t m_nbChunk;
};
}
}

View File

@ -190,13 +190,15 @@ river::io::NodeAirTAudio::NodeAirTAudio(const std::string& _name, const std11::s
airtaudio::StreamParameters params;
params.deviceId = deviceId;
params.deviceName = streamName;
// TODO : Remove limit of 2 channels ...
params.nChannels = hardwareFormat.getMap().size();
if (m_isInput == true) {
m_info.inputChannels = 2;
params.nChannels = 2;
if (m_info.inputChannels < params.nChannels) {
RIVER_CRITICAL("Can not open hardware device with more channel (" << params.nChannels << ") that is autorized by hardware (" << m_info.inputChannels << ").");
}
} else {
m_info.outputChannels = 2;
params.nChannels = 2;
if (m_info.outputChannels < params.nChannels) {
RIVER_CRITICAL("Can not open hardware device with more channel (" << params.nChannels << ") that is autorized by hardware (" << m_info.inputChannels << ").");
}
}
airtaudio::StreamOptions option;
etk::from_string(option.mode, tmpObject->getStringValue("timestamp-mode", "soft"));

View File

@ -12,6 +12,209 @@
namespace river_test_aec {
class Linker {
private:
std11::shared_ptr<river::Manager> m_manager;
std11::shared_ptr<river::Interface> m_interfaceOut;
std11::shared_ptr<river::Interface> m_interfaceIn;
drain::CircularBuffer m_buffer;
public:
Linker(std11::shared_ptr<river::Manager> _manager, const std::string& _input, const std::string& _output) :
m_manager(_manager) {
//Set stereo output:
std::vector<audio::channel> channelMap;
if (false) { //"speaker" == _output) {
channelMap.push_back(audio::channel_frontCenter);
} else {
channelMap.push_back(audio::channel_frontLeft);
channelMap.push_back(audio::channel_frontRight);
}
m_buffer.setCapacity(std11::chrono::milliseconds(2000), sizeof(int16_t)*channelMap.size(), 48000);
m_interfaceOut = m_manager->createOutput(48000,
channelMap,
audio::format_int16,
_output);
if(m_interfaceOut == nullptr) {
APPL_ERROR("nullptr interface");
return;
}
// set callback mode ...
m_interfaceOut->setOutputCallback(std11::bind(&Linker::onDataNeeded,
this,
std11::placeholders::_1,
std11::placeholders::_2,
std11::placeholders::_3,
std11::placeholders::_4,
std11::placeholders::_5,
std11::placeholders::_6));
m_interfaceOut->addVolumeGroup("FLOW");
if ("speaker" == _output) {
m_interfaceOut->setParameter("volume", "FLOW", "0dB");
}
m_interfaceIn = m_manager->createInput(48000,
channelMap,
audio::format_int16,
_input);
if(m_interfaceIn == nullptr) {
APPL_ERROR("nullptr interface");
return;
}
// set callback mode ...
m_interfaceIn->setInputCallback(std11::bind(&Linker::onDataReceived,
this,
std11::placeholders::_1,
std11::placeholders::_2,
std11::placeholders::_3,
std11::placeholders::_4,
std11::placeholders::_5,
std11::placeholders::_6));
}
void onDataNeeded(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)");
}
m_buffer.read(_data, _nbChunk);
}
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)");
}
m_buffer.write(_data, _nbChunk);
}
void start() {
if(m_interfaceIn == nullptr) {
APPL_ERROR("nullptr interface");
return;
}
if(m_interfaceOut == nullptr) {
APPL_ERROR("nullptr interface");
return;
}
m_interfaceOut->start();
m_interfaceIn->start();
}
void stop() {
if(m_interfaceIn == nullptr) {
APPL_ERROR("nullptr interface");
return;
}
if(m_interfaceOut == nullptr) {
APPL_ERROR("nullptr interface");
return;
}
m_manager->generateDotAll("activeProcess.dot");
m_interfaceOut->stop();
m_interfaceIn->stop();
}
};
static const std::string configurationRiver =
"{\n"
" speaker:{\n"
" io:'output',\n"
" map-on:{\n"
" interface:'auto',\n"
" name:'hw:0,0',\n"
" timestamp-mode:'trigered',\n"
" },\n"
" frequency:0,\n"
" channel-map:['front-left', 'front-right'],\n"
" type:'auto',\n"
" nb-chunk:1024,\n"
" },\n"
" microphone:{\n"
" io:'input',\n"
" map-on:{\n"
" interface:'auto',\n"
" name:'hw:0,0',\n"
" timestamp-mode:'trigered',\n"
" },\n"
" frequency:0,\n"
" channel-map:['front-left', 'front-right'],\n"
" type:'auto',\n"
" nb-chunk:1024\n"
" },\n"
" speaker-test:{\n"
" io:'output',\n"
" map-on:{\n"
" interface:'alsa',\n"
" name:'hw:2,0',\n"
" timestamp-mode:'trigered',\n"
" },\n"
//" group:'groupSynchro',\n"
" frequency:0,\n"
" channel-map:['front-left', 'front-right'],\n"
" type:'auto',\n"
" nb-chunk:1024\n"
" },\n"
" microphone-test:{\n"
" io:'input',\n"
" map-on:{\n"
" interface:'alsa',\n"
" name:'hw:2,0',\n"
" timestamp-mode:'trigered',\n"
" },\n"
//" group:'groupSynchro',\n"
" frequency:0,\n"
" channel-map:['front-center'],\n"
" type:'auto',\n"
" nb-chunk:1024\n"
" },\n"
" # virtual Nodes :\n"
" microphone-clean:{\n"
" io:'aec',\n"
" map-on-microphone:{\n"
" io:'input',\n"
" map-on:'microphone-test'\n"
" },\n"
" map-on-feedback:{\n"
" io:'feedback',\n"
" map-on:'speaker-test',\n"
" },\n"
" frequency:48000,\n"
" channel-map:[\n"
" 'front-left', 'front-right'\n"
//" 'front-center'\n"
" ],\n"
" nb-chunk:1024,\n"
" type:'int16',\n"
" algo:'river-remover',\n"
" algo-mode:'cutter',\n"
" feedback-delay:10000,\n"
" mux-demux-type:'int16'\n"
" }\n"
"}\n";
TEST(TestUser, testAECManually) {
river::initString(configurationRiver);
std11::shared_ptr<river::Manager> manager;
manager = river::Manager::create("testApplication");
std11::shared_ptr<Linker> processLink1 = std11::make_shared<Linker>(manager, "microphone-clean", "speaker");
std11::shared_ptr<Linker> processLink2 = std11::make_shared<Linker>(manager, "microphone", "speaker-test");
processLink1->start();
processLink2->start();
sleep(30);
processLink1->stop();
processLink2->stop();
processLink1.reset();
processLink2.reset();
manager.reset();
river::unInit();
}
};
#undef __class__

View File

@ -82,7 +82,7 @@ namespace river_test_playback_callback {
" io:'output',\n"
" map-on:{\n"
" interface:'auto',\n"
" name:'default',\n"
" name:'hw:2,0',\n"
" },\n"
" frequency:0,\n"
" channel-map:['front-left', 'front-right'],\n"