[DEV] first step
This commit is contained in:
commit
1100b27c54
356
airtio/Interface.cpp
Normal file
356
airtio/Interface.cpp
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||||
|
* @license APACHE v2.0 (see license file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Interface.h"
|
||||||
|
#include <airtalgo/ChannelReorder.h>
|
||||||
|
#include <airtalgo/FormatUpdate.h>
|
||||||
|
#include <airtalgo/Resampler.h>
|
||||||
|
#include <airtalgo/EndPointCallback.h>
|
||||||
|
#include <airtalgo/EndPointWrite.h>
|
||||||
|
#include <airtalgo/EndPointRead.h>
|
||||||
|
|
||||||
|
|
||||||
|
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<airtalgo::channel>& _map,
|
||||||
|
airtalgo::format _format,
|
||||||
|
const std::shared_ptr<airtio::io::Node>& _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> airtio::Interface::create(const std::string& _name,
|
||||||
|
float _freq,
|
||||||
|
const std::vector<airtalgo::channel>& _map,
|
||||||
|
airtalgo::format _format,
|
||||||
|
const std::shared_ptr<airtio::io::Node>& _node) {
|
||||||
|
std::shared_ptr<airtio::Interface> out = std::make_shared<airtio::Interface>(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<airtalgo::ChannelReorder> algo = boost::make_shared<airtalgo::ChannelReorder>();
|
||||||
|
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<airtalgo::Resampler> algo = boost::make_shared<airtalgo::Resampler>();
|
||||||
|
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<airtalgo::FormatUpdate> algo = boost::make_shared<airtalgo::FormatUpdate>();
|
||||||
|
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<airtalgo::EndPointRead> algo = boost::make_shared<airtalgo::EndPointRead>();
|
||||||
|
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<airtalgo::EndPointWrite> algo = boost::make_shared<airtalgo::EndPointWrite>();
|
||||||
|
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<airtalgo::FormatUpdate> algo = boost::make_shared<airtalgo::FormatUpdate>();
|
||||||
|
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<airtalgo::Resampler> algo = boost::make_shared<airtalgo::Resampler>();
|
||||||
|
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<airtalgo::ChannelReorder> algo = boost::make_shared<airtalgo::ChannelReorder>();
|
||||||
|
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<std::mutex> lock(m_mutex);
|
||||||
|
//m_node->interfaceRemove(shared_from_this());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void airtio::Interface::setWriteCallbackInt16(size_t _chunkSize, writeNeedDataFunction_int16_t _function) {
|
||||||
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
|
if (m_listAlgo.size() <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::shared_ptr<airtalgo::EndPointWrite> algo = boost::dynamic_pointer_cast<airtalgo::EndPointWrite>(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<std::mutex> lock(m_mutex);
|
||||||
|
if (m_listAlgo.size() > 0) {
|
||||||
|
std::shared_ptr<airtalgo::EndPoint> algoEP = boost::dynamic_pointer_cast<airtalgo::EndPoint>(m_listAlgo[0]);
|
||||||
|
if (algoEP != nullptr) {
|
||||||
|
m_listAlgo.erase(m_listAlgo.begin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::shared_ptr<airtalgo::Algo> algo = boost::make_shared<airtalgo::EndPointCallback16>(_function, _dataType);
|
||||||
|
std::cout << "[INFO] set property: " << m_map << " " << m_format << " " << m_freq <<std::endl;
|
||||||
|
algo->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<std::mutex> lock(m_mutex);
|
||||||
|
if (m_listAlgo.size() > 0) {
|
||||||
|
std::shared_ptr<airtalgo::EndPoint> algoEP = boost::dynamic_pointer_cast<airtalgo::EndPoint>(m_listAlgo[m_listAlgo.size()-1]);
|
||||||
|
if (algoEP != nullptr) {
|
||||||
|
m_listAlgo.erase(m_listAlgo.begin()+m_listAlgo.size()-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::shared_ptr<airtalgo::Algo> algo = boost::make_shared<airtalgo::EndPointCallback16>(_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<std::mutex> lock(m_mutex);
|
||||||
|
m_node->interfaceAdd(shared_from_this());
|
||||||
|
}
|
||||||
|
|
||||||
|
void airtio::Interface::stop(bool _fast, bool _abort) {
|
||||||
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
|
m_node->interfaceRemove(shared_from_this());
|
||||||
|
}
|
||||||
|
|
||||||
|
void airtio::Interface::abort() {
|
||||||
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
|
// TODO :...
|
||||||
|
}
|
||||||
|
|
||||||
|
void airtio::Interface::setVolume(float _gainDB) {
|
||||||
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
|
// TODO :...
|
||||||
|
}
|
||||||
|
|
||||||
|
float airtio::Interface::getVolume() const {
|
||||||
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
|
// TODO :...
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<float,float> airtio::Interface::getVolumeRange() const {
|
||||||
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
|
return std::make_pair(-120.0f, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void airtio::Interface::write(const std::vector<int16_t>& _value) {
|
||||||
|
write(&_value[0], _value.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void airtio::Interface::write(const int16_t* _value, size_t _nbChunk) {
|
||||||
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
|
std::shared_ptr<airtalgo::EndPointWrite> algo = boost::dynamic_pointer_cast<airtalgo::EndPointWrite>(m_listAlgo[0]);
|
||||||
|
if (algo == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
algo->write(_value, _nbChunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO : add API aCCess mutex for Read and write...
|
||||||
|
std::vector<int16_t> airtio::Interface::read(size_t _nbChunk) {
|
||||||
|
// TODO :...
|
||||||
|
std::vector<int16_t> 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<data.size(); ++iii) {
|
||||||
|
data[iii] = m_circularBuffer[iii];
|
||||||
|
}
|
||||||
|
m_circularBuffer.erase(m_circularBuffer.begin(), m_circularBuffer.begin()+data.size());
|
||||||
|
m_mutex.unlock();
|
||||||
|
*/
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void airtio::Interface::read(const int16_t* _value, size_t _nbChunk) {
|
||||||
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
|
// TODO :...
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t airtio::Interface::size() const {
|
||||||
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
|
// TODO :...
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void airtio::Interface::setBufferSize(size_t _nbChunk) {
|
||||||
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
|
// TODO :...
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void airtio::Interface::setBufferSize(const std::chrono::duration<int64_t, boost::micro>& _time) {
|
||||||
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
|
// TODO :...
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void airtio::Interface::clearInternalBuffer() {
|
||||||
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
|
// TODO :...
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::chrono::system_clock::time_point airtio::Interface::getCurrentTime() const {
|
||||||
|
std::unique_lock<std::mutex> 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<std::mutex> 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; iii<m_listAlgo.size(); ++iii) {
|
||||||
|
//std::cout << " Algo " << iii+1 << "/" << m_listAlgo.size() << std::endl;
|
||||||
|
if (m_listAlgo[iii] != nullptr) {
|
||||||
|
m_listAlgo[iii]->process(_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);
|
||||||
|
*/
|
||||||
|
}
|
169
airtio/Interface.h
Normal file
169
airtio/Interface.h
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||||
|
* @license APACHE v2.0 (see license file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __AIRTIO_INTERFACE_H__
|
||||||
|
#define __AIRTIO_INTERFACE_H__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <chrono>
|
||||||
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
#include <airtalgo/format.h>
|
||||||
|
#include <airtalgo/channel.h>
|
||||||
|
#include <airtalgo/Process.h>
|
||||||
|
#include <airtalgo/EndPointCallback.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace airtio {
|
||||||
|
namespace io {
|
||||||
|
class Node;
|
||||||
|
}
|
||||||
|
class Interface : public std::enable_shared_from_this<Interface> {
|
||||||
|
friend class io::Node;
|
||||||
|
friend class Manager;
|
||||||
|
protected:
|
||||||
|
mutable std::mutex m_mutex;
|
||||||
|
protected:
|
||||||
|
std::shared_ptr<airtio::io::Node> m_node;
|
||||||
|
float m_freq;
|
||||||
|
std::vector<airtalgo::channel> m_map;
|
||||||
|
airtalgo::format m_format;
|
||||||
|
std::shared_ptr<airtalgo::Process> m_process;
|
||||||
|
protected:
|
||||||
|
std::string m_name;
|
||||||
|
public:
|
||||||
|
virtual std::string getName() {
|
||||||
|
return m_name;
|
||||||
|
};
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* @brief Constructor
|
||||||
|
*/
|
||||||
|
Interface();
|
||||||
|
bool init(const std::string& _name,
|
||||||
|
float _freq,
|
||||||
|
const std::vector<airtalgo::channel>& _map,
|
||||||
|
airtalgo::format _format,
|
||||||
|
const std::shared_ptr<airtio::io::Node>& _node);
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Destructor
|
||||||
|
*/
|
||||||
|
virtual ~Interface() {};
|
||||||
|
static std::shared_ptr<Interface> create(const std::string& _name,
|
||||||
|
float _freq,
|
||||||
|
const std::vector<airtalgo::channel>& _map,
|
||||||
|
airtalgo::format _format,
|
||||||
|
const std::shared_ptr<airtio::io::Node>& _node);
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief When we want to implement a Callback Mode :
|
||||||
|
*/
|
||||||
|
//virtual void setWriteCallback(size_t _chunkSize, writeNeedDataFunction_int16_t _function) {};
|
||||||
|
virtual void setOutputCallback(size_t _chunkSize, airtalgo::needDataFunction _function, enum airtalgo::formatDataType _dataType);
|
||||||
|
virtual void setInputCallback(size_t _chunkSize, airtalgo::haveNewDataFunction _function, enum airtalgo::formatDataType _dataType);
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Start the Audio interface flow.
|
||||||
|
* @param[in] _time Time to start the flow (0) to start as fast as possible...
|
||||||
|
* @note _time to play buffer when output interface (if possible)
|
||||||
|
* @note _time to read buffer when inut interface (if possible)
|
||||||
|
*/
|
||||||
|
virtual void start(const std::chrono::system_clock::time_point& _time = std::chrono::system_clock::time_point());
|
||||||
|
/**
|
||||||
|
* @brief Stop the current flow.
|
||||||
|
* @param[in] _fast The stream stop as fast as possible (not write all the buffer in speaker) but apply cross fade out.
|
||||||
|
* @param[in] _abort The stream stop whith no garenty of good audio stop.
|
||||||
|
*/
|
||||||
|
virtual void stop(bool _fast=false, bool _abort=false);
|
||||||
|
/**
|
||||||
|
* @brief Abort flow (no audio garenty)
|
||||||
|
*/
|
||||||
|
virtual void abort();
|
||||||
|
/**
|
||||||
|
* @brief Set the volume of this interface
|
||||||
|
* @param[in] _gainDB Gain in decibel to apply
|
||||||
|
*/
|
||||||
|
virtual void setVolume(float _gainDB);
|
||||||
|
/**
|
||||||
|
* @brief Get the volume of this interface
|
||||||
|
* @return The gain in decibel applyied
|
||||||
|
*/
|
||||||
|
virtual float getVolume() const;
|
||||||
|
/**
|
||||||
|
* @brief Get the volume range of this interface
|
||||||
|
* @return The gain in decibel range of this interface
|
||||||
|
*/
|
||||||
|
virtual std::pair<float,float> getVolumeRange() const;
|
||||||
|
/**
|
||||||
|
* @brief write some audio sample in the speakers
|
||||||
|
* @param[in] _value Data To write on output
|
||||||
|
*/
|
||||||
|
// TODO : TimeOut ???
|
||||||
|
virtual void write(const std::vector<int16_t>& _value);
|
||||||
|
/**
|
||||||
|
* @brief write some audio sample in the speakers
|
||||||
|
* @param[in] _value Data To write on output
|
||||||
|
* @param[in] _nbChunk Number of audio chunk to write
|
||||||
|
*/
|
||||||
|
// TODO : TimeOut ???
|
||||||
|
virtual void write(const int16_t* _value, size_t _nbChunk);
|
||||||
|
/**
|
||||||
|
* @brief write some audio sample in the speakers
|
||||||
|
* @param[in] _value Data To write on output
|
||||||
|
*/
|
||||||
|
// TODO : TimeOut ???
|
||||||
|
virtual std::vector<int16_t> read(size_t _nbChunk);
|
||||||
|
/**
|
||||||
|
* @brief read some audio sample from Microphone
|
||||||
|
* @param[in] _value Data To write on output
|
||||||
|
* @param[in] _nbChunk Number of audio chunk to write
|
||||||
|
*/
|
||||||
|
// TODO : TimeOut ???
|
||||||
|
virtual void read(const int16_t* _value, size_t _nbChunk);
|
||||||
|
/**
|
||||||
|
* @brief Get number of chunk in the local buffer
|
||||||
|
* @return Number of chunk
|
||||||
|
*/
|
||||||
|
virtual size_t size() const;
|
||||||
|
/**
|
||||||
|
* @brief Set buffer size in chunk number
|
||||||
|
* @param[in] _nbChunk Number of chunk in the buffer
|
||||||
|
*/
|
||||||
|
virtual void setBufferSize(size_t _nbChunk);
|
||||||
|
/**
|
||||||
|
* @brief Set buffer size in chunk number
|
||||||
|
* @param[in] _nbChunk Number of chunk in the buffer
|
||||||
|
*/
|
||||||
|
virtual void setBufferSize(const std::chrono::duration<int64_t, std::micro>& _time);
|
||||||
|
/**
|
||||||
|
* @brief Remove internal Buffer
|
||||||
|
*/
|
||||||
|
virtual void clearInternalBuffer();
|
||||||
|
/**
|
||||||
|
* @brief Write : Get the time of the next sample time to write in the local buffer
|
||||||
|
* @brief Read : Get the time of the next sample time to read in the local buffer
|
||||||
|
*/
|
||||||
|
virtual std::chrono::system_clock::time_point getCurrentTime() const;
|
||||||
|
private:
|
||||||
|
virtual void systemNewInputData(std::chrono::system_clock::time_point _time, void* _data, int32_t _nbChunk);
|
||||||
|
virtual void systemNeedOutputData(std::chrono::system_clock::time_point _time, void* _data, int32_t _nbChunk, size_t _chunkSize);
|
||||||
|
|
||||||
|
std::vector<int8_t> m_data;
|
||||||
|
float m_volume; //!< Local channel Volume
|
||||||
|
bool process(std::chrono::system_clock::time_point& _time,
|
||||||
|
void* _input,
|
||||||
|
size_t _inputNbChunk,
|
||||||
|
void*& _output,
|
||||||
|
size_t& _outputNbChunk);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
126
airtio/Manager.cpp
Normal file
126
airtio/Manager.cpp
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||||
|
* @license APACHE v2.0 (see license file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Manager.h"
|
||||||
|
#include "InterfaceDirect.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "io/Manager.h"
|
||||||
|
#include "io/Node.h"
|
||||||
|
|
||||||
|
std::shared_ptr<airtio::Manager> airtio::Manager::create(const std::string& _applicationUniqueId) {
|
||||||
|
return std::make_shared<airtio::Manager>(_applicationUniqueId);
|
||||||
|
}
|
||||||
|
|
||||||
|
airtio::Manager::Manager(const std::string& _applicationUniqueId) :
|
||||||
|
m_applicationUniqueId(_applicationUniqueId),
|
||||||
|
m_listOpenInterface(),
|
||||||
|
m_masterVolume(0.0f),
|
||||||
|
m_masterVolumeRange(std::make_pair(-120.0f, 0.0f)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
airtio::Manager::~Manager() {
|
||||||
|
// TODO : Stop all interfaces...
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string,std::string> > airtio::Manager::getListStreamInput() {
|
||||||
|
std::vector<std::pair<std::string,std::string> > output;
|
||||||
|
output.push_back(std::make_pair<std::string,std::string>("default", "48000 Hz, 16 bits, 2 channels: Default input "));
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string,std::string> > airtio::Manager::getListStreamOutput() {
|
||||||
|
std::vector<std::pair<std::string,std::string> > output;
|
||||||
|
output.push_back(std::make_pair<std::string,std::string>("default", "48000 Hz, 16 bits, 2 channels: Default output "));
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void airtio::Manager::setMasterOutputVolume(float _gainDB) {
|
||||||
|
if (_gainDB < m_masterVolumeRange.first) {
|
||||||
|
//throw std::range_error(std::string(_gainDB) + " is out of bonds : [" + m_masterVolumeRange.first + ".." + m_masterVolumeRange.second + "]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_gainDB > m_masterVolumeRange.second) {
|
||||||
|
//throw std::range_error(std::string(_gainDB) + " is out of bonds : [" + m_masterVolumeRange.first + ".." + m_masterVolumeRange.second + "]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_masterVolume = _gainDB;
|
||||||
|
for (std::list<std::weak_ptr<airtio::InterfaceDirect> >::iterator it(m_listOpenInterface.begin());
|
||||||
|
it != m_listOpenInterface.end();
|
||||||
|
++it) {
|
||||||
|
std::shared_ptr<airtio::InterfaceDirect> tmpElem = it->lock();
|
||||||
|
if (tmpElem == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// TODO : Deprecated ...
|
||||||
|
tmpElem->setMasterVolume(m_masterVolume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float airtio::Manager::getMasterOutputVolume() {
|
||||||
|
return m_masterVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<float,float> airtio::Manager::getMasterOutputVolumeRange() {
|
||||||
|
return m_masterVolumeRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
void airtio::Manager::setSectionVolume(const std::string& _section, float _gainDB) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
float airtio::Manager::getSectionVolume(const std::string& _section) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<float,float> airtio::Manager::getSectionVolumeRange(const std::string& _section) {
|
||||||
|
return std::make_pair(0.0f, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<airtio::Interface>
|
||||||
|
airtio::Manager::createOutput(float _freq,
|
||||||
|
const std::vector<airtalgo::channel>& _map,
|
||||||
|
airtalgo::format _format,
|
||||||
|
const std::string& _streamName,
|
||||||
|
const std::string& _name) {
|
||||||
|
// get global hardware interface:
|
||||||
|
std::shared_ptr<airtio::io::Manager> manager = airtio::io::Manager::getInstance();
|
||||||
|
// get the output or input channel :
|
||||||
|
std::shared_ptr<airtio::io::Node> node = manager->getNode(_streamName, false);
|
||||||
|
// create user iterface:
|
||||||
|
std::shared_ptr<airtio::InterfaceDirect> interface;
|
||||||
|
interface = std::make_shared<airtio::InterfaceDirect>(_name, _freq, _map, _format, node);
|
||||||
|
interface->init();
|
||||||
|
// store it in a list (needed to apply some parameters).
|
||||||
|
m_listOpenInterface.push_back(interface);
|
||||||
|
// TODO : DEPRECATED ...
|
||||||
|
interface->setMasterVolume(m_masterVolume);
|
||||||
|
return interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<airtio::Interface>
|
||||||
|
airtio::Manager::createInput(float _freq,
|
||||||
|
const std::vector<airtalgo::channel>& _map,
|
||||||
|
airtalgo::format _format,
|
||||||
|
const std::string& _streamName,
|
||||||
|
const std::string& _name) {
|
||||||
|
// get global hardware interface:
|
||||||
|
std::shared_ptr<airtio::io::Manager> manager = airtio::io::Manager::getInstance();
|
||||||
|
// get the output or input channel :
|
||||||
|
std::shared_ptr<airtio::io::Node> node = manager->getNode(_streamName, true);
|
||||||
|
// create user iterface:
|
||||||
|
std::shared_ptr<airtio::InterfaceDirect> interface;
|
||||||
|
interface = std::make_shared<airtio::InterfaceDirect>(_name, _freq, _map, _format, node);
|
||||||
|
interface->init();
|
||||||
|
// store it in a list (needed to apply some parameters).
|
||||||
|
m_listOpenInterface.push_back(interface);
|
||||||
|
// TODO : DEPRECATED ...
|
||||||
|
interface->setMasterVolume(m_masterVolume);
|
||||||
|
return interface;
|
||||||
|
}
|
117
airtio/Manager.h
Normal file
117
airtio/Manager.h
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||||
|
* @license APACHE v2.0 (see license file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __AIRTIO_MANAGER_H__
|
||||||
|
#define __AIRTIO_MANAGER_H__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <airtio/Interface.h>
|
||||||
|
#include <airtalgo/format.h>
|
||||||
|
#include <airtalgo/channel.h>
|
||||||
|
|
||||||
|
namespace airtio {
|
||||||
|
/**
|
||||||
|
* @brief Audio interface manager : Single interface for every application that want to access on the Audio input/output
|
||||||
|
*/
|
||||||
|
class Manager {
|
||||||
|
private:
|
||||||
|
const std::string& m_applicationUniqueId; //!< name of the application that open the Audio Interface.
|
||||||
|
std::list<std::weak_ptr<airtio::InterfaceDirect> > m_listOpenInterface; //!< List of all open Stream.
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* @brief Constructor
|
||||||
|
*/
|
||||||
|
Manager() {};
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<airtio::Manager> create(const std::string& _applicationUniqueId);
|
||||||
|
/**
|
||||||
|
* @brief Destructor
|
||||||
|
*/
|
||||||
|
virtual ~Manager() {};
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Get all input audio stream description.
|
||||||
|
* @return a list of all availlables input stream (name + description)
|
||||||
|
*/
|
||||||
|
virtual std::vector<std::pair<std::string,std::string> > getListStreamInput() = 0;
|
||||||
|
/**
|
||||||
|
* @brief Get all output audio stream description.
|
||||||
|
* @return a list of all availlables output stream (name + description)
|
||||||
|
*/
|
||||||
|
virtual std::vector<std::pair<std::string,std::string> > getListStreamOutput() = 0;
|
||||||
|
protected:
|
||||||
|
float m_masterVolume;
|
||||||
|
std::pair<float,float> m_masterVolumeRange;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Set the output volume master of the Audio interface
|
||||||
|
* @param[in] _gainDB Gain in decibel to apply in volume Master
|
||||||
|
*/
|
||||||
|
virtual void setMasterOutputVolume(float _gainDB);
|
||||||
|
/**
|
||||||
|
* @brief Get the output volume master of the Audio interface
|
||||||
|
* @return The gain in decibel applyied in volume Master
|
||||||
|
*/
|
||||||
|
virtual float getMasterOutputVolume();
|
||||||
|
/**
|
||||||
|
* @brief Get the output volume master range of the Audio interface
|
||||||
|
* @return The gain in decibel range of the output volume Master
|
||||||
|
*/
|
||||||
|
virtual std::pair<float,float> getMasterOutputVolumeRange();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the section volume of the Audio interface
|
||||||
|
* @param[in] _gainDB Gain in decibel to apply in volume section
|
||||||
|
* @param[in] _section section name to apply volume (a section is : tts, reco, player, interjection ...)
|
||||||
|
*/
|
||||||
|
virtual void setSectionVolume(const std::string& _section, float _gainDB);
|
||||||
|
/**
|
||||||
|
* @brief Get the section volume of the Audio interface
|
||||||
|
* @param[in] _section section name to apply volume (a section is : tts, reco, player, interjection ...)
|
||||||
|
* @return The gain in decibel applyied in volume section
|
||||||
|
*/
|
||||||
|
virtual float getSectionVolume(const std::string& _section);
|
||||||
|
/**
|
||||||
|
* @brief Get the section volume range of the Audio interface
|
||||||
|
* @param[in] _section section name to apply volume (a section is : tts, reco, player, interjection ...)
|
||||||
|
* @return The gain in decibel range of the section volume
|
||||||
|
*/
|
||||||
|
virtual std::pair<float,float> getSectionVolumeRange(const std::string& _section);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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] _streamName Stream name to open: "" or "default" open current selected output
|
||||||
|
* @param[in] _name Name of this interface
|
||||||
|
* @return a pointer on the interface
|
||||||
|
*/
|
||||||
|
virtual std::shared_ptr<Interface> createOutput(float _freq,
|
||||||
|
const std::vector<airtalgo::channel>& _map,
|
||||||
|
airtalgo::format _format,
|
||||||
|
const std::string& _streamName = "",
|
||||||
|
const std::string& _name = "");
|
||||||
|
/**
|
||||||
|
* @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] _streamName Stream name to open: "" or "default" open current selected input
|
||||||
|
* @param[in] _name Name of this interface
|
||||||
|
* @return a pointer on the interface
|
||||||
|
*/
|
||||||
|
virtual std::shared_ptr<Interface> createInput(float _freq,
|
||||||
|
const std::vector<airtalgo::channel>& _map,
|
||||||
|
airtalgo::format _format,
|
||||||
|
const std::string& _streamName = "",
|
||||||
|
const std::string& _name = "");
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
13
airtio/debug.cpp
Normal file
13
airtio/debug.cpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||||
|
* @license APACHE v2.0 (see license file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <airtio/debug.h>
|
||||||
|
|
||||||
|
|
||||||
|
int32_t airtio::getLogId() {
|
||||||
|
static int32_t g_val = etk::log::registerInstance("airtio");
|
||||||
|
return g_val;
|
||||||
|
}
|
51
airtio/debug.h
Normal file
51
airtio/debug.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||||
|
* @license APACHE v2.0 (see license file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __AIRTIO_DEBUG_H__
|
||||||
|
#define __AIRTIO_DEBUG_H__
|
||||||
|
|
||||||
|
#include <etk/log.h>
|
||||||
|
|
||||||
|
namespace airtio {
|
||||||
|
int32_t getLogId();
|
||||||
|
};
|
||||||
|
// TODO : Review this problem of multiple intanciation of "std::stringbuf sb"
|
||||||
|
#define AIRTIO_BASE(info,data) \
|
||||||
|
do { \
|
||||||
|
if (info <= etk::log::getLevel(airtio::getLogId())) { \
|
||||||
|
std::stringbuf sb; \
|
||||||
|
std::ostream tmpStream(&sb); \
|
||||||
|
tmpStream << data; \
|
||||||
|
etk::log::logStream(airtio::getLogId(), info, __LINE__, __class__, __func__, tmpStream); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define AIRTIO_CRITICAL(data) AIRTIO_BASE(1, data)
|
||||||
|
#define AIRTIO_ERROR(data) AIRTIO_BASE(2, data)
|
||||||
|
#define AIRTIO_WARNING(data) AIRTIO_BASE(3, data)
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define AIRTIO_INFO(data) AIRTIO_BASE(4, data)
|
||||||
|
#define AIRTIO_DEBUG(data) AIRTIO_BASE(5, data)
|
||||||
|
#define AIRTIO_VERBOSE(data) AIRTIO_BASE(6, data)
|
||||||
|
#define AIRTIO_TODO(data) AIRTIO_BASE(4, "TODO : " << data)
|
||||||
|
#else
|
||||||
|
#define AIRTIO_INFO(data) do { } while(false)
|
||||||
|
#define AIRTIO_DEBUG(data) do { } while(false)
|
||||||
|
#define AIRTIO_VERBOSE(data) do { } while(false)
|
||||||
|
#define AIRTIO_TODO(data) do { } while(false)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define AIRTIO_ASSERT(cond,data) \
|
||||||
|
do { \
|
||||||
|
if (!(cond)) { \
|
||||||
|
AIRTIO_CRITICAL(data); \
|
||||||
|
assert(!#cond); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
20
airtio/debugRemove.h
Normal file
20
airtio/debugRemove.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||||
|
* @license APACHE v2.0 (see license file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __AIRTIO_DEBUG_H__
|
||||||
|
#undef __AIRTIO_DEBUG_H__
|
||||||
|
|
||||||
|
#undef AIRTIO_BASE
|
||||||
|
#undef AIRTIO_CRITICAL
|
||||||
|
#undef AIRTIO_ERROR
|
||||||
|
#undef AIRTIO_WARNING
|
||||||
|
#undef AIRTIO_INFO
|
||||||
|
#undef AIRTIO_DEBUG
|
||||||
|
#undef AIRTIO_VERBOSE
|
||||||
|
#undef AIRTIO_TODO
|
||||||
|
#undef AIRTIO_ASSERT
|
||||||
|
#endif
|
||||||
|
|
28
airtio/io/Manager.cpp
Normal file
28
airtio/io/Manager.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||||
|
* @license APACHE v2.0 (see license file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Manager.h"
|
||||||
|
#include <memory>
|
||||||
|
#include "Node.h"
|
||||||
|
|
||||||
|
std::shared_ptr<airtio::io::Manager> airtio::io::Manager::getInstance() {
|
||||||
|
static std::shared_ptr<airtio::io::Manager> manager(new Manager());
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<airtio::io::Node> airtio::io::Manager::getNode(const std::string& _streamName, bool _isInput) {
|
||||||
|
for (size_t iii=0; iii< m_list.size(); ++iii) {
|
||||||
|
std::shared_ptr<airtio::io::Node> tmppp = m_list[iii].lock();
|
||||||
|
if ( tmppp!=nullptr
|
||||||
|
&& _streamName == tmppp->getName()
|
||||||
|
&& _isInput == tmppp->isInput()) {
|
||||||
|
return tmppp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::shared_ptr<airtio::io::Node> tmp = airtio::io::Node::create(_streamName, _isInput);
|
||||||
|
m_list.push_back(tmp);
|
||||||
|
return tmp;
|
||||||
|
}
|
46
airtio/io/Manager.h
Normal file
46
airtio/io/Manager.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||||
|
* @license APACHE v2.0 (see license file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __AIRTIO_IO_MANAGER_H__
|
||||||
|
#define __AIRTIO_IO_MANAGER_H__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <list>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <std/chrono.hpp>
|
||||||
|
#include <std/function.hpp>
|
||||||
|
#include <audio_algo_core/format.hpp>
|
||||||
|
#include <audio_algo_core/channel.hpp>
|
||||||
|
#include <std/shared_ptr.hpp>
|
||||||
|
#include <std/weak_ptr.hpp>
|
||||||
|
|
||||||
|
namespace airtio {
|
||||||
|
namespace io {
|
||||||
|
class Node;
|
||||||
|
class Manager {
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief Constructor
|
||||||
|
*/
|
||||||
|
Manager() {};
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<Manager> getInstance();
|
||||||
|
/**
|
||||||
|
* @brief Destructor
|
||||||
|
*/
|
||||||
|
virtual ~Manager() {};
|
||||||
|
private:
|
||||||
|
std::vector<std::weak_ptr<airtio::io::Node> > m_list;
|
||||||
|
public:
|
||||||
|
std::shared_ptr<airtio::io::Node> getNode(const std::string& _streamName, bool _isInput);
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
259
airtio/io/Node.cpp
Normal file
259
airtio/io/Node.cpp
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||||
|
* @license APACHE v2.0 (see license file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Node.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#ifndef INT16_MAX
|
||||||
|
#define INT16_MAX 0x7fff
|
||||||
|
#endif
|
||||||
|
#ifndef INT16_MIN
|
||||||
|
#define INT16_MIN (-INT16_MAX - 1)
|
||||||
|
#endif
|
||||||
|
#ifndef INT32_MAX
|
||||||
|
#define INT32_MAX 0x7fffffffL
|
||||||
|
#endif
|
||||||
|
#ifndef INT32_MIN
|
||||||
|
#define INT32_MIN (-INT32_MAX - 1L)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// RT audio out callback
|
||||||
|
static int rtAudioCallbackStatic(void* _outputBuffer,
|
||||||
|
void* _inputBuffer,
|
||||||
|
unsigned int _nBufferFrames,
|
||||||
|
double _streamTime,
|
||||||
|
RtAudioStreamStatus _status,
|
||||||
|
void* _data) {
|
||||||
|
airtio::io::Node* interface = static_cast<airtio::io::Node*>(_data);
|
||||||
|
return interface->rtAudioCallback(static_cast<int16_t*>(_outputBuffer),
|
||||||
|
static_cast<int16_t*>(_inputBuffer),
|
||||||
|
_nBufferFrames,
|
||||||
|
_streamTime,
|
||||||
|
_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
int airtio::io::Node::rtAudioCallback(int16_t* _outputBuffer,
|
||||||
|
int16_t* _inputBuffer,
|
||||||
|
unsigned int _nBufferFrames,
|
||||||
|
double _streamTime,
|
||||||
|
RtAudioStreamStatus _status) {
|
||||||
|
std::mutex::scoped_lock lock(m_mutex);
|
||||||
|
|
||||||
|
std::chrono::system_clock::time_point ttime = boost::chrono::system_clock::time_point();//boost::chrono::system_clock::now();
|
||||||
|
|
||||||
|
if (_outputBuffer != nullptr) {
|
||||||
|
//std::cout << "data Output" << std::endl;
|
||||||
|
std::vector<int32_t> output;
|
||||||
|
output.resize(_nBufferFrames*m_map.size(), 0);
|
||||||
|
std::vector<int16_t> outputTmp;
|
||||||
|
outputTmp.resize(_nBufferFrames*m_map.size());
|
||||||
|
for (size_t iii=0; iii< m_list.size(); ++iii) {
|
||||||
|
if (m_list[iii] != nullptr) {
|
||||||
|
//std::cout << " IO : " << iii+1 << "/" << m_list.size() << " name="<< m_list[iii]->getName() << std::endl;
|
||||||
|
m_list[iii]->systemNeedOutputData(ttime, &outputTmp[0], _nBufferFrames, sizeof(int16_t)*m_map.size());
|
||||||
|
//m_list[iii]->systemNeedOutputData(ttime, _outputBuffer, _nBufferFrames, sizeof(int16_t)*m_map.size());
|
||||||
|
// Add data to the output tmp buffer :
|
||||||
|
for (size_t kkk=0; kkk<output.size(); ++kkk) {
|
||||||
|
output[kkk] += static_cast<int32_t>(outputTmp[kkk]);
|
||||||
|
//*_outputBuffer++ = static_cast<int16_t>(outputTmp[kkk]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (size_t kkk=0; kkk<output.size(); ++kkk) {
|
||||||
|
*_outputBuffer++ = static_cast<int16_t>(std::min(std::max(INT16_MIN, output[kkk]), INT16_MAX));
|
||||||
|
//*_outputBuffer++ = static_cast<int16_t>(output[kkk]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_inputBuffer != nullptr) {
|
||||||
|
std::cout << "data Input" << std::endl;
|
||||||
|
for (size_t iii=0; iii< m_list.size(); ++iii) {
|
||||||
|
if (m_list[iii] != nullptr) {
|
||||||
|
std::cout << " IO : " << iii+1 << "/" << m_list.size() << " name="<< m_list[iii]->getName() << std::endl;
|
||||||
|
m_list[iii]->systemNewInputData(ttime, _inputBuffer, _nBufferFrames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::shared_ptr<airtio::io::Node> airtio::io::Node::create(const std::string& _streamName, bool _isInput) {
|
||||||
|
return std::shared_ptr<airtio::io::Node>(new airtio::io::Node(_streamName, _isInput));
|
||||||
|
}
|
||||||
|
|
||||||
|
airtio::io::Node::Node(const std::string& _streamName, bool _isInput) :
|
||||||
|
m_streamName(_streamName),
|
||||||
|
m_frequency(48000),
|
||||||
|
m_format(airtalgo::format_int16),
|
||||||
|
m_isInput(_isInput) {
|
||||||
|
std::cout << "-----------------------------------------------------------------" << std::endl;
|
||||||
|
std::cout << "-- CREATE NODE --" << std::endl;
|
||||||
|
std::cout << "-----------------------------------------------------------------" << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
if (m_streamName == "") {
|
||||||
|
m_streamName = "default";
|
||||||
|
}
|
||||||
|
// set default channel property :
|
||||||
|
m_map.push_back(airtalgo::channel_frontLeft);
|
||||||
|
m_map.push_back(airtalgo::channel_frontRight);
|
||||||
|
|
||||||
|
// search device ID :
|
||||||
|
std::cout << "Open :" << std::endl;
|
||||||
|
std::cout << " m_streamName=" << m_streamName << std::endl;
|
||||||
|
std::cout << " m_freq=" << m_frequency << std::endl;
|
||||||
|
std::cout << " m_map=" << m_map << std::endl;
|
||||||
|
std::cout << " m_format=" << m_format << std::endl;
|
||||||
|
std::cout << " m_isInput=" << m_isInput << std::endl;
|
||||||
|
int32_t deviceId = 0;
|
||||||
|
std::cout << "Device list:" << std::endl;
|
||||||
|
for (int32_t iii=0; iii<m_adac.getDeviceCount(); ++iii) {
|
||||||
|
m_info = m_adac.getDeviceInfo(iii);
|
||||||
|
std::cout << " " << iii << " name :" << m_info.name << std::endl;
|
||||||
|
if (m_info.name == m_streamName) {
|
||||||
|
std::cout << " Select ..." << std::endl;
|
||||||
|
deviceId = iii;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Open specific ID :
|
||||||
|
m_info = m_adac.getDeviceInfo(deviceId);
|
||||||
|
// display property :
|
||||||
|
{
|
||||||
|
std::cout << "Device " << deviceId << " property :" << std::endl;
|
||||||
|
std::cout << " probe=" << (m_info.probed==true?"true":"false") << std::endl;
|
||||||
|
std::cout << " name=" << m_info.name << std::endl;
|
||||||
|
std::cout << " outputChannels=" << m_info.outputChannels << std::endl;
|
||||||
|
std::cout << " inputChannels=" << m_info.inputChannels << std::endl;
|
||||||
|
std::cout << " duplexChannels=" << m_info.duplexChannels << std::endl;
|
||||||
|
std::cout << " isDefaultOutput=" << (m_info.isDefaultOutput==true?"true":"false") << std::endl;
|
||||||
|
std::cout << " isDefaultInput=" << (m_info.isDefaultInput==true?"true":"false") << std::endl;
|
||||||
|
//std::string rrate;
|
||||||
|
std::stringstream rrate;
|
||||||
|
for (int32_t jjj=0; jjj<m_info.sampleRates.size(); ++jjj) {
|
||||||
|
rrate << m_info.sampleRates[jjj] << ";";
|
||||||
|
}
|
||||||
|
std::cout << " rates=" << rrate.str() << std::endl;
|
||||||
|
switch(m_info.nativeFormats) {
|
||||||
|
case RTAUDIO_SINT8:
|
||||||
|
std::cout << " native Format: 8-bit signed integer" << std::endl;
|
||||||
|
break;
|
||||||
|
case RTAUDIO_SINT16:
|
||||||
|
std::cout << " native Format: 16-bit signed integer" << std::endl;
|
||||||
|
break;
|
||||||
|
case RTAUDIO_SINT24:
|
||||||
|
std::cout << " native Format: 24-bit signed integer" << std::endl;
|
||||||
|
break;
|
||||||
|
case RTAUDIO_SINT32:
|
||||||
|
std::cout << " native Format: 32-bit signed integer" << std::endl;
|
||||||
|
break;
|
||||||
|
case RTAUDIO_FLOAT32:
|
||||||
|
std::cout << " native Format: Normalized between plus/minus 1.0" << std::endl;
|
||||||
|
break;
|
||||||
|
case RTAUDIO_FLOAT64:
|
||||||
|
std::cout << " native Format: Normalized between plus/minus 1.0" << std::endl;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
std::cout << " native Format: Unknow" << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// open Audio device:
|
||||||
|
unsigned int nbChunk= 1024;
|
||||||
|
RtAudio::StreamParameters params;
|
||||||
|
params.deviceId = deviceId;
|
||||||
|
if (m_isInput == true) {
|
||||||
|
m_info.inputChannels = 2;
|
||||||
|
params.nChannels = 2;
|
||||||
|
} else {
|
||||||
|
m_info.outputChannels = 2;
|
||||||
|
params.nChannels = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_rtaudioFrameSize = nbChunk;
|
||||||
|
std::cout << "Open output stream nbChannels=" << params.nChannels << std::endl;
|
||||||
|
try {
|
||||||
|
if (m_isInput == true) {
|
||||||
|
m_adac.openStream( nullptr, ¶ms, RTAUDIO_SINT16, m_frequency, &m_rtaudioFrameSize, &rtAudioCallbackStatic, (void *)this );
|
||||||
|
} else {
|
||||||
|
m_adac.openStream( ¶ms, nullptr, RTAUDIO_SINT16, m_frequency, &m_rtaudioFrameSize, &rtAudioCallbackStatic, (void *)this );
|
||||||
|
}
|
||||||
|
} catch ( RtAudioError& e ) {
|
||||||
|
e.printMessage();
|
||||||
|
std::cout << "[ERROR]Can not open device Output" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
airtio::io::Node::~Node() {
|
||||||
|
std::mutex::scoped_lock lock(m_mutex);
|
||||||
|
std::cout << "-----------------------------------------------------------------" << std::endl;
|
||||||
|
std::cout << "-- DESTRO NODE --" << std::endl;
|
||||||
|
std::cout << "-----------------------------------------------------------------" << std::endl;
|
||||||
|
std::cout << "close input stream" << std::endl;
|
||||||
|
if (m_adac.isStreamOpen() ) {
|
||||||
|
m_adac.closeStream();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void airtio::io::Node::start() {
|
||||||
|
std::mutex::scoped_lock lock(m_mutex);
|
||||||
|
std::cout << "[INFO] Start stream : '" << m_streamName << "' mode=" << (m_isInput?"input":"output")<< std::endl;
|
||||||
|
try {
|
||||||
|
m_adac.startStream();
|
||||||
|
} catch (RtAudioError& e ) {
|
||||||
|
e.printMessage();
|
||||||
|
std::cout << "[ERROR] Can not start stream Input" << std::endl;
|
||||||
|
if (m_adac.isStreamOpen() ) {
|
||||||
|
m_adac.closeStream();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void airtio::io::Node::stop() {
|
||||||
|
std::mutex::scoped_lock lock(m_mutex);
|
||||||
|
std::cout << "[INFO] Stop stream : '" << m_streamName << "' mode=" << (m_isInput?"input":"output")<< std::endl;
|
||||||
|
try {
|
||||||
|
m_adac.stopStream();
|
||||||
|
} catch ( RtAudioError& e ) {
|
||||||
|
e.printMessage();
|
||||||
|
std::cout << "[ERROR] Can not stop stream" << std::endl;
|
||||||
|
if (m_adac.isStreamOpen() ) {
|
||||||
|
m_adac.closeStream();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void airtio::io::Node::interfaceAdd(const std::shared_ptr<airtio::Interface>& _interface) {
|
||||||
|
for (size_t iii=0; iii< m_list.size(); ++iii) {
|
||||||
|
if (_interface == m_list[iii]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_list.push_back(_interface);
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void airtio::io::Node::interfaceRemove(const std::shared_ptr<airtio::Interface>& _interface) {
|
||||||
|
for (size_t iii=0; iii< m_list.size(); ++iii) {
|
||||||
|
if (_interface == m_list[iii]) {
|
||||||
|
m_list.erase(m_list.begin()+iii);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_list.size() == 0) {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
95
airtio/io/Node.h
Normal file
95
airtio/io/Node.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/** @file
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||||
|
* @license APACHE v2.0 (see license file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __AIRTIO_IO_NODE_H__
|
||||||
|
#define __AIRTIO_IO_NODE_H__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <list>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <chrono>
|
||||||
|
#include <functional>
|
||||||
|
#include <airtalgo/format.h>
|
||||||
|
#include <airtalgo/channel.h>
|
||||||
|
#include "io/Manager.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <airtio/Interface.h>
|
||||||
|
|
||||||
|
namespace airtio {
|
||||||
|
namespace io {
|
||||||
|
class Manager;
|
||||||
|
class Node {
|
||||||
|
private:
|
||||||
|
mutable std::mutex m_mutex;
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief Constructor
|
||||||
|
*/
|
||||||
|
Node(const std::string& _streamName, bool _isInput);
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<Node> create(const std::string& _streamName, bool _isInput);
|
||||||
|
/**
|
||||||
|
* @brief Destructor
|
||||||
|
*/
|
||||||
|
virtual ~Node();
|
||||||
|
private:
|
||||||
|
std::vector<std::shared_ptr<airtio::Interface> > m_list;
|
||||||
|
public:
|
||||||
|
void interfaceAdd(const std::shared_ptr<airtio::Interface>& _interface);
|
||||||
|
void interfaceRemove(const std::shared_ptr<airtio::Interface>& _interface);
|
||||||
|
private:
|
||||||
|
RtAudio m_adac; //!< Real audio interface
|
||||||
|
RtAudio::DeviceInfo m_info;
|
||||||
|
unsigned int m_rtaudioFrameSize;
|
||||||
|
public:
|
||||||
|
int rtAudioCallback(int16_t* _outputBuffer,
|
||||||
|
int16_t* _inputBuffer,
|
||||||
|
unsigned int _nBufferFrames,
|
||||||
|
double _streamTime,
|
||||||
|
RtAudioStreamStatus _status);
|
||||||
|
private:
|
||||||
|
std::string m_streamName;
|
||||||
|
public:
|
||||||
|
const std::string& getName() {
|
||||||
|
return m_streamName;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::vector<airtalgo::channel> m_map;
|
||||||
|
public:
|
||||||
|
const std::vector<airtalgo::channel>& getMap() {
|
||||||
|
return m_map;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
float m_frequency;
|
||||||
|
public:
|
||||||
|
float getFrequency() {
|
||||||
|
return m_frequency;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
airtalgo::format m_format;
|
||||||
|
public:
|
||||||
|
airtalgo::format getFormat() {
|
||||||
|
return m_format;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
bool m_isInput;
|
||||||
|
public:
|
||||||
|
bool isInput() {
|
||||||
|
return m_isInput;
|
||||||
|
}
|
||||||
|
bool isOutput() {
|
||||||
|
return !m_isInput;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
36
lutin_airtio.py
Normal file
36
lutin_airtio.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
import lutinModule as module
|
||||||
|
import lutinTools as tools
|
||||||
|
import lutinDebug as debug
|
||||||
|
|
||||||
|
def get_desc():
|
||||||
|
return "airtio : Multi-nodal audio interface"
|
||||||
|
|
||||||
|
|
||||||
|
def create(target):
|
||||||
|
myModule = module.Module(__file__, 'airtio', 'LIBRARY')
|
||||||
|
|
||||||
|
myModule.add_src_file([
|
||||||
|
'airtio/debug.cpp',
|
||||||
|
'airtio/Manager.cpp',
|
||||||
|
'airtio/Interface.cpp',
|
||||||
|
'airtio/io/Node.cpp',
|
||||||
|
'airtio/io/Manager.cpp'
|
||||||
|
])
|
||||||
|
|
||||||
|
myModule.add_module_depend(['airtaudio', 'airtalgo'])
|
||||||
|
myModule.add_export_path(tools.get_current_path(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# add the currrent module at the
|
||||||
|
return myModule
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
457
test/main.cpp
Normal file
457
test/main.cpp
Normal file
@ -0,0 +1,457 @@
|
|||||||
|
#include "ros/ros.h"
|
||||||
|
#include <audio_base/Manager.hpp>
|
||||||
|
#include <audio_base/Interface.hpp>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
|
||||||
|
class testOutWrite {
|
||||||
|
private:
|
||||||
|
std::vector<audio_algo_core::channel> m_channelMap;
|
||||||
|
boost::shared_ptr<audio_base::Manager> m_manager;
|
||||||
|
boost::shared_ptr<audio_base::Interface> m_interface;
|
||||||
|
public:
|
||||||
|
testOutWrite(boost::shared_ptr<audio_base::Manager> _manager) :
|
||||||
|
m_manager(_manager){
|
||||||
|
//Set stereo output:
|
||||||
|
m_channelMap.push_back(audio_algo_core::channel_frontLeft);
|
||||||
|
m_channelMap.push_back(audio_algo_core::channel_frontRight);
|
||||||
|
m_interface = m_manager->createOutput(48000,
|
||||||
|
m_channelMap,
|
||||||
|
audio_algo_core::format_int16,
|
||||||
|
"default",
|
||||||
|
"WriteMode");
|
||||||
|
}
|
||||||
|
~testOutWrite() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
m_interface->start();
|
||||||
|
double phase=0;
|
||||||
|
std::vector<int16_t> data;
|
||||||
|
data.resize(1024*m_channelMap.size());
|
||||||
|
double baseCycle = 2.0*M_PI/(double)48000 * (double)440;
|
||||||
|
for (int32_t kkk=0; kkk<100; ++kkk) {
|
||||||
|
for (int32_t iii=0; iii<data.size()/m_channelMap.size(); iii++) {
|
||||||
|
for (int32_t jjj=0; jjj<m_channelMap.size(); jjj++) {
|
||||||
|
data[m_channelMap.size()*iii+jjj] = cos(phase) * 30000;
|
||||||
|
}
|
||||||
|
phase += baseCycle;
|
||||||
|
if (phase >= 2*M_PI) {
|
||||||
|
phase -= 2*M_PI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ROS_INFO("send data");
|
||||||
|
m_interface->write(data);
|
||||||
|
}
|
||||||
|
m_interface->stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class testOutCallback {
|
||||||
|
private:
|
||||||
|
boost::shared_ptr<audio_base::Manager> m_manager;
|
||||||
|
boost::shared_ptr<audio_base::Interface> m_interface;
|
||||||
|
double m_phase;
|
||||||
|
public:
|
||||||
|
testOutCallback(boost::shared_ptr<audio_base::Manager> _manager) :
|
||||||
|
m_manager(_manager),
|
||||||
|
m_phase(0) {
|
||||||
|
//Set stereo output:
|
||||||
|
std::vector<audio_algo_core::channel> channelMap;
|
||||||
|
channelMap.push_back(audio_algo_core::channel_frontLeft);
|
||||||
|
channelMap.push_back(audio_algo_core::channel_frontRight);
|
||||||
|
m_interface = m_manager->createOutput(48000,
|
||||||
|
channelMap,
|
||||||
|
audio_algo_core::format_int16,
|
||||||
|
"default",
|
||||||
|
"WriteModeCallback");
|
||||||
|
// set callback mode ...
|
||||||
|
m_interface->setOutputCallbackInt16(1024, boost::bind(&testOutCallback::onDataNeeded, this, _1, _2, _3));
|
||||||
|
}
|
||||||
|
|
||||||
|
~testOutCallback() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int16_t> onDataNeeded(const boost::chrono::system_clock::time_point& _playTime,
|
||||||
|
const size_t& _nbChunk,
|
||||||
|
const std::vector<audio_algo_core::channel>& _map) {
|
||||||
|
std::vector<int16_t> data;
|
||||||
|
data.resize(_nbChunk*_map.size());
|
||||||
|
double baseCycle = 2.0*M_PI/(double)48000 * (double)550;
|
||||||
|
ROS_INFO("Get data ...");
|
||||||
|
|
||||||
|
for (int32_t iii=0; iii<data.size()/_map.size(); iii++) {
|
||||||
|
for (int32_t jjj=0; jjj<_map.size(); jjj++) {
|
||||||
|
data[_map.size()*iii+jjj] = cos(m_phase) * 30000;
|
||||||
|
}
|
||||||
|
m_phase += baseCycle;
|
||||||
|
if (m_phase >= 2*M_PI) {
|
||||||
|
m_phase -= 2*M_PI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
m_interface->start();
|
||||||
|
// wait 2 second ...
|
||||||
|
usleep(2000000);
|
||||||
|
m_interface->stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class testInRead {
|
||||||
|
private:
|
||||||
|
std::vector<audio_algo_core::channel> m_channelMap;
|
||||||
|
boost::shared_ptr<audio_base::Manager> m_manager;
|
||||||
|
boost::shared_ptr<audio_base::Interface> m_interface;
|
||||||
|
public:
|
||||||
|
testInRead(boost::shared_ptr<audio_base::Manager> _manager) :
|
||||||
|
m_manager(_manager){
|
||||||
|
//Set stereo output:
|
||||||
|
m_channelMap.push_back(audio_algo_core::channel_frontLeft);
|
||||||
|
m_channelMap.push_back(audio_algo_core::channel_frontRight);
|
||||||
|
m_interface = m_manager->createInput(48000,
|
||||||
|
m_channelMap,
|
||||||
|
audio_algo_core::format_int16,
|
||||||
|
"default",
|
||||||
|
"WriteMode");
|
||||||
|
}
|
||||||
|
~testInRead() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
m_interface->start();
|
||||||
|
std::vector<int16_t> data;
|
||||||
|
for (int32_t kkk=0; kkk<100; ++kkk) {
|
||||||
|
data = m_interface->read(1024);
|
||||||
|
int64_t value = 0;
|
||||||
|
for (size_t iii=0; iii<data.size(); ++iii) {
|
||||||
|
value += std::abs(data[iii]);
|
||||||
|
}
|
||||||
|
value /= data.size();
|
||||||
|
ROS_INFO("Get data ... average = %d", static_cast<int32_t>(value));
|
||||||
|
}
|
||||||
|
m_interface->stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class testInCallback {
|
||||||
|
private:
|
||||||
|
boost::shared_ptr<audio_base::Manager> m_manager;
|
||||||
|
boost::shared_ptr<audio_base::Interface> m_interface;
|
||||||
|
double m_phase;
|
||||||
|
public:
|
||||||
|
testInCallback(boost::shared_ptr<audio_base::Manager> _manager) :
|
||||||
|
m_manager(_manager),
|
||||||
|
m_phase(0) {
|
||||||
|
//Set stereo output:
|
||||||
|
std::vector<audio_algo_core::channel> channelMap;
|
||||||
|
channelMap.push_back(audio_algo_core::channel_frontLeft);
|
||||||
|
channelMap.push_back(audio_algo_core::channel_frontRight);
|
||||||
|
m_interface = m_manager->createInput(48000,
|
||||||
|
channelMap,
|
||||||
|
audio_algo_core::format_int16,
|
||||||
|
"default",
|
||||||
|
"WriteModeCallback");
|
||||||
|
// set callback mode ...
|
||||||
|
m_interface->setInputCallbackInt16(1024, boost::bind(&testInCallback::onDataReceived, this, _1, _2, _3, _4));
|
||||||
|
}
|
||||||
|
|
||||||
|
~testInCallback() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDataReceived(const boost::chrono::system_clock::time_point& _playTime,
|
||||||
|
const size_t& _nbChunk,
|
||||||
|
const std::vector<audio_algo_core::channel>& _map,
|
||||||
|
const std::vector<int16_t>& _data) {
|
||||||
|
int64_t value = 0;
|
||||||
|
for (size_t iii=0; iii<_data.size(); ++iii) {
|
||||||
|
value += std::abs(_data[iii]);
|
||||||
|
}
|
||||||
|
value /= _data.size();
|
||||||
|
ROS_INFO("Get data ... average = %d", static_cast<int32_t>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
m_interface->start();
|
||||||
|
// wait 2 second ...
|
||||||
|
usleep(2000000);
|
||||||
|
m_interface->stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class testOutCallbackFloat {
|
||||||
|
private:
|
||||||
|
boost::shared_ptr<audio_base::Manager> m_manager;
|
||||||
|
boost::shared_ptr<audio_base::Interface> m_interface;
|
||||||
|
double m_phase;
|
||||||
|
float m_freq;
|
||||||
|
int32_t m_nbChannels;
|
||||||
|
float m_generateFreq;
|
||||||
|
|
||||||
|
public:
|
||||||
|
testOutCallbackFloat(boost::shared_ptr<audio_base::Manager> _manager,
|
||||||
|
float _freq=48000.0f,
|
||||||
|
int32_t _nbChannels=2,
|
||||||
|
audio_algo_core::format _format=audio_algo_core::format_int16) :
|
||||||
|
m_manager(_manager),
|
||||||
|
m_phase(0),
|
||||||
|
m_freq(_freq),
|
||||||
|
m_nbChannels(_nbChannels),
|
||||||
|
m_generateFreq(550.0f) {
|
||||||
|
//Set stereo output:
|
||||||
|
std::vector<audio_algo_core::channel> channelMap;
|
||||||
|
if (m_nbChannels == 1) {
|
||||||
|
channelMap.push_back(audio_algo_core::channel_frontCenter);
|
||||||
|
} else if (m_nbChannels == 2) {
|
||||||
|
channelMap.push_back(audio_algo_core::channel_frontLeft);
|
||||||
|
channelMap.push_back(audio_algo_core::channel_frontRight);
|
||||||
|
} else if (m_nbChannels == 4) {
|
||||||
|
channelMap.push_back(audio_algo_core::channel_frontLeft);
|
||||||
|
channelMap.push_back(audio_algo_core::channel_frontRight);
|
||||||
|
channelMap.push_back(audio_algo_core::channel_rearLeft);
|
||||||
|
channelMap.push_back(audio_algo_core::channel_rearRight);
|
||||||
|
} else {
|
||||||
|
ROS_ERROR("Can not generate with channel != 1,2,4");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (_format) {
|
||||||
|
case audio_algo_core::format_int16:
|
||||||
|
m_interface = m_manager->createOutput(m_freq,
|
||||||
|
channelMap,
|
||||||
|
_format,
|
||||||
|
"default",
|
||||||
|
"WriteModeCallbackI16");
|
||||||
|
// set callback mode ...
|
||||||
|
ROS_ERROR("Set callback");
|
||||||
|
m_interface->setOutputCallbackInt16(1024, boost::bind(&testOutCallbackFloat::onDataNeededI16, this, _1, _2, _3));
|
||||||
|
break;
|
||||||
|
case audio_algo_core::format_int16_on_int32:
|
||||||
|
m_interface = m_manager->createOutput(m_freq,
|
||||||
|
channelMap,
|
||||||
|
_format,
|
||||||
|
"default",
|
||||||
|
"WriteModeCallbackI16onI32");
|
||||||
|
// set callback mode ...
|
||||||
|
m_interface->setOutputCallbackInt32(1024, boost::bind(&testOutCallbackFloat::onDataNeededI16_I32, this, _1, _2, _3));
|
||||||
|
break;
|
||||||
|
case audio_algo_core::format_int32:
|
||||||
|
m_interface = m_manager->createOutput(m_freq,
|
||||||
|
channelMap,
|
||||||
|
_format,
|
||||||
|
"default",
|
||||||
|
"WriteModeCallbackI32");
|
||||||
|
// set callback mode ...
|
||||||
|
m_interface->setOutputCallbackInt32(1024, boost::bind(&testOutCallbackFloat::onDataNeededI32, this, _1, _2, _3));
|
||||||
|
break;
|
||||||
|
case audio_algo_core::format_float:
|
||||||
|
m_interface = m_manager->createOutput(m_freq,
|
||||||
|
channelMap,
|
||||||
|
_format,
|
||||||
|
"default",
|
||||||
|
"WriteModeCallbackFloat");
|
||||||
|
// set callback mode ...
|
||||||
|
m_interface->setOutputCallbackFloat(1024, boost::bind(&testOutCallbackFloat::onDataNeededFloat, this, _1, _2, _3));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~testOutCallbackFloat() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int16_t> onDataNeededI16(const boost::chrono::system_clock::time_point& _playTime,
|
||||||
|
const size_t& _nbChunk,
|
||||||
|
const std::vector<audio_algo_core::channel>& _map) {
|
||||||
|
std::vector<int16_t> data;
|
||||||
|
data.resize(_nbChunk*_map.size());
|
||||||
|
double baseCycle = 2.0*M_PI/(double)m_freq * (double)m_generateFreq;
|
||||||
|
ROS_INFO("Get data ... %ld", _map.size());
|
||||||
|
|
||||||
|
for (int32_t iii=0; iii<data.size()/_map.size(); iii++) {
|
||||||
|
for (int32_t jjj=0; jjj<_map.size(); jjj++) {
|
||||||
|
data[_map.size()*iii+jjj] = cos(m_phase) * (double)INT16_MAX;
|
||||||
|
}
|
||||||
|
m_phase += baseCycle;
|
||||||
|
if (m_phase >= 2*M_PI) {
|
||||||
|
m_phase -= 2*M_PI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int32_t> onDataNeededI16_I32(const boost::chrono::system_clock::time_point& _playTime,
|
||||||
|
const size_t& _nbChunk,
|
||||||
|
const std::vector<audio_algo_core::channel>& _map) {
|
||||||
|
std::vector<int32_t> data;
|
||||||
|
data.resize(_nbChunk*_map.size());
|
||||||
|
double baseCycle = 2.0*M_PI/(double)m_freq * (double)m_generateFreq;
|
||||||
|
//ROS_INFO("Get data ...");
|
||||||
|
|
||||||
|
for (int32_t iii=0; iii<data.size()/_map.size(); iii++) {
|
||||||
|
for (int32_t jjj=0; jjj<_map.size(); jjj++) {
|
||||||
|
data[_map.size()*iii+jjj] = cos(m_phase) * (double)INT16_MAX;
|
||||||
|
}
|
||||||
|
m_phase += baseCycle;
|
||||||
|
if (m_phase >= 2*M_PI) {
|
||||||
|
m_phase -= 2*M_PI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int32_t> onDataNeededI32(const boost::chrono::system_clock::time_point& _playTime,
|
||||||
|
const size_t& _nbChunk,
|
||||||
|
const std::vector<audio_algo_core::channel>& _map) {
|
||||||
|
std::vector<int32_t> data;
|
||||||
|
data.resize(_nbChunk*_map.size());
|
||||||
|
double baseCycle = 2.0*M_PI/(double)m_freq * (double)m_generateFreq;
|
||||||
|
//ROS_INFO("Get data ...");
|
||||||
|
|
||||||
|
for (int32_t iii=0; iii<data.size()/_map.size(); iii++) {
|
||||||
|
for (int32_t jjj=0; jjj<_map.size(); jjj++) {
|
||||||
|
data[_map.size()*iii+jjj] = cos(m_phase) * (double)INT32_MAX;
|
||||||
|
}
|
||||||
|
m_phase += baseCycle;
|
||||||
|
if (m_phase >= 2*M_PI) {
|
||||||
|
m_phase -= 2*M_PI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<float> onDataNeededFloat(const boost::chrono::system_clock::time_point& _playTime,
|
||||||
|
const size_t& _nbChunk,
|
||||||
|
const std::vector<audio_algo_core::channel>& _map) {
|
||||||
|
std::vector<float> data;
|
||||||
|
data.resize(_nbChunk*_map.size());
|
||||||
|
double baseCycle = 2.0*M_PI/(double)m_freq * (double)m_generateFreq;
|
||||||
|
//ROS_INFO("Get data ...");
|
||||||
|
|
||||||
|
for (int32_t iii=0; iii<data.size()/_map.size(); iii++) {
|
||||||
|
for (int32_t jjj=0; jjj<_map.size(); jjj++) {
|
||||||
|
data[_map.size()*iii+jjj] = cos(m_phase);
|
||||||
|
}
|
||||||
|
m_phase += baseCycle;
|
||||||
|
if (m_phase >= 2*M_PI) {
|
||||||
|
m_phase -= 2*M_PI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
if (m_interface != NULL) {
|
||||||
|
m_interface->start();
|
||||||
|
// wait 2 second ...
|
||||||
|
usleep(1000000);
|
||||||
|
m_interface->stop();
|
||||||
|
} else {
|
||||||
|
ROS_ERROR("Can not create interface !!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
boost::shared_ptr<audio_base::Manager> manager;
|
||||||
|
manager = audio_base::Manager::create("testApplication");
|
||||||
|
#if 0
|
||||||
|
ROS_INFO("test output (Write mode)");
|
||||||
|
{
|
||||||
|
boost::shared_ptr<testOutWrite> process = boost::make_shared<testOutWrite>(manager);
|
||||||
|
process->run();
|
||||||
|
process.reset();
|
||||||
|
}
|
||||||
|
usleep(500000);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
ROS_INFO("test output (callback mode)");
|
||||||
|
{
|
||||||
|
boost::shared_ptr<testOutCallback> process = boost::make_shared<testOutCallback>(manager);
|
||||||
|
process->run();
|
||||||
|
process.reset();
|
||||||
|
}
|
||||||
|
usleep(500000);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
ROS_INFO("test input (Read mode)");
|
||||||
|
{
|
||||||
|
boost::shared_ptr<testInRead> process = boost::make_shared<testInRead>(manager);
|
||||||
|
process->run();
|
||||||
|
process.reset();
|
||||||
|
}
|
||||||
|
usleep(500000);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
ROS_INFO("test input (callback mode)");
|
||||||
|
{
|
||||||
|
boost::shared_ptr<testInCallback> process = boost::make_shared<testInCallback>(manager);
|
||||||
|
process->run();
|
||||||
|
process.reset();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
ROS_INFO("test convert flaot to output (callback mode)");
|
||||||
|
std::vector<float> listFreq;
|
||||||
|
listFreq.push_back(4000);
|
||||||
|
listFreq.push_back(8000);
|
||||||
|
listFreq.push_back(16000);
|
||||||
|
listFreq.push_back(32000);
|
||||||
|
listFreq.push_back(48000);
|
||||||
|
listFreq.push_back(48001);
|
||||||
|
listFreq.push_back(64000);
|
||||||
|
listFreq.push_back(96000);
|
||||||
|
listFreq.push_back(11250);
|
||||||
|
listFreq.push_back(2250);
|
||||||
|
listFreq.push_back(44100);
|
||||||
|
listFreq.push_back(88200);
|
||||||
|
|
||||||
|
std::vector<int32_t> listChannel;
|
||||||
|
listChannel.push_back(1);
|
||||||
|
listChannel.push_back(2);
|
||||||
|
listChannel.push_back(4);
|
||||||
|
std::vector<audio_algo_core::format> listFormat;
|
||||||
|
listFormat.push_back(audio_algo_core::format_int16);
|
||||||
|
listFormat.push_back(audio_algo_core::format_int16_on_int32);
|
||||||
|
listFormat.push_back(audio_algo_core::format_int32);
|
||||||
|
listFormat.push_back(audio_algo_core::format_float);
|
||||||
|
for (int32_t iii=0; iii<listFreq.size(); ++iii) {
|
||||||
|
for (int32_t jjj=0; jjj<listChannel.size(); ++jjj) {
|
||||||
|
for (std::vector<audio_algo_core::format>::iterator formatIt = listFormat.begin(); formatIt != listFormat.end(); ++formatIt) {
|
||||||
|
float freq = listFreq[iii];
|
||||||
|
int32_t channel = listChannel[jjj];
|
||||||
|
ROS_INFO("freq = %f channel=%d format=%s", freq, channel, getFormatString(*formatIt).c_str());
|
||||||
|
boost::shared_ptr<testOutCallbackFloat> process = boost::make_shared<testOutCallbackFloat>(manager, freq, channel, *formatIt);
|
||||||
|
process->run();
|
||||||
|
process.reset();
|
||||||
|
usleep(500000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ROS_INFO("TEST ended");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user