From 38dabd5887dd9009b6cb73c641c8ce04d1d80778 Mon Sep 17 00:00:00 2001 From: Andrea Bondavalli Date: Tue, 15 Nov 2022 22:00:51 +0100 Subject: [PATCH] Added support to the daemon for a fake driver version. This allows daemon execution without the RAVENNA driver for testing purposes and to allow regression tests to run into a Docker container. --- build.sh | 4 +- daemon/CMakeLists.txt | 19 +++- daemon/driver_interface.hpp | 29 ++++++ daemon/fake_driver_manager.cpp | 185 +++++++++++++++++++++++++++++++++ daemon/fake_driver_manager.hpp | 84 +++++++++++++++ daemon/main.cpp | 4 +- daemon/session_manager.cpp | 1 - daemon/session_manager.hpp | 2 +- daemon/tests/daemon_test.cpp | 2 +- 9 files changed, 318 insertions(+), 12 deletions(-) create mode 100644 daemon/driver_interface.hpp create mode 100644 daemon/fake_driver_manager.cpp create mode 100644 daemon/fake_driver_manager.hpp diff --git a/build.sh b/build.sh index 3f12b0f..c62c6b8 100755 --- a/build.sh +++ b/build.sh @@ -1,4 +1,4 @@ -#!/bin/bash +!/bin/bash # # Tested on Ubuntu 18.04 # @@ -43,7 +43,7 @@ cd .. cd daemon echo "Building aes67-daemon ..." -cmake -DCPP_HTTPLIB_DIR="$TOPDIR"/3rdparty/cpp-httplib -DRAVENNA_ALSA_LKM_DIR="$TOPDIR"/3rdparty/ravenna-alsa-lkm -DENABLE_TESTS=ON -DWITH_AVAHI=ON . +cmake -DCPP_HTTPLIB_DIR="$TOPDIR"/3rdparty/cpp-httplib -DRAVENNA_ALSA_LKM_DIR="$TOPDIR"/3rdparty/ravenna-alsa-lkm -DENABLE_TESTS=ON -DWITH_AVAHI=ON -DFAKE_DRIVER=OFF . make cd .. diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 27d74e9..2390458 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -8,16 +8,17 @@ if( ENABLE_TESTS ) endif() option(WITH_AVAHI "Include mDNS support via Avahi" OFF) +option(FAKE_DRIVER "Use fake driver instead of RAVENNA" OFF) set(CMAKE_CXX_STANDARD 17) # ravena lkm _should_ be provided by the CLI. Nonetheless, we should be able # to find it in system dirs too... -if ( NOT RAVENNNA_ALSA_LKM_DIR ) +if (NOT RAVENNNA_ALSA_LKM_DIR) find_path(RAVENNA_ALSA_LKM_DIR "common/MergingRAVENNACommon.h" REQUIRED) endif() # use sysroot cpp-http lib unless one was explicitly provided in cmdline -if ( NOT CPP_HTTPLIB_DIR ) +if (NOT CPP_HTTPLIB_DIR) find_path( CPP_HTTPLIB_DIR "httplib.h" REQUIRED) endif() @@ -31,13 +32,21 @@ find_package(Boost COMPONENTS system thread log program_options REQUIRED) include_directories(aes67-daemon ${RAVENNA_ALSA_LKM_DIR}/common ${RAVENNA_ALSA_LKM_DIR}/driver ${CPP_HTTPLIB_DIR} ${Boost_INCLUDE_DIR}) add_definitions( -DBOOST_LOG_DYN_LINK -DBOOST_LOG_USE_NATIVE_SYSLOG ) add_compile_options( -Wall ) -add_executable(aes67-daemon error_code.cpp json.cpp main.cpp driver_handler.cpp driver_manager.cpp session_manager.cpp http_server.cpp config.cpp interface.cpp log.cpp sap.cpp browser.cpp rtsp_client.cpp mdns_client.cpp mdns_server.cpp rtsp_server.cpp utils.cpp) +set(SOURCES error_code.cpp json.cpp main.cpp session_manager.cpp http_server.cpp config.cpp interface.cpp log.cpp sap.cpp browser.cpp rtsp_client.cpp mdns_client.cpp mdns_server.cpp rtsp_server.cpp utils.cpp) -if( ENABLE_TESTS ) +if(FAKE_DRIVER) + MESSAGE(STATUS "FAKE_DRIVER") + add_definitions(-D_USE_FAKE_DRIVER_) + list(APPEND SOURCES fake_driver_manager.cpp) +else() + list(APPEND SOURCES driver_handler.cpp driver_manager.cpp) +endif() +add_executable(aes67-daemon ${SOURCES}) + +if(ENABLE_TESTS) add_subdirectory(tests) endif() - target_link_libraries(aes67-daemon ${Boost_LIBRARIES}) if(WITH_AVAHI) MESSAGE(STATUS "WITH_AVAHI") diff --git a/daemon/driver_interface.hpp b/daemon/driver_interface.hpp new file mode 100644 index 0000000..43702fc --- /dev/null +++ b/daemon/driver_interface.hpp @@ -0,0 +1,29 @@ +// +// driver_interface.hpp +// +// Copyright (c) 2019 2022 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 . +// + +#ifndef _DRIVER_INTERFACE_HPP_ +#define _DRIVER_INTERFACE_HPP_ + +#ifdef _USE_FAKE_DRIVER_ +#include "fake_driver_manager.hpp" +#else +#include "driver_manager.hpp" +#endif + +#endif diff --git a/daemon/fake_driver_manager.cpp b/daemon/fake_driver_manager.cpp new file mode 100644 index 0000000..40983e0 --- /dev/null +++ b/daemon/fake_driver_manager.cpp @@ -0,0 +1,185 @@ +// +// fake_driver_manager.cpp +// +// Copyright (c) 2019 2022 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 "log.hpp" +#include "fake_driver_manager.hpp" + +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) { + sample_rate_ = config.get_sample_rate(); + + TPTPConfig ptp_config; + ptp_config.ui8Domain = config.get_ptp_domain(); + ptp_config.ui8DSCP = config.get_ptp_dscp(); + + if (hello()) + return false; + + bool res(false); + if (config.get_driver_restart()) { + res = 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(const Config& config) { + if (config.get_driver_restart()) { + stop(); + } + bye(); + return true; +} + +std::error_code DriverManager::hello() { + return std::error_code{}; +} + +std::error_code DriverManager::bye() { + return std::error_code{}; +} + +std::error_code DriverManager::start() { + return std::error_code{}; +} + +std::error_code DriverManager::stop() { + return std::error_code{}; +} + +std::error_code DriverManager::reset() { + return std::error_code{}; +} + +std::error_code DriverManager::set_ptp_config(const TPTPConfig& config) { + BOOST_LOG_TRIVIAL(info) << "fake_driver_manager:: setting PTP Domain " + << (int)config.ui8Domain << " DSCP " + << (int)config.ui8DSCP; + ptp_config_ = config; + return std::error_code{}; +} + +std::error_code DriverManager::get_ptp_config(TPTPConfig& config) { + config = ptp_config_; + BOOST_LOG_TRIVIAL(debug) << "fake_driver_manager:: PTP Domain " + << (int)config.ui8Domain << " DSCP " + << (int)config.ui8DSCP; + return std::error_code{}; +} + +std::error_code DriverManager::get_ptp_status(TPTPStatus& status) { + status.nPTPLockStatus = PTPLS_UNLOCKED; + status.ui64GMID = 0xABABABABABABABAB; + status.i32Jitter = 0; + BOOST_LOG_TRIVIAL(debug) << "fake_driver_manager:: PTP Status " + << ptp_status_str[status.nPTPLockStatus] << " GMID " + << status.ui64GMID << " Jitter " << status.i32Jitter; + return std::error_code{}; +} + +std::error_code DriverManager::set_interface_name(const std::string& ifname) { + return std::error_code{}; +} + +std::error_code DriverManager::add_rtp_stream( + const TRTP_stream_info& stream_info, + uint64_t& stream_handle) { + stream_handle = ++g_handle; + handles_.insert(stream_handle); + BOOST_LOG_TRIVIAL(info) << "fake_driver_manager:: add RTP stream success handle " + << stream_handle; + return std::error_code{}; +} + +std::error_code DriverManager::get_rtp_stream_status( + uint64_t stream_handle, + TRTP_stream_status& stream_status) { + stream_status.u.flags = 0x0; + stream_status.sink_min_time = 0; + if (handles_.find(stream_handle) == handles_.end()) { + return DriverErrc::invalid_value; + } + return std::error_code{}; +} + +std::error_code DriverManager::remove_rtp_stream(uint64_t stream_handle) { + if (handles_.find(stream_handle) == handles_.end()) { + return DriverErrc::invalid_value; + } + handles_.erase(stream_handle); + return std::error_code{}; +} + +std::error_code DriverManager::ping() { + return std::error_code{}; +} + +std::error_code DriverManager::set_sample_rate(uint32_t sample_rate) { + sample_rate_ = sample_rate; + return std::error_code{}; +} + +std::error_code DriverManager::set_tic_frame_size_at_1fs(uint64_t frame_size) { + frame_size_ = frame_size; + return std::error_code{}; +} + +std::error_code DriverManager::set_max_tic_frame_size(uint64_t frame_size) { + max_frame_size_ = frame_size; + return std::error_code{}; +} + +std::error_code DriverManager::set_playout_delay(int32_t delay) { + delay_ = delay; + return std::error_code{}; +} + +std::error_code DriverManager::get_sample_rate(uint32_t& sample_rate) { + sample_rate = sample_rate_; + BOOST_LOG_TRIVIAL(info) << "fake_driver_manager:: sample rate " << sample_rate; + return std::error_code{}; +} + +std::error_code DriverManager::get_number_of_inputs(int32_t& inputs) { + inputs = 0; + return std::error_code{}; +} + +std::error_code DriverManager::get_number_of_outputs(int32_t& outputs) { + outputs = 0; + return std::error_code{}; +} diff --git a/daemon/fake_driver_manager.hpp b/daemon/fake_driver_manager.hpp new file mode 100644 index 0000000..f6c6708 --- /dev/null +++ b/daemon/fake_driver_manager.hpp @@ -0,0 +1,84 @@ +// +// fake_driver_manager.hpp +// +// Copyright (c) 2019 2022 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 . +// + +#ifndef _FAKE_DRIVER_MANAGER_HPP_ +#define _FAKE_DRIVER_MANAGER_HPP_ + +#include + +#include "error_code.hpp" +#include "RTP_stream_info.h" +#include "audio_streamer_clock_PTP_defs.h" + +class DriverManager { + public: + static std::shared_ptr create(); + + // driver interface + bool init(const Config& config); + bool terminate(const Config& config); + + std::error_code ping(); // unused, return error + std::error_code set_ptp_config(const TPTPConfig& config); + std::error_code get_ptp_config(TPTPConfig& config); + std::error_code get_ptp_status(TPTPStatus& status); + std::error_code set_interface_name(const std::string& ifname); + std::error_code add_rtp_stream(const TRTP_stream_info& stream_info, + uint64_t& stream_handle); + std::error_code get_rtp_stream_status(uint64_t stream_handle, + TRTP_stream_status& stream_status); + std::error_code remove_rtp_stream(uint64_t stream_handle); + std::error_code get_sample_rate(uint32_t& sample_rate); + std::error_code set_sample_rate(uint32_t sample_rate); + std::error_code set_tic_frame_size_at_1fs(uint64_t frame_size); + std::error_code set_max_tic_frame_size(uint64_t frame_size); + std::error_code set_playout_delay(int32_t delay); + std::error_code get_number_of_inputs(int32_t& inputs); + std::error_code get_number_of_outputs(int32_t& outputs); + + int32_t get_current_output_volume() { return output_volume_; }; + int32_t get_current_output_switch() { return output_switch_; }; + uint32_t get_current_sample_rate() { return sample_rate_; }; + + protected: + // singleton, use create to build + DriverManager(){}; + + // these are used in init/terminate + std::error_code hello(); + std::error_code start(); + std::error_code stop(); + std::error_code reset(); + std::error_code bye(); + + std::error_code retcode_; + + int32_t output_volume_{-20}; + int32_t output_switch_{0}; + uint32_t sample_rate_{0}; + uint64_t frame_size_{0}; + uint64_t max_frame_size_{0}; + uint32_t delay_{0}; + TPTPConfig ptp_config_; + + std::set handles_; + inline static uint16_t g_handle{0}; +}; + +#endif diff --git a/daemon/main.cpp b/daemon/main.cpp index 76b0986..e65f7ba 100644 --- a/daemon/main.cpp +++ b/daemon/main.cpp @@ -23,7 +23,7 @@ #include "browser.hpp" #include "config.hpp" -#include "driver_manager.hpp" +#include "driver_interface.hpp" #include "http_server.hpp" #include "interface.hpp" #include "log.hpp" @@ -35,7 +35,7 @@ namespace po = boost::program_options; namespace postyle = boost::program_options::command_line_style; namespace logging = boost::log; -static std::string version("bondagit-1.5.2"); +static std::string version("bondagit-1.5.3"); static std::atomic terminate = false; void termination_handler(int signum) { diff --git a/daemon/session_manager.cpp b/daemon/session_manager.cpp index ffa5dbc..31daf9d 100644 --- a/daemon/session_manager.cpp +++ b/daemon/session_manager.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include "json.hpp" #include "log.hpp" diff --git a/daemon/session_manager.hpp b/daemon/session_manager.hpp index b580b14..3fcc16f 100644 --- a/daemon/session_manager.hpp +++ b/daemon/session_manager.hpp @@ -27,7 +27,7 @@ #include #include "config.hpp" -#include "driver_manager.hpp" +#include "driver_interface.hpp" #include "igmp.hpp" #include "sap.hpp" diff --git a/daemon/tests/daemon_test.cpp b/daemon/tests/daemon_test.cpp index 3e8cabe..bb7501f 100644 --- a/daemon/tests/daemon_test.cpp +++ b/daemon/tests/daemon_test.cpp @@ -612,7 +612,7 @@ BOOST_AUTO_TEST_CASE(sink_check_status) { auto is_sink_some_muted = pt.get("sink_flags.some_muted"); auto is_sink_all_muted = pt.get("sink_flags.all_muted"); // BOOST_REQUIRE_MESSAGE(is_sink_muted, "sink is muted"); - BOOST_REQUIRE_MESSAGE(!is_sink_all_muted, "all sinks are mutes"); + BOOST_REQUIRE_MESSAGE(!is_sink_all_muted, "all sinks are muted"); BOOST_REQUIRE_MESSAGE(!is_sink_some_muted, "some sinks are muted"); BOOST_REQUIRE_MESSAGE(cli.remove_sink(0), "removed sink 0"); }