Files
utun2/tools/chatgui/CMakeLists.txt
T
evgeny ffe563bb9f Enable VibeChat UTUN service and package the Wintun driver
Add a settings button to open the current config in an external editor. Wait for core, UTUN and chat startup before reporting readiness; verify startup failures and restarts. Include Wintun DLL and license notices in Windows builds and installers.
2026-10-19 12:33:35 +02:00

777 lines
43 KiB
CMake
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
cmake_minimum_required(VERSION 3.16)
project(vibechat VERSION 0.1.0 LANGUAGES C CXX)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/chatgui_version.txt" "${PROJECT_VERSION}\n")
# Проверка Windows-упаковки с подставленными инструментами выполняется на Unix.
if(UNIX)
find_package(Python3 QUIET COMPONENTS Interpreter)
if(Python3_Interpreter_FOUND)
add_test(NAME test_windows_installer COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/test_windows_installer.py")
endif()
endif()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_C_STANDARD 99)
find_package(OpenSSL REQUIRED)
find_package(Qt6 COMPONENTS Widgets Network Test QUIET)
if(NOT Qt6_FOUND)
find_package(Qt5 COMPONENTS Widgets Network Test REQUIRED)
set(QT_LIBS Qt5::Widgets Qt5::Network)
set(QT_CORE Qt5::Core)
set(QT_TEST_LIB Qt5::Test)
set(QT_PACKAGE Qt5)
else()
set(QT_LIBS Qt6::Widgets Qt6::Network)
set(QT_CORE Qt6::Core)
set(QT_TEST_LIB Qt6::Test)
set(QT_PACKAGE Qt6)
endif()
# Каталоги в ресурсах: перевод работает и в переносимой сборке без файлов рядом с exe.
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/chatgui_qt_package.txt" "${QT_PACKAGE}\n")
get_target_property(QT_QMAKE ${QT_PACKAGE}::qmake IMPORTED_LOCATION)
execute_process(COMMAND "${QT_QMAKE}" -query QT_HOST_BINS
OUTPUT_VARIABLE QT_BINARY_DIR OUTPUT_STRIP_TRAILING_WHITESPACE RESULT_VARIABLE QT_BINARY_RESULT)
if(NOT QT_BINARY_RESULT EQUAL 0)
message(FATAL_ERROR "Cannot query Qt host tools directory")
endif()
find_program(QT_GUI_LRELEASE NAMES lrelease HINTS "${QT_BINARY_DIR}" NO_DEFAULT_PATH)
if(NOT QT_GUI_LRELEASE)
message(FATAL_ERROR "Qt lrelease is required to build GUI translations (install Qt Linguist tools)")
endif()
execute_process(COMMAND "${QT_QMAKE}" -query QT_INSTALL_TRANSLATIONS
OUTPUT_VARIABLE QT_TRANSLATIONS_DIR OUTPUT_STRIP_TRAILING_WHITESPACE RESULT_VARIABLE QT_TRANSLATIONS_RESULT)
if(NOT QT_TRANSLATIONS_RESULT EQUAL 0)
message(FATAL_ERROR "Cannot query Qt translations directory")
endif()
set(QT_RUSSIAN_CATALOG "${QT_TRANSLATIONS_DIR}/qtbase_ru.qm")
if(NOT EXISTS "${QT_RUSSIAN_CATALOG}")
message(FATAL_ERROR "Qt Russian translations missing: ${QT_RUSSIAN_CATALOG}")
endif()
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/translations")
set(GUI_QM_FILES)
foreach(LANGUAGE en ru)
set(QM_FILE "${CMAKE_CURRENT_BINARY_DIR}/translations/chatgui_${LANGUAGE}.qm")
add_custom_command(OUTPUT "${QM_FILE}"
COMMAND "${QT_GUI_LRELEASE}" -nounfinished "${CMAKE_CURRENT_SOURCE_DIR}/translations/chatgui_${LANGUAGE}.ts" -qm "${QM_FILE}"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/translations/chatgui_${LANGUAGE}.ts"
VERBATIM)
list(APPEND GUI_QM_FILES "${QM_FILE}")
endforeach()
add_custom_target(chatgui_translations DEPENDS ${GUI_QM_FILES})
configure_file(translations/translations.qrc.in "${CMAKE_CURRENT_BINARY_DIR}/translations.qrc" @ONLY)
find_package(rlottie REQUIRED HINTS "${CMAKE_CURRENT_SOURCE_DIR}/rlottie_build")
message(STATUS "rlottie package: ${rlottie_DIR}")
find_package(ZLIB REQUIRED)
find_package(OpenSSL REQUIRED)
set(ZXING_READERS ON CACHE BOOL "")
set(ZXING_WRITERS "OLD" CACHE STRING "")
set(ZXING_ENABLE_QRCODE ON CACHE BOOL "")
set(ZXING_ENABLE_AZTEC OFF CACHE BOOL "")
set(ZXING_ENABLE_DATAMATRIX OFF CACHE BOOL "")
set(ZXING_ENABLE_MAXICODE OFF CACHE BOOL "")
set(ZXING_ENABLE_PDF417 OFF CACHE BOOL "")
set(ZXING_ENABLE_1D OFF CACHE BOOL "")
set(ZXING_C_API OFF CACHE BOOL "")
set(ZXING_EXAMPLES OFF CACHE BOOL "")
set(ZXING_EXAMPLES_QT OFF CACHE BOOL "")
set(ZXING_BLACKBOX_TESTS OFF CACHE BOOL "")
set(ZXING_UNIT_TESTS OFF CACHE BOOL "")
set(BUILD_SHARED_LIBS OFF CACHE BOOL "")
add_subdirectory(zxing-cpp)
set_target_properties(ZXing PROPERTIES AUTOMOC OFF)
# FFmpeg - custom built shared libraries
set(FFMPEG_INSTALL_DIR "${CMAKE_SOURCE_DIR}/ffmpeg/ffmpeg_build/install")
set(ENV{PKG_CONFIG_PATH} "${FFMPEG_INSTALL_DIR}/lib/pkgconfig")
find_package(PkgConfig QUIET)
if(PkgConfig_FOUND)
pkg_check_modules(FFMPEG_PC libavcodec libavformat libavutil libswscale libswresample IMPORTED_TARGET)
if(FFMPEG_PC_FOUND)
set(FFMPEG_FOUND TRUE)
set(FFMPEG_TARGET PkgConfig::FFMPEG_PC)
set(FFMPEG_INCLUDE_DIRS "${FFMPEG_PC_INCLUDE_DIRS}")
endif()
endif()
if(NOT FFMPEG_FOUND)
message(STATUS "pkg-config search failed, trying direct library search")
find_path(FFMPEG_INCLUDE_DIR libavcodec/avcodec.h PATHS "${FFMPEG_INSTALL_DIR}/include" NO_DEFAULT_PATH)
find_library(AVCODEC_LIBRARY avcodec PATHS "${FFMPEG_INSTALL_DIR}/lib" NO_DEFAULT_PATH)
find_library(AVFORMAT_LIBRARY avformat PATHS "${FFMPEG_INSTALL_DIR}/lib" NO_DEFAULT_PATH)
find_library(AVUTIL_LIBRARY avutil PATHS "${FFMPEG_INSTALL_DIR}/lib" NO_DEFAULT_PATH)
find_library(SWSCALE_LIBRARY swscale PATHS "${FFMPEG_INSTALL_DIR}/lib" NO_DEFAULT_PATH)
find_library(SWRESAMPLE_LIBRARY swresample PATHS "${FFMPEG_INSTALL_DIR}/lib" NO_DEFAULT_PATH)
if(FFMPEG_INCLUDE_DIR AND AVCODEC_LIBRARY AND AVFORMAT_LIBRARY AND AVUTIL_LIBRARY)
set(FFMPEG_FOUND TRUE)
set(FFMPEG_INCLUDE_DIRS "${FFMPEG_INCLUDE_DIR}")
set(FFMPEG_LIBRARIES "${AVCODEC_LIBRARY}" "${AVFORMAT_LIBRARY}" "${AVUTIL_LIBRARY}" "${SWSCALE_LIBRARY}" "${SWRESAMPLE_LIBRARY}")
message(STATUS "FFmpeg found via direct search")
endif()
endif()
if(NOT FFMPEG_FOUND)
message(WARNING "FFmpeg not found at ${FFMPEG_INSTALL_DIR}. Video transcoding disabled. Run ./ffmpeg/build_ffmpeg.sh to enable.")
set(FFMPEG_TARGET "")
set(FFMPEG_LIBRARIES "")
set(FFMPEG_INCLUDE_DIRS "")
endif()
if(UNIX AND NOT APPLE AND FFMPEG_FOUND)
set(CMAKE_BUILD_RPATH "${FFMPEG_INSTALL_DIR}/lib")
set(CMAKE_INSTALL_RPATH "${FFMPEG_INSTALL_DIR}/lib")
endif()
# uTun core library (C, built from ../src/ and ../lib/)
add_subdirectory(libutun)
# Ручная проверка codec backend перед включением в capabilities звонка; не часть ctest.
if(PkgConfig_FOUND)
pkg_check_modules(CALL_X265 QUIET x265 IMPORTED_TARGET)
if(CALL_X265_FOUND)
add_executable(probe_call_x265 EXCLUDE_FROM_ALL tests/probe_call_x265.cpp)
target_link_libraries(probe_call_x265 PRIVATE utun PkgConfig::CALL_X265)
endif()
endif()
# Общий sender остаётся в libutun; Qt захватывает видео, FFmpeg/Opus работают в publisher workers.
add_library(chatgui_live_video STATIC src/live_video_encoder.cpp src/call_video_encoder.cpp src/call_video_decoder.cpp)
target_link_libraries(chatgui_live_video PUBLIC ${QT_LIBS} utun PRIVATE ${FFMPEG_TARGET} ${FFMPEG_LIBRARIES})
target_include_directories(chatgui_live_video PRIVATE ${FFMPEG_INCLUDE_DIRS})
if(FFMPEG_FOUND)
target_compile_definitions(chatgui_live_video PRIVATE HAVE_FFMPEG)
add_executable(test_video_frame_image tests/test_video_frame_image.cpp)
target_compile_definitions(test_video_frame_image PRIVATE HAVE_FFMPEG)
target_include_directories(test_video_frame_image PRIVATE ${FFMPEG_INCLUDE_DIRS})
target_link_libraries(test_video_frame_image PRIVATE ${QT_LIBS} ${QT_TEST_LIB} utun ${FFMPEG_TARGET} ${FFMPEG_LIBRARIES})
add_test(NAME test_video_frame_image COMMAND test_video_frame_image)
set_tests_properties(test_video_frame_image PROPERTIES TIMEOUT 30)
add_executable(test_call_video_encoder tests/test_call_video_encoder.cpp)
target_include_directories(test_call_video_encoder PRIVATE ${FFMPEG_INCLUDE_DIRS})
target_link_libraries(test_call_video_encoder PRIVATE chatgui_live_video ${QT_TEST_LIB} ${FFMPEG_TARGET} ${FFMPEG_LIBRARIES})
add_test(NAME test_call_video_encoder COMMAND test_call_video_encoder)
set_tests_properties(test_call_video_encoder PROPERTIES TIMEOUT 120)
if(UNIX AND NOT APPLE)
add_executable(test_call_video_gpu tests/test_call_video_gpu.cpp)
target_include_directories(test_call_video_gpu PRIVATE ${FFMPEG_INCLUDE_DIRS})
target_link_libraries(test_call_video_gpu PRIVATE chatgui_live_video ${QT_TEST_LIB} ${FFMPEG_TARGET} ${FFMPEG_LIBRARIES})
foreach(symbol avcodec_find_encoder_by_name avcodec_open2 avcodec_send_frame avcodec_receive_packet avcodec_free_context)
target_link_options(test_call_video_gpu PRIVATE "-Wl,--wrap=${symbol}")
endforeach()
add_test(NAME test_call_video_gpu COMMAND test_call_video_gpu)
set_tests_properties(test_call_video_gpu PROPERTIES TIMEOUT 60)
add_executable(test_call_video_clock tests/test_call_video_clock.cpp src/call_video_engine.cpp)
target_link_libraries(test_call_video_clock PRIVATE chatgui_live_video)
foreach(symbol call_audio_get_clock call_video_port_open call_video_port_close call_video_port_status
call_video_port_pull call_video_port_request_key call_video_port_decoded)
target_link_options(test_call_video_clock PRIVATE "-Wl,--wrap=${symbol}")
endforeach()
add_test(NAME test_call_video_clock COMMAND test_call_video_clock)
set_tests_properties(test_call_video_clock PROPERTIES TIMEOUT 15)
endif()
endif()
add_library(chatgui_camera STATIC src/call_camera_capture.cpp src/call_camera_worker.cpp src/call_camera_source.h)
target_link_libraries(chatgui_camera PUBLIC ${QT_LIBS} utun)
add_library(chatgui_audio_capture STATIC src/audio_capture.cpp)
target_link_libraries(chatgui_audio_capture PUBLIC ${QT_LIBS} utun)
if(WIN32)
target_link_libraries(chatgui_audio_capture PRIVATE ole32)
endif()
add_library(chatgui_stream_publish STATIC src/stream_publish_engine.cpp src/stream_publish_window.cpp src/call_video_engine.cpp)
target_link_libraries(chatgui_stream_publish PUBLIC chatgui_live_video chatgui_camera chatgui_audio_capture)
target_include_directories(chatgui_stream_publish PRIVATE ${CMAKE_SOURCE_DIR}/../../lib/libopus/include)
set(GUI_CAPTURE_ENABLED 0)
if(QT_PACKAGE STREQUAL "Qt6" AND FFMPEG_FOUND)
set(GUI_BASE_QT6_FOUND ${Qt6_FOUND})
find_package(Qt6 6.6 COMPONENTS Multimedia MultimediaWidgets QUIET)
set(Qt6_FOUND ${GUI_BASE_QT6_FOUND})
if(TARGET Qt6::Multimedia AND TARGET Qt6::MultimediaWidgets)
target_compile_definitions(chatgui_stream_publish PUBLIC HAVE_STREAM_CAPTURE)
target_compile_definitions(chatgui_camera PUBLIC HAVE_STREAM_CAPTURE)
target_link_libraries(chatgui_camera PUBLIC Qt6::Multimedia)
target_link_libraries(chatgui_stream_publish PUBLIC Qt6::Multimedia Qt6::MultimediaWidgets)
add_executable(test_call_camera_capture tests/test_call_camera_capture.cpp)
target_link_libraries(test_call_camera_capture PRIVATE chatgui_camera ${QT_TEST_LIB})
if(UNIX AND NOT APPLE)
target_sources(test_call_camera_capture PRIVATE src/call_video_engine.cpp)
target_compile_definitions(test_call_camera_capture PRIVATE TEST_CALL_VIDEO_ENGINE)
target_link_libraries(test_call_camera_capture PRIVATE chatgui_live_video)
foreach(symbol call_audio_get_clock call_video_port_open call_video_port_close call_video_port_status
call_video_port_pull call_video_port_request_key call_video_port_decoded)
target_link_options(test_call_camera_capture PRIVATE "-Wl,--wrap=${symbol}")
endforeach()
endif()
add_test(NAME test_call_camera_capture COMMAND test_call_camera_capture)
set_tests_properties(test_call_camera_capture PROPERTIES TIMEOUT 40 ENVIRONMENT "QT_QPA_PLATFORM=offscreen")
set(GUI_CAPTURE_ENABLED 1)
else()
message(STATUS "Qt Multimedia 6.6+ missing: stream publication unavailable")
endif()
endif()
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/chatgui_capture_enabled.txt" "${GUI_CAPTURE_ENABLED}\n")
if(GUI_CAPTURE_ENABLED AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
find_package(Qt6 COMPONENTS DBus REQUIRED)
pkg_check_modules(STREAM_PIPEWIRE REQUIRED IMPORTED_TARGET libpipewire-0.3>=0.3.44)
add_library(chatgui_portal_capture STATIC src/stream_portal_capture.cpp)
target_link_libraries(chatgui_portal_capture PUBLIC Qt6::Multimedia Qt6::DBus PRIVATE utun PkgConfig::STREAM_PIPEWIRE)
target_compile_definitions(chatgui_stream_publish PUBLIC UTUN_STREAM_PORTAL)
target_link_libraries(chatgui_stream_publish PRIVATE chatgui_portal_capture)
add_executable(test_stream_portal tests/test_stream_portal.cpp)
target_link_libraries(test_stream_portal PRIVATE chatgui_portal_capture Qt6::Network ${QT_TEST_LIB} utun)
find_program(STREAM_DBUS_RUN_SESSION dbus-run-session REQUIRED)
add_test(NAME test_stream_portal COMMAND ${STREAM_DBUS_RUN_SESSION} -- $<TARGET_FILE:test_stream_portal>)
set_tests_properties(test_stream_portal PROPERTIES TIMEOUT 45)
endif()
if(GUI_CAPTURE_ENABLED AND UNIX AND NOT APPLE AND QT_FEATURE_xcb)
find_package(X11 REQUIRED COMPONENTS Xfixes)
target_sources(chatgui_stream_publish PRIVATE src/stream_screen_cursor.cpp)
target_compile_definitions(chatgui_stream_publish PUBLIC UTUN_STREAM_X11_CURSOR)
target_link_libraries(chatgui_stream_publish PRIVATE X11::X11 X11::Xfixes)
endif()
if(GUI_CAPTURE_ENABLED AND WIN32)
if(Qt6_VERSION VERSION_GREATER_EQUAL 6.7)
target_sources(chatgui_stream_publish PRIVATE src/stream_screen_cursor_win.cpp)
target_compile_definitions(chatgui_stream_publish PUBLIC UTUN_STREAM_WIN_CURSOR)
target_link_libraries(chatgui_stream_publish PRIVATE user32 gdi32)
else()
message(STATUS "Windows cursor overlay requires Qt 6.7+ native monitor handles")
endif()
endif()
add_library(chatgui_notifications STATIC src/message_notification.cpp src/user_activity_monitor.cpp)
target_link_libraries(chatgui_notifications PUBLIC ${QT_PACKAGE}::Widgets PRIVATE utun)
if(WIN32)
target_link_libraries(chatgui_notifications PRIVATE user32)
elseif(APPLE)
target_link_libraries(chatgui_notifications PRIVATE "-framework ApplicationServices")
endif()
# Голосовой стек звонка (SoundTouch + voice_jitter + call_audio + call_tones),
# C++ внутри, C-интерфейс наружу (call_audio.h).
set(LIB_DIR "${CMAKE_SOURCE_DIR}/../../lib")
set(CALL_DIR "${CMAKE_SOURCE_DIR}/../../src/call")
include(${CALL_DIR}/voice_sources.cmake)
utun_setup_voice("${LIB_DIR}" "${CALL_DIR}")
add_library(utun_voice STATIC ${UTUN_VOICE_SOURCES})
target_include_directories(utun_voice PUBLIC ${UTUN_VOICE_INCLUDE_DIRS})
set_source_files_properties(${CALL_DIR}/call_audio.c ${CALL_DIR}/call_tones.c PROPERTIES LANGUAGE C)
set_source_files_properties(${CMAKE_SOURCE_DIR}/../../src/radio/radio_audio.c PROPERTIES LANGUAGE C)
set_target_properties(utun_voice PROPERTIES POSITION_INDEPENDENT_CODE ON)
add_executable(vibechat WIN32
src/main.cpp
src/single_instance.cpp
src/mainwindow.cpp
src/channellist.cpp
src/creategroupdialog.cpp
src/channeldelegate.cpp
src/channelsettingsdialog.cpp
src/chatview.cpp
src/messagedelegate.cpp
src/message_links.cpp
src/messagelist.cpp
src/attachment_key_ui.cpp
src/messagefeedback.cpp
src/accountlist.cpp
src/accountdelegate.cpp
src/flagpainter.cpp
src/memberpropsdialog.cpp
src/renamedialog.cpp
src/memberlistmodel.cpp
src/emoji.cpp
src/emojipanel.cpp
src/emojitabbar.cpp
src/inputbar.cpp
src/lottieicon.cpp
src/animtimer.cpp
src/qrcode_utils.cpp
src/invite_link.cpp
src/invitedialog.cpp
src/dminvitedialog.cpp
src/inviteby.cpp
src/joindialog.cpp
src/settingsdialog.cpp
src/networksettingspage.cpp
src/databasesettingspage.cpp
src/statuspage.cpp
src/nodespage.cpp
src/soundsettingspage.cpp
src/sound_manager.cpp
src/voice_audio_io.cpp
src/audio_device.cpp
src/audiorecorder.cpp
src/voicemessageencoder.cpp
src/voiceplayback.cpp
src/media_blocks.cpp
src/videoplayer_engine.cpp
src/videoplayer_window.cpp
src/streamplayer_window.cpp
src/imageviewer_window.cpp
src/member_files/browser.cpp
src/member_files/batch.cpp
src/avatars/avatarcache.cpp
src/avatars/avatarcrop.cpp
src/avatars/avatargallery.cpp
src/avatars/avatarmanager.cpp
src/avatars/groupavatarmanager.cpp
src/audiodevicesettingspage.cpp
src/storagesettingspage.cpp
src/connmonitorwindow.cpp
src/callwindow.cpp
src/call_audio_engine.cpp
src/radio_audio_engine.cpp
src/radiopanel.cpp
src/ptt_hotkey_manager.cpp
src/radiosettingspage.cpp
transport/utun_node.cpp
transport/node_config.cpp
transport/config_updater.cpp
transport/gui_bridge_impl.cpp
transport/stream_bridge.cpp
transport/miniaudio_impl.c
transport/audio_diagnostics.cpp
db/db_manager.cpp
../../lib/sqlite3.c
resources/chatgui.qrc
"${CMAKE_CURRENT_BINARY_DIR}/translations.qrc"
)
add_dependencies(vibechat chatgui_translations)
# Проводник и ярлыки Windows читают значок из EXE до запуска Qt.
if(WIN32)
enable_language(RC)
configure_file(resources/vibechat.rc.in "${CMAKE_CURRENT_BINARY_DIR}/vibechat.rc" @ONLY)
target_sources(vibechat PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/vibechat.rc")
set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/vibechat.rc" PROPERTIES
OBJECT_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/resources/icons/app_icon.ico")
message(STATUS "Windows executable icon: resources/icons/app_icon.ico")
# Wintun загружается через LoadLibrary и не попадает в обход импортов EXE.
add_custom_command(TARGET vibechat POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/../../lib/wintun.dll"
"$<TARGET_FILE_DIR:vibechat>/wintun.dll"
COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:vibechat>/licenses/wintun"
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/../../lib/wintun-LICENSE.txt"
"${CMAKE_CURRENT_SOURCE_DIR}/../../lib/wintun-api-LICENSE.txt"
"$<TARGET_FILE_DIR:vibechat>/licenses/wintun"
COMMENT "Deploying Wintun driver DLL and licenses" VERBATIM)
endif()
target_include_directories(vibechat PRIVATE ${CMAKE_SOURCE_DIR}/../../lib ${CMAKE_SOURCE_DIR}/../../src ${CMAKE_SOURCE_DIR}/db ${CMAKE_SOURCE_DIR}/../../lib/libopus/include ${FFMPEG_INCLUDE_DIRS})
target_compile_definitions(vibechat PRIVATE SQLITE_THREADSAFE=1 USE_SQLITE VIBECHAT_VERSION="${PROJECT_VERSION}")
# Лицензии лежат рядом с бинарником при сборке и устанавливаются с приложением.
set(UTUN_LICENSE_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/../../LICENSE"
"${CMAKE_CURRENT_SOURCE_DIR}/../../LICENSING"
"${CMAKE_CURRENT_SOURCE_DIR}/../../THIRD_PARTY_NOTICES")
add_custom_target(vibechat_licenses ALL
COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:vibechat>/licenses"
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${UTUN_LICENSE_FILES} "$<TARGET_FILE_DIR:vibechat>/licenses"
COMMENT "Copying uTun license documents")
install(FILES ${UTUN_LICENSE_FILES} DESTINATION share/licenses/utun)
if(FFMPEG_FOUND)
target_compile_definitions(vibechat PRIVATE HAVE_FFMPEG)
endif()
set_source_files_properties(../../lib/sqlite3.c transport/miniaudio_impl.c PROPERTIES LANGUAGE C)
# Глобальное состояние клавиатуры для PTT: Windows user32 / Linux X11.
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
find_package(X11 REQUIRED)
if(Qt6_FOUND)
find_package(Qt6 COMPONENTS DBus REQUIRED)
set(QT_DBUS Qt6::DBus)
else()
find_package(Qt5 COMPONENTS DBus REQUIRED)
set(QT_DBUS Qt5::DBus)
endif()
target_sources(vibechat PRIVATE src/ptt_portal.cpp)
target_compile_definitions(vibechat PRIVATE UTUN_PTT_PORTAL)
target_link_libraries(vibechat PRIVATE ${QT_DBUS})
target_include_directories(vibechat PRIVATE ${X11_INCLUDE_DIR})
target_compile_definitions(chatgui_notifications PRIVATE UTUN_ACTIVITY_DBUS)
target_link_libraries(chatgui_notifications PRIVATE ${QT_DBUS})
if(Qt6_FOUND)
find_package(KF6IdleTime QUIET)
set(ACTIVITY_KIDLETIME_TARGET KF6::IdleTime)
else()
find_package(KF5IdleTime QUIET)
set(ACTIVITY_KIDLETIME_TARGET KF5::IdleTime)
endif()
if(TARGET ${ACTIVITY_KIDLETIME_TARGET})
target_compile_definitions(chatgui_notifications PRIVATE UTUN_ACTIVITY_KIDLETIME)
target_link_libraries(chatgui_notifications PRIVATE ${ACTIVITY_KIDLETIME_TARGET})
else()
message(STATUS "KIdleTime not found: Wayland activity uses GNOME IdleMonitor or ChatGUI input")
endif()
elseif(UNIX AND NOT APPLE)
find_package(X11 QUIET)
endif()
if(TARGET X11::X11)
target_link_libraries(chatgui_notifications PRIVATE X11::X11)
endif()
if(TARGET X11::Xss)
target_compile_definitions(chatgui_notifications PRIVATE UTUN_ACTIVITY_X11)
target_link_libraries(chatgui_notifications PRIVATE X11::Xss)
elseif(UNIX AND NOT APPLE)
message(STATUS "X11 screen saver library not found: X11 activity uses ChatGUI input")
endif()
target_link_libraries(vibechat PRIVATE chatgui_notifications chatgui_stream_publish)
if(WIN32)
target_link_libraries(vibechat PRIVATE ${QT_LIBS} rlottie::rlottie ZLIB::ZLIB OpenSSL::Crypto ZXing::ZXing utun utun_voice pthread user32 ${FFMPEG_TARGET} ${FFMPEG_LIBRARIES})
else()
target_link_libraries(vibechat PRIVATE ${QT_LIBS} rlottie::rlottie ZLIB::ZLIB OpenSSL::Crypto ZXing::ZXing utun utun_voice pthread dl ${X11_LIBRARIES} ${FFMPEG_TARGET} ${FFMPEG_LIBRARIES})
endif()
# ============================================================================
# Tests
# ============================================================================
add_executable(test_member_sync
../../lib/sqlite3.c
../../tests/test_member_sync.c
)
target_include_directories(test_member_sync PRIVATE
transport ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/../../lib
${CMAKE_SOURCE_DIR}/../../src
zxing-cpp/core/src ../../tests
)
target_compile_definitions(test_member_sync PRIVATE USE_SQLITE SQLITE_THREADSAFE=1)
set_source_files_properties(../../lib/sqlite3.c ../../tests/test_member_sync.c PROPERTIES LANGUAGE C)
if(WIN32)
target_link_libraries(test_member_sync PRIVATE OpenSSL::Crypto pthread)
else()
target_link_libraries(test_member_sync PRIVATE OpenSSL::Crypto pthread dl)
endif()
# ============================================================================
# Tests
# ============================================================================
enable_testing()
add_executable(test_single_instance tests/test_single_instance.cpp src/single_instance.cpp)
target_link_libraries(test_single_instance PRIVATE ${QT_LIBS} ${QT_TEST_LIB} utun pthread ${CMAKE_DL_LIBS})
if(WIN32)
target_link_libraries(test_single_instance PRIVATE user32)
endif()
add_test(NAME test_single_instance COMMAND test_single_instance)
set_tests_properties(test_single_instance PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" TIMEOUT 30)
add_executable(test_message_notification tests/test_message_notification.cpp)
target_link_libraries(test_message_notification PRIVATE chatgui_notifications ${QT_TEST_LIB} pthread ${CMAKE_DL_LIBS})
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
find_program(NOTIFICATION_DBUS_RUN_SESSION NAMES dbus-run-session)
if(NOT NOTIFICATION_DBUS_RUN_SESSION)
message(FATAL_ERROR "dbus-run-session is required for the isolated notification test")
endif()
target_compile_definitions(test_message_notification PRIVATE UTUN_TEST_ACTIVITY_DBUS)
target_link_libraries(test_message_notification PRIVATE ${QT_DBUS})
add_test(NAME test_message_notification COMMAND ${NOTIFICATION_DBUS_RUN_SESSION} -- $<TARGET_FILE:test_message_notification>)
else()
add_test(NAME test_message_notification COMMAND test_message_notification)
endif()
set_tests_properties(test_message_notification PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" TIMEOUT 60)
add_executable(test_message_events tests/test_message_events.cpp transport/gui_bridge_impl.cpp)
target_link_libraries(test_message_events PRIVATE ${QT_LIBS} ${QT_TEST_LIB} utun utun_voice pthread ${CMAKE_DL_LIBS})
add_test(NAME test_message_events COMMAND test_message_events)
set_tests_properties(test_message_events PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" TIMEOUT 15)
# Ручной запуск с DISPLAY: проверяет применение desktop hints оконным менеджером, не меняя настройки рабочих столов.
if(TARGET X11::X11)
add_executable(test_message_notification_x11 tests/test_message_notification_x11.cpp)
target_link_libraries(test_message_notification_x11 PRIVATE chatgui_notifications ${QT_TEST_LIB} X11::X11 pthread ${CMAKE_DL_LIBS})
endif()
add_executable(test_file_drop tests/test_file_drop.cpp src/inputbar.cpp src/audiorecorder.cpp src/audio_device.cpp src/sound_manager.cpp
src/voicemessageencoder.cpp src/emojipanel.cpp src/emojitabbar.cpp src/emoji.cpp src/animtimer.cpp src/lottieicon.cpp
src/voice_audio_io.cpp transport/miniaudio_impl.c transport/audio_diagnostics.cpp)
target_include_directories(test_file_drop PRIVATE ${UTUN_INCLUDE_DIRS})
target_link_libraries(test_file_drop PRIVATE ${QT_LIBS} ${QT_TEST_LIB} rlottie::rlottie ZLIB::ZLIB
utun_voice utun pthread ${CMAKE_DL_LIBS})
add_test(NAME test_file_drop COMMAND test_file_drop)
set_tests_properties(test_file_drop PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" TIMEOUT 30)
add_executable(test_channel_replies tests/test_channel_replies.cpp db/db_manager.cpp src/nodespage.cpp)
target_include_directories(test_channel_replies PRIVATE ${UTUN_INCLUDE_DIRS})
target_link_libraries(test_channel_replies PRIVATE ${QT_LIBS} ${QT_TEST_LIB} utun utun_voice pthread ${CMAKE_DL_LIBS})
add_test(NAME test_channel_replies COMMAND test_channel_replies)
set_tests_properties(test_channel_replies PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" TIMEOUT 30)
add_executable(test_member_files_browser tests/test_member_files_browser.cpp src/member_files/browser.cpp src/member_files/batch.cpp db/db_manager.cpp
src/channellist.cpp src/channeldelegate.cpp src/avatars/groupavatarmanager.cpp)
target_link_libraries(test_member_files_browser PRIVATE ${QT_LIBS} ${QT_TEST_LIB} utun pthread)
add_test(NAME test_member_files_browser COMMAND test_member_files_browser)
set_tests_properties(test_member_files_browser PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" TIMEOUT 30)
add_executable(test_avatars tests/test_avatars.cpp src/avatars/avatarcache.cpp src/avatars/avatarmanager.cpp
src/avatars/avatarcrop.cpp src/avatars/avatargallery.cpp src/imageviewer_window.cpp db/db_manager.cpp)
target_link_libraries(test_avatars PRIVATE ${QT_LIBS} ${QT_TEST_LIB} utun pthread)
add_test(NAME test_avatars COMMAND test_avatars)
set_tests_properties(test_avatars PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" TIMEOUT 60)
add_executable(test_group_avatars tests/test_group_avatars.cpp src/avatars/groupavatarmanager.cpp src/channelsettingsdialog.cpp db/db_manager.cpp)
target_link_libraries(test_group_avatars PRIVATE ${QT_LIBS} ${QT_TEST_LIB} utun pthread)
add_test(NAME test_group_avatars COMMAND test_group_avatars)
set_tests_properties(test_group_avatars PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" TIMEOUT 30)
add_executable(test_gui_language tests/test_gui_language.cpp src/networksettingspage.cpp
transport/node_config.cpp transport/config_updater.cpp "${CMAKE_CURRENT_BINARY_DIR}/translations.qrc")
add_dependencies(test_gui_language chatgui_translations)
target_compile_definitions(test_gui_language PRIVATE GUI_TS_DIR="${CMAKE_CURRENT_SOURCE_DIR}/translations")
target_link_libraries(test_gui_language PRIVATE ${QT_LIBS} ${QT_TEST_LIB} OpenSSL::Crypto utun pthread)
add_test(NAME test_gui_language COMMAND test_gui_language)
set_tests_properties(test_gui_language PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" TIMEOUT 30)
add_executable(test_emoji_playback tests/test_emoji_playback.cpp src/animtimer.cpp src/lottieicon.cpp
src/emojipanel.cpp src/emojitabbar.cpp src/emoji.cpp src/chatview.cpp)
target_link_libraries(test_emoji_playback PRIVATE ${QT_LIBS} ${QT_TEST_LIB} rlottie::rlottie ZLIB::ZLIB utun)
add_test(NAME test_emoji_playback COMMAND test_emoji_playback)
set_tests_properties(test_emoji_playback PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" TIMEOUT 30)
add_executable(test_invite_links tests/test_invite_links.cpp src/message_links.cpp src/messagedelegate.cpp src/chatview.cpp
src/accountdelegate.cpp src/flagpainter.cpp src/animtimer.cpp src/lottieicon.cpp src/emoji.cpp
src/voiceplayback.cpp src/sound_manager.cpp src/voice_audio_io.cpp src/audio_device.cpp
transport/miniaudio_impl.c transport/audio_diagnostics.cpp)
target_include_directories(test_invite_links PRIVATE ${UTUN_INCLUDE_DIRS})
target_link_libraries(test_invite_links PRIVATE ${QT_LIBS} ${QT_TEST_LIB} rlottie::rlottie ZLIB::ZLIB utun_voice utun pthread ${CMAKE_DL_LIBS})
add_test(NAME test_invite_links COMMAND test_invite_links)
set_tests_properties(test_invite_links PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" TIMEOUT 30)
add_executable(test_local_invite_ui tests/test_local_invite_ui.cpp src/invitedialog.cpp src/qrcode_utils.cpp)
target_include_directories(test_local_invite_ui PRIVATE ${UTUN_INCLUDE_DIRS})
target_link_libraries(test_local_invite_ui PRIVATE ${QT_LIBS} ${QT_TEST_LIB} ZXing::ZXing utun)
add_test(NAME test_local_invite_ui COMMAND test_local_invite_ui)
set_tests_properties(test_local_invite_ui PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" TIMEOUT 30)
add_executable(test_config_updater
tests/test_config_updater.cpp
transport/config_updater.cpp
)
target_include_directories(test_config_updater PRIVATE ${CMAKE_SOURCE_DIR})
target_link_libraries(test_config_updater PRIVATE ${QT_CORE} pthread)
add_test(NAME test_config_updater COMMAND test_config_updater)
# тест адаптивного джиттер-буфера голоса (кодированные кадры + SoundTouch time-stretch)
add_executable(test_radio_jitter
tests/test_radio_jitter.cpp
)
target_include_directories(test_radio_jitter PRIVATE ${CMAKE_SOURCE_DIR}/../../src)
target_link_libraries(test_radio_jitter PRIVATE utun_voice pthread)
add_test(NAME test_radio_jitter COMMAND test_radio_jitter)
add_executable(test_call_jitter tests/test_call_jitter.cpp)
target_include_directories(test_call_jitter PRIVATE ${CMAKE_SOURCE_DIR}/../../src)
target_link_libraries(test_call_jitter PRIVATE utun_voice utun pthread)
add_test(NAME test_call_jitter COMMAND test_call_jitter)
add_executable(test_call_delay tests/test_call_delay.cpp)
target_link_libraries(test_call_delay PRIVATE utun_voice utun pthread)
add_test(NAME test_call_delay COMMAND test_call_delay)
add_executable(test_soundtouch_clock tests/test_soundtouch_clock.cpp)
target_link_libraries(test_soundtouch_clock PRIVATE utun_voice utun pthread)
add_test(NAME test_soundtouch_clock COMMAND test_soundtouch_clock)
add_executable(test_call_timeline tests/test_call_timeline.cpp)
target_link_libraries(test_call_timeline PRIVATE utun_voice utun pthread)
add_test(NAME test_call_timeline COMMAND test_call_timeline)
# тест аудио-движка рации (per-source jitter + микшер + soft-clip)
add_executable(test_radio_audio
tests/test_radio_audio.cpp
)
target_include_directories(test_radio_audio PRIVATE ${CMAKE_SOURCE_DIR}/../../src ${CMAKE_SOURCE_DIR}/../../lib ${CMAKE_SOURCE_DIR}/../../lib/libopus/include)
target_link_libraries(test_radio_audio PRIVATE utun_voice utun pthread)
add_test(NAME test_radio_audio COMMAND test_radio_audio)
add_executable(test_radio_member_mute tests/test_radio_member_mute.cpp)
target_include_directories(test_radio_member_mute PRIVATE ${UTUN_INCLUDE_DIRS})
target_link_libraries(test_radio_member_mute PRIVATE ${QT_CORE} utun_voice utun pthread)
add_test(NAME test_radio_member_mute COMMAND test_radio_member_mute)
set(RADIO_MEMBER_TEST_SOURCES src/memberlistmodel.cpp src/avatars/avatarcache.cpp src/avatars/avatarmanager.cpp
src/avatars/avatarcrop.cpp src/avatars/avatargallery.cpp src/imageviewer_window.cpp db/db_manager.cpp)
add_executable(test_radio_mute_bridge tests/test_radio_mute_bridge.cpp transport/utun_node.cpp transport/gui_bridge_impl.cpp transport/stream_bridge.cpp
src/accountdelegate.cpp src/flagpainter.cpp ${RADIO_MEMBER_TEST_SOURCES})
target_include_directories(test_radio_mute_bridge PRIVATE ${UTUN_INCLUDE_DIRS})
target_link_libraries(test_radio_mute_bridge PRIVATE ${QT_LIBS} ${QT_TEST_LIB} utun_voice utun pthread)
add_test(NAME test_radio_mute_bridge COMMAND test_radio_mute_bridge)
set_tests_properties(test_radio_mute_bridge PROPERTIES TIMEOUT 15 ENVIRONMENT "QT_QPA_PLATFORM=offscreen")
add_executable(test_utun_node tests/test_utun_node.cpp transport/utun_node.cpp transport/gui_bridge_impl.cpp transport/stream_bridge.cpp)
target_include_directories(test_utun_node PRIVATE ${UTUN_INCLUDE_DIRS})
target_link_libraries(test_utun_node PRIVATE ${QT_LIBS} ${QT_TEST_LIB} utun_voice utun pthread)
add_test(NAME test_utun_node COMMAND test_utun_node)
set_tests_properties(test_utun_node PROPERTIES TIMEOUT 30 ENVIRONMENT "QT_QPA_PLATFORM=offscreen")
set_tests_properties(test_radio_member_mute PROPERTIES TIMEOUT 20)
if(UNIX AND NOT APPLE)
target_compile_definitions(test_radio_member_mute PRIVATE UTUN_TEST_WRAP_VAD)
target_link_options(test_radio_member_mute PRIVATE "-Wl,--wrap=silero_vad_create_default" "-Wl,--wrap=silero_vad_destroy"
"-Wl,--wrap=silero_vad_reset" "-Wl,--wrap=silero_vad_process")
endif()
add_executable(test_audio_event_queue tests/test_audio_event_queue.cpp)
target_link_libraries(test_audio_event_queue PRIVATE pthread)
add_test(NAME test_audio_event_queue COMMAND test_audio_event_queue)
add_executable(test_voice_audio_io tests/test_voice_audio_io.cpp src/voice_audio_io.cpp)
target_include_directories(test_voice_audio_io PRIVATE ${UTUN_INCLUDE_DIRS})
target_link_libraries(test_voice_audio_io PRIVATE utun pthread)
add_test(NAME test_voice_audio_io COMMAND test_voice_audio_io)
if(ONNXRUNTIME_INCLUDE_DIR AND ONNXRUNTIME_LIB)
add_executable(test_silero_vad ../../tests/test_silero_vad.c)
target_compile_definitions(test_silero_vad PRIVATE TEST_SILERO_SPEECH_PATH="${CMAKE_CURRENT_SOURCE_DIR}/../../tests/data/silero_speech.pcm")
target_link_libraries(test_silero_vad PRIVATE utun)
add_test(NAME test_silero_vad COMMAND test_silero_vad "${CMAKE_CURRENT_SOURCE_DIR}/../../lib/silero_vad.onnx")
endif()
set_tests_properties(test_audio_event_queue test_voice_audio_io PROPERTIES TIMEOUT 15)
if(UNIX AND NOT APPLE)
add_executable(test_audio_timing tests/test_audio_timing.c transport/audio_diagnostics.cpp)
target_link_libraries(test_audio_timing PRIVATE utun pthread dl m)
target_compile_options(test_audio_timing PRIVATE -UNDEBUG)
add_test(NAME test_audio_timing COMMAND test_audio_timing)
add_executable(test_voice_tx tests/test_voice_tx.cpp)
target_include_directories(test_voice_tx PRIVATE ${UTUN_INCLUDE_DIRS})
target_link_libraries(test_voice_tx PRIVATE utun_voice utun pthread)
target_link_options(test_voice_tx PRIVATE "-Wl,--wrap=radio_talk_begin" "-Wl,--wrap=radio_talk_end"
"-Wl,--wrap=radio_talk_send" "-Wl,--wrap=call_send_media" "-Wl,--wrap=chat_setting_get_int"
"-Wl,--wrap=silero_vad_create_default" "-Wl,--wrap=silero_vad_destroy" "-Wl,--wrap=silero_vad_reset"
"-Wl,--wrap=silero_vad_process" "-Wl,--wrap=get_time_tb")
add_test(NAME test_voice_tx COMMAND test_voice_tx)
endif()
# smoke-тест видео-декодера (FFmpeg). Ручной запуск: test_video_engine <mp4>
add_executable(test_video_engine
tests/test_video_engine.cpp
src/videoplayer_engine.cpp
src/sound_manager.cpp
src/voice_audio_io.cpp
src/audio_device.cpp
transport/miniaudio_impl.c
transport/audio_diagnostics.cpp
)
target_include_directories(test_video_engine PRIVATE ${CMAKE_SOURCE_DIR}/../../lib ${CMAKE_SOURCE_DIR}/../../src ${CMAKE_SOURCE_DIR}/db ${CMAKE_SOURCE_DIR}/../../lib/libopus/include ${FFMPEG_INCLUDE_DIRS})
target_compile_definitions(test_video_engine PRIVATE USE_SQLITE SQLITE_THREADSAFE=1)
if(FFMPEG_FOUND)
target_compile_definitions(test_video_engine PRIVATE HAVE_FFMPEG)
endif()
set_source_files_properties(transport/miniaudio_impl.c PROPERTIES LANGUAGE C)
if(WIN32)
target_link_libraries(test_video_engine PRIVATE ${QT_LIBS} ${QT_CORE} utun_voice utun pthread ${FFMPEG_TARGET} ${FFMPEG_LIBRARIES})
else()
target_link_libraries(test_video_engine PRIVATE ${QT_LIBS} ${QT_CORE} utun_voice utun pthread dl ${FFMPEG_TARGET} ${FFMPEG_LIBRARIES})
endif()
add_executable(test_ptt_key_chord tests/test_ptt_key_chord.cpp)
add_executable(test_stream_view tests/test_stream_view.cpp src/streamplayer_window.cpp transport/stream_bridge.cpp
src/videoplayer_window.cpp src/videoplayer_engine.cpp src/sound_manager.cpp src/voice_audio_io.cpp src/audio_device.cpp
transport/miniaudio_impl.c transport/audio_diagnostics.cpp)
target_include_directories(test_stream_view PRIVATE ${UTUN_INCLUDE_DIRS} ${FFMPEG_INCLUDE_DIRS})
target_link_libraries(test_stream_view PRIVATE ${QT_LIBS} ${QT_TEST_LIB} utun_voice utun pthread ${CMAKE_DL_LIBS} ${FFMPEG_TARGET} ${FFMPEG_LIBRARIES})
if(FFMPEG_FOUND)
target_compile_definitions(test_stream_view PRIVATE HAVE_FFMPEG)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_compile_definitions(test_stream_view PRIVATE TEST_NULL_AUDIO)
target_link_options(test_stream_view PRIVATE "-Wl,--wrap=ma_context_init" "-Wl,--wrap=ma_device_init"
"-Wl,--wrap=audio_stream_frame_time")
if(FFMPEG_FOUND)
target_link_options(test_stream_view PRIVATE "-Wl,--wrap=avcodec_open2" "-Wl,--wrap=avcodec_receive_frame"
"-Wl,--wrap=avcodec_free_context")
endif()
endif()
add_test(NAME test_stream_view COMMAND test_stream_view)
set_tests_properties(test_stream_view PROPERTIES TIMEOUT 30 ENVIRONMENT "QT_QPA_PLATFORM=offscreen")
add_executable(test_stream_audio tests/test_stream_audio.cpp)
target_include_directories(test_stream_audio PRIVATE ${UTUN_INCLUDE_DIRS})
target_link_libraries(test_stream_audio PRIVATE utun_voice utun pthread ${CMAKE_DL_LIBS})
add_test(NAME test_stream_audio COMMAND test_stream_audio)
set_tests_properties(test_stream_audio PROPERTIES TIMEOUT 30)
add_executable(test_stream_publish tests/test_stream_publish.cpp transport/stream_bridge.cpp
src/sound_manager.cpp src/voice_audio_io.cpp src/audio_device.cpp transport/miniaudio_impl.c transport/audio_diagnostics.cpp)
target_link_libraries(test_stream_publish PRIVATE chatgui_stream_publish ${QT_TEST_LIB} utun_voice pthread ${CMAKE_DL_LIBS})
if(FFMPEG_FOUND)
target_compile_definitions(test_stream_publish PRIVATE HAVE_FFMPEG)
target_include_directories(test_stream_publish PRIVATE ${FFMPEG_INCLUDE_DIRS})
target_link_libraries(test_stream_publish PRIVATE ${FFMPEG_TARGET} ${FFMPEG_LIBRARIES})
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_compile_definitions(test_stream_publish PRIVATE TEST_NULL_AUDIO)
target_link_options(test_stream_publish PRIVATE "-Wl,--wrap=ma_context_init" "-Wl,--wrap=ma_device_init"
"-Wl,--wrap=ma_device_uninit" "-Wl,--wrap=opus_codec_encode")
if(FFMPEG_FOUND)
target_link_options(test_stream_publish PRIVATE "-Wl,--wrap=avcodec_open2")
endif()
endif()
add_test(NAME test_stream_publish COMMAND test_stream_publish)
set_tests_properties(test_stream_publish PROPERTIES TIMEOUT 60 ENVIRONMENT "QT_QPA_PLATFORM=offscreen")
target_link_libraries(test_ptt_key_chord PRIVATE ${QT_CORE})
add_test(NAME test_ptt_key_chord COMMAND test_ptt_key_chord)
add_executable(test_voice_file tests/test_voice_file.cpp src/voiceplayback.cpp src/sound_manager.cpp src/voice_audio_io.cpp src/audio_device.cpp transport/miniaudio_impl.c transport/audio_diagnostics.cpp)
target_include_directories(test_voice_file PRIVATE ${UTUN_INCLUDE_DIRS})
target_link_libraries(test_voice_file PRIVATE ${QT_LIBS} utun_voice utun pthread ${CMAKE_DL_LIBS})
add_test(NAME test_voice_file COMMAND test_voice_file)
if(WIN32)
# AudioDevice закрывает неисправный WASAPI в worker с собственным COM apartment.
foreach(audio_target vibechat test_file_drop test_invite_links test_video_engine test_stream_view test_stream_publish test_voice_file)
target_link_libraries(${audio_target} PRIVATE ole32)
endforeach()
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_executable(test_audio_recovery tests/test_audio_recovery.cpp src/audio_device.cpp src/sound_manager.cpp src/voice_audio_io.cpp
src/audiorecorder.cpp src/call_audio_engine.cpp src/radio_audio_engine.cpp
transport/miniaudio_impl.c transport/audio_diagnostics.cpp transport/config_updater.cpp)
target_include_directories(test_audio_recovery PRIVATE ${UTUN_INCLUDE_DIRS})
target_link_libraries(test_audio_recovery PRIVATE chatgui_audio_capture ${QT_LIBS} utun_voice utun pthread dl)
target_link_options(test_audio_recovery PRIVATE "-Wl,--wrap=ma_context_init" "-Wl,--wrap=ma_context_uninit"
"-Wl,--wrap=ma_device_init" "-Wl,--wrap=ma_device_start" "-Wl,--wrap=ma_device_uninit" "-Wl,--wrap=audio_context_failed"
"-Wl,--wrap=call_send_media")
add_test(NAME test_audio_recovery COMMAND test_audio_recovery)
set_tests_properties(test_audio_recovery PROPERTIES TIMEOUT 15)
add_test(NAME test_microphone_watchdog COMMAND test_audio_recovery --microphone-watchdog)
set_tests_properties(test_microphone_watchdog PROPERTIES TIMEOUT 25)
add_test(NAME test_audio_buffer_tuning COMMAND test_audio_recovery --buffer-tuning)
set_tests_properties(test_audio_buffer_tuning PROPERTIES TIMEOUT 20)
add_executable(test_radio_panel tests/test_radio_panel.cpp src/radiopanel.cpp src/radio_audio_engine.cpp
src/radiosettingspage.cpp src/ptt_hotkey_manager.cpp
src/sound_manager.cpp src/voice_audio_io.cpp src/audio_device.cpp
transport/miniaudio_impl.c transport/audio_diagnostics.cpp transport/config_updater.cpp ${RADIO_MEMBER_TEST_SOURCES})
target_include_directories(test_radio_panel PRIVATE ${UTUN_INCLUDE_DIRS})
target_link_libraries(test_radio_panel PRIVATE chatgui_audio_capture ${QT_LIBS} ${QT_TEST_LIB} utun_voice utun pthread dl ${X11_LIBRARIES})
target_link_options(test_radio_panel PRIVATE "-Wl,--wrap=ma_context_init" "-Wl,--wrap=ma_device_start"
"-Wl,--wrap=radio_talk_begin" "-Wl,--wrap=radio_talk_end" "-Wl,--wrap=radio_talk_send"
"-Wl,--wrap=silero_vad_create_default" "-Wl,--wrap=silero_vad_destroy" "-Wl,--wrap=silero_vad_reset"
"-Wl,--wrap=silero_vad_process")
add_test(NAME test_radio_panel COMMAND test_radio_panel)
set_tests_properties(test_radio_panel PROPERTIES TIMEOUT 25 ENVIRONMENT "QT_QPA_PLATFORM=offscreen")
add_executable(test_ptt_portal tests/test_ptt_portal.cpp src/ptt_portal.cpp)
target_link_libraries(test_ptt_portal PRIVATE ${QT_DBUS} ${QT_TEST_LIB} utun pthread)
find_program(DBUS_RUN_SESSION dbus-run-session)
if(NOT DBUS_RUN_SESSION)
message(FATAL_ERROR "dbus-run-session is required for the isolated PTT portal test")
endif()
add_test(NAME test_ptt_portal COMMAND ${DBUS_RUN_SESSION} -- $<TARGET_FILE:test_ptt_portal>)
add_executable(test_linux_audio tests/test_linux_audio.c transport/audio_diagnostics.cpp)
target_link_libraries(test_linux_audio PRIVATE utun pthread dl m)
# assert выполняет вызовы стенда, поэтому не отключаем его в Release.
target_compile_options(test_linux_audio PRIVATE -UNDEBUG)
add_test(NAME test_linux_audio COMMAND test_linux_audio)
add_executable(test_audio_diagnostics tests/test_audio_diagnostics.cpp)
target_link_libraries(test_audio_diagnostics PRIVATE utun pthread)
target_compile_options(test_audio_diagnostics PRIVATE -UNDEBUG)
add_test(NAME test_audio_diagnostics COMMAND test_audio_diagnostics)
endif()