cmake_minimum_required(VERSION 3.16)

project(webrtcpush
    VERSION 1.0.1
    LANGUAGES C CXX
    DESCRIPTION "RV1106 WebRTC push streamer (MPP H.264 + libdatachannel)")

set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release CACHE STRING "" FORCE)
endif()

# 产物瘦身
add_link_options(-Wl,--gc-sections)
add_compile_options(-ffunction-sections -fdata-sections)

# ---- 路径 ----
set(SDK_ROOT $ENV{RV1106_SDK})
if(NOT SDK_ROOT)
    message(FATAL_ERROR "请先 export RV1106_SDK=<luckfox-pico 路径>")
endif()
message(STATUS "RV1106 SDK : ${SDK_ROOT}")

set(DEPS_PREFIX $ENV{WEBRTCPUSH_DEPS})
if(NOT DEPS_PREFIX)
    set(DEPS_PREFIX ${CMAKE_SOURCE_DIR}/third_party/install)
endif()
message(STATUS "Deps prefix: ${DEPS_PREFIX}")

find_file(CA_CERT_BUNDLE
    NAMES ca-certificates.crt
    PATHS /etc/ssl/certs /etc/pki/tls/certs
    NO_DEFAULT_PATH
    NO_CMAKE_FIND_ROOT_PATH)
if(NOT CA_CERT_BUNDLE)
    message(FATAL_ERROR "CA certificate bundle not found on the build host")
endif()
message(STATUS "CA bundle    : ${CA_CERT_BUNDLE}")

list(APPEND CMAKE_PREFIX_PATH ${DEPS_PREFIX})
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)

# ---- 找 SDK 预编译 media ----
include(FindRV1106Media)
message(STATUS "Media inc: ${RV1106_MEDIA_INCLUDE_DIRS}")
message(STATUS "Media lib dir: ${RV1106_MEDIA_LIB_DIRS}")

# ---- 找本地交叉编译的依赖 ----
find_package(PkgConfig QUIET)
# libdatachannel
find_library(LIBDATACHANNEL_LIB  NAMES datachannel  libdatachannel  PATHS ${DEPS_PREFIX}/lib REQUIRED)
find_path(LIBDATACHANNEL_INC     NAMES rtc/rtc.hpp rtc.hpp          PATHS ${DEPS_PREFIX}/include REQUIRED)
# libjuice (libdatachannel 内置; 静态链接进 libdatachannel.so 时可能无独立 .so)
find_library(LIBJUICE_LIB         NAMES juice libjuice              PATHS ${DEPS_PREFIX}/lib)
# mbedTLS (libdatachannel/wss 间接依赖, 显式链接确保运行时符号)
find_library(LIBMBEDTLS_LIB       NAMES mbedtls   PATHS ${DEPS_PREFIX}/lib REQUIRED)
find_library(LIBMBEDX509_LIB      NAMES mbedx509  PATHS ${DEPS_PREFIX}/lib REQUIRED)
find_library(LIBMBEDCRYPTO_LIB    NAMES mbedcrypto PATHS ${DEPS_PREFIX}/lib REQUIRED)
# nlohmann/json (header-only, 用于 ws_signaling/webrtc_pusher 解析 JSON 信令)
find_path(NLOHMANN_JSON_INC       NAMES nlohmann/json.hpp           PATHS ${DEPS_PREFIX}/include REQUIRED)
# librga (RV1106 RGA 硬件缩放, SDK 自带)
find_library(LIBRGA_LIB            NAMES rga librga                  PATHS ${SDK_ROOT}/media/rga/release_rga_rv1106_arm-rockchip830-linux-uclibcgnueabihf/lib)
find_path(LIBRGA_INC
    NAMES RgaApi.h im2d.h
    PATHS ${SDK_ROOT}/media/rga/release_rga_rv1106_arm-rockchip830-linux-uclibcgnueabihf/include
    PATH_SUFFIXES rga)
