// // driver_manager.cpp // // Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // #include #include "driver_manager.hpp" #include "log.hpp" static const std::vector alsa_msg_str = { "Start", "Stop", "Reset", "StartIO", "StopIO", "SetSampleRate", "GetSampleRate", "GetAudioMode", "SetDSDAudioMode", "SetTICFrameSizeAt1FS", "SetMaxTICFrameSize", "SetNumberOfInputs", "SetNumberOfOutputs", "GetNumberOfInputs", "GetNumberOfOutputs", "SetInterfaceName", "Add_RTPStream", "Remove_RTPStream", "Update_RTPStream_Name", "GetPTPInfo", "Hello", "Bye", "Ping", "SetMasterOutputVolume", "SetMasterOutputSwitch", "GetMasterOutputVolume", "GetMasterOutputSwitch", "SetPlayoutDelay", "SetCaptureDelay", "GetRTPStreamStatus", "SetPTPConfig", "GetPTPConfig", "GetPTPStatus" }; static const std::vector ptp_status_str = { "unlocked", "locking", "locked" }; std::shared_ptr DriverManager::create() { // no need to be thread-safe here static std::weak_ptr instance; if (auto ptr = instance.lock()) { return ptr; } auto ptr = std::shared_ptr(new DriverManager()); instance = ptr; return ptr; } bool DriverManager::init(const Config& config) { if (!DriverHandler::init(config)) { return false; } sample_rate = config.get_sample_rate(); TPTPConfig ptp_config; ptp_config.ui8Domain = config.get_ptp_domain(); ptp_config.ui8DSCP = config.get_ptp_dscp(); bool res = hello() || start() || reset() || set_interface_name(config.get_interface_name()) || set_ptp_config(ptp_config) || set_tic_frame_size_at_1fs(config.get_tic_frame_size_at_1fs()) || set_playout_delay(config.get_playout_delay()) || set_max_tic_frame_size(config.get_max_tic_frame_size()); return !res; } bool DriverManager::terminate() { stop(); bye(); return DriverHandler::terminate(); } std::error_code DriverManager::hello() { this->send_command(MT_ALSA_Msg_Hello, 0, nullptr); return retcode_; } std::error_code DriverManager::bye() { this->send_command(MT_ALSA_Msg_Bye, 0, nullptr); return retcode_; } std::error_code DriverManager::start() { this->send_command(MT_ALSA_Msg_Start, 0, nullptr); return retcode_; } std::error_code DriverManager::stop() { this->send_command(MT_ALSA_Msg_Stop, 0, nullptr); return retcode_; } std::error_code DriverManager::reset() { this->send_command(MT_ALSA_Msg_Reset, 0, nullptr); return retcode_; } std::error_code DriverManager::set_ptp_config(const TPTPConfig& config) { BOOST_LOG_TRIVIAL(info) << "driver_manager:: setting PTP Domain " << (int)config.ui8Domain << " DSCP " << (int)config.ui8DSCP; this->send_command(MT_ALSA_Msg_SetPTPConfig, sizeof(TPTPConfig), reinterpret_cast(&config)); return retcode_; } std::error_code DriverManager::get_ptp_config(TPTPConfig& config) { this->send_command(MT_ALSA_Msg_GetPTPConfig); if (!retcode_) { memcpy(&config, recv_data_, sizeof(TPTPConfig)); BOOST_LOG_TRIVIAL(debug) << "driver_manager:: PTP Domain " << (int)config.ui8Domain << " DSCP " << (int)config.ui8DSCP; } return retcode_; } std::error_code DriverManager::get_ptp_status(TPTPStatus& status) { this->send_command(MT_ALSA_Msg_GetPTPStatus); if (!retcode_) { memcpy(&status, recv_data_, sizeof(TPTPStatus)); BOOST_LOG_TRIVIAL(debug) << "driver_manager:: PTP Status " << ptp_status_str[status.nPTPLockStatus] << " GMID " << status.ui64GMID << " Jitter " << status.i32Jitter; } return retcode_; } std::error_code DriverManager::set_interface_name(const std::string& ifname) { BOOST_LOG_TRIVIAL(info) << "driver_manager:: setting interface " << ifname; this->send_command(MT_ALSA_Msg_SetInterfaceName, ifname.length() + 1, reinterpret_cast(ifname.c_str())); return retcode_; } std::error_code DriverManager::add_rtp_stream( const TRTP_stream_info& stream_info, uint64_t& stream_handle) { this->send_command(MT_ALSA_Msg_Add_RTPStream, sizeof(TRTP_stream_info), reinterpret_cast(&stream_info)); if (!retcode_) { memcpy(&stream_handle, recv_data_, sizeof(stream_handle)); BOOST_LOG_TRIVIAL(info) << "driver_manager:: add RTP stream success handle " << stream_handle; } return retcode_; } std::error_code DriverManager::get_rtp_stream_status( uint64_t stream_handle, TRTP_stream_status& stream_status) { this->send_command(MT_ALSA_Msg_GetRTPStreamStatus, sizeof(uint64_t), reinterpret_cast(&stream_handle)); if (!retcode_) { memcpy(&stream_status, recv_data_, sizeof(stream_status)); } return retcode_; } std::error_code DriverManager::remove_rtp_stream(uint64_t stream_handle) { this->send_command(MT_ALSA_Msg_Remove_RTPStream, sizeof(uint64_t), reinterpret_cast(&stream_handle)); return retcode_; } std::error_code DriverManager::ping() { this->send_command(MT_ALSA_Msg_Ping); return retcode_; } std::error_code DriverManager::set_sample_rate(uint32_t sample_rate) { this->send_command(MT_ALSA_Msg_SetSampleRate, sizeof(uint32_t), reinterpret_cast(&sample_rate)); return retcode_; } std::error_code DriverManager::set_tic_frame_size_at_1fs(uint64_t frame_size) { this->send_command(MT_ALSA_Msg_SetTICFrameSizeAt1FS, sizeof(uint64_t), reinterpret_cast(&frame_size)); return retcode_; } std::error_code DriverManager::set_max_tic_frame_size(uint64_t frame_size) { this->send_command(MT_ALSA_Msg_SetMaxTICFrameSize, sizeof(uint64_t), reinterpret_cast(&frame_size)); return retcode_; } std::error_code DriverManager::set_playout_delay(int32_t delay) { this->send_command(MT_ALSA_Msg_SetPlayoutDelay, sizeof(uint32_t), reinterpret_cast(&delay)); return retcode_; } std::error_code DriverManager::get_sample_rate(uint32_t& sample_rate) { this->send_command(MT_ALSA_Msg_GetSampleRate); if (!retcode_) { memcpy(&sample_rate, recv_data_, sizeof(uint32_t)); BOOST_LOG_TRIVIAL(info) << "driver_manager:: sample rate " << sample_rate; } return retcode_; } std::error_code DriverManager::get_number_of_inputs(int32_t& inputs) { this->send_command(MT_ALSA_Msg_GetNumberOfInputs); if (!retcode_) { memcpy(&inputs, recv_data_, sizeof(uint32_t)); BOOST_LOG_TRIVIAL(info) << "driver_manager:: number of inputs " << inputs; } return retcode_; } std::error_code DriverManager::get_number_of_outputs(int32_t& outputs) { this->send_command(MT_ALSA_Msg_GetNumberOfOutputs); if (!retcode_) { memcpy(&outputs, recv_data_, sizeof(uint32_t)); BOOST_LOG_TRIVIAL(info) << "driver_manager:: number of outputs " << outputs; } return retcode_; } void DriverManager::on_command_done(enum MT_ALSA_msg_id id, size_t size, const uint8_t* data) { BOOST_LOG_TRIVIAL(info) << "driver_manager:: cmd " << alsa_msg_str[id] << " done data len " << size; memcpy(recv_data_, data, size); retcode_ = std::error_code{}; } void DriverManager::on_command_error(enum MT_ALSA_msg_id id, std::error_code error) { BOOST_LOG_TRIVIAL(error) << "driver_manager:: cmd " << alsa_msg_str[id] << " failed with error " << error.message(); retcode_ = error; } void DriverManager::on_event(enum MT_ALSA_msg_id id, size_t& resp_size, uint8_t* resp, size_t req_size, const uint8_t* req) { BOOST_LOG_TRIVIAL(debug) << "driver_manager:: event " << alsa_msg_str[id] << " data len " << req_size; switch (id) { case MT_ALSA_Msg_Hello: resp_size = 0; break; case MT_ALSA_Msg_Bye: resp_size = 0; break; case MT_ALSA_Msg_SetMasterOutputVolume: if (req_size == sizeof(int32_t)) { memcpy(&output_volume, req, req_size); BOOST_LOG_TRIVIAL(info) << "driver_manager:: event SetMasterOutputVolume " << output_volume; } resp_size = 0; break; case MT_ALSA_Msg_SetMasterOutputSwitch: if (req_size == sizeof(int32_t)) { memcpy(&output_switch, req, req_size); BOOST_LOG_TRIVIAL(info) << "driver_manager:: event SetMasterOutputSwitch " << output_switch; } resp_size = 0; break; case MT_ALSA_Msg_SetSampleRate: if (req_size == sizeof(uint32_t)) { memcpy(&sample_rate, req, req_size); BOOST_LOG_TRIVIAL(info) << "driver_manager:: event SetSampleRate " << sample_rate; } resp_size = 0; break; case MT_ALSA_Msg_GetMasterOutputVolume: resp_size = sizeof(int32_t); memcpy(resp, &output_volume, resp_size); BOOST_LOG_TRIVIAL(info) << "driver_manager:: event GetMasterOutputVolume " << output_volume; break; case MT_ALSA_Msg_GetMasterOutputSwitch: resp_size = sizeof(int32_t); memcpy(resp, &output_switch, resp_size); BOOST_LOG_TRIVIAL(info) << "driver_manager:: event GetMasterOutputSwitch " << output_switch; break; default: BOOST_LOG_TRIVIAL(error) << "driver_manager:: unknown event " << alsa_msg_str[id] << " data len " << req_size; break; } } void DriverManager::on_event_error(enum MT_ALSA_msg_id id, std::error_code error) { BOOST_LOG_TRIVIAL(error) << "driver_manager:: event " << alsa_msg_str[id] << " error " << error; }