diff --git a/.github/workflows/daemon-tests.yml b/.github/workflows/daemon-tests.yml
new file mode 100644
index 0000000..1972a9f
--- /dev/null
+++ b/.github/workflows/daemon-tests.yml
@@ -0,0 +1,19 @@
+name: Daemon regression Tests
+
+on: [push]
+
+jobs:
+ daemon_tests_job:
+ runs-on: ubuntu-latest
+ name: A job to run AES67 daemon regression tests
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+
+ - name: Build daemon tests docker image
+ run: docker build --progress=plain -f ./Dockerfile.daemon_tests -t aes67-daemon-tests .
+
+ - name: Run daemon regression tests
+ run: docker run aes67-daemon-tests
diff --git a/Dockerfile.daemon_tests b/Dockerfile.daemon_tests
new file mode 100644
index 0000000..4173851
--- /dev/null
+++ b/Dockerfile.daemon_tests
@@ -0,0 +1,11 @@
+FROM ubuntu
+RUN echo 'APT::Install-Suggests "0";' >> /etc/apt/apt.conf.d/00-docker
+RUN echo 'APT::Install-Recommends "0";' >> /etc/apt/apt.conf.d/00-docker
+RUN DEBIAN_FRONTEND=noninteractive \
+ apt-get update && \
+ apt-get install -qq -f -y build-essential clang git cmake libboost-all-dev valgrind linux-sound-base alsa-base alsa-utils libasound2-dev libavahi-client-dev \
+ && rm -rf /var/lib/apt/lists/*
+COPY . .
+RUN ./buildfake.sh
+WORKDIR ./daemon/tests
+CMD ./daemon-test -p
diff --git a/build.sh b/build.sh
index 3f12b0f..2c38df0 100755
--- a/build.sh
+++ b/build.sh
@@ -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/buildfake.sh b/buildfake.sh
new file mode 100755
index 0000000..3d6b550
--- /dev/null
+++ b/buildfake.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+#
+# Tested on Ubuntu 18.04
+#
+
+#we need clang when compiling on ARMv7
+export CC=/usr/bin/clang
+export CXX=/usr/bin/clang++
+
+TOPDIR=$(pwd)
+
+git config --global http.sslverify false
+
+cd 3rdparty
+if [ ! -d ravenna-alsa-lkm ]; then
+ git clone --single-branch --branch aes67-daemon https://github.com/bondagit/ravenna-alsa-lkm.git
+fi
+
+if [ ! -d cpp-httplib ]; then
+ git clone https://github.com/yhirose/cpp-httplib.git
+ cd cpp-httplib
+ git checkout 42f9f9107f87ad2ee04be117dbbadd621c449552
+ cd ..
+fi
+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=OFF -DFAKE_DRIVER=ON .
+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 6d44cb7..770251e 100644
--- a/daemon/session_manager.cpp
+++ b/daemon/session_manager.cpp
@@ -30,7 +30,6 @@
#include
#include
#include