/** @file * @author Edouard DUPIN * @copyright 2015, Edouard DUPIN, all right reserved * @license APACHE v2.0 (see license file) */ #include #include #include #undef __class__ #define __class__ "io::NodeAirTAudio" std::string asString(const std::chrono::system_clock::time_point& tp) { // convert to system time: std::time_t t = std::chrono::system_clock::to_time_t(tp); // convert in human string std::string ts = std::ctime(&t); // remove \n ts.resize(ts.size()-1); return ts; } namespace std { static std::ostream& operator <<(std::ostream& _os, const std::chrono::system_clock::time_point& _obj) { std::chrono::microseconds us = std::chrono::duration_cast(_obj.time_since_epoch()); _os << us.count(); return _os; } } int32_t river::io::NodeAirTAudio::duplexCallback(const void* _inputBuffer, const std::chrono::system_clock::time_point& _timeInput, void* _outputBuffer, const std::chrono::system_clock::time_point& _timeOutput, uint32_t _nbChunk, const std::vector& _status) { std::unique_lock lock(m_mutex); // TODO : Manage status ... if (_inputBuffer != nullptr) { RIVER_VERBOSE("data Input size request :" << _nbChunk << " [BEGIN] status=" << _status << " nbIO=" << m_list.size()); newInput(_inputBuffer, _nbChunk, _timeInput); } if (_outputBuffer != nullptr) { RIVER_VERBOSE("data Output size request :" << _nbChunk << " [BEGIN] status=" << _status << " nbIO=" << m_list.size()); newOutput(_outputBuffer, _nbChunk, _timeOutput); } return 0; } int32_t river::io::NodeAirTAudio::recordCallback(const void* _inputBuffer, const std::chrono::system_clock::time_point& _timeInput, uint32_t _nbChunk, const std::vector& _status) { std::unique_lock lock(m_mutex); // TODO : Manage status ... RIVER_VERBOSE("data Input size request :" << _nbChunk << " [BEGIN] status=" << _status << " nbIO=" << m_list.size()); newInput(_inputBuffer, _nbChunk, _timeInput); return 0; } int32_t river::io::NodeAirTAudio::playbackCallback(void* _outputBuffer, const std::chrono::system_clock::time_point& _timeOutput, uint32_t _nbChunk, const std::vector& _status) { std::unique_lock lock(m_mutex); // TODO : Manage status ... RIVER_VERBOSE("data Output size request :" << _nbChunk << " [BEGIN] status=" << _status << " nbIO=" << m_list.size()); newOutput(_outputBuffer, _nbChunk, _timeOutput); return 0; } std::shared_ptr river::io::NodeAirTAudio::create(const std::string& _name, const std::shared_ptr& _config) { return std::shared_ptr(new river::io::NodeAirTAudio(_name, _config)); } river::io::NodeAirTAudio::NodeAirTAudio(const std::string& _name, const std::shared_ptr& _config) : Node(_name, _config) { drain::IOFormatInterface interfaceFormat = getInterfaceFormat(); drain::IOFormatInterface hardwareFormat = getHarwareFormat(); /** map-on:{ # select hardware interface and name interface:"alsa", # interface : "alsa", "pulse", "core", ... name:"default", # name of the interface }, nb-chunk:1024 # number of chunk to open device (create the latency anf the frequency to call user) */ enum airtaudio::type typeInterface = airtaudio::type_undefined; std::string streamName = "default"; const std::shared_ptr tmpObject = m_config->getObject("map-on"); if (tmpObject == nullptr) { RIVER_WARNING("missing node : 'map-on' ==> auto map : 'auto:default'"); } else { std::string value = tmpObject->getStringValue("interface", "default"); typeInterface = airtaudio::getTypeFromString(value); streamName = tmpObject->getStringValue("name", "default"); } int32_t nbChunk = m_config->getNumberValue("nb-chunk", 1024); // intanciate specific API ... m_adac.instanciate(typeInterface); m_adac.setName(_name); // TODO : Check return ... std::string type = m_config->getStringValue("type", "int16"); if (streamName == "") { streamName = "default"; } // search device ID : RIVER_INFO("Open :"); RIVER_INFO(" m_streamName=" << streamName); RIVER_INFO(" m_freq=" << hardwareFormat.getFrequency()); RIVER_INFO(" m_map=" << hardwareFormat.getMap()); RIVER_INFO(" m_format=" << hardwareFormat.getFormat()); RIVER_INFO(" m_isInput=" << m_isInput); int32_t deviceId = 0; RIVER_INFO("Device list:"); for (int32_t iii=0; iii lock(m_mutex); RIVER_INFO("close input stream"); if (m_adac.isStreamOpen() ) { m_adac.closeStream(); } }; void river::io::NodeAirTAudio::start() { std::unique_lock lock(m_mutex); RIVER_INFO("Start stream : '" << m_name << "' mode=" << (m_isInput?"input":"output") ); enum airtaudio::error err = m_adac.startStream(); if (err != airtaudio::error_none) { RIVER_ERROR("Start stream : '" << m_name << "' mode=" << (m_isInput?"input":"output") << " can not start stream ... " << err); } } void river::io::NodeAirTAudio::stop() { std::unique_lock lock(m_mutex); RIVER_INFO("Stop stream : '" << m_name << "' mode=" << (m_isInput?"input":"output") ); enum airtaudio::error err = m_adac.stopStream(); if (err != airtaudio::error_none) { RIVER_ERROR("Stop stream : '" << m_name << "' mode=" << (m_isInput?"input":"output") << " can not stop stream ... " << err); } }