# RKMPI / librockit (RV1106 编码走内核态 rockit.ko, 必须用 RK_MPI_VENC_* 接口)
find_path(ROCKIT_INC              NAMES rk_mpi_venc.h               PATHS ${SDK_ROOT}/media/rockit/rockit/mpi/sdk/include REQUIRED)
find_library(ROCKIT_LIB           NAMES rockit                      PATHS ${SDK_ROOT}/media/rockit/rockit/lib/lib32 REQUIRED)
# librockit 依赖 libdrm
find_library(LIBDRM_LIB            NAMES drm                        PATHS ${SDK_ROOT}/sysdrv/source/out/output/lib ${SDK_ROOT}/media/rockit/rockit/lib/lib32)

message(STATUS "libdatachannel : ${LIBDATACHANNEL_LIB}")
if(LIBJUICE_LIB)
    message(STATUS "libjuice       : ${LIBJUICE_LIB}")
else()
    message(STATUS "libjuice       : (静态链接进 libdatachannel.so, 无独立 .so)")
endif()
message(STATUS "mbedtls        : ${LIBMBEDTLS_LIB}")
message(STATUS "nlohmann/json   : ${NLOHMANN_JSON_INC}")
if(LIBRGA_LIB)
    message(STATUS "librga         : ${LIBRGA_LIB}")
else()
    message(WARNING "librga 未找到 (RGA 硬件缩放将不可用)")
endif()
message(STATUS "librockit      : ${ROCKIT_LIB}")
message(STATUS "rockit inc     : ${ROCKIT_INC}")
if(LIBDRM_LIB)
    message(STATUS "libdrm         : ${LIBDRM_LIB}")
endif()

# ---- 目标 ----
add_executable(webrtcpush
    src/main.cpp
    src/ws_signaling.cpp
    src/webrtc_pusher.cpp
    src/hw_scaler.cpp
    src/isp_aiq.c
    src/time_sync.c
    src/mpp_encoder.c
    src/camera_v4l2.c
    src/test_pattern.c)

# Keep symbols in build/webrtcpush for board core analysis. The deploy copy is
# still stripped below, so this has no runtime size cost on the device.
target_compile_options(webrtcpush PRIVATE -g)
target_link_options(webrtcpush PRIVATE -Wl,--build-id=sha1)

target_include_directories(webrtcpush PRIVATE
    ${CMAKE_SOURCE_DIR}/include
    ${RV1106_MEDIA_INCLUDE_DIRS}
    ${LIBDATACHANNEL_INC}
    ${NLOHMANN_JSON_INC}
    ${ROCKIT_INC})
if(LIBRGA_INC)
    target_include_directories(webrtcpush PRIVATE ${LIBRGA_INC})
endif()

# 动态库查找路径优先项目目录 (运行时 RPATH=$ORIGIN/lib)
target_link_directories(webrtcpush PRIVATE
    ${RV1106_MEDIA_LIB_DIRS}
    ${DEPS_PREFIX}/lib)

target_link_libraries(webrtcpush PRIVATE
    rv1106::media
    ${LIBDATACHANNEL_LIB}
    ${LIBMBEDTLS_LIB}
    ${LIBMBEDX509_LIB}
    ${LIBMBEDCRYPTO_LIB}
    ${ROCKIT_LIB})
if(LIBRGA_LIB)
    target_link_libraries(webrtcpush PRIVATE ${LIBRGA_LIB})
endif()
# libjuice 若有独立 .so 则链接 (静态链接进 libdatachannel 时跳过)
if(LIBJUICE_LIB)
    target_link_libraries(webrtcpush PRIVATE ${LIBJUICE_LIB})
endif()

# 为每个 media 库目录单独加 -Wl,-rpath-link (列表展开时不会丢前缀)
set(_rpath_link_opts -Wl,-rpath-link,${DEPS_PREFIX}/lib)
foreach(_d ${RV1106_MEDIA_LIB_DIRS})
    list(APPEND _rpath_link_opts -Wl,-rpath-link,${_d})
endforeach()
list(APPEND _rpath_link_opts -Wl,-rpath-link,${SDK_ROOT}/media/rockit/rockit/lib/lib32)
target_link_options(webrtcpush PRIVATE ${_rpath_link_opts})

# 运行时 RPATH=$ORIGIN/lib, 让可执行文件在 deploy/lib/ 旁找到 .so
# 用 BUILD_RPATH 属性而非手动 -Wl,-rpath,\$ORIGIN, 避免 Makefile 生成器双重转义成 $$ORIGIN
set_target_properties(webrtcpush PROPERTIES
    BUILD_RPATH "$ORIGIN/lib"
    INSTALL_RPATH "$ORIGIN/lib"
    BUILD_WITH_INSTALL_RPATH TRUE
    INSTALL_RPATH_USE_LINK_PATH FALSE)

