/** @file * @author Edouard DUPIN * @copyright 2015, Edouard DUPIN, all right reserved * @license APACHE v2.0 (see license file) */ #ifdef __AIRTAUDIO_INFERFACE__ #include #include #include #undef __class__ #define __class__ "io::NodeAirTAudio" static std::string asString(const std11::chrono::system_clock::time_point& tp) { // convert to system time: std::time_t t = std11::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; } int32_t river::io::NodeAirTAudio::recordCallback(const void* _inputBuffer, const std11::chrono::system_clock::time_point& _timeInput, uint32_t _nbChunk, const std::vector& _status) { std11::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 std11::chrono::system_clock::time_point& _timeOutput, uint32_t _nbChunk, const std::vector& _status) { std11::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; } std11::shared_ptr river::io::NodeAirTAudio::create(const std::string& _name, const std11::shared_ptr& _config) { return std11::shared_ptr(new river::io::NodeAirTAudio(_name, _config)); } river::io::NodeAirTAudio::NodeAirTAudio(const std::string& _name, const std11::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 std11::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 = -1; // TODO : Remove this from here (create an extern interface ...) RIVER_INFO("Device list:"); for (int32_t iii=0; iiigetStringValue("timestamp-mode", "soft")); RIVER_DEBUG("interfaceFormat=" << interfaceFormat); RIVER_DEBUG("hardwareFormat=" << hardwareFormat); m_rtaudioFrameSize = nbChunk; RIVER_INFO("Open output stream nbChannels=" << params.nChannels); enum airtaudio::error err = airtaudio::error_none; if (m_isInput == true) { m_process.setInputConfig(hardwareFormat); m_process.setOutputConfig(interfaceFormat); err = m_adac.openStream(nullptr, ¶ms, hardwareFormat.getFormat(), hardwareFormat.getFrequency(), &m_rtaudioFrameSize, std11::bind(&river::io::NodeAirTAudio::recordCallback, this, std11::placeholders::_1, std11::placeholders::_2, std11::placeholders::_5, std11::placeholders::_6), option ); } else { m_process.setInputConfig(interfaceFormat); m_process.setOutputConfig(hardwareFormat); err = m_adac.openStream(¶ms, nullptr, hardwareFormat.getFormat(), hardwareFormat.getFrequency(), &m_rtaudioFrameSize, std11::bind(&river::io::NodeAirTAudio::playbackCallback, this, std11::placeholders::_3, std11::placeholders::_4, std11::placeholders::_5, std11::placeholders::_6), option ); } if (err != airtaudio::error_none) { RIVER_ERROR("Create stream : '" << m_name << "' mode=" << (m_isInput?"input":"output") << " can not create stream " << err); } m_process.updateInterAlgo(); } river::io::NodeAirTAudio::~NodeAirTAudio() { std11::unique_lock lock(m_mutex); RIVER_INFO("close input stream"); if (m_adac.isStreamOpen() ) { m_adac.closeStream(); } }; void river::io::NodeAirTAudio::start() { std11::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() { std11::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); } } #endif