# ---- 部署目录: 把所有 .so 和可执行文件收到 deploy/ ----
# 原则: 只打包"设备系统里没有"的库 (实测 luckfox 固件自带 libc/libstdc++/libgcc 等
#       uClibc 运行时, 不打包; 需要打包的仅: 自编 third_party + RKMPI 生态)。
# 主程序带 RPATH=$ORIGIN/lib；run.sh 额外设置 LD_LIBRARY_PATH 兼容 uClibc 间接依赖。
# 注意: cp -a 保留符号链接 (soname 链), 之前 cp -L 导致运行时报缺库。
set(DEPLOY_DIR ${CMAKE_BINARY_DIR}/deploy)
add_custom_target(deploy
    COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPLOY_DIR}/lib
    COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:webrtcpush> ${DEPLOY_DIR}/
    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/scripts/run.sh ${DEPLOY_DIR}/run.sh
    COMMAND ${CMAKE_COMMAND} -E copy ${CA_CERT_BUNDLE} ${DEPLOY_DIR}/lib/ca-certificates.crt
    COMMAND chmod +x ${DEPLOY_DIR}/run.sh
    # 1) 自编第三方库 (设备固件必无): libdatachannel(+juice) + mbedTLS + libcurl
    #    curl: 当前 wss 信令走 libdatachannel 自带 WebSocket 未用 curl,
    #          但按要求保留在包内 (静态链接需有调用代码才有意义, 先动态随包)
    COMMAND cp -a ${DEPS_PREFIX}/lib/libdatachannel.so* ${DEPLOY_DIR}/lib/ 2>/dev/null || true
    COMMAND cp -a ${DEPS_PREFIX}/lib/libjuice.so* ${DEPLOY_DIR}/lib/ 2>/dev/null || true
    COMMAND cp -a ${DEPS_PREFIX}/lib/libcurl.so* ${DEPLOY_DIR}/lib/ 2>/dev/null || true
    COMMAND cp -a ${DEPS_PREFIX}/lib/libmbedtls.so* ${DEPLOY_DIR}/lib/ 2>/dev/null || true
    COMMAND cp -a ${DEPS_PREFIX}/lib/libmbedx509.so* ${DEPLOY_DIR}/lib/ 2>/dev/null || true
    COMMAND cp -a ${DEPS_PREFIX}/lib/libmbedcrypto.so* ${DEPLOY_DIR}/lib/ 2>/dev/null || true
    # 2) RKMPI 生态 (实测设备系统无 librockchip_mpp.so.1): rockit + mpp + rga
    #    注意 librockit.so 运行时依赖 librockchip_mpp.so.1 和 librga.so
    COMMAND cp -a ${RV1106_MEDIA_FILES} ${DEPLOY_DIR}/lib/ 2>/dev/null || true
    COMMAND cp -a ${SDK_ROOT}/media/rga/release_rga_rv1106_arm-rockchip830-linux-uclibcgnueabihf/lib/librga.so* ${DEPLOY_DIR}/lib/ 2>/dev/null || true
    # 3) strip 瘦身
    COMMAND ${CMAKE_STRIP} ${DEPLOY_DIR}/webrtcpush
    # 4) 完整性自检: 每个 NEEDED 必须能被 deploy/lib 满足, 缺了直接报错
    COMMAND bash ${CMAKE_SOURCE_DIR}/scripts/check_deps.sh ${DEPLOY_DIR}
    # 5) 同时生成 BusyBox 可直接解包的 .tar 和体积更小的 .tar.gz
    COMMAND tar -cf ${CMAKE_BINARY_DIR}/webrtcpush_deploy.tar -C ${CMAKE_BINARY_DIR} deploy
    COMMAND tar -czf ${CMAKE_BINARY_DIR}/webrtcpush_deploy.tar.gz -C ${CMAKE_BINARY_DIR} deploy
    DEPENDS webrtcpush
    COMMENT "收集部署包 -> ${DEPLOY_DIR}")
