summaryrefslogtreecommitdiff
path: root/lib/avtp_pipeline/platform/Linux
diff options
context:
space:
mode:
Diffstat (limited to 'lib/avtp_pipeline/platform/Linux')
-rw-r--r--lib/avtp_pipeline/platform/Linux/CMakeLists.txt227
-rw-r--r--lib/avtp_pipeline/platform/Linux/arm_imx6sx_linux.cmake26
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_avdecc/CMakeLists.txt25
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_avdecc/openavb_avdecc.c188
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_host/CMakeLists.txt6
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c69
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c62
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/CMakeLists.txt2
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.c279
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.h50
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_osal.c203
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_osal.h45
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_pipeline_interaction.c513
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_read_ini.c620
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_save_state.c363
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_save_state.h70
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc_msg/CMakeLists.txt2
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_client_osal.c181
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_osal.h64
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_server_osal.c271
-rw-r--r--lib/avtp_pipeline/platform/Linux/avtp/openavb_avtp_time_osal.c1
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c149
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.h30
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_client_osal.c3
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.c472
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.h1
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_maap.c596
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_ptp.c75
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_shaper.c426
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_srp.c412
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_server_osal.c10
-rw-r--r--lib/avtp_pipeline/platform/Linux/generic.cmake1
-rw-r--r--lib/avtp_pipeline/platform/Linux/gst_al/gst_al.h1
-rw-r--r--lib/avtp_pipeline/platform/Linux/gst_al/gst_al_01.c1
-rw-r--r--lib/avtp_pipeline/platform/Linux/gst_al/gst_al_10.c1
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_file_talker.ini10
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener.ini21
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener_auto.ini17
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_talker.ini20
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_intf.md31
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_listener.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_talker.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/openavb_intf_alsa.c220
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_listener.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_talker.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_h264_gst/openavb_intf_h264_gst.c32
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_listener.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_talker.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/openavb_intf_mjpeg_gst.c1
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_listener.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_talker.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/openavb_intf_mpeg2ts_file.c1
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_listener.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_talker.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/openavb_intf_mpeg2ts_gst.c1
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_wav_file/openavb_intf_wav_file.c69
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_listener.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_talker.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal.c152
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal.h37
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal_pub.h62
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_os_services_osal.h3
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_os_services_osal_pub.h2
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal.c40
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal.h1
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal_avdecc.c79
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c40
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h22
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_poll_osal.h1
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_tasks.h8
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_time_osal.c26
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_time_osal.h1
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_time_osal_pub.h3
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/avtp_rx.c1
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.c1
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.h1
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock.c44
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.c68
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.h6
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/rawsock_rx.c1
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/rawsock_tx.c11
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.c21
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.h1
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/sendmmsg_rawsock.c503
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/sendmmsg_rawsock.h110
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.c50
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.h10
-rw-r--r--lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c100
-rw-r--r--lib/avtp_pipeline/platform/Linux/x86_i210_linux.cmake43
89 files changed, 6538 insertions, 850 deletions
diff --git a/lib/avtp_pipeline/platform/Linux/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/CMakeLists.txt
index 039d0218..14f427cc 100644
--- a/lib/avtp_pipeline/platform/Linux/CMakeLists.txt
+++ b/lib/avtp_pipeline/platform/Linux/CMakeLists.txt
@@ -1,6 +1,6 @@
-cmake_minimum_required ( VERSION 2.6 )
+cmake_minimum_required ( VERSION 2.6 )
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
-project ( AVB )
+project ( AVB )
# Some CMake voodoo to set the default build type
IF(NOT CMAKE_BUILD_TYPE)
@@ -20,7 +20,7 @@ STRING ( TOUPPER "${CMAKE_BUILD_TYPE}_BUILD" BUILD_TYPE_STRING )
SET ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D${BUILD_TYPE_STRING}" )
# CMake automatically adds some compiler flags based on CMAKE_BUILD_TYPE
-# for Debug: "-g"
+# for Debug: "-g"
# for RelWithDebInfo: "-O2 -g"
# for Release: "-03 -DNDEBUG"
# for MinSizeRel: "-0s -DNDEBUG"
@@ -66,10 +66,13 @@ MESSAGE ("-- SDK_INSTALL_SDK_EAVB_DIR : ${SDK_INSTALL_SDK_EAVB_DIR}")
# Turn on all build warnings
set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -Wall" )
+# Turn off strict aliasing
+set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing" )
+
# Set default visibility of symbols (requires GCC version > 4)
set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden" )
-# Need this to use pthread attributes
+# Need this to use pthread attributes
set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE" )
# Increase ini parser's max line length
@@ -80,6 +83,17 @@ if ( GSTREAMER_1_0)
set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGSTREAMER_1_0" )
endif ()
+# For AVDECC, disable features we won't need.
+if (DEFINED AVB_FEATURE_AVDECC)
+ if ( AVB_FEATURE_AVDECC )
+ set ( AVB_FEATURE_FQTSS 0 )
+ set ( AVB_FEATURE_GSTREAMER 0 )
+ set ( AVB_FEATURE_ENDPOINT 0 )
+ set ( AVB_FEATURE_IGB 0 )
+ set ( IGB_LAUNCHTIME_ENABLED 0 )
+ endif ()
+endif ()
+
# Default feature flags
if (NOT DEFINED AVB_FEATURE_FQTSS)
set ( AVB_FEATURE_FQTSS 1 )
@@ -92,6 +106,10 @@ endif ()
if (NOT DEFINED AVB_FEATURE_ENDPOINT)
set ( AVB_FEATURE_ENDPOINT 0 )
endif ()
+# Default AVDECC feature
+if (NOT DEFINED AVB_FEATURE_AVDECC)
+ set ( AVB_FEATURE_AVDECC 0 )
+endif ()
if (NOT DEFINED AVB_FEATURE_IGB)
set ( AVB_FEATURE_IGB 1 )
endif ()
@@ -115,10 +133,13 @@ endif ()
if (AVB_FEATURE_ENDPOINT)
set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAVB_FEATURE_ENDPOINT=1" )
endif ()
+if (AVB_FEATURE_AVDECC)
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAVB_FEATURE_AVDECC=1" )
+endif ()
if (AVB_FEATURE_IGB)
- set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAVB_FEATURE_IGB=1" )
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAVB_FEATURE_IGB=1" )
else ()
- set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAVB_FEATURE_IGB=0" )
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAVB_FEATURE_IGB=0" )
endif ()
#Export Platform defines
@@ -148,13 +169,13 @@ if (NOT DEFINED SDK_DOC_ONLY)
if (NOT DEFINED ARCH)
MESSAGE ( FATAL_ERROR "Aborting: ARCH not set" )
- endif ()
+ endif ()
if (NOT DEFINED LINUX_KERNEL_DIR)
MESSAGE ( FATAL_ERROR "Aborting: LINUX_KERNEL_DIR not set" )
- endif ()
+ endif ()
if (NOT DEFINED GLIB_PKG_INCLUDE_DIRS OR NOT DEFINED GLIB_PKG_LIBRARIES)
MESSAGE ( FATAL_ERROR "Aborting: glib-2.0 library not found" )
- endif ()
+ endif ()
if (AVB_FEATURE_GSTREAMER)
if (NOT DEFINED GST_PKG_INCLUDE_DIRS OR NOT DEFINED GST_PKG_LIBRARIES)
MESSAGE ( FATAL_ERROR "Aborting: gstreamer library not found" )
@@ -162,7 +183,7 @@ if (NOT DEFINED SDK_DOC_ONLY)
endif ()
if (NOT DEFINED ALSA_INCLUDE_DIRS)
MESSAGE ( FATAL_ERROR "Aborting: alsa library not found" )
- endif ()
+ endif ()
endif()
# Add /usr/lib to library search path
@@ -188,7 +209,7 @@ link_directories ( ${PLATFORM_LINK_DIRECTORIES} )
# These should be cleaned up to limit the dependencies
# across components.
#
-include_directories(
+include_directories(
${AVB_TCAL_DIR}
${AVB_HAL_DIR}
${AVB_HAL_DIR}/mcr
@@ -197,10 +218,16 @@ include_directories(
${AVB_SRC_DIR}/include
${AVB_OSAL_DIR}/avtp
${AVB_OSAL_DIR}/tl
- ${AVB_SRC_DIR}/avtp
+ ${AVB_SRC_DIR}/avtp
+ ${AVB_SRC_DIR}/avdecc
+ ${AVB_SRC_DIR}/acmp
+ ${AVB_SRC_DIR}/adp
+ ${AVB_SRC_DIR}/aecp
+ ${AVB_SRC_DIR}/aem
${AVB_SRC_DIR}/endpoint
${AVB_SRC_DIR}/srp
${AVB_SRC_DIR}/maap
+ ${AVB_SRC_DIR}/shaper
${AVB_SRC_DIR}/inih
${AVB_SRC_DIR}/map_mjpeg
${AVB_SRC_DIR}/map_mpeg2ts
@@ -215,9 +242,12 @@ include_directories(
${AVB_SRC_DIR}/mediaq
${AVB_SRC_DIR}/rawsock
${AVB_SRC_DIR}/qmgr
- ${AVB_SRC_DIR}/tl
+ ${AVB_SRC_DIR}/tl
${AVB_SRC_DIR}/util
+ ${AVB_SRC_DIR}/avdecc_msg
+ ${AVB_OSAL_DIR}/avdecc
${AVB_OSAL_DIR}/endpoint
+ ${AVB_OSAL_DIR}/avdecc_msg
${AVB_SRC_DIR}/../common
${AVB_SRC_DIR}/mcs
)
@@ -243,14 +273,24 @@ add_subdirectory ( inih )
add_subdirectory ( rawsock )
add_subdirectory ( openavb_common )
-add_subdirectory ( avtp )
-add_subdirectory ( mediaq )
-add_subdirectory ( mcr )
-add_subdirectory ( mcs )
-add_subdirectory ( tl )
-add_subdirectory ( qmgr )
-if (AVB_FEATURE_ENDPOINT)
- add_subdirectory ( endpoint )
+# TODO: Make the above avbBase, then make avbTl and avbAvdecc from below
+
+if (AVB_FEATURE_AVDECC)
+ add_subdirectory ( avdecc )
+ add_subdirectory ( acmp )
+ add_subdirectory ( adp )
+ add_subdirectory ( aecp )
+ add_subdirectory ( aem )
+else ()
+ add_subdirectory ( avtp )
+ add_subdirectory ( mediaq )
+ add_subdirectory ( mcr )
+ add_subdirectory ( mcs )
+ add_subdirectory ( tl )
+ add_subdirectory ( qmgr )
+ if (AVB_FEATURE_ENDPOINT)
+ add_subdirectory ( endpoint )
+ endif ()
endif ()
add_library ( avbTl ${SRC_FILES} )
@@ -261,80 +301,93 @@ endif ()
install ( TARGETS avbTl ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
-# avb_host (openavb_host and openavb_harness)
-add_subdirectory ( ${AVB_OSAL_DIR}/avb_host )
-
-# mapping modules
-macro (add_map_mod MAP_NAME)
- SET ( SRC_FILES "" )
- add_subdirectory ( ${MAP_NAME} )
- add_library ( ${MAP_NAME} ${SRC_FILES} )
- install ( TARGETS ${MAP_NAME} ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
-endmacro()
-add_map_mod ( "map_ctrl" )
-add_map_mod ( "map_mjpeg" )
-add_map_mod ( "map_mpeg2ts" )
-add_map_mod ( "map_null" )
-add_map_mod ( "map_pipe" )
-add_map_mod ( "map_aaf_audio" )
-add_map_mod ( "map_uncmp_audio" )
-add_map_mod ( "map_h264" )
-
-# Interface modules (common)
-macro (add_intf_mod INTF_NAME)
- SET ( SRC_FILES "" )
- add_subdirectory ( ${INTF_NAME} )
- add_library ( ${INTF_NAME} ${SRC_FILES} )
- install ( TARGETS ${INTF_NAME} ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
- install ( DIRECTORY "${AVB_SRC_DIR}/${INTF_NAME}/" DESTINATION ${AVB_INSTALL_BIN_DIR} FILES_MATCHING PATTERN "*.ini" )
-endmacro()
-add_intf_mod ( "intf_ctrl" )
-add_intf_mod ( "intf_echo" )
-add_intf_mod ( "intf_logger" )
-add_intf_mod ( "intf_null" )
-add_intf_mod ( "intf_tonegen" )
-add_intf_mod ( "intf_viewer" )
-
-# Interface modules (platform)
-macro (add_intf_mod_platform INTF_NAME)
- SET ( SRC_FILES "" )
- SET ( INTF_INCLUDE_DIR "")
- SET ( INTF_LIBRARY_DIR "")
- SET ( INTF_LIBRARY "")
- add_subdirectory ( ${AVB_OSAL_DIR}/${INTF_NAME} )
- include_directories ( ${INTF_INCLUDE_DIR} )
- add_library ( ${INTF_NAME} ${SRC_FILES} )
- install ( TARGETS ${INTF_NAME} ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
- install ( DIRECTORY "${AVB_OSAL_DIR}/${INTF_NAME}/" DESTINATION ${AVB_INSTALL_BIN_DIR} FILES_MATCHING PATTERN "*.ini" )
-endmacro()
-
-add_intf_mod_platform ( "intf_alsa" )
-if (AVB_FEATURE_GSTREAMER)
- add_intf_mod_platform ( "intf_mpeg2ts_gst" )
- add_intf_mod_platform ( "intf_mjpeg_gst" )
- add_intf_mod_platform ( "intf_h264_gst" )
+if (AVB_FEATURE_AVDECC)
+ # avb_avdecc (openavb_avdecc)
+ add_subdirectory ( ${AVB_OSAL_DIR}/avb_avdecc )
+else ()
+ # avb_host (openavb_host and openavb_harness)
+ add_subdirectory ( ${AVB_OSAL_DIR}/avb_host )
+endif ()
+
+if (NOT AVB_FEATURE_AVDECC)
+ # mapping modules
+ macro (add_map_mod MAP_NAME)
+ SET ( SRC_FILES "" )
+ add_subdirectory ( ${MAP_NAME} )
+ add_library ( ${MAP_NAME} ${SRC_FILES} )
+ install ( TARGETS ${MAP_NAME} ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
+ endmacro()
+ add_map_mod ( "map_ctrl" )
+ add_map_mod ( "map_mjpeg" )
+ add_map_mod ( "map_mpeg2ts" )
+ add_map_mod ( "map_null" )
+ add_map_mod ( "map_pipe" )
+ add_map_mod ( "map_aaf_audio" )
+ add_map_mod ( "map_uncmp_audio" )
+ add_map_mod ( "map_h264" )
+
+ # Interface modules (common)
+ macro (add_intf_mod INTF_NAME)
+ SET ( SRC_FILES "" )
+ add_subdirectory ( ${INTF_NAME} )
+ add_library ( ${INTF_NAME} ${SRC_FILES} )
+ install ( TARGETS ${INTF_NAME} ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
+ install ( DIRECTORY "${AVB_SRC_DIR}/${INTF_NAME}/" DESTINATION ${AVB_INSTALL_BIN_DIR} FILES_MATCHING PATTERN "*.ini" )
+ endmacro()
+ add_intf_mod ( "intf_ctrl" )
+ add_intf_mod ( "intf_echo" )
+ add_intf_mod ( "intf_logger" )
+ add_intf_mod ( "intf_null" )
+ add_intf_mod ( "intf_tonegen" )
+ add_intf_mod ( "intf_viewer" )
+
+ # Interface modules (platform)
+ macro (add_intf_mod_platform INTF_NAME)
+ SET ( SRC_FILES "" )
+ SET ( INTF_INCLUDE_DIR "")
+ SET ( INTF_LIBRARY_DIR "")
+ SET ( INTF_LIBRARY "")
+ add_subdirectory ( ${AVB_OSAL_DIR}/${INTF_NAME} )
+ include_directories ( ${INTF_INCLUDE_DIR} )
+ add_library ( ${INTF_NAME} ${SRC_FILES} )
+ install ( TARGETS ${INTF_NAME} ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
+ install ( DIRECTORY "${AVB_OSAL_DIR}/${INTF_NAME}/" DESTINATION ${AVB_INSTALL_BIN_DIR} FILES_MATCHING PATTERN "*.ini" )
+ endmacro()
+
+ add_intf_mod_platform ( "intf_alsa" )
+ if (AVB_FEATURE_GSTREAMER)
+ add_intf_mod_platform ( "intf_mpeg2ts_gst" )
+ add_intf_mod_platform ( "intf_mjpeg_gst" )
+ add_intf_mod_platform ( "intf_h264_gst" )
+ endif ()
+ add_intf_mod_platform ( "intf_mpeg2ts_file" )
+ add_intf_mod_platform ( "intf_wav_file" )
endif ()
-add_intf_mod_platform ( "intf_mpeg2ts_file" )
-add_intf_mod_platform ( "intf_wav_file" )
# API documentation
add_subdirectory ( documents )
-# SDKS
-add_subdirectory ( sdk )
+if (NOT AVB_FEATURE_AVDECC)
+ # SDKS
+ add_subdirectory ( sdk )
-# rawsock_rx
-add_executable (rawsock_rx ${AVB_OSAL_DIR}/rawsock/rawsock_rx.c)
-target_link_libraries (rawsock_rx avbTl ${GLIB_PKG_LIBRARIES} pthread rt pci ${PLATFORM_LINK_LIBRARIES} )
-install ( TARGETS rawsock_rx RUNTIME DESTINATION ${AVB_INSTALL_BIN_DIR} )
+ # rawsock_rx
+ add_executable (rawsock_rx ${AVB_OSAL_DIR}/rawsock/rawsock_rx.c)
+ target_link_libraries (rawsock_rx avbTl ${GLIB_PKG_LIBRARIES} pthread rt ${PLATFORM_LINK_LIBRARIES} )
+ install ( TARGETS rawsock_rx RUNTIME DESTINATION ${AVB_INSTALL_BIN_DIR} )
-# rawsock_tx
-add_executable (rawsock_tx ${AVB_OSAL_DIR}/rawsock/rawsock_tx.c)
-target_link_libraries (rawsock_tx avbTl ${GLIB_PKG_LIBRARIES} pthread rt pci ${PLATFORM_LINK_LIBRARIES} )
-install ( TARGETS rawsock_tx RUNTIME DESTINATION ${AVB_INSTALL_BIN_DIR} )
+ # rawsock_tx
+ add_executable (rawsock_tx ${AVB_OSAL_DIR}/rawsock/rawsock_tx.c)
+ target_link_libraries (rawsock_tx avbTl ${GLIB_PKG_LIBRARIES} pthread rt ${PLATFORM_LINK_LIBRARIES} )
+ install ( TARGETS rawsock_tx RUNTIME DESTINATION ${AVB_INSTALL_BIN_DIR} )
+endif ()
# Copy additional installation files
if (AVB_FEATURE_ENDPOINT)
- install ( FILES ${AVB_SRC_DIR}/endpoint/endpoint.ini DESTINATION ${AVB_INSTALL_BIN_DIR} )
- install ( PROGRAMS ${AVB_SRC_DIR}/endpoint/shutdown_openavb_endpoint.sh DESTINATION ${AVB_INSTALL_BIN_DIR} )
+ install ( FILES ${AVB_SRC_DIR}/endpoint/endpoint.ini DESTINATION ${AVB_INSTALL_BIN_DIR} )
+ install ( PROGRAMS ${AVB_SRC_DIR}/endpoint/shutdown_openavb_endpoint.sh DESTINATION ${AVB_INSTALL_BIN_DIR} )
+endif ()
+if (AVB_FEATURE_AVDECC)
+ install ( FILES ${AVB_SRC_DIR}/avdecc/avdecc.ini DESTINATION ${AVB_INSTALL_BIN_DIR} )
+ install ( PROGRAMS ${AVB_SRC_DIR}/avdecc/shutdown_openavb_avdecc.sh DESTINATION ${AVB_INSTALL_BIN_DIR} )
endif ()
diff --git a/lib/avtp_pipeline/platform/Linux/arm_imx6sx_linux.cmake b/lib/avtp_pipeline/platform/Linux/arm_imx6sx_linux.cmake
new file mode 100644
index 00000000..ee559020
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/arm_imx6sx_linux.cmake
@@ -0,0 +1,26 @@
+set ( GSTREAMER_1_0 0 )
+set ( AVB_FEATURE_PCAP 1 )
+set ( AVB_FEATURE_IGB 0 )
+set ( IGB_LAUNCHTIME_ENABLED 0 )
+
+# and another kernel sources
+#set ( LINUX_KERNEL_DIR "/usr/src/kernel" )
+
+# build configuration
+set ( OPENAVB_HAL "arm_im6sx" )
+set ( OPENAVB_OSAL "Linux" )
+set ( OPENAVB_TCAL "GNU" )
+set ( OPENAVB_PLATFORM "${OPENAVB_HAL}-${OPENAVB_OSAL}" )
+
+# Platform Additions
+set ( PLATFORM_INCLUDE_DIRECTORIES
+ ${CMAKE_SOURCE_DIR}/platform/arm_imx6x/include
+ ${CMAKE_SOURCE_DIR}/openavb_common
+ ${CMAKE_SOURCE_DIR}/../../daemons/common
+ ${CMAKE_SOURCE_DIR}/../../daemons/mrpd
+ ${CMAKE_SOURCE_DIR}/../../daemons/maap/common
+)
+
+# TODO_OPENAVB : need this?
+# Set platform specific define
+#set ( PLATFORM_DEFINE "AVB_DELAY_TWEAK_USEC=15" )
diff --git a/lib/avtp_pipeline/platform/Linux/avb_avdecc/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/avb_avdecc/CMakeLists.txt
new file mode 100644
index 00000000..12e9e6e2
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avb_avdecc/CMakeLists.txt
@@ -0,0 +1,25 @@
+include_directories(
+ ${AVB_OSAL_DIR}/avdecc
+ ${AVB_SRC_DIR}/util
+ )
+
+# Rules to build the AVB AVDECC
+add_executable ( openavb_avdecc openavb_avdecc.c )
+target_link_libraries( openavb_avdecc
+ avbTl
+ ${PLATFORM_LINK_LIBRARIES}
+ ${ALSA_LIBRARIES}
+ ${GSTRTP_PKG_LIBRARIES}
+ ${GLIB_PKG_LIBRARIES}
+ ${GST_PKG_LIBRARIES}
+ pthread
+ rt
+ dl )
+
+# Install rules
+install ( TARGETS openavb_avdecc RUNTIME DESTINATION ${AVB_INSTALL_BIN_DIR} )
+
+if (AVB_FEATURE_GSTREAMER)
+include_directories( ${GLIB_PKG_INCLUDE_DIRS} ${GST_PKG_INCLUDE_DIRS} )
+target_link_libraries( openavb_avdecc ${GLIB_PKG_LIBRARIES} ${GST_PKG_LIBRARIES} ${PLATFORM_LINK_LIBRARIES} )
+endif ()
diff --git a/lib/avtp_pipeline/platform/Linux/avb_avdecc/openavb_avdecc.c b/lib/avtp_pipeline/platform/Linux/avb_avdecc/openavb_avdecc.c
new file mode 100644
index 00000000..c1d9e9a8
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avb_avdecc/openavb_avdecc.c
@@ -0,0 +1,188 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : AVDECC main implementation.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include "openavb_avdecc_pub.h"
+#include "openavb_plugin.h"
+#include "openavb_trace_pub.h"
+
+#define AVB_LOG_COMPONENT "AVDECC Main"
+#include "openavb_log_pub.h"
+
+bool avdeccRunning = TRUE;
+
+/***********************************************
+ * Signal handler - used to respond to signals.
+ * Allows graceful cleanup.
+ */
+static void openavbAvdeccSigHandler(int signal)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HOST);
+
+ if (signal == SIGINT || signal == SIGTERM) {
+ if (avdeccRunning) {
+ AVB_LOG_INFO("AVDECC shutting down");
+ avdeccRunning = FALSE;
+ }
+ else {
+ // Force shutdown
+ exit(2);
+ }
+ }
+ else {
+ AVB_LOG_ERROR("Unexpected signal");
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_HOST);
+}
+
+void openavbAvdeccHostUsage(char *programName)
+{
+ printf(
+ "\n"
+ "Usage: %s [options] file...\n"
+ " -I val Use given (val) interface globally, can be overriden by giving the ifname= option to the config line.\n"
+ " -l val Filename of the log file to use. If not specified, results will be logged to stderr.\n"
+ "\n"
+ "Examples:\n"
+ " %s talker.ini\n"
+ " Control 1 stream with data from the ini file.\n\n"
+ " %s talker1.ini talker2.ini\n"
+ " Control 2 streams with data from the ini files.\n\n"
+ " %s -I eth0 talker1.ini listener2.ini\n"
+ " Control 2 streams with data from the ini files, using the eth0 interface.\n\n"
+ ,
+ programName, programName, programName, programName);
+}
+
+/**********************************************
+ * main
+ */
+int main(int argc, char *argv[])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HOST);
+
+ char *programName;
+ char *optIfnameGlobal = NULL;
+ char *optLogFileName = NULL;
+
+ programName = strrchr(argv[0], '/');
+ programName = programName ? programName + 1 : argv[0];
+
+ if (argc < 2) {
+ openavbAvdeccHostUsage(programName);
+ exit(-1);
+ }
+
+ // Process command line
+ bool optDone = FALSE;
+ while (!optDone) {
+ int opt = getopt(argc, argv, "hI:l:");
+ if (opt != EOF) {
+ switch (opt) {
+ case 'I':
+ optIfnameGlobal = strdup(optarg);
+ break;
+ case 'l':
+ optLogFileName = strdup(optarg);
+ break;
+ case 'h':
+ default:
+ openavbAvdeccHostUsage(programName);
+ exit(-1);
+ }
+ }
+ else {
+ optDone = TRUE;
+ }
+ }
+
+ int iniIdx = optind;
+ int tlCount = argc - iniIdx;
+
+ if (!osalAvdeccInitialize(optLogFileName, optIfnameGlobal, (const char **) (argv + iniIdx), tlCount)) {
+ osalAvdeccFinalize();
+ exit(-1);
+ }
+
+ // Setup signal handler
+ // We catch SIGINT and shutdown cleanly
+ bool err;
+ struct sigaction sa;
+ sa.sa_handler = openavbAvdeccSigHandler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ err = sigaction(SIGINT, &sa, NULL);
+ if (err)
+ {
+ AVB_LOG_ERROR("Failed to setup SIGINT handler");
+ osalAvdeccFinalize();
+ exit(-1);
+ }
+ err = sigaction(SIGTERM, &sa, NULL);
+ if (err)
+ {
+ AVB_LOG_ERROR("Failed to setup SIGTERM handler");
+ osalAvdeccFinalize();
+ exit(-1);
+ }
+ err = sigaction(SIGUSR1, &sa, NULL);
+ if (err)
+ {
+ AVB_LOG_ERROR("Failed to setup SIGUSR1 handler");
+ osalAvdeccFinalize();
+ exit(-1);
+ }
+
+ // Ignore SIGPIPE signals.
+ signal(SIGPIPE, SIG_IGN);
+
+ while (avdeccRunning) {
+ SLEEP_MSEC(1);
+ }
+
+ osalAvdeccFinalize();
+
+ if (optLogFileName) {
+ free(optLogFileName);
+ optLogFileName = NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_HOST);
+ exit(0);
+}
diff --git a/lib/avtp_pipeline/platform/Linux/avb_host/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/avb_host/CMakeLists.txt
index 5efffa64..f11837c4 100644
--- a/lib/avtp_pipeline/platform/Linux/avb_host/CMakeLists.txt
+++ b/lib/avtp_pipeline/platform/Linux/avb_host/CMakeLists.txt
@@ -32,8 +32,7 @@ target_link_libraries( openavb_host
${GLIB_PKG_LIBRARIES}
pthread
rt
- dl
- pci )
+ dl )
# Rules to build the AVB harness
@@ -62,8 +61,7 @@ target_link_libraries( openavb_harness
${GLIB_PKG_LIBRARIES}
pthread
rt
- dl
- pci )
+ dl )
# Install rules
install ( TARGETS openavb_host RUNTIME DESTINATION ${AVB_INSTALL_BIN_DIR} )
diff --git a/lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c b/lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c
index 71a7a6e4..4c89041d 100644
--- a/lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c
+++ b/lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -53,7 +54,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
bool bRunning = TRUE;
-// Platform indendent mapping modules
+// Platform independent mapping modules
extern bool openavbMapPipeInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
extern bool openavbMapAVTPAudioInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
extern bool openavbMapCtrlInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
@@ -63,7 +64,7 @@ extern bool openavbMapMpeg2tsInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pM
extern bool openavbMapNullInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
extern bool openavbMapUncmpAudioInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
-// Platform indendent interface modules
+// Platform independent interface modules
extern bool openavbIntfEchoInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
extern bool openavbIntfCtrlInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
extern bool openavbIntfLoggerInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
@@ -90,9 +91,15 @@ static void openavbTLSigHandler(int signal)
{
AVB_TRACE_ENTRY(AVB_TRACE_HOST);
- if (signal == SIGINT) {
- AVB_LOG_INFO("Host shutting down");
- bRunning = FALSE;
+ if (signal == SIGINT || signal == SIGTERM) {
+ if (bRunning) {
+ AVB_LOG_INFO("Host shutting down");
+ bRunning = FALSE;
+ }
+ else {
+ // Force shutdown
+ exit(2);
+ }
}
else if (signal == SIGUSR1) {
AVB_LOG_DEBUG("Waking up streaming thread");
@@ -115,6 +122,7 @@ void openavbTlHarnessUsage(char *programName)
" -s val Stream count. Starts 'val' number of streams for each configuration file. stream_uid will be overriden.\n"
" -d val Last byte of destination address from static pool. Full address will be 91:e0:f0:00:fe:val.\n"
" -I val Use given (val) interface globally, can be overriden by giving the ifname= option to the config line.\n"
+ " -l val Filename of the log file to use. If not specified, results will be logged to stderr.\n"
"\n"
"Examples:\n"
" %s talker.ini\n"
@@ -165,6 +173,7 @@ int main(int argc, char *argv[])
bool optDestAddrSet = FALSE;
U8 destAddr[ETH_ALEN] = {0x91, 0xe0, 0xf0, 0x00, 0xfe, 0x00};
char *optIfnameGlobal = NULL;
+ char *optLogFileName = NULL;
// Talker listener vars
int iniIdx = 0;
@@ -182,8 +191,12 @@ int main(int argc, char *argv[])
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0; // not SA_RESTART
sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
sigaction(SIGUSR1, &sa, NULL);
+ // Ignore SIGPIPE signals.
+ signal(SIGPIPE, SIG_IGN);
+
registerStaticMapModule(openavbMapPipeInitialize);
registerStaticMapModule(openavbMapAVTPAudioInitialize);
registerStaticMapModule(openavbMapCtrlInitialize);
@@ -218,7 +231,7 @@ int main(int argc, char *argv[])
bool optDone = FALSE;
while (!optDone) {
- int opt = getopt(argc, argv, "a:his:d:I:");
+ int opt = getopt(argc, argv, "a:his:d:I:l:");
if (opt != EOF) {
switch (opt) {
case 'a':
@@ -238,6 +251,9 @@ int main(int argc, char *argv[])
case 'I':
optIfnameGlobal = strdup(optarg);
break;
+ case 'l':
+ optLogFileName = strdup(optarg);
+ break;
case '?':
default:
openavbTlHarnessUsage(programName);
@@ -249,7 +265,7 @@ int main(int argc, char *argv[])
}
}
- osalAVBInitialize(optIfnameGlobal);
+ osalAVBInitialize(optLogFileName, optIfnameGlobal);
// Setup the talker listener counts and lists
iniIdx = optind;
@@ -354,14 +370,16 @@ int main(int argc, char *argv[])
if (!optInteractive) {
// Non-interactive mode
- // Run the streams
+ // Run any streams where the stop initial state was not requested.
for (i1 = 0; i1 < tlCount; i1++) {
- printf("Starting: %s\n", tlIniList[i1]);
- openavbTLRun(tlHandleList[i1]);
+ if (openavbTLGetInitialState(tlHandleList[i1]) != TL_INIT_STATE_STOPPED) {
+ printf("Starting: %s\n", tlIniList[i1]);
+ openavbTLRun(tlHandleList[i1]);
+ }
}
while (bRunning) {
- sleep(1);
+ SLEEP_MSEC(1);
}
for (i1 = 0; i1 < tlCount; i1++) {
@@ -374,6 +392,14 @@ int main(int argc, char *argv[])
else {
// Interactive mode
+ // Run any streams where the running initial state was requested.
+ for (i1 = 0; i1 < tlCount; i1++) {
+ if (openavbTLGetInitialState(tlHandleList[i1]) == TL_INIT_STATE_RUNNING) {
+ printf("Starting: %s\n", tlIniList[i1]);
+ openavbTLRun(tlHandleList[i1]);
+ }
+ }
+
openavbTlHarnessMenu();
while (bRunning) {
char buf[16];
@@ -501,7 +527,7 @@ int main(int argc, char *argv[])
// Close the streams
for (i1 = 0; i1 < tlCount; i1++) {
if (tlHandleList[i1]) {
- printf("Stopping: %s\n", tlIniList[i1]);
+ printf("Closing: %s\n", tlIniList[i1]);
openavbTLClose(tlHandleList[i1]);
@@ -533,6 +559,11 @@ int main(int argc, char *argv[])
optStreamAddr = NULL;
}
+ if (optLogFileName) {
+ free(optLogFileName);
+ optLogFileName = NULL;
+ }
+
#ifdef AVB_FEATURE_GSTREAMER
// If we're supporting the interface modules which use GStreamer,
// De-initialize GStreamer to clean up resources.
diff --git a/lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c b/lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c
index 4a02546a..dd03f4a8 100644
--- a/lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c
+++ b/lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -48,7 +49,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
bool bRunning = TRUE;
-// Platform indendent mapping modules
+// Platform independent mapping modules
extern bool openavbMapPipeInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
extern bool openavbMapAVTPAudioInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
extern bool openavbMapCtrlInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
@@ -58,7 +59,7 @@ extern bool openavbMapMpeg2tsInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pM
extern bool openavbMapNullInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
extern bool openavbMapUncmpAudioInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
-// Platform indendent interface modules
+// Platform independent interface modules
extern bool openavbIntfEchoInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
extern bool openavbIntfCtrlInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
extern bool openavbIntfLoggerInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
@@ -84,9 +85,15 @@ static void openavbTLSigHandler(int signal)
{
AVB_TRACE_ENTRY(AVB_TRACE_HOST);
- if (signal == SIGINT) {
- AVB_LOG_INFO("Host shutting down");
- bRunning = FALSE;
+ if (signal == SIGINT || signal == SIGTERM) {
+ if (bRunning) {
+ AVB_LOG_INFO("Host shutting down");
+ bRunning = FALSE;
+ }
+ else {
+ // Force shutdown
+ exit(2);
+ }
}
else if (signal == SIGUSR1) {
AVB_LOG_DEBUG("Waking up streaming thread");
@@ -104,6 +111,7 @@ void openavbTlHostUsage(char *programName)
"\n"
"Usage: %s [options] file...\n"
" -I val Use given (val) interface globally, can be overriden by giving the ifname= option to the config line.\n"
+ " -l val Filename of the log file to use. If not specified, results will be logged to stderr.\n"
"\n"
"Examples:\n"
" %s talker.ini\n"
@@ -128,6 +136,7 @@ int main(int argc, char *argv[])
int iniIdx = 0;
char *programName;
char *optIfnameGlobal = NULL;
+ char *optLogFileName = NULL;
programName = strrchr(argv[0], '/');
programName = programName ? programName + 1 : argv[0];
@@ -143,12 +152,15 @@ int main(int argc, char *argv[])
// Process command line
bool optDone = FALSE;
while (!optDone) {
- int opt = getopt(argc, argv, "hI:");
+ int opt = getopt(argc, argv, "hI:l:");
if (opt != EOF) {
switch (opt) {
case 'I':
optIfnameGlobal = strdup(optarg);
break;
+ case 'l':
+ optLogFileName = strdup(optarg);
+ break;
case 'h':
default:
openavbTlHostUsage(programName);
@@ -160,7 +172,7 @@ int main(int argc, char *argv[])
}
}
- osalAVBInitialize(optIfnameGlobal);
+ osalAVBInitialize(optLogFileName, optIfnameGlobal);
iniIdx = optind;
U32 tlCount = argc - iniIdx;
@@ -185,6 +197,13 @@ int main(int argc, char *argv[])
osalAVBFinalize();
exit(-1);
}
+ err = sigaction(SIGTERM, &sa, NULL);
+ if (err)
+ {
+ AVB_LOG_ERROR("Failed to setup SIGTERM handler");
+ osalAVBFinalize();
+ exit(-1);
+ }
err = sigaction(SIGUSR1, &sa, NULL);
if (err)
{
@@ -193,6 +212,9 @@ int main(int argc, char *argv[])
exit(-1);
}
+ // Ignore SIGPIPE signals.
+ signal(SIGPIPE, SIG_IGN);
+
registerStaticMapModule(openavbMapPipeInitialize);
registerStaticMapModule(openavbMapAVTPAudioInitialize);
registerStaticMapModule(openavbMapCtrlInitialize);
@@ -262,12 +284,15 @@ int main(int argc, char *argv[])
gst_init(0, NULL);
#endif
+ // Run any streams where the stop initial state was not requested.
for (i1 = 0; i1 < tlCount; i1++) {
- openavbTLRun(tlHandleList[i1]);
+ if (openavbTLGetInitialState(tlHandleList[i1]) != TL_INIT_STATE_STOPPED) {
+ openavbTLRun(tlHandleList[i1]);
+ }
}
while (bRunning) {
- sleep(1);
+ SLEEP_MSEC(1);
}
for (i1 = 0; i1 < tlCount; i1++) {
@@ -280,6 +305,11 @@ int main(int argc, char *argv[])
openavbTLCleanup();
+ if (optLogFileName) {
+ free(optLogFileName);
+ optLogFileName = NULL;
+ }
+
#ifdef AVB_FEATURE_GSTREAMER
// If we're supporting the interface modules which use GStreamer,
// De-initialize GStreamer to clean up resources.
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/avdecc/CMakeLists.txt
new file mode 100644
index 00000000..139597f9
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.c b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.c
new file mode 100644
index 00000000..9c22fc36
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.c
@@ -0,0 +1,279 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : Reads the AVDECC .ini file for an endpoint
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include "openavb_avdecc_cfg.h"
+#include "openavb_trace.h"
+#include "openavb_rawsock.h"
+#include "ini.h"
+
+#define AVB_LOG_COMPONENT "AVDECC Cfg"
+#include "openavb_log.h"
+
+// macro to make matching names easier
+#define MATCH(A, B)(strcasecmp((A), (B)) == 0)
+#define MATCH_FIRST(A, B)(strncasecmp((A), (B), strlen(B)) == 0)
+
+static void cfgValErr(const char *section, const char *name, const char *value)
+{
+ AVB_LOGF_ERROR("Invalid value: section=%s, name=%s, value=%s",
+ section, name, value);
+}
+
+static int cfgCallback(void *user, const char *section, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ if (!user || !section || !name || !value) {
+ AVB_LOG_ERROR("Config: invalid arguments passed to callback");
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+
+ openavb_avdecc_cfg_t *pCfg = (openavb_avdecc_cfg_t*)user;
+
+ AVB_LOGF_DEBUG("name=[%s] value=[%s]", name, value);
+
+ bool valOK = FALSE;
+ char *pEnd;
+
+ if (MATCH(section, "network"))
+ {
+ if (MATCH(name, "ifname"))
+ {
+ if_info_t ifinfo;
+ if (openavbCheckInterface(value, &ifinfo)) {
+ strncpy(pCfg->ifname, value, sizeof(pCfg->ifname) - 1);
+ memcpy(pCfg->ifmac, &ifinfo.mac, ETH_ALEN);
+ valOK = TRUE;
+ }
+ }
+ }
+ else if (MATCH(section, "vlan"))
+ {
+ if (MATCH(name, "vlanID")) {
+ errno = 0;
+ pCfg->vlanID = strtoul(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "vlanPCP")) {
+ errno = 0;
+ pCfg->vlanPCP = strtoul(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0)
+ valOK = TRUE;
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+ }
+ else if (MATCH(section, "fast_connect"))
+ {
+ if (MATCH(name, "fast_connect")) {
+ errno = 0;
+ pCfg->bFastConnectSupported = (strtoul(value, &pEnd, 10) != 0);
+ if (*pEnd == '\0' && errno == 0)
+ valOK = TRUE;
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+ }
+ else if (MATCH(section, "discovery"))
+ {
+ if (MATCH(name, "valid_time")) {
+ errno = 0;
+ pCfg->valid_time = strtoul(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0) {
+ if (pCfg->valid_time < 2 || pCfg->valid_time > 62) {
+ AVB_LOG_ERROR("valid_time must be between 2 and 62 (inclusive)");
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+ if ((pCfg->valid_time & 1) != 0) {
+ AVB_LOGF_WARNING("valid_time converted to an even number (%d to %d)", pCfg->valid_time, pCfg->valid_time - 1);
+ }
+ pCfg->valid_time /= 2; // Convert from seconds to 2-second units.
+ valOK = TRUE;
+ }
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+ }
+ else if (MATCH(section, "descriptor_entity"))
+ {
+ if (MATCH(name, "avdeccId")) {
+ errno = 0;
+ pCfg->avdeccId = strtoul(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "entity_model_id")) {
+ errno = 0;
+ U64 nTemp = strtoull(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0) {
+ valOK = TRUE;
+ int i;
+ for (i = 7; i >= 0; --i) {
+ pCfg->entity_model_id[i] = (U8) (nTemp & 0xFF);
+ nTemp = (nTemp >> 8);
+ }
+ AVB_LOGF_DEBUG("entity_model_id = " ENTITYID_FORMAT, ENTITYID_ARGS(pCfg->entity_model_id));
+ }
+ }
+ else if (MATCH(name, "entity_name"))
+ {
+ strncpy(pCfg->entity_name, value, sizeof(pCfg->entity_name));
+ // String does not need to be 0-terminated.
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "firmware_version"))
+ {
+ strncpy(pCfg->firmware_version, value, sizeof(pCfg->firmware_version));
+ // String does not need to be 0-terminated.
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "group_name"))
+ {
+ strncpy(pCfg->group_name, value, sizeof(pCfg->group_name));
+ // String does not need to be 0-terminated.
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "serial_number"))
+ {
+ strncpy(pCfg->serial_number, value, sizeof(pCfg->serial_number));
+ // String does not need to be 0-terminated.
+ valOK = TRUE;
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+ }
+ else if (MATCH(section, "localization"))
+ {
+ if (MATCH(name, "locale_identifier"))
+ {
+ strncpy(pCfg->locale_identifier, value, sizeof(pCfg->locale_identifier));
+ // String does not need to be 0-terminated.
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "vendor_name"))
+ {
+ strncpy(pCfg->vendor_name, value, sizeof(pCfg->vendor_name));
+ // String does not need to be 0-terminated.
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "model_name"))
+ {
+ strncpy(pCfg->model_name, value, sizeof(pCfg->model_name));
+ // String does not need to be 0-terminated.
+ valOK = TRUE;
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+
+ if (!valOK) {
+ cfgValErr(section, name, value);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 1; // OK
+}
+
+// Parse ini file, and create config data
+//
+int openavbReadAvdeccConfig(const char *ini_file, openavb_avdecc_cfg_t *pCfg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ // defaults - most are handled by setting everything to 0
+ memset(pCfg, 0, sizeof(openavb_avdecc_cfg_t));
+ pCfg->valid_time = 31; // See IEEE Std 1722.1-2013 clause 6.2.1.6
+ pCfg->avdeccId = 0xfffe;
+
+ int result = ini_parse(ini_file, cfgCallback, pCfg);
+ if (result < 0) {
+ AVB_LOGF_ERROR("Couldn't parse INI file: %s", ini_file);
+ return -1;
+ }
+ if (result > 0) {
+ AVB_LOGF_ERROR("Error in INI file: %s, line %d", ini_file, result);
+ return -1;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+
+ // Yay, we did it.
+ return 0;
+}
+
+// Clean up any configuration-related stuff
+//
+void openavbAvdeccUnconfigure(openavb_avdecc_cfg_t *pCfg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+}
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.h b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.h
new file mode 100644
index 00000000..5de0dab1
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.h
@@ -0,0 +1,50 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* HEADER SUMMARY : Declarations used by the endpoint configuration
+*
+* Defines the endpoint configuration data, and the functions
+* to read the configuration data.
+*/
+
+#ifndef AVB_ENDPOINT_AVDECC_CONFIG_H
+#define AVB_ENDPOINT_AVDECC_CONFIG_H
+
+#include "openavb_types.h"
+#include "openavb_avdecc_pub.h"
+
+#define DEFAULT_AVDECC_INI_FILE "avdecc.ini"
+
+int openavbReadAvdeccConfig(const char *inifile, openavb_avdecc_cfg_t *pCfg);
+void openavbAvdeccUnconfigure(openavb_avdecc_cfg_t *pCfg);
+
+#endif // AVB_ENDPOINT_AVDECC_CONFIG_H
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_osal.c b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_osal.c
new file mode 100644
index 00000000..2e097548
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_osal.c
@@ -0,0 +1,203 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include "openavb_platform.h"
+#include "openavb_trace.h"
+#include "openavb_avdecc_cfg.h"
+#include "openavb_avdecc_read_ini_pub.h"
+#include "openavb_avdecc_msg.h"
+#include "openavb_list.h"
+
+#define AVB_LOG_COMPONENT "AVDECC"
+
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+// the following are from openavb_avdecc.c
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+extern openavb_tl_data_cfg_t * streamList;
+extern bool avdeccRunning;
+
+static pthread_t avdeccServerHandle;
+static void* avdeccServerThread(void *arg);
+
+static bool avdeccInitSucceeded;
+
+bool startAvdecc(const char* ifname, const char **inifiles, int numfiles)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+ LOG_EAVB_CORE_VERSION();
+
+ // Ensure that we're running as root
+ // (need to be root to use raw sockets)
+ uid_t euid = geteuid();
+ if (euid != (uid_t)0) {
+ fprintf(stderr, "Error: needs to run as root\n\n");
+ goto error;
+ }
+
+ // Get the AVDECC configuration
+ memset(&gAvdeccCfg, 0, sizeof(openavb_avdecc_cfg_t));
+ openavbReadAvdeccConfig(DEFAULT_AVDECC_INI_FILE, &gAvdeccCfg);
+
+ // Determine which interface to use.
+ if (ifname) {
+ strncpy(gAvdeccCfg.ifname, ifname, sizeof(gAvdeccCfg.ifname));
+ } else if (gAvdeccCfg.ifname[0] == '\0') {
+ AVB_LOG_ERROR("No interface specified. Use the -I flag, or add one to " DEFAULT_AVDECC_INI_FILE ".");
+ goto error;
+ }
+
+ // Read the information from the supplied INI files.
+ openavb_tl_data_cfg_t * prevStream = NULL, * newStream;
+ U32 i1;
+ for (i1 = 0; i1 < numfiles; i1++) {
+
+ char iniFile[1024];
+ snprintf(iniFile, sizeof(iniFile), "%s", inifiles[i1]);
+ // Create a new item with this INI information.
+ newStream = malloc(sizeof(openavb_tl_data_cfg_t));
+ if (!newStream) {
+ AVB_LOG_ERROR("Out of memory");
+ goto error;
+ }
+ memset(newStream, 0, sizeof(openavb_tl_data_cfg_t));
+ if (!openavbReadTlDataIniFile(iniFile, newStream)) {
+ AVB_LOGF_ERROR("Error reading ini file: %s", inifiles[i1]);
+ goto error;
+ }
+ // Append this item to the list of items.
+ if (!prevStream) {
+ // First item.
+ streamList = newStream;
+ } else {
+ // Subsequent item.
+ prevStream->next = newStream;
+ }
+ prevStream = newStream;
+ }
+
+ /* Run AVDECC in its own thread. */
+ avdeccRunning = TRUE;
+ avdeccInitSucceeded = FALSE;
+ int err = pthread_create(&avdeccServerHandle, NULL, avdeccServerThread, NULL);
+ if (err) {
+ AVB_LOGF_ERROR("Failed to start AVDECC thread: %s", strerror(err));
+ goto error;
+ }
+
+ /* Wait a while to see if the thread was able to start AVDECC. */
+ int i;
+ for (i = 0; avdeccRunning && !avdeccInitSucceeded && i < 5000; ++i) {
+ SLEEP_MSEC(1);
+ }
+ if (!avdeccInitSucceeded) {
+ goto error;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return true;
+
+error:
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+}
+
+void stopAvdecc()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ avdeccRunning = FALSE;
+ pthread_join(avdeccServerHandle, NULL);
+
+ AVB_LOG_INFO("Shutting down");
+
+ // Free the INI file items.
+ while (streamList) {
+ openavb_tl_data_cfg_t * del = streamList;
+ streamList = streamList->next;
+ free(del);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+}
+
+static void* avdeccServerThread(void *arg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ while (avdeccRunning) {
+ if (!openavbAvdeccInitialize()) {
+ AVB_LOG_ERROR("Failed to initialize AVDECC");
+ break;
+ }
+
+ AVB_LOG_DEBUG("AVDECC Initialized");
+
+ if (!openavbAvdeccStart()) {
+ AVB_LOG_ERROR("Failed to start AVDECC");
+ openavbAvdeccStop();
+ break;
+ }
+
+ if (!openavbAvdeccMsgServerOpen()) {
+ AVB_LOG_ERROR("Failed to start AVDECC Server");
+ openavbAvdeccStop();
+ break;
+ }
+ else {
+ AVB_LOG_INFO("AVDECC Started");
+ avdeccInitSucceeded = TRUE;
+
+ // Wait until AVDECC is finished.
+ while (avdeccRunning) {
+ openavbAvdeccMsgSrvrService();
+ }
+
+ openavbAvdeccMsgServerClose();
+ }
+
+ // Stop AVDECC
+ AVB_LOG_DEBUG("AVDECC Stopping");
+ openavbAvdeccStop();
+ AVB_LOG_INFO("AVDECC Stopped");
+ }
+
+ // Shutdown AVDECC
+ openavbAvdeccCleanup();
+
+ avdeccRunning = FALSE;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return NULL;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_osal.h b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_osal.h
new file mode 100644
index 00000000..b52f99b1
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_osal.h
@@ -0,0 +1,45 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OSAL_AVDECC_H
+#define OSAL_AVDECC_H
+
+// should only be included from openavb_avdecc.h
+
+#include <linux/un.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <signal.h>
+
+bool startAvdecc(const char* ifname, const char *inifiles[], int numfiles);
+void stopAvdecc();
+
+#endif // OSAL_AVDECC_H
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_pipeline_interaction.c b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_pipeline_interaction.c
new file mode 100644
index 00000000..5e6a5051
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_pipeline_interaction.c
@@ -0,0 +1,513 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#define AVB_LOG_COMPONENT "AVDECC"
+#include "openavb_log.h"
+#include "openavb_trace_pub.h"
+
+#include "openavb_aem_types_pub.h"
+#include "openavb_avdecc_pipeline_interaction_pub.h"
+#include "openavb_avdecc_msg_server.h"
+
+
+bool openavbAVDECCRunListener(openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput, U16 configIdx, openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ // Sanity tests.
+ if (!pDescriptorStreamInput) {
+ AVB_LOG_ERROR("openavbAVDECCRunListener Invalid descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pListenerStreamInfo) {
+ AVB_LOG_ERROR("openavbAVDECCRunListener Invalid streaminfo");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamInput->stream) {
+ AVB_LOG_ERROR("openavbAVDECCRunListener Invalid StreamInput descriptor stream");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamInput->stream->client) {
+ AVB_LOG_ERROR("openavbAVDECCRunListener Invalid stream client pointer");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Send the Stream ID to the client.
+ // The client will stop a running Listener if the settings differ from its current values.
+ if (!openavbAvdeccMsgSrvrListenerStreamID(pDescriptorStreamInput->stream->client->avdeccMsgHandle,
+ ((pListenerStreamInfo->flags & OPENAVB_ACMP_FLAG_CLASS_B) != 0 ? SR_CLASS_B : SR_CLASS_A),
+ pListenerStreamInfo->stream_id, /* The first 6 bytes of the steam_id are the source MAC Address */
+ (((U16) pListenerStreamInfo->stream_id[6]) << 8 | (U16) pListenerStreamInfo->stream_id[7]),
+ pListenerStreamInfo->stream_dest_mac,
+ pListenerStreamInfo->stream_vlan_id)) {
+ AVB_LOG_ERROR("Error send Stream ID to Listener");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Tell the client to start running.
+ if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptorStreamInput->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_RUNNING)) {
+ AVB_LOG_ERROR("Error requesting Listener change to Running");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ AVB_LOG_INFO("Listener state change to Running requested");
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+bool openavbAVDECCRunTalker(openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput, U16 configIdx, openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ // Sanity tests.
+ if (!pDescriptorStreamOutput) {
+ AVB_LOG_ERROR("openavbAVDECCRunTalker Invalid descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pTalkerStreamInfo) {
+ AVB_LOG_ERROR("openavbAVDECCRunTalker Invalid streaminfo");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamOutput->stream) {
+ AVB_LOG_ERROR("openavbAVDECCRunTalker Invalid StreamInput descriptor stream");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamOutput->stream->client) {
+ AVB_LOG_ERROR("openavbAVDECCRunTalker Invalid stream client pointer");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Tell the client to start running.
+ // Note that that Talker may already be running; this call ensures that it really is.
+ if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptorStreamOutput->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_RUNNING)) {
+ AVB_LOG_ERROR("Error requesting Talker change to Running");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ AVB_LOG_INFO("Talker state change to Running requested");
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+bool openavbAVDECCStopListener(openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput, U16 configIdx, openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ // Sanity tests.
+ if (!pDescriptorStreamInput) {
+ AVB_LOG_ERROR("openavbAVDECCStopListener Invalid descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pListenerStreamInfo) {
+ AVB_LOG_ERROR("openavbAVDECCStopListener Invalid streaminfo");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamInput->stream) {
+ AVB_LOG_ERROR("openavbAVDECCStopListener Invalid StreamInput descriptor stream");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamInput->stream->client) {
+ AVB_LOG_ERROR("openavbAVDECCStopListener Invalid stream client pointer");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Don't request if already stopped.
+ if (pDescriptorStreamInput->stream->client->lastReportedState == OPENAVB_AVDECC_MSG_STOPPED) {
+ AVB_LOG_INFO("Listener state change to Stopped ignored, as Listener already Stopped");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+ }
+
+ // Send the request to the client.
+ if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptorStreamInput->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_STOPPED)) {
+ AVB_LOG_ERROR("Error requesting Listener change to Stopped");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ AVB_LOG_INFO("Listener state change to Stopped requested");
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+bool openavbAVDECCStopTalker(openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput, U16 configIdx, openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ // Sanity tests.
+ if (!pDescriptorStreamOutput) {
+ AVB_LOG_ERROR("openavbAVDECCStopTalker Invalid descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pTalkerStreamInfo) {
+ AVB_LOG_ERROR("openavbAVDECCStopTalker Invalid streaminfo");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamOutput->stream) {
+ AVB_LOG_ERROR("openavbAVDECCStopTalker Invalid StreamInput descriptor stream");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamOutput->stream->client) {
+ AVB_LOG_ERROR("openavbAVDECCStopTalker Invalid stream client pointer");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Don't request if already stopped.
+ if (pDescriptorStreamOutput->stream->client->lastReportedState == OPENAVB_AVDECC_MSG_STOPPED) {
+ AVB_LOG_INFO("Talker state change to Stopped ignored, as Talker already Stopped");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+ }
+
+ // Send the request to the client.
+ if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptorStreamOutput->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_STOPPED)) {
+ AVB_LOG_ERROR("Error requesting Talker change to Stopped");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ AVB_LOG_INFO("Talker state change to Stopped requested");
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+bool openavbAVDECCGetTalkerStreamInfo(openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput, U16 configIdx, openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ // Sanity tests.
+ if (!pDescriptorStreamOutput) {
+ AVB_LOG_ERROR("openavbAVDECCGetTalkerStreamInfo Invalid descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pTalkerStreamInfo) {
+ AVB_LOG_ERROR("openavbAVDECCGetTalkerStreamInfo Invalid streaminfo");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamOutput->stream) {
+ AVB_LOG_ERROR("openavbAVDECCGetTalkerStreamInfo Invalid StreamInput descriptor stream");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Get the destination MAC Address.
+ if (!pDescriptorStreamOutput->stream->dest_addr.mac ||
+ memcmp(pDescriptorStreamOutput->stream->dest_addr.buffer.ether_addr_octet, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0) {
+ AVB_LOG_DEBUG("openavbAVDECCGetTalkerStreamInfo Invalid stream dest_addr");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ memcpy(pTalkerStreamInfo->stream_dest_mac, pDescriptorStreamOutput->stream->dest_addr.mac, ETH_ALEN);
+ AVB_LOGF_DEBUG("Talker stream_dest_mac: " ETH_FORMAT,
+ ETH_OCTETS(pTalkerStreamInfo->stream_dest_mac));
+
+ // Get the Stream ID.
+ if (!pDescriptorStreamOutput->stream->stream_addr.mac ||
+ memcmp(pDescriptorStreamOutput->stream->stream_addr.buffer.ether_addr_octet, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0) {
+ AVB_LOG_ERROR("openavbAVDECCGetTalkerStreamInfo Invalid stream stream_addr");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ memcpy(pTalkerStreamInfo->stream_id, pDescriptorStreamOutput->stream->stream_addr.mac, ETH_ALEN);
+ U8 *pStreamUID = pTalkerStreamInfo->stream_id + 6;
+ *(U16 *)(pStreamUID) = htons(pDescriptorStreamOutput->stream->stream_uid);
+ AVB_LOGF_DEBUG("Talker stream_id: " ETH_FORMAT "/%u",
+ ETH_OCTETS(pTalkerStreamInfo->stream_id),
+ (((U16) pTalkerStreamInfo->stream_id[6]) << 8) | (U16) pTalkerStreamInfo->stream_id[7]);
+
+ // Get the VLAN ID.
+ pTalkerStreamInfo->stream_vlan_id = pDescriptorStreamOutput->stream->vlan_id;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+bool openavbAVDECCSetTalkerStreamInfo(openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput,
+ U8 sr_class, U8 stream_id_valid, const U8 stream_src_mac[6], U16 stream_uid, U8 stream_dest_valid, const U8 stream_dest_mac[6], U8 stream_vlan_id_valid, U16 stream_vlan_id)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ // Sanity tests.
+ if (!pDescriptorStreamOutput) {
+ AVB_LOG_ERROR("openavbAVDECCSetTalkerStreamInfo Invalid descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamOutput->stream) {
+ AVB_LOG_ERROR("openavbAVDECCSetTalkerStreamInfo Invalid StreamInput descriptor stream");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamOutput->stream->client) {
+ AVB_LOG_ERROR("openavbAVDECCSetTalkerStreamInfo Invalid stream client pointer");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Send the information to the client.
+ if (!openavbAvdeccMsgSrvrTalkerStreamID(pDescriptorStreamOutput->stream->client->avdeccMsgHandle,
+ sr_class, stream_id_valid, stream_src_mac, stream_uid, stream_dest_valid, stream_dest_mac, stream_vlan_id_valid, stream_vlan_id)) {
+ AVB_LOG_ERROR("Error sending stream info updates to Talker");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+openavbAvdeccMsgStateType_t openavbAVDECCGetRequestedState(openavb_aem_descriptor_stream_io_t *pDescriptorStream, U16 configIdx)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ // Sanity tests.
+ if (!pDescriptorStream) {
+ AVB_LOG_ERROR("openavbAVDECCGetRequestedState Invalid descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return OPENAVB_AVDECC_MSG_UNKNOWN;
+ }
+ if (!pDescriptorStream->stream) {
+ AVB_LOG_ERROR("openavbAVDECCGetRequestedState Invalid descriptor stream");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return OPENAVB_AVDECC_MSG_UNKNOWN;
+ }
+ if (!pDescriptorStream->stream->client) {
+ AVB_LOG_DEBUG("openavbAVDECCGetRequestedState Invalid stream client pointer");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return OPENAVB_AVDECC_MSG_UNKNOWN;
+ }
+
+ // Return the current state.
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return pDescriptorStream->stream->client->lastRequestedState;
+}
+
+openavbAvdeccMsgStateType_t openavbAVDECCGetStreamingState(openavb_aem_descriptor_stream_io_t *pDescriptorStream, U16 configIdx)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ // Sanity tests.
+ if (!pDescriptorStream) {
+ AVB_LOG_ERROR("openavbAVDECCGetStreamingState Invalid descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return OPENAVB_AVDECC_MSG_UNKNOWN;
+ }
+ if (!pDescriptorStream->stream) {
+ AVB_LOG_ERROR("openavbAVDECCGetStreamingState Invalid descriptor stream");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return OPENAVB_AVDECC_MSG_UNKNOWN;
+ }
+ if (!pDescriptorStream->stream->client) {
+ AVB_LOG_DEBUG("openavbAVDECCGetStreamingState Invalid stream client pointer");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return OPENAVB_AVDECC_MSG_UNKNOWN;
+ }
+
+ // Return the current state.
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return pDescriptorStream->stream->client->lastReportedState;
+}
+
+void openavbAVDECCPauseStream(openavb_aem_descriptor_stream_io_t *pDescriptor, bool bPause)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ // Sanity test.
+ if (!pDescriptor) {
+ AVB_LOG_ERROR("openavbAVDECCPauseStream Invalid descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+ if (!pDescriptor->stream) {
+ AVB_LOG_ERROR("openavbAVDECCPauseStream Invalid StreamInput descriptor stream");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+ if (!pDescriptor->stream->client) {
+ AVB_LOG_ERROR("openavbAVDECCPauseStream Invalid stream client pointer");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+
+ if (pDescriptor->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) {
+
+ if (bPause) {
+ // If the client is not running (or already paused), ignore this command.
+ if (pDescriptor->stream->client->lastReportedState != OPENAVB_AVDECC_MSG_RUNNING) {
+ AVB_LOG_DEBUG("Listener state change to pause ignored, as Listener not running");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+
+ // Send the request to the client.
+ if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptor->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_PAUSED)) {
+ AVB_LOG_ERROR("Error requesting Listener change to Paused");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+
+ AVB_LOG_INFO("Listener state change from Running to Paused requested");
+ }
+ else {
+ // If the client is not paused, ignore this command.
+ if (pDescriptor->stream->client->lastReportedState != OPENAVB_AVDECC_MSG_PAUSED) {
+ AVB_LOG_DEBUG("Listener state change to pause ignored, as Listener not paused");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+
+ // Send the request to the client.
+ if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptor->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_RUNNING)) {
+ AVB_LOG_ERROR("Error requesting Listener change to Running");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+
+ AVB_LOG_INFO("Listener state change from Paused to Running requested");
+ }
+ }
+ else if (pDescriptor->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+
+ if (bPause) {
+ // If the client is not running (or already paused), ignore this command.
+ if (pDescriptor->stream->client->lastReportedState != OPENAVB_AVDECC_MSG_RUNNING) {
+ AVB_LOG_DEBUG("Talker state change to pause ignored, as Talker not running");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+
+ // Send the request to the client.
+ if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptor->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_PAUSED)) {
+ AVB_LOG_ERROR("Error requesting Talker change to Paused");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+
+ AVB_LOG_INFO("Talker state change from Running to Paused requested");
+ }
+ else {
+ // If the client is not paused, ignore this command.
+ if (pDescriptor->stream->client->lastReportedState != OPENAVB_AVDECC_MSG_PAUSED) {
+ AVB_LOG_DEBUG("Talker state change to pause ignored, as Talker not paused");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+
+ // Send the request to the client.
+ if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptor->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_RUNNING)) {
+ AVB_LOG_ERROR("Error requesting Talker change to Running");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+
+ AVB_LOG_INFO("Talker state change from Paused to Running requested");
+ }
+ }
+ else {
+ AVB_LOG_ERROR("openavbAVDECCPauseStream unsupported descriptor");
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+}
+
+// Get the current counter value in pValue. Returns TRUE if the counter is supported, FALSE otherwise.
+bool openavbAVDECCGetCounterValue(void *pDescriptor, U16 descriptorType, U32 counterFlag, U32 *pValue)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ if (!pDescriptor) {
+ /* Asked for a non-existing descriptor. */
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ switch (descriptorType) {
+ case OPENAVB_AEM_DESCRIPTOR_ENTITY:
+ // The only counters are entity-specific.
+ break;
+
+ case OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE:
+ // AVDECC_TODO - Get the LINK_UP, LINK_DOWN, FRAMES_TX, FRAMES_RX, RX_CRC_ERROR. and GPTP_GM_CHANGED counts from the gPTP daemon.
+ break;
+
+ case OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN:
+ {
+ switch (counterFlag) {
+ case OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_LOCKED:
+ AVB_LOG_ERROR("OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_LOCKED Not Implemented!");
+ if (pValue) { *pValue = 1; }
+ return TRUE;
+
+ case OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_UNLOCKED:
+ AVB_LOG_ERROR("OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_UNLOCKED Not Implemented!");
+ if (pValue) { *pValue = 1; }
+ return TRUE;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ case OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT:
+ // AVDECC_TODO - Get the MEDIA_LOCKED, MEDIA_UNLOCKED, STREAM_RESET, SEQ_NUM_MISMATCH, MEDIA_RESET,
+ // TIMESTAMP_UNCERTAIN, TIMESTAMP_VALID, TIMESTAMP_NOT_VALID, UNSUPPORTED_FORMAT,
+ // LATE_TIMESTAMP, EARLY_TIMESTAMP, FRAMES_RX, and FRAMES_TX counts.
+ break;
+
+ default:
+ break;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_read_ini.c b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_read_ini.c
new file mode 100644
index 00000000..06c8b280
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_read_ini.c
@@ -0,0 +1,620 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "ini.h"
+
+#include "openavb_platform.h"
+#include "openavb_trace.h"
+#include "openavb_audio_pub.h"
+#include "openavb_avdecc_pub.h"
+#include "openavb_avdecc_read_ini_pub.h"
+#include "openavb_avdecc_save_state.h"
+
+#define AVB_LOG_COMPONENT "TL INI"
+#include "openavb_log.h"
+
+#define MATCH(A, B)(strcasecmp((A), (B)) == 0)
+#define MATCH_LEFT(A, B, C)(strncasecmp((A), (B), (C)) == 0)
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+
+static bool parse_mac(const char *str, cfg_mac_t *mac)
+{
+ memset(&mac->buffer, 0, sizeof(struct ether_addr));
+
+ mac->mac = ether_aton_r(str, &mac->buffer);
+ if (mac->mac)
+ return TRUE;
+
+ AVB_LOGF_ERROR("Failed to parse addr: %s", str);
+ return FALSE;
+}
+
+static void openavbIniCfgInit(openavb_tl_data_cfg_t *pCfg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ memset(pCfg, 0, sizeof(openavb_tl_data_cfg_t));
+
+ // Set default values.
+ // (These values should match those set in openavbTLInitCfg().)
+ pCfg->role = AVB_ROLE_UNDEFINED;
+ pCfg->initial_state = TL_INIT_STATE_UNSPECIFIED;
+ pCfg->stream_uid = 0xFFFF;
+ pCfg->max_interval_frames = 1;
+ pCfg->max_frame_size = 1500;
+ pCfg->max_transit_usec = 50000;
+ pCfg->max_transmit_deficit_usec = 50000;
+ pCfg->internal_latency = 0;
+ pCfg->max_stale = MICROSECONDS_PER_SECOND;
+ pCfg->batch_factor = 1;
+ pCfg->report_seconds = 0;
+ pCfg->start_paused = FALSE;
+ pCfg->sr_class = SR_CLASS_B;
+ pCfg->sr_rank = SR_RANK_REGULAR;
+ pCfg->raw_tx_buffers = 8;
+ pCfg->raw_rx_buffers = 100;
+ pCfg->tx_blocking_in_intf = 0;
+ pCfg->rx_signal_mode = 1;
+ pCfg->vlan_id = 0xFFFF;
+ pCfg->fixed_timestamp = 0;
+ pCfg->spin_wait = FALSE;
+ pCfg->thread_rt_priority = 0;
+ pCfg->thread_affinity = 0xFFFFFFFF;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+}
+
+// callback function - called for each name/value pair by ini parsing library
+static int openavbIniCfgCallback(void *user, const char *tlSection, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ openavb_tl_data_cfg_t *pCfg = (openavb_tl_data_cfg_t *)user;
+
+ AVB_LOGF_DEBUG("name=[%s] value=[%s]", name, value);
+
+ bool valOK = FALSE;
+ char *pEnd;
+
+ if (MATCH(name, "role")) {
+ if (MATCH(value, "talker")) {
+ pCfg->role = AVB_ROLE_TALKER;
+ valOK = TRUE;
+ }
+ else if (MATCH(value, "listener")) {
+ pCfg->role = AVB_ROLE_LISTENER;
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "initial_state")) {
+ if (MATCH(value, "running")) {
+ pCfg->initial_state = TL_INIT_STATE_RUNNING;
+ valOK = TRUE;
+ }
+ else if (MATCH(value, "stopped")) {
+ pCfg->initial_state = TL_INIT_STATE_STOPPED;
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "dest_addr")) {
+ valOK = parse_mac(value, &pCfg->dest_addr);
+ }
+ else if (MATCH(name, "stream_addr")) {
+ valOK = parse_mac(value, &pCfg->stream_addr);
+ }
+ else if (MATCH(name, "stream_uid")) {
+ errno = 0;
+ pCfg->stream_uid = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->stream_uid <= UINT16_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "max_interval_frames")) {
+ errno = 0;
+ pCfg->max_interval_frames = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->max_interval_frames <= UINT16_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "max_frame_size")) {
+ errno = 0;
+ pCfg->max_frame_size = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->max_interval_frames <= UINT16_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "sr_class")) {
+ if (strlen(value) == 1) {
+ if (tolower(value[0]) == 'a') {
+ pCfg->sr_class = SR_CLASS_A;
+ valOK = TRUE;
+ }
+ else if (tolower(value[0]) == 'b') {
+ pCfg->sr_class = SR_CLASS_B;
+ valOK = TRUE;
+ }
+ }
+ }
+ else if (MATCH(name, "sr_rank")) {
+ if (strlen(value) == 1) {
+ if (value[0] == '1') {
+ pCfg->sr_rank = SR_RANK_REGULAR;
+ valOK = TRUE;
+ }
+ else if (value[0] == '0') {
+ pCfg->sr_rank = SR_RANK_EMERGENCY;
+ valOK = TRUE;
+ }
+ }
+ }
+ else if (MATCH(name, "max_transit_usec")) {
+ errno = 0;
+ pCfg->max_transit_usec = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->max_transit_usec <= UINT32_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "max_transmit_deficit_usec")) {
+ errno = 0;
+ pCfg->max_transmit_deficit_usec = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->max_transmit_deficit_usec <= UINT32_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "internal_latency")) {
+ errno = 0;
+ pCfg->internal_latency = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->internal_latency <= UINT32_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "batch_factor")) {
+ errno = 0;
+ pCfg->batch_factor = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->batch_factor > 0
+ && pCfg->batch_factor <= INT32_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "max_stale")) {
+ errno = 0;
+ pCfg->max_stale = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->max_stale >= 0
+ && pCfg->max_stale <= INT32_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "raw_tx_buffers")) {
+ errno = 0;
+ pCfg->raw_tx_buffers = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->raw_tx_buffers <= UINT32_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "raw_rx_buffers")) {
+ errno = 0;
+ pCfg->raw_rx_buffers = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->raw_rx_buffers <= UINT32_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "report_seconds")) {
+ errno = 0;
+ pCfg->report_seconds = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && (int)pCfg->report_seconds >= 0
+ && pCfg->report_seconds <= INT32_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "start_paused")) {
+ // ignore this item - tl_host doesn't use it because
+ // it pauses before reading any of its streams.
+ errno = 0;
+ long tmp;
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && tmp >= 0
+ && tmp <= 1) {
+ pCfg->start_paused = (tmp == 1);
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "vlan_id")) {
+ errno = 0;
+ long tmp;
+ tmp = strtol(value, &pEnd, 0);
+ // vlanID is 12 bit field
+ if (*pEnd == '\0' && errno == 0
+ && tmp >= 0x0
+ && tmp <= 0xFFF) {
+ pCfg->vlan_id = tmp;
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "fixed_timestamp")) {
+ errno = 0;
+ long tmp;
+ tmp = strtol(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0) {
+ pCfg->fixed_timestamp = tmp;
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "spin_wait")) {
+ errno = 0;
+ long tmp;
+ tmp = strtol(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0) {
+ pCfg->spin_wait = (tmp == 1);
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "tx_blocking_in_intf")) {
+ errno = 0;
+ long tmp;
+ tmp = strtol(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0) {
+ pCfg->tx_blocking_in_intf = tmp;
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "thread_rt_priority")) {
+ errno = 0;
+ long tmp;
+ tmp = strtol(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0) {
+ pCfg->thread_rt_priority = tmp;
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "thread_affinity")) {
+ errno = 0;
+ unsigned long tmp;
+ tmp = strtoul(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0) {
+ pCfg->thread_affinity = tmp;
+ valOK = TRUE;
+ }
+ }
+
+ else if (MATCH(name, "friendly_name")) {
+ strncpy(pCfg->friendly_name, value, FRIENDLY_NAME_SIZE - 1);
+ valOK = TRUE;
+ }
+
+ else if (MATCH(name, "current_sampling_rate")) {
+ errno = 0;
+ pCfg->current_sampling_rate = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->current_sampling_rate <= UINT32_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "sampling_rates")) {
+ errno = 0;
+ memset(pCfg->sampling_rates,0,sizeof(pCfg->sampling_rates));
+ char *rate, *copy;
+ copy = strdup(value);
+ rate = strtok(copy,",");
+ int i = 0,break_flag = 0;
+ while (rate != NULL )
+ {
+ pCfg->sampling_rates[i] = strtol(rate,&pEnd, 10);
+ if (*pEnd != '\0' || errno != 0
+ || pCfg->sampling_rates[i] > UINT32_MAX)
+ {
+ break_flag = 1;
+ break;
+ }
+ rate = strtok(NULL,",");
+ i++;
+ }
+ if (break_flag != 1)
+ {
+ valOK = TRUE;
+ pCfg->sampling_rates_count = i;
+ }
+ }
+ else if (strcmp(name, "intf_nv_audio_rate") == 0) {
+ long int val = strtol(value, &pEnd, 10);
+ if (val >= AVB_AUDIO_RATE_8KHZ && val <= AVB_AUDIO_RATE_192KHZ) {
+ pCfg->audioRate = val;
+ valOK = TRUE;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid audio rate configured for intf_nv_audio_rate.");
+ pCfg->audioRate = AVB_AUDIO_RATE_44_1KHZ;
+ }
+ }
+ else if (strcmp(name, "intf_nv_audio_bit_depth") == 0) {
+ long int val = strtol(value, &pEnd, 10);
+ if (val >= AVB_AUDIO_BIT_DEPTH_1BIT && val <= AVB_AUDIO_BIT_DEPTH_64BIT) {
+ pCfg->audioBitDepth = val;
+ valOK = TRUE;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid audio type configured for intf_nv_audio_bits.");
+ pCfg->audioBitDepth = AVB_AUDIO_BIT_DEPTH_24BIT;
+ }
+ }
+ else if (strcmp(name, "intf_nv_audio_channels") == 0) {
+ long int val = strtol(value, &pEnd, 10);
+ if (val >= AVB_AUDIO_CHANNELS_1 && val <= AVB_AUDIO_CHANNELS_8) {
+ pCfg->audioChannels = val;
+ valOK = TRUE;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid audio channels configured for intf_nv_audio_channels.");
+ pCfg->audioChannels = AVB_AUDIO_CHANNELS_2;
+ }
+ }
+ else if (MATCH(name, "map_fn")) {
+ errno = 0;
+ memset(pCfg->map_fn,0,sizeof(pCfg->map_fn));
+ strncpy(pCfg->map_fn,value,sizeof(pCfg->map_fn)-1);
+ valOK = TRUE;
+ }
+
+ else {
+ // Ignored item.
+ AVB_LOGF_DEBUG("Unhandled configuration item: name=%s, value=%s", name, value);
+
+ // Don't abort for this item.
+ valOK = TRUE;
+ }
+
+ if (!valOK) {
+ // bad value
+ AVB_LOGF_ERROR("Invalid value: name=%s, value=%s", name, value);
+ return 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+
+ return 1; // OK
+}
+
+bool openavbReadTlDataIniFile(const char *fileName, openavb_tl_data_cfg_t *pCfg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ openavbIniCfgInit(pCfg);
+
+ // Use the .INI file name as the default friendly name.
+ strncpy(pCfg->friendly_name, fileName, FRIENDLY_NAME_SIZE - 1);
+ char * pszComma = strchr(pCfg->friendly_name, ',');
+ if (pszComma) {
+ // Get rid of anything following the file name.
+ *pszComma = '\0';
+ }
+ char * pszExtension = strrchr(pCfg->friendly_name, '.');
+ if (pszExtension && strcasecmp(pszExtension, ".ini") == 0) {
+ // Get rid of the .INI file extension.
+ *pszExtension = '\0';
+ }
+
+ int result = ini_parse(fileName, openavbIniCfgCallback, pCfg);
+ if (result < 0) {
+ AVB_LOGF_ERROR("Couldn't parse INI file: %s", fileName);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (result > 0) {
+ AVB_LOGF_ERROR("Error in INI file: %s, line %d", fileName, result);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ if (pCfg->current_sampling_rate != 0 && pCfg->audioRate != 0 &&
+ pCfg->current_sampling_rate != pCfg->audioRate)
+ {
+ AVB_LOGF_ERROR("current_sampling_rate(%u) and intf_nv_audio_rate(%u) do not match.", pCfg->current_sampling_rate, pCfg->audioRate);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ if (pCfg->current_sampling_rate == 0)
+ {
+ /* Make sure we have a default sampling rate. */
+ if (pCfg->audioRate != 0) {
+ pCfg->current_sampling_rate = pCfg->audioRate;
+ } else if (pCfg->sampling_rates[0] != 0) {
+ pCfg->current_sampling_rate = pCfg->sampling_rates[0];
+ } else {
+ pCfg->current_sampling_rate = AVB_AUDIO_RATE_48KHZ;
+ }
+ if (pCfg->audioRate == 0) {
+ AVB_LOGF_WARNING("current_sampling_rate not specified in %s. Defaulting to %u", fileName, pCfg->current_sampling_rate);
+ }
+ }
+ if (pCfg->sampling_rates_count == 0)
+ {
+ /* Set the list of sampling rates to the current sampling rate. */
+ pCfg->sampling_rates[0] = pCfg->current_sampling_rate;
+ pCfg->sampling_rates_count = 1;
+ if (pCfg->audioRate == 0) {
+ AVB_LOGF_WARNING("sampling_rates not specified in %s. Defaulting to %u", fileName, pCfg->current_sampling_rate);
+ }
+ } else {
+ /* Make sure the current sampling rate is in the list of sampling rates. */
+ U16 i;
+ for (i = 0; i < pCfg->sampling_rates_count; ++i) {
+ if (pCfg->sampling_rates[i] == pCfg->current_sampling_rate) break;
+ }
+ if (i >= pCfg->sampling_rates_count) {
+ AVB_LOGF_ERROR("current_sampling_rate(%u) not in list of sampling_rates.", pCfg->current_sampling_rate);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+
+// Save the connection to the saved state
+//
+bool openavbAvdeccSaveState(const openavb_tl_data_cfg_t *pListener, U16 flags, U16 talker_unique_id, const U8 talker_entity_id[8], const U8 controller_entity_id[8])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ int i;
+
+ // Don't add to the saved state list if fast connect support is not enabled.
+ if (!gAvdeccCfg.bFastConnectSupported) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+
+ // If the supplied saved state matches one of the ones already saved, do nothing and return.
+ // If the Talker or Controller has changed, delete the old information.
+ for (i = 0; i < 1000; ++i) {
+ const openavb_saved_state_t * pTest = openavbAvdeccGetSavedState(i);
+ if (!pTest) {
+ break;
+ }
+
+ if (strcmp(pTest->listener_friendly_name, pListener->friendly_name) == 0) {
+ if (pTest->flags == flags &&
+ pTest->talker_unique_id == talker_unique_id &&
+ memcmp(pTest->talker_entity_id, talker_entity_id, 8) == 0 &&
+ memcmp(pTest->controller_entity_id, controller_entity_id, 8) == 0) {
+ // The supplied data is a match for the existing item. Do nothing.
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return true;
+ }
+
+ // Delete this item. We will create a new item with the updated information.
+ openavbAvdeccDeleteSavedState(i);
+ break;
+ }
+ }
+
+ // Add the supplied state to the list of states.
+ openavbAvdeccAddSavedState(pListener->friendly_name, flags, talker_unique_id, talker_entity_id, controller_entity_id);
+
+ AVB_LOGF_DEBUG("New saved state: listener_id=%s, flags=0x%04x, talker_unique_id=0x%04x, talker_entity_id=" ENTITYID_FORMAT ", controller_entity_id=" ENTITYID_FORMAT,
+ pListener->friendly_name,
+ flags,
+ talker_unique_id,
+ ENTITYID_ARGS(talker_entity_id),
+ ENTITYID_ARGS(controller_entity_id));
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return true;
+}
+
+// Delete a connection with saved state
+//
+bool openavbAvdeccClearSavedState(const openavb_tl_data_cfg_t *pListener)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ int i;
+
+ // Delete the saved state matching the supplied one.
+ // If the supplied saved state does not match any of the ones already saved, do nothing and return.
+ for (i = 0; i < 1000; ++i) {
+ const openavb_saved_state_t * pTest = openavbAvdeccGetSavedState(i);
+ if (!pTest) {
+ break;
+ }
+
+ if (strcmp(pTest->listener_friendly_name, pListener->friendly_name) == 0) {
+ // We found the index for the item to delete.
+ // Delete the item and save the updated file.
+ openavbAvdeccDeleteSavedState(i);
+ AVB_LOGF_DEBUG("Cleared saved state: listener_id=\"%s\"", pListener->friendly_name);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return true;
+ }
+ }
+
+ AVB_LOGF_WARNING("Unable to find saved state to clear: listener_id=\"%s\"", pListener->friendly_name);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+}
+
+// Determine if the connection has a saved state
+//
+bool openavbAvdeccGetSaveStateInfo(const openavb_tl_data_cfg_t *pListener, U16 *p_flags, U16 *p_talker_unique_id, U8 (*p_talker_entity_id)[8], U8 (*p_controller_entity_id)[8])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ int i;
+
+ // Don't return anything from the saved state list if fast connect support is not enabled.
+ if (!gAvdeccCfg.bFastConnectSupported) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+
+ // If the loaded saved state information matches the Listener supplied, return the information for it.
+ for (i = 0; i < 1000; ++i) {
+ const openavb_saved_state_t * pTest = openavbAvdeccGetSavedState(i);
+ if (!pTest) {
+ break;
+ }
+
+ if (strcmp(pTest->listener_friendly_name, pListener->friendly_name) == 0) {
+ AVB_LOGF_DEBUG("Saved state available for listener_id=%s, flags=0x%04x, talker_unique_id=0x%04x, talker_entity_id=" ENTITYID_FORMAT ", controller_entity_id=" ENTITYID_FORMAT,
+ pListener->friendly_name,
+ pTest->flags,
+ pTest->talker_unique_id,
+ ENTITYID_ARGS(pTest->talker_entity_id),
+ ENTITYID_ARGS(pTest->controller_entity_id));
+ if (p_flags) {
+ *p_flags = pTest->flags;
+ }
+ if (p_talker_unique_id) {
+ *p_talker_unique_id = pTest->talker_unique_id;
+ }
+ if (p_talker_entity_id) {
+ memcpy(*p_talker_entity_id, pTest->talker_entity_id, 8);
+ }
+ if (p_controller_entity_id) {
+ memcpy(*p_controller_entity_id, pTest->controller_entity_id, 8);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return true;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_save_state.c b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_save_state.c
new file mode 100644
index 00000000..4287449b
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_save_state.c
@@ -0,0 +1,363 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : Support for ACMP saved state
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include "openavb_avdecc_cfg.h"
+#include "openavb_avdecc_save_state.h"
+#include "openavb_trace.h"
+
+#define AVB_LOG_COMPONENT "AVDECC Cfg"
+#include "openavb_log.h"
+
+#define MAX_SAVED_STATES 4
+static openavb_saved_state_t s_sSavedStateInfo[MAX_SAVED_STATES];
+static int s_nNumSavedStates = -1;
+
+
+static int get_hex_value(char c)
+{
+ if (c >= '0' && c <= '9') return ((int) c - (int) '0');
+ if (c >= 'A' && c <= 'F') return ((int) c - (int) 'A' + 10);
+ if (c >= 'a' && c <= 'f') return ((int) c - (int) 'a' + 10);
+ return -1;
+}
+
+static bool get_entity_id(const char *input, U8 output[8])
+{
+ int i;
+ for (i = 0; i < 8; ++i) {
+ // Get the hexadecimal number
+ int n1 = get_hex_value(*input++);
+ if (n1 < 0) return false;
+ int n2 = get_hex_value(*input++);
+ if (n2 < 0) return false;
+ output[i] = (U8) (n1 << 4 | n2);
+
+ // Verify the colon separator
+ if (i < 7) {
+ if (*input++ != ':') {
+ return false;
+ }
+ }
+ }
+
+ // Make sure anything trailing the Entity ID is not interesting.
+ return (*input == '\0' || isspace(*input));
+}
+
+static bool get_saved_state_info(const char *ini_file)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ FILE* file;
+ char temp_buffer[FRIENDLY_NAME_SIZE + 10];
+ long temp_int;
+ char *pEnd;
+
+ s_nNumSavedStates = -1;
+
+ char *pvtFilename = strdup(ini_file);
+ if (!pvtFilename) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+
+ s_nNumSavedStates = 0;
+
+ char *override = strchr(pvtFilename, ',');
+ if (override)
+ *override++ = '\0';
+
+ file = fopen(pvtFilename, "r");
+ if (!file) {
+ // No file to read. Ignore this error.
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return true;
+ }
+
+ for (s_nNumSavedStates = 0; s_nNumSavedStates < MAX_SAVED_STATES; ++s_nNumSavedStates) {
+ // Extract the friendly name.
+ while (TRUE) {
+ if (fgets(temp_buffer, sizeof(temp_buffer), file) == NULL) {
+ if (!feof(file)) {
+ AVB_LOGF_ERROR("Error reading from INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return true;
+ }
+
+ // Remove any white space from the end of the friendly name.
+ int length = strlen(temp_buffer);
+ while (length > 0 &&
+ (temp_buffer[length - 1] == '\r' ||
+ temp_buffer[length - 1] == '\n')) {
+ temp_buffer[--length] = '\0';
+ }
+ if (length <= 0) {
+ // Empty line. Ignore it.
+ continue;
+ }
+
+ // Successfully extracted the friendly name.
+ strncpy(s_sSavedStateInfo[s_nNumSavedStates].listener_friendly_name, temp_buffer, FRIENDLY_NAME_SIZE);
+ s_sSavedStateInfo[s_nNumSavedStates].listener_friendly_name[FRIENDLY_NAME_SIZE - 1] = '\0';
+ break;
+ }
+
+ // Extract the flags.
+ if (fgets(temp_buffer, sizeof(temp_buffer), file) == NULL) {
+ AVB_LOGF_ERROR("Error reading from INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+ errno = 0;
+ temp_int = strtol(temp_buffer, &pEnd, 10);
+ if (*pEnd != '\n' || errno != 0 || temp_int < 0 || temp_int > 0xFFFF) {
+ AVB_LOGF_ERROR("Error getting Flags from INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+ s_sSavedStateInfo[s_nNumSavedStates].flags = (U16) temp_int;
+
+ // Extract the talker_unique_id.
+ if (fgets(temp_buffer, sizeof(temp_buffer), file) == NULL) {
+ AVB_LOGF_ERROR("Error reading from INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+ errno = 0;
+ temp_int = strtol(temp_buffer, &pEnd, 10);
+ if (*pEnd != '\n' || errno != 0 || temp_int < 0 || temp_int > 0xFFFF) {
+ AVB_LOGF_ERROR("Error getting Talker Unique ID from INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+ s_sSavedStateInfo[s_nNumSavedStates].talker_unique_id = (U16) temp_int;
+
+ // Extract the Talker Entity ID.
+ if (fgets(temp_buffer, sizeof(temp_buffer), file) == NULL) {
+ AVB_LOGF_ERROR("Error reading from INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+ if (!get_entity_id(temp_buffer, s_sSavedStateInfo[s_nNumSavedStates].talker_entity_id)) {
+ AVB_LOGF_ERROR("Error getting Talker Entity ID from INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+
+ // Extract the Controller Entity ID.
+ if (fgets(temp_buffer, sizeof(temp_buffer), file) == NULL) {
+ AVB_LOGF_ERROR("Error reading from INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+ if (!get_entity_id(temp_buffer, s_sSavedStateInfo[s_nNumSavedStates].controller_entity_id)) {
+ AVB_LOGF_ERROR("Error getting Talker Entity ID from INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+
+ AVB_LOGF_DEBUG("Loaded saved state %d from file: listener_id=%s, talker_entity_id=" ENTITYID_FORMAT ", controller_entity_id=" ENTITYID_FORMAT,
+ s_nNumSavedStates,
+ s_sSavedStateInfo[s_nNumSavedStates].listener_friendly_name,
+ ENTITYID_ARGS(s_sSavedStateInfo[s_nNumSavedStates].talker_entity_id),
+ ENTITYID_ARGS(s_sSavedStateInfo[s_nNumSavedStates].controller_entity_id));
+ }
+
+ fclose(file);
+ free(pvtFilename);
+
+ AVB_LOGF_DEBUG("Extracted %d saved states from INI file: %s", s_nNumSavedStates, ini_file);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+
+ return true;
+}
+
+static bool write_saved_state_info(const char *ini_file)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ FILE* file;
+ int i;
+
+ char *pvtFilename = strdup(ini_file);
+ if (!pvtFilename) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+
+ char *override = strchr(pvtFilename, ',');
+ if (override)
+ *override++ = '\0';
+
+ file = fopen(pvtFilename, "w");
+ if (!file) {
+ AVB_LOGF_WARNING("Error saving to INI file: %s", ini_file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+
+ for (i = 0; i < s_nNumSavedStates; ++i) {
+ if (fprintf(file, "%s\n%u\n%u\n" ENTITYID_FORMAT "\n" ENTITYID_FORMAT "\n\n",
+ s_sSavedStateInfo[i].listener_friendly_name,
+ s_sSavedStateInfo[i].flags,
+ s_sSavedStateInfo[i].talker_unique_id,
+ ENTITYID_ARGS(s_sSavedStateInfo[i].talker_entity_id),
+ ENTITYID_ARGS(s_sSavedStateInfo[i].controller_entity_id)) < 0) {
+ AVB_LOGF_ERROR("Error writing to INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+ }
+
+ fclose(file);
+ free(pvtFilename);
+
+ AVB_LOGF_DEBUG("Saved state to INI file: %s", ini_file);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+
+ return true;
+}
+
+// Returns a pointer to the saved state information for the index supplied.
+// To use, start at index 0 and increment upward.
+// If NULL is returned, then no values for that or any higher indexes.
+const openavb_saved_state_t * openavbAvdeccGetSavedState(int index)
+{
+ // Load the file data, if needed.
+ if (s_nNumSavedStates < 0 && !get_saved_state_info(DEFAULT_AVDECC_SAVE_INI_FILE)) {
+ return NULL;
+ }
+
+ // Can we return a saved state for the requested index?
+ if (s_nNumSavedStates <= 0 || index >= s_nNumSavedStates) {
+ return NULL;
+ }
+
+ // Return the requested index.
+ return &(s_sSavedStateInfo[index]);
+}
+
+// Add a saved state to the list of saved states.
+// Returns the index for the new saved state, or -1 if an error occurred.
+int openavbAvdeccAddSavedState(const char listener_friendly_name[FRIENDLY_NAME_SIZE], U16 flags, U16 talker_unique_id, const U8 talker_entity_id[8], const U8 controller_entity_id[8])
+{
+ // Load the file data, if needed.
+ if (s_nNumSavedStates < 0 && !get_saved_state_info(DEFAULT_AVDECC_SAVE_INI_FILE)) {
+ return -1;
+ }
+
+ // If the list is full, delete the oldest item to make space for it.
+ while (s_nNumSavedStates >= MAX_SAVED_STATES) {
+ openavbAvdeccDeleteSavedState(0);
+ }
+
+ // Append the supplied state to the list of states.
+ strncpy(s_sSavedStateInfo[s_nNumSavedStates].listener_friendly_name, listener_friendly_name, FRIENDLY_NAME_SIZE);
+ s_sSavedStateInfo[s_nNumSavedStates].listener_friendly_name[FRIENDLY_NAME_SIZE - 1] = '\0';
+ s_sSavedStateInfo[s_nNumSavedStates].flags = flags;
+ s_sSavedStateInfo[s_nNumSavedStates].talker_unique_id = talker_unique_id;
+ memcpy(s_sSavedStateInfo[s_nNumSavedStates].talker_entity_id, talker_entity_id, 8);
+ memcpy(s_sSavedStateInfo[s_nNumSavedStates].controller_entity_id, controller_entity_id, 8);
+ s_nNumSavedStates++;
+
+ // Create a new saved state file with all the previous states, and our state.
+ if (!write_saved_state_info(DEFAULT_AVDECC_SAVE_INI_FILE)) {
+ AVB_LOGF_ERROR("Error saving state: listener_id=%s, talker_entity_id=" ENTITYID_FORMAT ", controller_entity_id=" ENTITYID_FORMAT,
+ listener_friendly_name,
+ ENTITYID_ARGS(talker_entity_id),
+ ENTITYID_ARGS(controller_entity_id));
+ return -1;
+ }
+
+ // Return the last index, as that is the one we used.
+ return (s_nNumSavedStates - 1);
+}
+
+// Delete the saved state information at the specified index.
+// Returns TRUE if successfully deleted, FALSE otherwise.
+bool openavbAvdeccDeleteSavedState(int index)
+{
+ // Load the file data, if needed.
+ if (s_nNumSavedStates < 0 && !get_saved_state_info(DEFAULT_AVDECC_SAVE_INI_FILE)) {
+ return false;
+ }
+
+ // Is the index valid?
+ if (s_nNumSavedStates <= 0 || index >= s_nNumSavedStates) {
+ return false;
+ }
+
+ // If the index points to the last item, simply reduce the count.
+ if (index == s_nNumSavedStates - 1) {
+ s_nNumSavedStates--;
+ return (write_saved_state_info(DEFAULT_AVDECC_SAVE_INI_FILE));
+ }
+
+ // Shift the items after the index to where the index is.
+ memcpy(&(s_sSavedStateInfo[index]), &(s_sSavedStateInfo[index + 1]), sizeof(openavb_saved_state_t) * (--s_nNumSavedStates - index));
+ return (write_saved_state_info(DEFAULT_AVDECC_SAVE_INI_FILE));
+}
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_save_state.h b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_save_state.h
new file mode 100644
index 00000000..da715761
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_save_state.h
@@ -0,0 +1,70 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* HEADER SUMMARY : Support for ACMP saved state
+*
+* Defines the saved state data, and the functions
+* to read and write the saved state data.
+*/
+
+#ifndef AVB_ENDPOINT_AVDECC_SAVE_STATE_H
+#define AVB_ENDPOINT_AVDECC_SAVE_STATE_H
+
+#include "openavb_types.h"
+#include "openavb_avdecc_pub.h"
+#include "openavb_tl_pub.h"
+
+#define DEFAULT_AVDECC_SAVE_INI_FILE "avdecc_save.ini"
+
+struct openavb_saved_state {
+ char listener_friendly_name[FRIENDLY_NAME_SIZE];
+ U16 flags;
+ U16 talker_unique_id;
+ U8 talker_entity_id[8];
+ U8 controller_entity_id[8];
+};
+typedef struct openavb_saved_state openavb_saved_state_t;
+
+// Returns a pointer to the saved state information for the index supplied.
+// To use, start at index 0 and increment upward.
+// If NULL is returned, then no values for that or any higher indexes.
+const openavb_saved_state_t * openavbAvdeccGetSavedState(int index);
+
+// Add a saved state to the list of saved states.
+// Returns the index for the new saved state, or -1 if an error occurred.
+int openavbAvdeccAddSavedState(const char listener_friendly_name[FRIENDLY_NAME_SIZE], U16 flags, U16 talker_unique_id, const U8 talker_entity_id[8], const U8 controller_entity_id[8]);
+
+// Delete the saved state information at the specified index.
+// Returns TRUE if successfully deleted, FALSE otherwise.
+bool openavbAvdeccDeleteSavedState(int index);
+
+#endif // AVB_ENDPOINT_AVDECC_SAVE_STATE_H
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc_msg/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/avdecc_msg/CMakeLists.txt
new file mode 100644
index 00000000..139597f9
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc_msg/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_client_osal.c b/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_client_osal.c
new file mode 100644
index 00000000..04de29e0
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_client_osal.c
@@ -0,0 +1,181 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OPENAVB_AVDECC_MSG_CLIENT_OSAL_C
+#define OPENAVB_AVDECC_MSG_CLIENT_OSAL_C
+
+static void socketClose(int socketHandle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ if (socketHandle != AVB_AVDECC_MSG_HANDLE_INVALID) {
+ close(socketHandle);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+static bool openavbAvdeccMsgClntSendToServer(int socketHandle, openavbAvdeccMessage_t *msg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (!msg || socketHandle == AVB_AVDECC_MSG_HANDLE_INVALID) {
+ AVB_LOG_ERROR("Client send: invalid argument passed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ ssize_t nWrite = write(socketHandle, msg, OPENAVB_AVDECC_MSG_LEN);
+ AVB_LOGF_VERBOSE("Sent message, len=%zu, nWrite=%zu", OPENAVB_AVDECC_MSG_LEN, nWrite);
+
+ if (nWrite < OPENAVB_AVDECC_MSG_LEN) {
+ if (nWrite < 0) {
+ AVB_LOGF_ERROR("Client failed to write socket: %s", strerror(errno));
+ }
+ else if (nWrite == 0) {
+ AVB_LOG_ERROR("Client send: socket closed unexpectedly");
+ }
+ else {
+ AVB_LOG_ERROR("Client send: short write");
+ }
+ socketClose(socketHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+}
+
+int openavbAvdeccMsgClntOpenSrvrConnection(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ struct sockaddr_un server;
+ server.sun_family = AF_UNIX;
+ snprintf(server.sun_path, UNIX_PATH_MAX, AVB_AVDECC_MSG_UNIX_PATH);
+
+ int h = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (h < 0) {
+ AVB_LOGF_ERROR("Failed to open socket: %s", strerror(errno));
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return AVB_AVDECC_MSG_HANDLE_INVALID;
+ }
+
+ AVB_LOGF_DEBUG("Connecting to %s", server.sun_path);
+ int rslt = connect(h, (struct sockaddr*)&server, sizeof(struct sockaddr_un));
+ if (rslt < 0) {
+ AVB_LOGF_DEBUG("Failed to connect socket: %s", strerror(errno));
+ socketClose(h);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return AVB_AVDECC_MSG_HANDLE_INVALID;
+ }
+
+ AVB_LOG_DEBUG("Connected to AVDECC Msg");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return h;
+}
+
+void openavbAvdeccMsgClntCloseSrvrConnection(int socketHandle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ socketClose(socketHandle);
+ AVB_LOG_DEBUG("Closed connection to AVDECC Msg");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+bool openavbAvdeccMsgClntService(int socketHandle, int timeout)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ bool rc = FALSE;
+
+ if (socketHandle == AVB_AVDECC_MSG_HANDLE_INVALID) {
+ AVB_LOG_ERROR("Client service: invalid socket");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ struct pollfd fds[1];
+ memset(fds, 0, sizeof(struct pollfd));
+ fds[0].fd = socketHandle;
+ fds[0].events = POLLIN;
+
+ AVB_LOG_VERBOSE("Waiting for event...");
+ int pRet = poll(fds, 1, timeout);
+
+ if (pRet == 0) {
+ AVB_LOG_VERBOSE("Poll timeout");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+ }
+ else if (pRet < 0) {
+ if (errno == EINTR) {
+ AVB_LOG_VERBOSE("Poll interrupted");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+ }
+ else {
+ AVB_LOGF_ERROR("Poll error: %s", strerror(errno));
+ }
+ }
+ else {
+ AVB_LOGF_DEBUG("Poll returned %d events", pRet);
+ // only one fd, so it's readable.
+ openavbAvdeccMessage_t msgBuf;
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ ssize_t nRead = read(socketHandle, &msgBuf, OPENAVB_AVDECC_MSG_LEN);
+
+ if (nRead < OPENAVB_AVDECC_MSG_LEN) {
+ // sock closed
+ if (nRead == 0) {
+ AVB_LOG_ERROR("Socket closed unexpectedly");
+ }
+ else if (nRead < 0) {
+ AVB_LOGF_ERROR("Socket read error: %s", strerror(errno));
+ }
+ else {
+ AVB_LOG_ERROR("Socket read to short");
+ }
+ socketClose(socketHandle);
+ }
+ else {
+ // got a message
+ if (openavbAvdeccMsgClntReceiveFromServer(socketHandle, &msgBuf)) {
+ rc = TRUE;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid message received");
+ socketClose(socketHandle);
+ }
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return rc;
+}
+
+#endif // OPENAVB_AVDECC_MSG_CLIENT_OSAL_C
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_osal.h b/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_osal.h
new file mode 100644
index 00000000..b68ea38d
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_osal.h
@@ -0,0 +1,64 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OSAL_AVDECC_MSG_H
+#define OSAL_AVDECC_MSG_H
+
+// should only be included from openavb_avdecc_msg.h
+
+#include <linux/un.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <signal.h>
+
+typedef struct {
+ openavbAvdeccMsgType_t type;
+ AVBStreamID_t streamID;
+ union {
+ // Client-to-Server messages
+ openavbAvdeccMsgParams_VersionRequest_t versionRequest;
+ openavbAvdeccMsgParams_ClientInitIdentify_t clientInitIdentify;
+ openavbAvdeccMsgParams_C2S_TalkerStreamID_t c2sTalkerStreamID;
+ openavbAvdeccMsgParams_ClientChangeNotification_t clientChangeNotification;
+
+ // Server-to-Client messages
+ openavbAvdeccMsgParams_VersionCallback_t versionCallback;
+ openavbAvdeccMsgParams_ListenerStreamID_t listenerStreamID;
+ openavbAvdeccMsgParams_S2C_TalkerStreamID_t s2cTalkerStreamID;
+ openavbAvdeccMsgParams_ClientChangeRequest_t clientChangeRequest;
+ } params;
+} openavbAvdeccMessage_t;
+
+
+bool startAvdeccMsg(int mode, int ifindex, const char* ifname, unsigned mtu, unsigned link_kbit, unsigned nsr_kbit);
+void stopAvdeccMsg();
+
+#endif // OSAL_AVDECC_MSG_H
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_server_osal.c b/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_server_osal.c
new file mode 100644
index 00000000..e73b9701
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_server_osal.c
@@ -0,0 +1,271 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OPENAVB_AVDECC_MSG_SERVER_OSAL_C
+#define OPENAVB_AVDECC_MSG_SERVER_OSAL_C
+
+#define AVB_AVDECC_LISTEN_FDS 0 // first fds, was last MAX_AVB_STREAMS
+#define SOCK_INVALID (-1)
+#define POLL_FD_COUNT ((MAX_AVB_STREAMS) + 1)
+
+static int lsock = SOCK_INVALID;
+static struct pollfd fds[POLL_FD_COUNT];
+static struct sockaddr_un serverAddr;
+
+static void socketClose(int h)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (h < 0 || h >= POLL_FD_COUNT) {
+ AVB_LOG_ERROR("Closing socket; invalid handle");
+ }
+ else {
+ if (h != AVB_AVDECC_LISTEN_FDS) {
+ openavbAvdeccMsgSrvrCloseClientConnection(h);
+ }
+ close(fds[h].fd);
+ fds[h].fd = SOCK_INVALID;
+ fds[h].events = 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+static bool openavbAvdeccMsgSrvrSendToClient(int h, openavbAvdeccMessage_t *msg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (h < 0 || h >= POLL_FD_COUNT) {
+ AVB_LOG_ERROR("Sending message; invalid handle");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+ if (!msg) {
+ AVB_LOG_ERROR("Sending message; invalid argument passed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ int csock = fds[h].fd;
+ if (csock == SOCK_INVALID) {
+ AVB_LOG_ERROR("Socket closed unexpectedly");
+ return FALSE;
+ }
+
+ ssize_t nWrite = write(csock, msg, OPENAVB_AVDECC_MSG_LEN);
+ AVB_LOGF_VERBOSE("Sent message, len=%zu, nWrite=%zu", OPENAVB_AVDECC_MSG_LEN, nWrite);
+ if (nWrite < OPENAVB_AVDECC_MSG_LEN) {
+ if (nWrite < 0) {
+ AVB_LOGF_ERROR("Failed to write socket: %s", strerror(errno));
+ }
+ else if (nWrite == 0) {
+ AVB_LOG_ERROR("Socket closed unexpectedly");
+ }
+ else {
+ AVB_LOG_ERROR("Socket write too short");
+ }
+ socketClose(h);
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+}
+
+bool openavbAvdeccMsgServerOpen(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ int i;
+
+ // Perform the base initialization.
+ openavbAvdeccMsgInitialize();
+
+ for (i=0; i < POLL_FD_COUNT; i++) {
+ fds[i].fd = SOCK_INVALID;
+ fds[i].events = 0;
+ }
+
+ lsock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (lsock < 0) {
+ AVB_LOGF_ERROR("Failed to open socket: %s", strerror(errno));
+ goto error;
+ }
+ // serverAddr is file static
+ serverAddr.sun_family = AF_UNIX;
+ snprintf(serverAddr.sun_path, UNIX_PATH_MAX, AVB_AVDECC_MSG_UNIX_PATH);
+
+ // try remove old socket
+ if (unlink(serverAddr.sun_path) == -1 && errno != ENOENT) {
+ AVB_LOGF_ERROR("Failed to remove %s: %s", serverAddr.sun_path, strerror(errno));
+ }
+
+ int rslt = bind(lsock, (struct sockaddr*)&serverAddr, sizeof(struct sockaddr_un));
+ if (rslt != 0) {
+ AVB_LOGF_ERROR("Failed to create %s: %s", serverAddr.sun_path, strerror(errno));
+ AVB_LOG_WARNING("** If AVDECC Msg process crashed, run the cleanup script **");
+ goto error;
+ }
+
+ rslt = listen(lsock, 5);
+ if (rslt != 0) {
+ AVB_LOGF_ERROR("Failed to listen on socket: %s", strerror(errno));
+ goto error;
+ }
+ AVB_LOGF_DEBUG("Listening on socket: %s", serverAddr.sun_path);
+
+ fds[AVB_AVDECC_LISTEN_FDS].fd = lsock;
+ fds[AVB_AVDECC_LISTEN_FDS].events = POLLIN;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+
+ error:
+ if (lsock >= 0) {
+ close(lsock);
+ lsock = -1;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+}
+
+void openavbAvdeccMsgSrvrService(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ struct sockaddr_un addrClient;
+ socklen_t lenAddr;
+ int i, j;
+ int csock;
+
+ int nfds = POLL_FD_COUNT;
+ int pRet;
+
+ AVB_LOG_VERBOSE("Waiting for event...");
+ pRet = poll(fds, nfds, 1000);
+
+ if (pRet == 0) {
+ AVB_LOG_VERBOSE("poll timeout");
+ }
+ else if (pRet < 0) {
+ if (errno == EINTR) {
+ AVB_LOG_VERBOSE("Poll interrupted");
+ }
+ else {
+ AVB_LOGF_ERROR("Poll error: %s", strerror(errno));
+ }
+ }
+ else {
+ AVB_LOGF_VERBOSE("Poll returned %d events", pRet);
+ for (i=0; i<nfds; i++) {
+ if (fds[i].revents != 0) {
+ AVB_LOGF_VERBOSE("%d sock=%d, event=0x%x, revent=0x%x", i, fds[i].fd, fds[i].events, fds[i].revents);
+
+ if (i == AVB_AVDECC_LISTEN_FDS) {
+ // listen sock - indicates new connection from client
+ lenAddr = sizeof(addrClient);
+ csock = accept(lsock, (struct sockaddr*)&addrClient, &lenAddr);
+ if (csock < 0) {
+ AVB_LOGF_ERROR("Failed to accept connection: %s", strerror(errno));
+ }
+ else {
+ for (j = 0; j < POLL_FD_COUNT; j++) {
+ if (fds[j].fd == SOCK_INVALID) {
+ fds[j].fd = csock;
+ fds[j].events = POLLIN;
+ break;
+ }
+ }
+ if (j >= POLL_FD_COUNT) {
+ AVB_LOG_ERROR("Too many client connections");
+ close(csock);
+ }
+ }
+
+ AVB_LOG_INFO("New AVDECC Msg client connection detected");
+ }
+ else {
+ csock = fds[i].fd;
+ openavbAvdeccMessage_t msgBuf;
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ ssize_t nRead = read(csock, &msgBuf, OPENAVB_AVDECC_MSG_LEN);
+ AVB_LOGF_VERBOSE("Socket read h=%d,fd=%d: read=%zu, expect=%zu", i, csock, nRead, OPENAVB_AVDECC_MSG_LEN);
+
+ if (nRead < OPENAVB_AVDECC_MSG_LEN) {
+ // sock closed
+ if (nRead == 0) {
+ AVB_LOGF_DEBUG("Socket closed, h=%d", i);
+ }
+ else if (nRead < 0) {
+ AVB_LOGF_ERROR("Socket read, h=%d: %s", i, strerror(errno));
+ }
+ else {
+ AVB_LOGF_ERROR("Short read, h=%d", i);
+ }
+ socketClose(i);
+ }
+ else {
+ // got a message
+ if (!openavbAvdeccMsgSrvrReceiveFromClient(i, &msgBuf)) {
+ AVB_LOG_ERROR("Failed to handle message");
+ socketClose(i);
+ }
+ }
+ }
+ }
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+void openavbAvdeccMsgServerClose(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ int i;
+ for (i = 0; i < POLL_FD_COUNT; i++) {
+ if (fds[i].fd != SOCK_INVALID) {
+ socketClose(i);
+ }
+ }
+ if (lsock != SOCK_INVALID) {
+ close(lsock);
+ }
+
+ if (unlink(serverAddr.sun_path) != 0) {
+ AVB_LOGF_ERROR("Failed to unlink %s: %s", serverAddr.sun_path, strerror(errno));
+ }
+
+ // Perform the base cleanup.
+ openavbAvdeccMsgCleanup();
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+#endif // OPENAVB_AVDECC_MSG_SERVER_OSAL_C
diff --git a/lib/avtp_pipeline/platform/Linux/avtp/openavb_avtp_time_osal.c b/lib/avtp_pipeline/platform/Linux/avtp/openavb_avtp_time_osal.c
index 227174c7..6ff72c8b 100644
--- a/lib/avtp_pipeline/platform/Linux/avtp/openavb_avtp_time_osal.c
+++ b/lib/avtp_pipeline/platform/Linux/avtp/openavb_avtp_time_osal.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c
index d00e2380..6794a84b 100644
--- a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,15 +22,15 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
/*
-* MODULE SUMMARY : Reads the .ini file for an enpoint and
+* MODULE SUMMARY : Reads the .ini file for an endpoint
*/
#include <unistd.h>
@@ -50,6 +51,16 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#define MATCH(A, B)(strcasecmp((A), (B)) == 0)
#define MATCH_FIRST(A, B)(strncasecmp((A), (B), strlen(B)) == 0)
+static bool parse_mac(const char *str, struct ether_addr *mac)
+{
+ memset(mac, 0, sizeof(struct ether_addr));
+ if (ether_aton_r(str, mac) != NULL)
+ return TRUE;
+
+ AVB_LOGF_ERROR("Failed to parse addr: %s", str);
+ return FALSE;
+}
+
static void cfgValErr(const char *section, const char *name, const char *value)
{
AVB_LOGF_ERROR("Invalid value: section=%s, name=%s, value=%s",
@@ -65,9 +76,9 @@ static int cfgCallback(void *user, const char *section, const char *name, const
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return 0;
}
-
+
openavb_endpoint_cfg_t *pCfg = (openavb_endpoint_cfg_t*)user;
-
+
AVB_LOGF_DEBUG("name=[%s] value=[%s]", name, value);
bool valOK = FALSE;
@@ -79,7 +90,7 @@ static int cfgCallback(void *user, const char *section, const char *name, const
{
if_info_t ifinfo;
if (openavbCheckInterface(value, &ifinfo)) {
- strncpy(pCfg->ifname, value, IFNAMSIZ - 1);
+ strncpy(pCfg->ifname, value, sizeof(pCfg->ifname) - 1);
memcpy(pCfg->ifmac, &ifinfo.mac, ETH_ALEN);
pCfg->ifindex = ifinfo.index;
pCfg->mtu = ifinfo.mtu;
@@ -164,6 +175,60 @@ static int cfgCallback(void *user, const char *section, const char *name, const
return 0;
}
}
+ else if (MATCH(section, "maap"))
+ {
+ if (MATCH(name, "port")) {
+ errno = 0;
+ unsigned temp = strtoul(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0) {
+ if (temp >= 1 && temp <= 65535) {
+ pCfg->maapPort = temp;
+ valOK = TRUE;
+ }
+ }
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+ }
+ else if (MATCH(section, "shaper"))
+ {
+ if (MATCH(name, "port")) {
+ errno = 0;
+ unsigned temp = strtoul(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0) {
+ if (temp >= 1 && temp <= 65535) {
+ pCfg->shaperPort = temp;
+ valOK = TRUE;
+ }
+ }
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+ }
+
+ // Special section to load saved settings.
+ else if (MATCH(section, "saved"))
+ {
+ if (MATCH(name, "maap_preferred"))
+ {
+ valOK = parse_mac(value, &(pCfg->maap_preferred));
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+ }
+
else {
// unmatched item, fail
AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
@@ -183,7 +248,7 @@ static int cfgCallback(void *user, const char *section, const char *name, const
// Parse ini file, and create config data
//
-int openavbReadConfig(const char *ini_file, openavb_endpoint_cfg_t *pCfg)
+int openavbReadConfig(const char *ini_file, const char *save_ini_file, openavb_endpoint_cfg_t *pCfg)
{
AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
@@ -194,13 +259,73 @@ int openavbReadConfig(const char *ini_file, openavb_endpoint_cfg_t *pCfg)
int result = ini_parse(ini_file, cfgCallback, pCfg);
if (result < 0) {
AVB_LOGF_ERROR("Couldn't parse INI file: %s", ini_file);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return -1;
}
if (result > 0) {
AVB_LOGF_ERROR("Error in INI file: %s, line %d", ini_file, result);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return -1;
}
+ result = ini_parse(save_ini_file, cfgCallback, pCfg);
+ if (result > 0) {
+ AVB_LOGF_ERROR("Error in INI file: %s, line %d", ini_file, result);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return -1;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+
+ // Yay, we did it.
+ return 0;
+}
+
+// Create ini file with information to save.
+//
+int openavbSaveConfig(const char *ini_file, const openavb_endpoint_cfg_t *pCfg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ FILE* file;
+
+ char *pvtFilename = strdup(ini_file);
+ if (!pvtFilename) {
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return -1;
+ }
+
+ char *override = strchr(pvtFilename, ',');
+ if (override)
+ *override++ = '\0';
+
+ file = fopen(pvtFilename, "w");
+ if (!file) {
+ AVB_LOGF_WARNING("Error saving to INI file: %s", ini_file);
+ free (pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return -1;
+ }
+
+ if (fputs("[saved]\n", file) < 0) {
+ AVB_LOGF_ERROR("Error writing to INI file: %s", ini_file);
+ fclose(file);
+ free (pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return -1;
+ }
+ if (fprintf(file, "maap_preferred = " ETH_FORMAT "\n", ETH_OCTETS(pCfg->maap_preferred.ether_addr_octet)) < 0) {
+ AVB_LOGF_ERROR("Error writing to INI file: %s", ini_file);
+ fclose(file);
+ free (pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return -1;
+ }
+
+ fclose(file);
+ free (pvtFilename);
+
+ AVB_LOGF_DEBUG("Saved settings to INI file: %s", ini_file);
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
// Yay, we did it.
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.h b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.h
index 8cc989a5..b8249146 100644
--- a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.h
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -43,21 +44,28 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "net/if.h"
#define DEFAULT_INI_FILE "endpoint.ini"
+#define DEFAULT_SAVE_INI_FILE "endpoint_save.ini"
typedef struct {
- char ifname[IFNAMSIZ];
- U8 ifmac[ETH_ALEN];
- char *ptp_start_opts;
- int ifindex;
- unsigned link_kbit;
- unsigned nsr_kbit;
- unsigned mtu;
- unsigned fqtss_mode;
- bool noSrp;
- bool bypassAsCapableCheck;
+ char ifname[IFNAMSIZ + 10]; // Include space for the socket type prefix (e.g. "simple:eth0")
+ U8 ifmac[ETH_ALEN];
+ char *ptp_start_opts;
+ int ifindex;
+ unsigned link_kbit;
+ unsigned nsr_kbit;
+ unsigned mtu;
+ unsigned fqtss_mode;
+ bool noSrp;
+ unsigned maapPort;
+ unsigned shaperPort;
+ bool bypassAsCapableCheck;
+
+ // Information to be saved for future use.
+ struct ether_addr maap_preferred; // Last assigned MAAP address.
} openavb_endpoint_cfg_t;
-int openavbReadConfig(const char *inifile, openavb_endpoint_cfg_t *pCfg);
+int openavbReadConfig(const char *ini_file, const char *save_ini_file, openavb_endpoint_cfg_t *pCfg);
+int openavbSaveConfig(const char *save_ini_file, const openavb_endpoint_cfg_t *pCfg);
void openavbUnconfigure(openavb_endpoint_cfg_t *pCfg);
#endif // AVB_ENDPOINT_CONFIG_H
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_client_osal.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_client_osal.c
index dcdca3cd..316604bf 100644
--- a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_client_osal.c
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_client_osal.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -95,7 +96,7 @@ int openavbEptClntOpenSrvrConnection(tl_state_t *pTLState)
return AVB_ENDPOINT_HANDLE_INVALID;
}
- AVB_LOG_DEBUG("connected to endpoint");
+ AVB_LOG_DEBUG("Connected to endpoint");
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return h;
}
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.c
index db35a632..dfed5863 100644
--- a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.c
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -30,14 +31,11 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include <stdlib.h>
#include <string.h>
+
#include "openavb_platform.h"
#include "openavb_trace.h"
#include "openavb_endpoint.h"
#include "openavb_endpoint_cfg.h"
-#include "openavb_srp.h"
-#include "openavb_maap.h"
-#include "mrp_client.h"
-#include "openavb_list.h"
#include "openavb_rawsock.h"
#define AVB_LOG_COMPONENT "Endpoint"
@@ -51,37 +49,6 @@ extern bool endpointRunning;
static pthread_t endpointServerHandle;
static void* endpointServerThread(void *arg);
-inline int startPTP(void)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
-
- // make sure ptp, a seperate process, starts and is using the same interface as endpoint
- int retVal = 0;
-// char ptpCmd[80];
-// memset(ptpCmd, 0, 80);
-// snprintf(ptpCmd, 80, "./openavb_gptp %s -i %s &", x_cfg.ptp_start_opts, x_cfg.ifname);
-// AVB_LOGF_INFO("PTP start command: %s", ptpCmd);
-// if (system(ptpCmd) != 0) {
-// AVB_LOG_ERROR("PTP failed to start - Exiting");
-// retVal = -1;
-// }
-
- AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
- return retVal;
-}
-
-inline int stopPTP(void)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
-
- int retVal = 0;
-// if (system("killall -s SIGINT openavb_gptp") != 0) {
-// retVal = -1;
-// }
-
- AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
- return retVal;
-}
bool startEndpoint(int mode, int ifindex, const char* ifname, unsigned mtu, unsigned link_kbit, unsigned nsr_kbit)
{
@@ -101,19 +68,20 @@ bool startEndpoint(int mode, int ifindex, const char* ifname, unsigned mtu, unsi
x_cfg.fqtss_mode = mode;
x_cfg.ifindex = ifindex;
x_cfg.mtu = mtu;
- if (ifname)
- strncpy(x_cfg.ifname, ifname, sizeof(x_cfg.ifname));
+
+ x_cfg.link_kbit = link_kbit;
+ x_cfg.nsr_kbit = nsr_kbit;
+
+ openavbReadConfig(DEFAULT_INI_FILE, DEFAULT_SAVE_INI_FILE, &x_cfg);
if_info_t ifinfo;
- if (openavbCheckInterface(x_cfg.ifname, &ifinfo)) {
+ if (ifname && openavbCheckInterface(ifname, &ifinfo)) {
+ strncpy(x_cfg.ifname, ifname, sizeof(x_cfg.ifname));
memcpy(x_cfg.ifmac, &ifinfo.mac, ETH_ALEN);
x_cfg.ifindex = ifinfo.index;
x_cfg.mtu = ifinfo.mtu;
}
- x_cfg.link_kbit = link_kbit;
- x_cfg.nsr_kbit = nsr_kbit;
-
endpointRunning = TRUE;
int err = pthread_create(&endpointServerHandle, NULL, endpointServerThread, NULL);
if (err) {
@@ -158,425 +126,3 @@ static void* endpointServerThread(void *arg)
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return NULL;
}
-
-
-/*******************************************************************************
- * SRP proxies
- ******************************************************************************/
-
-static strmAttachCb_t _attachCb = NULL;
-static strmRegCb_t _registerCb = NULL;
-
-typedef struct {
- void* avtpHandle;
- bool talker;
- U8 streamId[8];
- U8 destAddr[6];
- U16 vlanId;
- int maxFrameSize;
- int maxIntervalFrames;
- int priority;
- int latency;
- int subtype;
-} strElem_t;
-
-openavb_list_t strElemList;
-
-#define SID_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x/%d"
-#define SID_OCTETS(a) (a)[0],(a)[1],(a)[2],(a)[3],(a)[4],(a)[5],(a)[6]<<8|(a)[7]
-
-void mrp_attach_cb(unsigned char streamid[8], int subtype)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
-
- AVB_LOGF_DEBUG("mrp_attach_cb "SID_FORMAT" subtype %d", SID_OCTETS(streamid), subtype);
-
- if (_attachCb) {
- openavb_list_node_t node = openavbListIterFirst(strElemList);
- while (node) {
- strElem_t *elem = openavbListData(node);
- if (elem && elem->talker && memcmp(streamid, elem->streamId, sizeof(elem->streamId)) == 0) {
- if (elem->subtype != subtype) {
- _attachCb(elem->avtpHandle, subtype);
- elem->subtype = subtype;
- }
- break;
- }
- node = openavbListIterNext(strElemList);
- }
- if (!node)
- AVB_LOG_DEBUG("attach_cb stream not ours");
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
-}
-
-void mrp_register_cb(unsigned char streamid[8], int join, unsigned char destaddr[6], unsigned int max_frame_size, unsigned int max_interval_frames, uint16_t vid, unsigned int latency)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
-
- AVB_LOGF_DEBUG("mrp_register_cb "SID_FORMAT" "ETH_FORMAT" join %d max_frame_size %d max_interval_frames %d vid %d latency %d",
- SID_OCTETS(streamid), ETH_OCTETS(destaddr), join, max_frame_size, max_interval_frames, vid, latency);
-
- if (_registerCb) {
- openavb_list_node_t node = openavbListIterFirst(strElemList);
- while (node) {
- strElem_t *elem = openavbListData(node);
- if (elem && !elem->talker && memcmp(streamid, elem->streamId, sizeof(elem->streamId)) == 0) {
- if (elem->subtype != join) {
- AVBTSpec_t tSpec;
- tSpec.maxFrameSize = max_frame_size;
- tSpec.maxIntervalFrames = max_interval_frames;
- _registerCb(elem->avtpHandle,
- join ? openavbSrp_AtTyp_TalkerAdvertise : openavbSrp_AtTyp_None,
- destaddr,
- &tSpec,
- 0, // SR_CLASS is ignored anyway
- latency,
- NULL
- );
- elem->subtype = join;
- }
- break;
- }
- node = openavbListIterNext(strElemList);
- }
- if (!node)
- AVB_LOG_DEBUG("register_cb stream not ours");
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
-}
-
-openavbRC openavbSrpInitialize(strmAttachCb_t attachCb, strmRegCb_t registerCb,
- char* ifname, U32 TxRateKbps, bool bypassAsCapableCheck)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
- int err;
-
- strElemList = openavbListNewList();
-
- _attachCb = attachCb;
- _registerCb = registerCb;
-
-
- err = mrp_connect();
- if (err) {
- AVB_LOGF_ERROR("mrp_connect failed: %s", strerror(errno));
- goto error;
- }
- err = mrp_monitor();
- if (err) {
- AVB_LOGF_ERROR("failed creating MRP monitor thread: %s", strerror(errno));
- goto error;
- }
-
- int class_a_id, a_priority;
- u_int16_t a_vid;
- int class_b_id, b_priority;
- u_int16_t b_vid;
-
- err = mrp_get_domain(&class_a_id,&a_priority, &a_vid, &class_b_id, &b_priority, &b_vid);
- if (err) {
- AVB_LOG_DEBUG("mrp_get_domain failed");
- goto error;
- }
-
- AVB_LOGF_INFO("detected domain Class A PRIO=%d VID=%04x...", a_priority, (int)a_vid);
- AVB_LOGF_INFO("detected domain Class B PRIO=%d VID=%04x...", b_priority, (int)b_vid);
-
- err = mrp_register_domain(&domain_class_a_id, &domain_class_a_priority, &domain_class_a_vid);
- if (err) {
- AVB_LOG_DEBUG("mrp_register_domain failed");
- goto error;
- }
-
- err = mrp_register_domain(&domain_class_b_id, &domain_class_b_priority, &domain_class_b_vid);
- if (err) {
- AVB_LOG_DEBUG("mrp_register_domain failed");
- goto error;
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
- return OPENAVB_SRP_SUCCESS;
-
-error:
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
- return OPENAVB_SRP_FAILURE;
-}
-
-void openavbSrpShutdown(void)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
- int err = mrp_disconnect();
- if (err) {
- AVB_LOGF_ERROR("mrp_disconnect failed: %s", strerror(errno));
- }
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
-}
-
-openavbRC openavbSrpRegisterStream(void* avtpHandle,
- AVBStreamID_t* _streamId,
- U8 DA[],
- AVBTSpec_t* tSpec,
- SRClassIdx_t SRClassIdx,
- bool Rank,
- U32 Latency)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
- int err;
-
- // convert streamId to 8 byte format
- uint8_t streamId[8];
- memcpy(streamId, _streamId->addr, sizeof(_streamId->addr));
- streamId[6] = _streamId->uniqueID >> 8;
- streamId[7] = _streamId->uniqueID & 0xFF;
-
- openavb_list_node_t node = openavbListNew(strElemList, sizeof(strElem_t));
- strElem_t* elem = openavbListData(node);
-
- elem->avtpHandle = avtpHandle;
- elem->talker = true;
- memcpy(elem->streamId, streamId, sizeof(elem->streamId));
- memcpy(elem->destAddr, DA, sizeof(elem->destAddr));
- elem->maxFrameSize = tSpec->maxFrameSize;
- elem->maxIntervalFrames = tSpec->maxIntervalFrames;
- elem->latency = Latency;
- elem->subtype = openavbSrp_LDSt_None;
-
- switch (SRClassIdx) {
- case SR_CLASS_A:
- elem->vlanId = domain_class_a_vid;
- elem->priority = domain_class_a_priority;
-
- err = mrp_advertise_stream(streamId,
- DA,
- domain_class_a_vid,
- tSpec->maxFrameSize,
- tSpec->maxIntervalFrames,
- domain_class_a_priority,
- Latency);
- break;
- case SR_CLASS_B:
- elem->vlanId = domain_class_b_vid;
- elem->priority = domain_class_b_priority;
-
- err = mrp_advertise_stream(streamId,
- DA,
- domain_class_b_vid,
- tSpec->maxFrameSize,
- tSpec->maxIntervalFrames,
- domain_class_b_priority,
- Latency);
- break;
- default:
- AVB_LOGF_ERROR("unknown SRClassIdx %d", (int)SRClassIdx);
- goto error;
- }
-
- if (err) {
- AVB_LOG_ERROR("mrp_advertise_stream failed");
- goto error;
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
- return OPENAVB_SRP_SUCCESS;
-
-error:
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
- return OPENAVB_SRP_FAILURE;
-}
-
-openavbRC openavbSrpDeregisterStream(AVBStreamID_t* _streamId)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
-
- // convert streamId to 8 byte format
- uint8_t streamId[8];
- memcpy(streamId, _streamId->addr, sizeof(_streamId->addr));
- streamId[6] = _streamId->uniqueID >> 8;
- streamId[7] = _streamId->uniqueID & 0xFF;
-
- openavb_list_node_t node = openavbListIterFirst(strElemList);
- while (node) {
- strElem_t *elem = openavbListData(node);
- if (elem && memcmp(streamId, elem->streamId, sizeof(elem->streamId)) == 0) {
- int err = mrp_unadvertise_stream(elem->streamId, elem->destAddr, elem->vlanId, elem->maxFrameSize, elem->maxIntervalFrames, elem->priority, elem->latency);
- if (err) {
- AVB_LOG_ERROR("mrp_unadvertise_stream failed");
- }
- openavbListDelete(strElemList, node);
- break;
- }
- node = openavbListIterNext(strElemList);
- }
- if (!node)
- AVB_LOGF_ERROR("%s: unknown stream "SID_FORMAT, __func__, SID_OCTETS(streamId));
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
- return OPENAVB_SRP_SUCCESS;
-}
-
-openavbRC openavbSrpAttachStream(void* avtpHandle,
- AVBStreamID_t* _streamId,
- openavbSrpLsnrDeclSubtype_t type)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
-
- // convert streamId to 8 byte format
- uint8_t streamId[8];
- memcpy(streamId, _streamId->addr, sizeof(_streamId->addr));
- streamId[6] = _streamId->uniqueID >> 8;
- streamId[7] = _streamId->uniqueID & 0xFF;
-
- AVB_LOGF_DEBUG("openavbSrpAttachStream "SID_FORMAT, SID_OCTETS(streamId));
-
- openavb_list_node_t node = openavbListIterFirst(strElemList);
- // lets check if this streamId is on our list
- while (node) {
- strElem_t *elem = openavbListData(node);
- if (elem && memcmp(streamId, elem->streamId, sizeof(elem->streamId)) == 0) {
- break;
- }
- node = openavbListIterNext(strElemList);
- }
- if (!node) {
- // not found so add it
- node = openavbListNew(strElemList, sizeof(strElem_t));
- strElem_t* elem = openavbListData(node);
-
- elem->avtpHandle = avtpHandle;
- elem->talker = false;
- memcpy(elem->streamId, streamId, sizeof(elem->streamId));
- elem->subtype = type;
- }
-
- int err = mrp_send_ready(streamId);
- if (err) {
- AVB_LOG_ERROR("mrp_send_ready failed");
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
- return OPENAVB_SRP_SUCCESS;
-}
-
-openavbRC openavbSrpDetachStream(AVBStreamID_t* _streamId)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
-
- // convert streamId to 8 byte format
- uint8_t streamId[8];
- memcpy(streamId, _streamId->addr, sizeof(_streamId->addr));
- streamId[6] = _streamId->uniqueID >> 8;
- streamId[7] = _streamId->uniqueID & 0xFF;
-
- AVB_LOGF_DEBUG("openavbSrpDetachStream "SID_FORMAT, SID_OCTETS(streamId));
-
- openavb_list_node_t node = openavbListIterFirst(strElemList);
- while (node) {
- strElem_t *elem = openavbListData(node);
- if (elem && memcmp(streamId, elem->streamId, sizeof(elem->streamId)) == 0) {
- int err = mrp_send_leave(streamId);
- if (err) {
- AVB_LOG_ERROR("mrp_send_leave failed");
- }
- openavbListDelete(strElemList, node);
- break;
- }
- node = openavbListIterNext(strElemList);
- }
- if (!node)
- AVB_LOGF_ERROR("%s: unknown stream "SID_FORMAT, __func__, SID_OCTETS(streamId));
-
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
- return OPENAVB_SRP_SUCCESS;
-}
-
-openavbRC openavbSrpGetClassParams(SRClassIdx_t SRClassIdx, U8* priority, U16* vid, U32* inverseIntervalSec)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
- switch (SRClassIdx) {
- case SR_CLASS_A:
- *priority = domain_class_a_priority;
- *vid = domain_class_a_vid;
- *inverseIntervalSec = 8000;
- break;
- case SR_CLASS_B:
- *priority = domain_class_b_priority;
- *vid = domain_class_b_vid;
- *inverseIntervalSec = 4000;
- break;
- default:
- AVB_LOGF_ERROR("unknown SRClassIdx %d", (int)SRClassIdx);
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
- return OPENAVB_SRP_FAILURE;
- }
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
- return OPENAVB_SRP_SUCCESS;
-}
-
-
-/*******************************************************************************
- * MAAP proxies
- ******************************************************************************/
-
-// OPENAVB_TODO: Real implementation should be added once OpenAVB's MAAP daemon is finished
-
-typedef struct {
- U8 destAddr[ETH_ALEN];
- bool taken;
-} maapAlloc_t;
-
-maapAlloc_t maapAllocList[MAX_AVB_STREAMS];
-
-bool openavbMaapInitialize(const char *ifname, openavbMaapRestartCb_t* cbfn)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_MAAP);
- int i = 0;
- U8 destAddr[ETH_ALEN] = {0x91, 0xe0, 0xf0, 0x00, 0x0e, 0x80};
- for (i = 0; i < MAX_AVB_STREAMS; i++) {
- memcpy(maapAllocList[i].destAddr, destAddr, ETH_ALEN);
- maapAllocList[i].taken = false;
- destAddr[5] += 1;
- }
- AVB_TRACE_EXIT(AVB_TRACE_MAAP);
- return true;
-}
-
-void openavbMaapFinalize()
-{
- AVB_TRACE_ENTRY(AVB_TRACE_MAAP);
- AVB_TRACE_EXIT(AVB_TRACE_MAAP);
-
-}
-
-void* openavbMaapAllocate(int count, /* out */ struct ether_addr *addr)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_MAAP);
- assert(count == 1);
-
- int i = 0;
- while (i < MAX_AVB_STREAMS && maapAllocList[i].taken) {
- i++;
- }
-
- if (i < MAX_AVB_STREAMS) {
- maapAllocList[i].taken = true;
- memcpy(addr, maapAllocList[i].destAddr, ETH_ALEN);
-
- AVB_TRACE_EXIT(AVB_TRACE_MAAP);
- return &maapAllocList[i];
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_MAAP);
- return NULL;
-}
-
-void openavbMaapRelease(void* handle)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_MAAP);
-
- maapAlloc_t *elem = handle;
- elem->taken = false;
-
- AVB_TRACE_EXIT(AVB_TRACE_MAAP);
-}
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.h b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.h
index 4f41f8d5..6b5118ae 100644
--- a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.h
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_maap.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_maap.c
new file mode 100644
index 00000000..0f754236
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_maap.c
@@ -0,0 +1,596 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include "openavb_platform.h"
+#include "openavb_trace.h"
+#include "openavb_maap.h"
+#include "maap_iface.h"
+#include "openavb_list.h"
+#include "openavb_rawsock.h"
+
+// These are used to support saving the MAAP Address
+#include "openavb_endpoint_cfg.h"
+extern openavb_endpoint_cfg_t x_cfg;
+
+#define AVB_LOG_COMPONENT "Endpoint MAAP"
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+#define MAAP_DYNAMIC_POOL_BASE 0x91E0F0000000LL /**< MAAP dynamic allocation pool base address - Defined in IEEE 1722-2016 Table B.9 */
+#define MAAP_DYNAMIC_POOL_SIZE 0xFE00 /**< MAAP dynamic allocation pool size - Defined in IEEE 1722-2016 Table B.9 */
+
+
+/*******************************************************************************
+ * MAAP proxies
+ ******************************************************************************/
+
+typedef struct {
+ struct ether_addr destAddr;
+ bool taken;
+} maapAlloc_t;
+
+static maapAlloc_t maapAllocList[MAX_AVB_STREAMS];
+static openavbMaapRestartCb_t *maapRestartCallback = NULL;
+static struct ether_addr *maapPreferredAddress = NULL;
+
+static bool maapRunning = FALSE;
+static pthread_t maapThreadHandle;
+static void* maapThread(void *arg);
+
+enum maapState_t {
+ MAAP_STATE_UNKNOWN,
+ MAAP_STATE_INITIALIZING, // Waiting for initialization
+ MAAP_STATE_REQUESTING, // Waiting address block request
+ MAAP_STATE_CONNECTED, // Have block of addresses
+ MAAP_STATE_RELEASING, // Releasing the block of addresses
+ MAAP_STATE_RELEASED, // Released the block of addresses
+ MAAP_STATE_NOT_AVAILABLE, // MAAP not configured, or freed
+ MAAP_STATE_ERROR
+};
+static enum maapState_t maapState = MAAP_STATE_UNKNOWN;
+static int maapReservationId = 0;
+
+static char maapDaemonPort[6] = {0};
+
+static MUTEX_HANDLE(maapMutex);
+#define MAAP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(maapMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define MAAP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(maapMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+static unsigned long long MaapMacAddrToLongLong(const struct ether_addr *addr)
+{
+ unsigned long long nAddress = 0ull;
+ int i;
+ for (i = 0; i < ETH_ALEN; ++i) {
+ nAddress = (nAddress << 8) | addr->ether_addr_octet[i];
+ }
+ return nAddress;
+}
+
+static void MaapResultToMacAddr(unsigned long long nAddress, struct ether_addr *destAddr)
+{
+ int i;
+ for (i = ETH_ALEN - 1; i >= 0; --i) {
+ destAddr->ether_addr_octet[i] = (U8)(nAddress & 0xFF);
+ nAddress >>= 8;
+ }
+}
+
+static void process_maap_notify(Maap_Notify *mn, int socketfd)
+{
+ assert(mn);
+
+ switch (mn->result)
+ {
+ case MAAP_NOTIFY_ERROR_NONE:
+ /* No error. Don't display anything. */
+ break;
+ case MAAP_NOTIFY_ERROR_REQUIRES_INITIALIZATION:
+ AVB_LOG_ERROR("MAAP is not initialized, so the command cannot be performed.");
+ break;
+ case MAAP_NOTIFY_ERROR_ALREADY_INITIALIZED:
+ AVB_LOG_ERROR("MAAP is already initialized, so the values cannot be changed.");
+ break;
+ case MAAP_NOTIFY_ERROR_RESERVE_NOT_AVAILABLE:
+ AVB_LOG_ERROR("The MAAP reservation is not available, or yield cannot allocate a replacement block. "
+ "Try again with a smaller address block size.");
+ break;
+ case MAAP_NOTIFY_ERROR_RELEASE_INVALID_ID:
+ AVB_LOG_ERROR("The MAAP reservation ID is not valid, so cannot be released or report its status.");
+ break;
+ case MAAP_NOTIFY_ERROR_OUT_OF_MEMORY:
+ AVB_LOG_ERROR("The MAAP application is out of memory.");
+ break;
+ case MAAP_NOTIFY_ERROR_INTERNAL:
+ AVB_LOG_ERROR("The MAAP application experienced an internal error.");
+ break;
+ default:
+ AVB_LOGF_ERROR("The MAAP application returned an unknown error %d.", mn->result);
+ break;
+ }
+
+ switch (mn->kind)
+ {
+ case MAAP_NOTIFY_INITIALIZED:
+ if (mn->result == MAAP_NOTIFY_ERROR_NONE) {
+ AVB_LOGF_DEBUG("MAAP initialized: 0x%012llx-0x%012llx (Size: %d)",
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ (unsigned int) mn->count);
+
+ // We successfully initialized. Reserve a block of addresses.
+ Maap_Cmd maapcmd;
+ memset(&maapcmd, 0, sizeof(Maap_Cmd));
+ maapcmd.kind = MAAP_CMD_RESERVE;
+ maapcmd.start = 0; // No preferred address
+ maapcmd.count = MAX_AVB_STREAMS;
+ if (maapPreferredAddress != NULL) {
+ // Suggest the addresses from the previous time this application was run.
+ maapcmd.start = MaapMacAddrToLongLong(maapPreferredAddress);
+ AVB_LOGF_DEBUG("MAAP Preferred Address: 0x%012llx", maapcmd.start);
+ }
+ if (send(socketfd, (char *) &maapcmd, sizeof(Maap_Cmd), 0) < 0)
+ {
+ /* Something went wrong. Abort! */
+ AVB_LOGF_ERROR("MAAP: Error %d writing to network socket (%s)", errno, strerror(errno));
+ maapState = MAAP_STATE_ERROR;
+ } else {
+ maapState = MAAP_STATE_REQUESTING;
+ }
+ } else {
+ AVB_LOGF_ERROR("MAAP previously initialized to 0x%012llx-0x%012llx (Size: %d)",
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ (unsigned int) mn->count);
+ maapState = MAAP_STATE_ERROR;
+ }
+ break;
+ case MAAP_NOTIFY_ACQUIRING:
+ if (mn->result == MAAP_NOTIFY_ERROR_NONE) {
+ AVB_LOGF_DEBUG("MAAP address range %d querying: 0x%012llx-0x%012llx (Size %d)",
+ mn->id,
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ mn->count);
+ } else {
+ AVB_LOGF_ERROR("MAAP unknown address range %d acquisition error", mn->id);
+ maapState = MAAP_STATE_ERROR;
+ }
+ break;
+ case MAAP_NOTIFY_ACQUIRED:
+ if (mn->result == MAAP_NOTIFY_ERROR_NONE) {
+ AVB_LOGF_INFO("MAAP address range %d acquired: 0x%012llx-0x%012llx (Size %d)",
+ mn->id,
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ mn->count);
+
+ // Update the stored addresses.
+ MAAP_LOCK();
+ int i = 0;
+ for (i = 0; i < mn->count && i < MAX_AVB_STREAMS; i++) {
+ MaapResultToMacAddr(mn->start + i, &(maapAllocList[i].destAddr));
+ if (maapAllocList[i].taken && maapRestartCallback) {
+ // Use the callback to notify that a change has occurred.
+ MAAP_UNLOCK();
+ maapRestartCallback(&(maapAllocList[i]), &(maapAllocList[i].destAddr));
+ MAAP_LOCK();
+ }
+ }
+ MAAP_UNLOCK();
+
+ // Save the address so we can request it in the future.
+ if (maapPreferredAddress != NULL) {
+ struct ether_addr assignedAddress;
+ MaapResultToMacAddr((unsigned long long) mn->start, &assignedAddress);
+ if (memcmp(maapPreferredAddress, &assignedAddress, sizeof(struct ether_addr)) != 0) {
+ // Save the updated settings. Done immediately, so they won't get lost on device reboot.
+ memcpy(maapPreferredAddress, &assignedAddress, sizeof(struct ether_addr));
+ openavbSaveConfig(DEFAULT_SAVE_INI_FILE, &x_cfg);
+ }
+ }
+
+ // We now have addresses we can use.
+ maapReservationId = mn->id;
+ maapState = MAAP_STATE_CONNECTED;
+ } else if (mn->id != -1) {
+ AVB_LOGF_ERROR("MAAP address range %d of size %d not acquired",
+ mn->id, mn->count);
+ maapState = MAAP_STATE_ERROR;
+ } else {
+ AVB_LOGF_ERROR("MAAP address range of size %d not acquired",
+ mn->count);
+ maapState = MAAP_STATE_ERROR;
+ }
+ break;
+ case MAAP_NOTIFY_RELEASED:
+ if (mn->result == MAAP_NOTIFY_ERROR_NONE) {
+ AVB_LOGF_DEBUG("MAAP address range %d released: 0x%012llx-0x%012llx (Size %d)",
+ mn->id,
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ mn->count);
+ maapState = MAAP_STATE_RELEASED;
+ } else {
+ AVB_LOGF_WARNING("MAAP address range %d not released",
+ mn->id);
+ }
+ break;
+ case MAAP_NOTIFY_STATUS:
+ if (mn->result == MAAP_NOTIFY_ERROR_NONE) {
+ AVB_LOGF_DEBUG("MAAP ID %d is address range 0x%012llx-0x%012llx (Size %d)",
+ mn->id,
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ mn->count);
+ } else {
+ AVB_LOGF_DEBUG("MAAP ID %d is not valid",
+ mn->id);
+ }
+ break;
+ case MAAP_NOTIFY_YIELDED:
+ if (mn->result != MAAP_NOTIFY_ERROR_REQUIRES_INITIALIZATION && mn->result != MAAP_NOTIFY_ERROR_RELEASE_INVALID_ID) {
+ if (mn->result != MAAP_NOTIFY_ERROR_NONE) {
+ AVB_LOGF_ERROR("MAAP Address range %d yielded: 0x%012llx-0x%012llx (Size %d). A new address range will not be allocated.",
+ mn->id,
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ mn->count);
+ maapState = MAAP_STATE_ERROR;
+ }
+ else {
+ AVB_LOGF_WARNING("MAAP Address range %d yielded: 0x%012llx-0x%012llx (Size %d)",
+ mn->id,
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ mn->count);
+ }
+ } else {
+ AVB_LOGF_ERROR("ID %d is not valid", mn->id);
+ }
+ break;
+ default:
+ AVB_LOGF_ERROR("MAAP notification type %d not recognized", mn->kind);
+ break;
+ }
+}
+
+
+/* Local function to interact with the MAAP daemon. */
+static void* maapThread(void *arg)
+{
+ int socketfd;
+ struct addrinfo hints, *ai, *p;
+ int ret;
+
+ fd_set master, read_fds;
+ int fdmax;
+
+ char recvbuffer[200];
+ int recvbytes;
+ Maap_Cmd maapcmd;
+
+ AVB_LOG_DEBUG("MAAP Thread Starting");
+
+ /* Create a localhost socket. */
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = 0;
+ if ((ret = getaddrinfo("localhost", maapDaemonPort, &hints, &ai)) != 0) {
+ AVB_LOGF_ERROR("getaddrinfo failure %s", gai_strerror(ret));
+ maapState = MAAP_STATE_ERROR;
+ return NULL;
+ }
+
+ for(p = ai; p != NULL; p = p->ai_next) {
+ socketfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+ if (socketfd == -1) {
+ continue;
+ }
+ ret = connect(socketfd, p->ai_addr, p->ai_addrlen);
+ if (ret == -1) {
+ close(socketfd);
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ freeaddrinfo(ai);
+
+ if (p == NULL) {
+ AVB_LOGF_ERROR("MAAP: Unable to connect to the daemon, error %d (%s)", errno, strerror(errno));
+ maapState = MAAP_STATE_ERROR;
+ return NULL;
+ }
+
+ if (fcntl(socketfd, F_SETFL, O_NONBLOCK) < 0)
+ {
+ AVB_LOG_ERROR("MAAP: Could not set the socket to non-blocking");
+ close(socketfd);
+ maapState = MAAP_STATE_ERROR;
+ return NULL;
+ }
+
+ FD_ZERO(&read_fds);
+ FD_ZERO(&master);
+ FD_SET(STDIN_FILENO, &master);
+ FD_SET(socketfd, &master);
+ fdmax = socketfd;
+
+ // Initialize the MAAP daemon.
+ // We will request a block of addresses when we get a response to the initialization.
+ maapState = MAAP_STATE_INITIALIZING;
+ memset(&maapcmd, 0, sizeof(Maap_Cmd));
+ maapcmd.kind = MAAP_CMD_INIT;
+ maapcmd.start = MAAP_DYNAMIC_POOL_BASE;
+ maapcmd.count = MAAP_DYNAMIC_POOL_SIZE;
+ if (send(socketfd, (char *) &maapcmd, sizeof(Maap_Cmd), 0) < 0)
+ {
+ /* Something went wrong. Abort! */
+ AVB_LOGF_ERROR("MAAP: Error %d writing to network socket (%s)", errno, strerror(errno));
+ maapState = MAAP_STATE_ERROR;
+ return NULL;
+ }
+
+
+ /*
+ * Main event loop
+ */
+
+ while (maapRunning || maapState <= MAAP_STATE_CONNECTED)
+ {
+ if (!maapRunning && maapState == MAAP_STATE_CONNECTED)
+ {
+ // Tell the MAAP daemon to release the addresses.
+ memset(&maapcmd, 0, sizeof(Maap_Cmd));
+ maapcmd.kind = MAAP_CMD_RELEASE;
+ maapcmd.id = maapReservationId;
+ if (send(socketfd, (char *) &maapcmd, sizeof(Maap_Cmd), 0) > 0)
+ {
+ maapState = MAAP_STATE_RELEASING;
+ // Use the wait below to give the daemon time to respond.
+ }
+ else
+ {
+ maapState = MAAP_STATE_NOT_AVAILABLE;
+ break;
+ }
+ }
+
+ /* Wait for something to happen. */
+ struct timeval tv_timeout = { 1, 0 };
+ read_fds = master;
+ ret = select(fdmax+1, &read_fds, NULL, NULL, &tv_timeout);
+ if (ret < 0)
+ {
+ AVB_LOGF_ERROR("MAAP: select() error %d (%s)", errno, strerror(errno));
+ maapState = MAAP_STATE_ERROR;
+ break;
+ }
+
+ /* Handle any responses received. */
+ if (FD_ISSET(socketfd, &read_fds))
+ {
+ while ((recvbytes = recv(socketfd, recvbuffer, sizeof(Maap_Notify), 0)) > 0)
+ {
+ recvbuffer[recvbytes] = '\0';
+
+ /* Process the response data (will be binary). */
+ if (recvbytes == sizeof(Maap_Notify))
+ {
+ process_maap_notify((Maap_Notify *) recvbuffer, socketfd);
+ }
+ else
+ {
+ AVB_LOGF_WARNING("MAAP: Received unexpected response of size %d", recvbytes);
+ }
+ }
+ if (recvbytes == 0)
+ {
+ /* The MAAP daemon closed the connection. Assume it shut down, and we should too. */
+ // AVDECC_TODO: Should we try to reconnect?
+ AVB_LOG_ERROR("MAAP daemon exited.");
+ maapState = MAAP_STATE_ERROR;
+ break;
+ }
+ if (recvbytes < 0 && errno != EWOULDBLOCK)
+ {
+ /* Something went wrong. Abort! */
+ AVB_LOGF_ERROR("MAAP: Error %d reading from network socket (%s)", errno, strerror(errno));
+ maapState = MAAP_STATE_ERROR;
+ break;
+ }
+ }
+ }
+
+ if (maapState < MAAP_STATE_NOT_AVAILABLE) {
+ maapState = MAAP_STATE_NOT_AVAILABLE;
+ }
+
+ close(socketfd);
+
+ AVB_LOG_DEBUG("MAAP Thread Done");
+ return NULL;
+}
+
+bool openavbMaapInitialize(const char *ifname, unsigned int maapPort, struct ether_addr *maapPrefAddr, openavbMaapRestartCb_t* cbfn)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAAP);
+
+ // Save the supplied callback function.
+ maapRestartCallback = cbfn;
+ maapPreferredAddress = maapPrefAddr;
+
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "maapMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(maapMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'maapMutex' mutex");
+
+ // Default to using addresses from the MAAP locally administered Pool.
+ int i = 0;
+ U8 destAddr[ETH_ALEN] = {0x91, 0xe0, 0xf0, 0x00, 0xfe, 0x80};
+ for (i = 0; i < MAX_AVB_STREAMS; i++) {
+ memcpy(maapAllocList[i].destAddr.ether_addr_octet, destAddr, ETH_ALEN);
+ maapAllocList[i].taken = false;
+ destAddr[5] += 1;
+ }
+
+ if (maapPort == 0) {
+ maapState = MAAP_STATE_NOT_AVAILABLE;
+ }
+ else {
+ maapState = MAAP_STATE_UNKNOWN;
+ sprintf(maapDaemonPort, "%u", maapPort);
+
+ maapRunning = TRUE;
+ int err = pthread_create(&maapThreadHandle, NULL, maapThread, NULL);
+ if (err) {
+ maapRunning = FALSE;
+ maapState = MAAP_STATE_ERROR;
+ AVB_LOGF_ERROR("Failed to start MAAP thread: %s", strerror(err));
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAAP);
+ return true;
+}
+
+void openavbMaapFinalize()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAAP);
+
+ maapRestartCallback = NULL;
+ maapPreferredAddress = NULL;
+
+ if (maapRunning) {
+ // Stop the MAAP thread.
+ maapRunning = FALSE;
+ pthread_join(maapThreadHandle, NULL);
+ }
+
+ MUTEX_CREATE_ERR();
+ MUTEX_DESTROY(maapMutex);
+ MUTEX_LOG_ERR("Error destroying mutex");
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAAP);
+}
+
+bool openavbMaapDaemonAvailable(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAAP);
+
+ if (!maapRunning) {
+ AVB_TRACE_EXIT(AVB_TRACE_MAAP);
+ return FALSE;
+ }
+
+ // Wait up to 10 seconds for the daemon to give us a block of addresses.
+ int j;
+ for (j = 0; j < 10 * 1000 / 50 && maapState < MAAP_STATE_CONNECTED; ++j) {
+ AVB_LOG_DEBUG("Waiting for MAAP Daemon status");
+ SLEEP_MSEC(50);
+ }
+
+ if (maapState != MAAP_STATE_CONNECTED) {
+ if (maapState != MAAP_STATE_NOT_AVAILABLE) {
+ AVB_LOG_WARNING("MAAP Daemon not available. Fallback multicast address allocation will be used.");
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAAP);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAAP);
+ return TRUE;
+}
+
+void* openavbMaapAllocate(int count, /* out */ struct ether_addr *addr)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAAP);
+ assert(count == 1);
+
+ // Wait up to 10 seconds for the daemon to give us a block of addresses.
+ int j;
+ for (j = 0; j < 10 * 1000 / 50 && maapState < MAAP_STATE_CONNECTED; ++j) {
+ AVB_LOG_DEBUG("Waiting for MAAP Daemon status");
+ SLEEP_MSEC(50);
+ }
+
+ MAAP_LOCK();
+
+ // Find the next non-allocated address.
+ int i = 0;
+ while (i < MAX_AVB_STREAMS && maapAllocList[i].taken) {
+ i++;
+ }
+
+ // Allocate an address from the pool.
+ if (i < MAX_AVB_STREAMS) {
+ maapAllocList[i].taken = true;
+ memcpy(addr, maapAllocList[i].destAddr.ether_addr_octet, sizeof(struct ether_addr));
+ AVB_LOGF_INFO("Allocated MAAP address " ETH_FORMAT, ETH_OCTETS(addr->ether_addr_octet));
+
+ MAAP_UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAAP);
+ return &maapAllocList[i];
+ }
+
+ MAAP_UNLOCK();
+
+ AVB_LOG_ERROR("All MAAP addresses already allocated");
+ AVB_TRACE_EXIT(AVB_TRACE_MAAP);
+ return NULL;
+}
+
+void openavbMaapRelease(void* handle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAAP);
+
+ MAAP_LOCK();
+ maapAlloc_t *elem = handle;
+ elem->taken = false;
+ AVB_LOGF_DEBUG("Freed MAAP address " ETH_FORMAT, ETH_OCTETS(elem->destAddr.ether_addr_octet));
+ MAAP_UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAAP);
+}
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_ptp.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_ptp.c
new file mode 100644
index 00000000..e74e7ac3
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_ptp.c
@@ -0,0 +1,75 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "openavb_platform.h"
+#include "openavb_trace.h"
+#include "openavb_endpoint.h"
+
+#define AVB_LOG_COMPONENT "Endpoint PTP"
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+
+inline int startPTP(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ // make sure ptp, a separate process, starts and is using the same interface as endpoint
+ int retVal = 0;
+// char ptpCmd[80];
+// memset(ptpCmd, 0, 80);
+// snprintf(ptpCmd, 80, "./openavb_gptp %s -i %s &", x_cfg.ptp_start_opts, x_cfg.ifname);
+// AVB_LOGF_INFO("PTP start command: %s", ptpCmd);
+// if (system(ptpCmd) != 0) {
+// AVB_LOG_ERROR("PTP failed to start - Exiting");
+// retVal = -1;
+// }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return retVal;
+}
+
+inline int stopPTP(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ int retVal = 0;
+// if (system("killall -s SIGINT openavb_gptp") != 0) {
+// retVal = -1;
+// }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return retVal;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_shaper.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_shaper.c
new file mode 100644
index 00000000..f8d2c3b0
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_shaper.c
@@ -0,0 +1,426 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include "openavb_platform.h"
+#include "openavb_trace.h"
+#include "openavb_shaper.h"
+#include "openavb_list.h"
+#include "openavb_rawsock.h"
+
+#define AVB_LOG_COMPONENT "Endpoint Shaper"
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+
+/*******************************************************************************
+ * Shaper proxies
+ ******************************************************************************/
+
+#define STREAMDA_LENGTH 18
+
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+
+typedef struct shaper_reservation
+{
+ int in_use;
+ SRClassIdx_t sr_class;
+ int measurement_interval; // microseconds
+ int max_frame_size; // bytes
+ int max_frames_per_interval; // number of frames per measurement_interval
+ unsigned char stream_da[ETH_ALEN];
+} shaper_reservation;
+
+#define MAX_SHAPER_RESERVATIONS 4
+static shaper_reservation shaperReservationList[MAX_SHAPER_RESERVATIONS];
+
+static bool shaperRunning = FALSE;
+static pthread_t shaperThreadHandle;
+static void* shaperThread(void *arg);
+
+enum shaperState_t {
+ SHAPER_STATE_UNKNOWN,
+ SHAPER_STATE_CONNECTED, // Connected, but shaping not enabled.
+ SHAPER_STATE_ENABLED, // Shaping enabled by the daemon
+ SHAPER_STATE_NOT_AVAILABLE, // Daemon not found or not connected.
+ SHAPER_STATE_ERROR
+};
+static enum shaperState_t shaperState = SHAPER_STATE_UNKNOWN;
+
+static int socketfd = -1;
+static char interfaceOnly[IFNAMSIZ];
+static char shaperDaemonPort[6] = {0};
+
+static MUTEX_HANDLE(shaperMutex);
+#define SHAPER_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(shaperMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define SHAPER_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(shaperMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+
+/* Local function to interact with the SHAPER daemon. */
+static void* shaperThread(void *arg)
+{
+ struct addrinfo hints, *ai, *p;
+ int ret;
+
+ fd_set master, read_fds;
+ int fdmax;
+
+ char recvbuffer[200];
+ int recvbytes;
+
+ AVB_LOG_DEBUG("Shaper Thread Starting");
+
+ /* Create a localhost socket. */
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = 0;
+ if ((ret = getaddrinfo("localhost", shaperDaemonPort, &hints, &ai)) != 0) {
+ AVB_LOGF_ERROR("getaddrinfo failure %s", gai_strerror(ret));
+ shaperState = SHAPER_STATE_ERROR;
+ return NULL;
+ }
+
+ for(p = ai; p != NULL; p = p->ai_next) {
+ socketfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+ if (socketfd == -1) {
+ continue;
+ }
+ ret = connect(socketfd, p->ai_addr, p->ai_addrlen);
+ if (ret == -1) {
+ close(socketfd);
+ socketfd = -1;
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ freeaddrinfo(ai);
+
+ if (p == NULL) {
+ AVB_LOGF_ERROR("Shaper: Unable to connect to the daemon, error %d (%s)", errno, strerror(errno));
+ shaperState = SHAPER_STATE_ERROR;
+ return NULL;
+ }
+
+ if (fcntl(socketfd, F_SETFL, O_NONBLOCK) < 0)
+ {
+ AVB_LOG_ERROR("Shaper: Could not set the socket to non-blocking");
+ close(socketfd);
+ socketfd = -1;
+ shaperState = SHAPER_STATE_ERROR;
+ return NULL;
+ }
+
+ FD_ZERO(&read_fds);
+ FD_ZERO(&master);
+ FD_SET(STDIN_FILENO, &master);
+ FD_SET(socketfd, &master);
+ fdmax = socketfd;
+
+
+ /*
+ * Main event loop
+ */
+
+ shaperState = SHAPER_STATE_CONNECTED;
+ AVB_LOG_INFO("Shaper daemon available");
+
+ while (shaperRunning || shaperState == SHAPER_STATE_ENABLED)
+ {
+ if (!shaperRunning && shaperState == SHAPER_STATE_ENABLED)
+ {
+ // TODO: Tell the SHAPER daemon to stop shaping.
+ break;
+ }
+
+ /* Wait for something to happen. */
+ struct timeval tv_timeout = { 1, 0 };
+ read_fds = master;
+ ret = select(fdmax+1, &read_fds, NULL, NULL, &tv_timeout);
+ if (ret < 0)
+ {
+ AVB_LOGF_ERROR("Shaper: select() error %d (%s)", errno, strerror(errno));
+ shaperState = SHAPER_STATE_ERROR;
+ break;
+ }
+
+ /* Handle any responses received. */
+ if (FD_ISSET(socketfd, &read_fds))
+ {
+ while ((recvbytes = recv(socketfd, recvbuffer, sizeof(recvbuffer) - 1, 0)) > 0)
+ {
+ /* Log the response data */
+ recvbuffer[recvbytes] = '\0';
+ if (strncmp(recvbuffer, "ERROR:", 6) == 0) {
+ AVB_LOGF_ERROR("Shaper Response: %s", recvbuffer + 7);
+ }
+ else if (strncmp(recvbuffer, "WARNING:", 8) == 0) {
+ AVB_LOGF_WARNING("Shaper Response: %s", recvbuffer + 9);
+ }
+ else if (strncmp(recvbuffer, "DEBUG:", 6) == 0) {
+ AVB_LOGF_DEBUG("Shaper Response: %s", recvbuffer + 7);
+ }
+ else {
+ AVB_LOGF_DEBUG("Shaper Response: %s", recvbuffer);
+ }
+ }
+ if (recvbytes == 0)
+ {
+ /* The SHAPER daemon closed the connection. Assume it shut down, and we should too. */
+ // AVDECC_TODO: Should we try to reconnect?
+ AVB_LOG_ERROR("Shaper daemon exited.");
+ shaperState = SHAPER_STATE_ERROR;
+ break;
+ }
+ if (recvbytes < 0 && errno != EWOULDBLOCK)
+ {
+ /* Something went wrong. Abort! */
+ AVB_LOGF_ERROR("Shaper: Error %d reading from network socket (%s)", errno, strerror(errno));
+ shaperState = SHAPER_STATE_ERROR;
+ break;
+ }
+ }
+ }
+
+ if (shaperState < SHAPER_STATE_NOT_AVAILABLE) {
+ shaperState = SHAPER_STATE_NOT_AVAILABLE;
+ }
+
+ close(socketfd);
+ socketfd = -1;
+
+ AVB_LOG_DEBUG("Shaper Thread Done");
+ return NULL;
+}
+
+bool openavbShaperInitialize(const char *ifname, unsigned int shaperPort)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SHAPER);
+
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "shaperMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(shaperMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'shaperMutex' mutex");
+
+ memset(shaperReservationList, 0, sizeof(shaperReservationList));
+
+ if (shaperPort == 0) {
+ shaperState = SHAPER_STATE_NOT_AVAILABLE;
+ }
+ else {
+ shaperState = SHAPER_STATE_UNKNOWN;
+ sprintf(shaperDaemonPort, "%u", shaperPort);
+
+ // Save the interface-only name to pass to the daemon later.
+ const char *ifonly = strchr(ifname, ':');
+ if (ifonly) {
+ ifonly++; // Go past the colon
+ } else {
+ ifonly = ifname; // No colon in interface name
+ }
+ strncpy(interfaceOnly, ifonly, sizeof(interfaceOnly));
+ interfaceOnly[sizeof(interfaceOnly) - 1] = '\0';
+
+ shaperRunning = TRUE;
+ int err = pthread_create(&shaperThreadHandle, NULL, shaperThread, NULL);
+ if (err) {
+ shaperRunning = FALSE;
+ shaperState = SHAPER_STATE_ERROR;
+ AVB_LOGF_ERROR("Failed to start SHAPER thread: %s", strerror(err));
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_SHAPER);
+ return true;
+}
+
+void openavbShaperFinalize()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SHAPER);
+
+ if (shaperRunning) {
+ // Stop the SHAPER thread.
+ shaperRunning = FALSE;
+ pthread_join(shaperThreadHandle, NULL);
+ }
+
+ MUTEX_CREATE_ERR();
+ MUTEX_DESTROY(shaperMutex);
+ MUTEX_LOG_ERR("Error destroying mutex");
+
+ AVB_TRACE_EXIT(AVB_TRACE_SHAPER);
+}
+
+bool openavbShaperDaemonAvailable(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SHAPER);
+
+ if (!shaperRunning) {
+ AVB_TRACE_EXIT(AVB_TRACE_SHAPER);
+ return FALSE;
+ }
+
+ // Wait for the daemon to connect.
+ if (shaperState == SHAPER_STATE_UNKNOWN) {
+ SLEEP_MSEC(50);
+ }
+
+ if (shaperState > SHAPER_STATE_UNKNOWN && shaperState < SHAPER_STATE_NOT_AVAILABLE) {
+ AVB_TRACE_EXIT(AVB_TRACE_SHAPER);
+ return TRUE;
+ }
+
+ if (shaperState != SHAPER_STATE_NOT_AVAILABLE) {
+ AVB_LOG_WARNING("Shaper Daemon not available.");
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_SHAPER);
+ return FALSE;
+}
+
+void* openavbShaperHandle(SRClassIdx_t sr_class, int measurement_interval_usec, int max_frame_size_bytes, int max_frames_per_interval, const unsigned char * stream_da)
+{
+ // If the daemon is not available, abort!
+ if (socketfd == -1 || !openavbShaperDaemonAvailable())
+ {
+ AVB_LOG_ERROR("Shaper reservation attempted with no daemon available");
+ return NULL;
+ }
+
+ // Find the first available index.
+ int i;
+ for (i = 0; i < MAX_SHAPER_RESERVATIONS; ++i)
+ {
+ if (!(shaperReservationList[i].in_use))
+ {
+ break;
+ }
+ }
+ if (i >= MAX_SHAPER_RESERVATIONS)
+ {
+ AVB_LOG_ERROR("No Shaper reservations are available");
+ return NULL;
+ }
+
+ // Fill in the information.
+ shaperReservationList[i].in_use = TRUE;
+ shaperReservationList[i].sr_class = sr_class;
+ shaperReservationList[i].measurement_interval = measurement_interval_usec;
+ shaperReservationList[i].max_frame_size = max_frame_size_bytes;
+ shaperReservationList[i].max_frames_per_interval = max_frames_per_interval;
+ memcpy(shaperReservationList[i].stream_da, stream_da, ETH_ALEN);
+
+ // Send the information to the Shaper daemon.
+ // Reserving Bandwidth Example: -ri eth2 -c A -s 125 -b 74 -f 1 -a ff:ff:ff:ff:ff:11\n
+ char szCommand[200];
+ sprintf(szCommand, "-ri %s -c %c -s %u -b %u -f %u -a %02x:%02x:%02x:%02x:%02x:%02x",
+ interfaceOnly,
+ ( shaperReservationList[i].sr_class == SR_CLASS_A ? 'A' : 'B' ),
+ shaperReservationList[i].measurement_interval,
+ shaperReservationList[i].max_frame_size,
+ shaperReservationList[i].max_frames_per_interval,
+ shaperReservationList[i].stream_da[0],
+ shaperReservationList[i].stream_da[1],
+ shaperReservationList[i].stream_da[2],
+ shaperReservationList[i].stream_da[3],
+ shaperReservationList[i].stream_da[4],
+ shaperReservationList[i].stream_da[5]);
+ AVB_LOGF_DEBUG("Sending Shaper command: %s", szCommand);
+ strcat(szCommand, "\n");
+ if (send(socketfd, szCommand, strlen(szCommand), 0) < 0)
+ {
+ /* Something went wrong. Abort! */
+ AVB_LOGF_ERROR("Shaper: Error %d writing to network socket (%s)", errno, strerror(errno));
+ shaperState = SHAPER_STATE_ERROR;
+ return NULL;
+ }
+
+ shaperState = SHAPER_STATE_ENABLED;
+
+ // TODO: Verify that the command was successful.
+
+ return (void *)(&(shaperReservationList[i]));
+}
+
+void openavbShaperRelease(void* handle)
+{
+ int i;
+ for (i = 0; i < MAX_SHAPER_RESERVATIONS; ++i)
+ {
+ if (handle == (void *)(&(shaperReservationList[i])))
+ {
+ if (shaperReservationList[i].in_use)
+ {
+ // Send the information to the Shaper daemon.
+ // Unreserving Bandwidth Example: -ua ff:ff:ff:ff:ff:11\n
+ char szCommand[200];
+ sprintf(szCommand, "-ua %02x:%02x:%02x:%02x:%02x:%02x",
+ shaperReservationList[i].stream_da[0],
+ shaperReservationList[i].stream_da[1],
+ shaperReservationList[i].stream_da[2],
+ shaperReservationList[i].stream_da[3],
+ shaperReservationList[i].stream_da[4],
+ shaperReservationList[i].stream_da[5]);
+
+ shaperReservationList[i].in_use = FALSE;
+
+ AVB_LOGF_DEBUG("Sending Shaper command: %s", szCommand);
+ strcat(szCommand, "\n");
+ if (send(socketfd, szCommand, strlen(szCommand), 0) < 0)
+ {
+ /* Something went wrong. */
+ AVB_LOGF_ERROR("Shaper: Error %d writing to network socket (%s)", errno, strerror(errno));
+ shaperState = SHAPER_STATE_ERROR;
+ }
+ else {
+ // TODO: Verify that the command was successful.
+ }
+ }
+ break;
+ }
+ }
+}
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_srp.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_srp.c
new file mode 100644
index 00000000..9a7d2b33
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_srp.c
@@ -0,0 +1,412 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "openavb_platform.h"
+#include "openavb_trace.h"
+#include "openavb_endpoint.h"
+#include "openavb_srp.h"
+#include "mrp_client.h"
+#include "openavb_list.h"
+
+#define AVB_LOG_COMPONENT "Endpoint SRP"
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+
+/*******************************************************************************
+ * SRP proxies
+ ******************************************************************************/
+
+static strmAttachCb_t _attachCb = NULL;
+static strmRegCb_t _registerCb = NULL;
+
+typedef struct {
+ void* avtpHandle;
+ bool talker;
+ U8 streamId[8];
+ U8 destAddr[6];
+ U16 vlanId;
+ int maxFrameSize;
+ int maxIntervalFrames;
+ int priority;
+ int latency;
+ int subtype;
+} strElem_t;
+
+openavb_list_t strElemList;
+
+#define SID_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x/%u"
+#define SID_OCTETS(a) (a)[0],(a)[1],(a)[2],(a)[3],(a)[4],(a)[5],(a)[6]<<8|(a)[7]
+
+// Callback for SRP to notify AVTP Talker that a Listener Declaration has been
+// registered (or de-registered)
+void mrp_attach_cb(unsigned char streamid[8], int subtype)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
+
+ AVB_LOGF_DEBUG("mrp_attach_cb "SID_FORMAT" subtype %d", SID_OCTETS(streamid), subtype);
+
+ if (_attachCb) {
+ openavb_list_node_t node = openavbListIterFirst(strElemList);
+ while (node) {
+ strElem_t *elem = openavbListData(node);
+ if (elem && elem->talker && memcmp(streamid, elem->streamId, sizeof(elem->streamId)) == 0) {
+ _attachCb(elem->avtpHandle, subtype);
+ elem->subtype = subtype;
+ AVB_LOGF_DEBUG("mrp_attach_cb subtype changed to %d", elem->subtype);
+ break;
+ }
+ else if (elem) {
+ AVB_LOGF_DEBUG("mrp_attach_cb skipping elem " SID_FORMAT ", talker %d",
+ SID_OCTETS(elem->streamId), elem->talker ? 1 : 0);
+ }
+ node = openavbListIterNext(strElemList);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+}
+
+// Callback for SRP to notify AVTP Listener that a Talker Declaration has been
+// registered (or de-registered)
+void mrp_register_cb(unsigned char streamid[8], int join, unsigned char destaddr[6], unsigned int max_frame_size, unsigned int max_interval_frames, uint16_t vid, unsigned int latency)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
+
+ AVB_LOGF_DEBUG("mrp_register_cb "SID_FORMAT" "ETH_FORMAT" join %d max_frame_size %d max_interval_frames %d vid %d latency %d",
+ SID_OCTETS(streamid), ETH_OCTETS(destaddr), join, max_frame_size, max_interval_frames, vid, latency);
+
+ if (_registerCb) {
+ openavb_list_node_t node = openavbListIterFirst(strElemList);
+ while (node) {
+ strElem_t *elem = openavbListData(node);
+ if (elem && !elem->talker && memcmp(streamid, elem->streamId, sizeof(elem->streamId)) == 0) {
+ AVBTSpec_t tSpec;
+ tSpec.maxFrameSize = max_frame_size;
+ tSpec.maxIntervalFrames = max_interval_frames;
+ _registerCb(elem->avtpHandle,
+ join ? openavbSrp_AtTyp_TalkerAdvertise : openavbSrp_AtTyp_None,
+ destaddr,
+ &tSpec,
+ 0, // SR_CLASS is ignored anyway
+ latency,
+ NULL
+ );
+ elem->subtype = join;
+ AVB_LOGF_DEBUG("mrp_register_cb subtype changed to %d", elem->subtype);
+ break;
+ }
+ else if (elem) {
+ AVB_LOGF_DEBUG("mrp_register_cb skipping elem " SID_FORMAT ", talker %d",
+ SID_OCTETS(elem->streamId), elem->talker ? 1 : 0);
+ }
+ node = openavbListIterNext(strElemList);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+}
+
+openavbRC openavbSrpInitialize(strmAttachCb_t attachCb, strmRegCb_t registerCb,
+ char* ifname, U32 TxRateKbps, bool bypassAsCapableCheck)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
+ int err;
+
+ strElemList = openavbListNewList();
+
+ _attachCb = attachCb;
+ _registerCb = registerCb;
+
+
+ err = mrp_connect();
+ if (err) {
+ AVB_LOGF_ERROR("mrp_connect failed: %s", strerror(errno));
+ goto error;
+ }
+ err = mrp_monitor();
+ if (err) {
+ AVB_LOGF_ERROR("failed creating MRP monitor thread: %s", strerror(errno));
+ goto error;
+ }
+
+ int class_a_id, a_priority;
+ u_int16_t a_vid;
+ int class_b_id, b_priority;
+ u_int16_t b_vid;
+
+ err = mrp_get_domain(&class_a_id,&a_priority, &a_vid, &class_b_id, &b_priority, &b_vid);
+ if (err) {
+ AVB_LOG_DEBUG("mrp_get_domain failed");
+ goto error;
+ }
+
+ AVB_LOGF_INFO("detected domain Class A PRIO=%d VID=%04x...", a_priority, (int)a_vid);
+ AVB_LOGF_INFO("detected domain Class B PRIO=%d VID=%04x...", b_priority, (int)b_vid);
+
+ err = mrp_register_domain(&domain_class_a_id, &domain_class_a_priority, &domain_class_a_vid);
+ if (err) {
+ AVB_LOG_DEBUG("mrp_register_domain failed");
+ goto error;
+ }
+
+ err = mrp_register_domain(&domain_class_b_id, &domain_class_b_priority, &domain_class_b_vid);
+ if (err) {
+ AVB_LOG_DEBUG("mrp_register_domain failed");
+ goto error;
+ }
+
+ err = mrp_join_vlan();
+ if (err) {
+ AVB_LOG_DEBUG("mrp_join_vlan failed");
+ goto error;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+ return OPENAVB_SRP_SUCCESS;
+
+error:
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+ return OPENAVB_SRP_FAILURE;
+}
+
+void openavbSrpShutdown(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
+ int err = mrp_disconnect();
+ if (err) {
+ AVB_LOGF_ERROR("mrp_disconnect failed: %s", strerror(errno));
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+}
+
+openavbRC openavbSrpRegisterStream(void* avtpHandle,
+ AVBStreamID_t* _streamId,
+ U8 DA[],
+ AVBTSpec_t* tSpec,
+ SRClassIdx_t SRClassIdx,
+ bool Rank,
+ U32 Latency)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
+ int err;
+
+ // convert streamId to 8 byte format
+ uint8_t streamId[8];
+ memcpy(streamId, _streamId->addr, sizeof(_streamId->addr));
+ streamId[6] = _streamId->uniqueID >> 8;
+ streamId[7] = _streamId->uniqueID & 0xFF;
+
+ openavb_list_node_t node = openavbListNew(strElemList, sizeof(strElem_t));
+ strElem_t* elem = openavbListData(node);
+
+ elem->avtpHandle = avtpHandle;
+ elem->talker = true;
+ memcpy(elem->streamId, streamId, sizeof(elem->streamId));
+ memcpy(elem->destAddr, DA, sizeof(elem->destAddr));
+ elem->maxFrameSize = tSpec->maxFrameSize;
+ elem->maxIntervalFrames = tSpec->maxIntervalFrames;
+ elem->latency = Latency;
+ elem->subtype = openavbSrp_LDSt_None;
+
+ switch (SRClassIdx) {
+ case SR_CLASS_A:
+ elem->vlanId = domain_class_a_vid;
+ elem->priority = domain_class_a_priority;
+
+ err = mrp_advertise_stream(streamId,
+ DA,
+ domain_class_a_vid,
+ tSpec->maxFrameSize,
+ tSpec->maxIntervalFrames,
+ domain_class_a_priority,
+ Latency);
+ break;
+ case SR_CLASS_B:
+ elem->vlanId = domain_class_b_vid;
+ elem->priority = domain_class_b_priority;
+
+ err = mrp_advertise_stream(streamId,
+ DA,
+ domain_class_b_vid,
+ tSpec->maxFrameSize,
+ tSpec->maxIntervalFrames,
+ domain_class_b_priority,
+ Latency);
+ break;
+ default:
+ AVB_LOGF_ERROR("unknown SRClassIdx %d", (int)SRClassIdx);
+ goto error;
+ }
+
+ if (err) {
+ AVB_LOG_ERROR("mrp_advertise_stream failed");
+ goto error;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+ return OPENAVB_SRP_SUCCESS;
+
+error:
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+ return OPENAVB_SRP_FAILURE;
+}
+
+openavbRC openavbSrpDeregisterStream(AVBStreamID_t* _streamId)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
+
+ // convert streamId to 8 byte format
+ uint8_t streamId[8];
+ memcpy(streamId, _streamId->addr, sizeof(_streamId->addr));
+ streamId[6] = _streamId->uniqueID >> 8;
+ streamId[7] = _streamId->uniqueID & 0xFF;
+
+ openavb_list_node_t node = openavbListIterFirst(strElemList);
+ while (node) {
+ strElem_t *elem = openavbListData(node);
+ if (elem && memcmp(streamId, elem->streamId, sizeof(elem->streamId)) == 0) {
+ int err = mrp_unadvertise_stream(elem->streamId, elem->destAddr, elem->vlanId, elem->maxFrameSize, elem->maxIntervalFrames, elem->priority, elem->latency);
+ if (err) {
+ AVB_LOG_ERROR("mrp_unadvertise_stream failed");
+ }
+ openavbListDelete(strElemList, node);
+ break;
+ }
+ node = openavbListIterNext(strElemList);
+ }
+ if (!node)
+ AVB_LOGF_ERROR("%s: unknown stream "SID_FORMAT, __func__, SID_OCTETS(streamId));
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+ return OPENAVB_SRP_SUCCESS;
+}
+
+openavbRC openavbSrpAttachStream(void* avtpHandle,
+ AVBStreamID_t* _streamId,
+ openavbSrpLsnrDeclSubtype_t type)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
+
+ // convert streamId to 8 byte format
+ uint8_t streamId[8];
+ memcpy(streamId, _streamId->addr, sizeof(_streamId->addr));
+ streamId[6] = _streamId->uniqueID >> 8;
+ streamId[7] = _streamId->uniqueID & 0xFF;
+
+ AVB_LOGF_DEBUG("openavbSrpAttachStream "SID_FORMAT, SID_OCTETS(streamId));
+
+ openavb_list_node_t node = openavbListIterFirst(strElemList);
+ // lets check if this streamId is on our list
+ while (node) {
+ strElem_t *elem = openavbListData(node);
+ if (elem && memcmp(streamId, elem->streamId, sizeof(elem->streamId)) == 0) {
+ break;
+ }
+ node = openavbListIterNext(strElemList);
+ }
+ if (!node) {
+ // not found so add it
+ node = openavbListNew(strElemList, sizeof(strElem_t));
+ strElem_t* elem = openavbListData(node);
+
+ elem->avtpHandle = avtpHandle;
+ elem->talker = false;
+ memcpy(elem->streamId, streamId, sizeof(elem->streamId));
+ elem->subtype = type;
+ }
+
+ int err = mrp_send_ready(streamId);
+ if (err) {
+ AVB_LOG_ERROR("mrp_send_ready failed");
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+ return OPENAVB_SRP_SUCCESS;
+}
+
+openavbRC openavbSrpDetachStream(AVBStreamID_t* _streamId)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
+
+ // convert streamId to 8 byte format
+ uint8_t streamId[8];
+ memcpy(streamId, _streamId->addr, sizeof(_streamId->addr));
+ streamId[6] = _streamId->uniqueID >> 8;
+ streamId[7] = _streamId->uniqueID & 0xFF;
+
+ AVB_LOGF_DEBUG("openavbSrpDetachStream "SID_FORMAT, SID_OCTETS(streamId));
+
+ openavb_list_node_t node = openavbListIterFirst(strElemList);
+ while (node) {
+ strElem_t *elem = openavbListData(node);
+ if (elem && memcmp(streamId, elem->streamId, sizeof(elem->streamId)) == 0) {
+ int err = mrp_send_leave(streamId);
+ if (err) {
+ AVB_LOG_ERROR("mrp_send_leave failed");
+ }
+ openavbListDelete(strElemList, node);
+ break;
+ }
+ node = openavbListIterNext(strElemList);
+ }
+ if (!node)
+ AVB_LOGF_ERROR("%s: unknown stream "SID_FORMAT, __func__, SID_OCTETS(streamId));
+
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+ return OPENAVB_SRP_SUCCESS;
+}
+
+openavbRC openavbSrpGetClassParams(SRClassIdx_t SRClassIdx, U8* priority, U16* vid, U32* inverseIntervalSec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
+ switch (SRClassIdx) {
+ case SR_CLASS_A:
+ *priority = domain_class_a_priority;
+ *vid = domain_class_a_vid;
+ *inverseIntervalSec = 8000;
+ break;
+ case SR_CLASS_B:
+ *priority = domain_class_b_priority;
+ *vid = domain_class_b_vid;
+ *inverseIntervalSec = 4000;
+ break;
+ default:
+ AVB_LOGF_ERROR("unknown SRClassIdx %d", (int)SRClassIdx);
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+ return OPENAVB_SRP_FAILURE;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+ return OPENAVB_SRP_SUCCESS;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_server_osal.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_server_osal.c
index c921d358..3454270f 100644
--- a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_server_osal.c
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_server_osal.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -117,6 +118,11 @@ bool openavbEndpointServerOpen(void)
serverAddr.sun_family = AF_UNIX;
snprintf(serverAddr.sun_path, UNIX_PATH_MAX, AVB_ENDPOINT_UNIX_PATH);
+ // try remove old socket
+ if (unlink(serverAddr.sun_path) < 0 && errno != ENOENT) {
+ AVB_LOGF_ERROR("Failed to remove %s: %s", serverAddr.sun_path, strerror(errno));
+ }
+
int rslt = bind(lsock, (struct sockaddr*)&serverAddr, sizeof(struct sockaddr_un));
if (rslt != 0) {
AVB_LOGF_ERROR("Failed to create %s: %s", serverAddr.sun_path, strerror(errno));
@@ -140,7 +146,7 @@ bool openavbEndpointServerOpen(void)
error:
if (lsock >= 0) {
close(lsock);
- lsock = -1;
+ lsock = SOCK_INVALID;
}
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return FALSE;
@@ -239,10 +245,12 @@ void openavbEndpointServerClose(void)
for (i = 0; i < POLL_FD_COUNT; i++) {
if (fds[i].fd != SOCK_INVALID) {
close(fds[i].fd);
+ fds[i].fd = SOCK_INVALID;
}
}
if (lsock != SOCK_INVALID) {
close(lsock);
+ lsock = SOCK_INVALID;
}
if (unlink(serverAddr.sun_path) != 0) {
diff --git a/lib/avtp_pipeline/platform/Linux/generic.cmake b/lib/avtp_pipeline/platform/Linux/generic.cmake
index 701c40f0..abe9fef8 100644
--- a/lib/avtp_pipeline/platform/Linux/generic.cmake
+++ b/lib/avtp_pipeline/platform/Linux/generic.cmake
@@ -15,6 +15,7 @@ set ( PLATFORM_INCLUDE_DIRECTORIES
${CMAKE_SOURCE_DIR}/openavb_common
${CMAKE_SOURCE_DIR}/../../daemons/common
${CMAKE_SOURCE_DIR}/../../daemons/mrpd
+ ${CMAKE_SOURCE_DIR}/../../daemons/maap/common
)
include_directories ( platform/generic/include )
diff --git a/lib/avtp_pipeline/platform/Linux/gst_al/gst_al.h b/lib/avtp_pipeline/platform/Linux/gst_al/gst_al.h
index d55284ae..dbdb5b09 100644
--- a/lib/avtp_pipeline/platform/Linux/gst_al/gst_al.h
+++ b/lib/avtp_pipeline/platform/Linux/gst_al/gst_al.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/gst_al/gst_al_01.c b/lib/avtp_pipeline/platform/Linux/gst_al/gst_al_01.c
index 86d7d475..9eedb4e8 100644
--- a/lib/avtp_pipeline/platform/Linux/gst_al/gst_al_01.c
+++ b/lib/avtp_pipeline/platform/Linux/gst_al/gst_al_01.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/gst_al/gst_al_10.c b/lib/avtp_pipeline/platform/Linux/gst_al/gst_al_10.c
index a3fa8a47..0d1898c5 100644
--- a/lib/avtp_pipeline/platform/Linux/gst_al/gst_al_10.c
+++ b/lib/avtp_pipeline/platform/Linux/gst_al/gst_al_10.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_file_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_file_talker.ini
index 0eddb28f..210ae966 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_file_talker.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_file_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
@@ -121,3 +127,7 @@ intf_fn = openavbIntfWavFileInitialize
# intf_nv_file_name: The fully qualified file name.
intf_nv_file_name = test.wav
+
+# AAF is defined to be big-endian.
+intf_nv_audio_endian = big
+
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener.ini
index b04ca608..c7c799de 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener.ini
@@ -9,6 +9,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = 84:7e:40:2b:63:f4
@@ -53,6 +59,10 @@ max_transit_usec = 50000
# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
# ifname = eth0
+current_sampling_rate = 48000
+
+sampling_rates = 44100,48000,96000
+
#####################################################################
# Mapping module configuration
#####################################################################
@@ -105,15 +115,14 @@ intf_fn = openavbIntfAlsaInitialize
intf_nv_device_name = default
# intf_nv_audio_rate: Valid values that are supported by AAF are:
-# 8000, 16000, 32000, 44100, 48000, 88200, 96000, 176400 and 192000
+# 8000, 16000, 24000, 32000, 44100, 48000, 88200, 96000, 176400 and 192000
intf_nv_audio_rate = 48000
# intf_nv_audio_bit_depth: Valid values that are supported by AAF are:
-# 8, 16, 32
+# 16, 24, 32
intf_nv_audio_bit_depth = 32
-# intf_nv_audio_channels: Valid values that are supported by AAF are:
-# 1 - 8
+# intf_nv_audio_channels
intf_nv_audio_channels = 2
# intf_nv_allow_resampling: 0 = disable software resampling. 1 = allow software resampling. Default is disable.
@@ -127,3 +136,7 @@ intf_nv_start_threshold_periods = 3
# This influence ALSA's period_time and period_size parameters and the result value should be the nearest possible.
# Initial playback latency is equal intf_nv_start_threshold_periods * intf_nv_period_time. If not set internal defaults are used.
# intf_nv_period_time = 31250
+
+# AAF is defined to be big-endian.
+intf_nv_audio_endian = big
+
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener_auto.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener_auto.ini
index 481dac65..d3d064b1 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener_auto.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener_auto.ini
@@ -9,6 +9,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = ba:bc:1a:ba:bc:1a
@@ -105,15 +111,14 @@ intf_fn = openavbIntfAlsaInitialize
intf_nv_device_name = default
# intf_nv_audio_rate: Valid values that are supported by AAF are:
-# 8000, 16000, 32000, 44100, 48000, 88200, 96000, 176400 and 192000
+# 8000, 16000, 24000, 32000, 44100, 48000, 88200, 96000, 176400 and 192000
intf_nv_audio_rate = 48000
# intf_nv_audio_bit_depth: Valid values that are supported by AAF are:
-# 8, 16, 32
+# 16, 24, 32
intf_nv_audio_bit_depth = 16
-# intf_nv_audio_channels: Valid values that are supported by AAF are:
-# 1 - 8
+# intf_nv_audio_channels
intf_nv_audio_channels = 2
# intf_nv_allow_resampling: 0 = disable software resampling. 1 = allow software resampling. Default is disable.
@@ -127,3 +132,7 @@ intf_nv_start_threshold_periods = 3
# This influence ALSA's period_time and period_size parameters and the result value should be the nearest possible.
# Initial playback latency is equal intf_nv_start_threshold_periods * intf_nv_period_time. If not set internal defaults are used.
# intf_nv_period_time = 31250
+
+# AAF is defined to be big-endian.
+intf_nv_audio_endian = big
+
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_talker.ini
index f98ba668..a6a85071 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_talker.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
@@ -92,6 +98,10 @@ max_transmit_deficit_usec = 50000
# vlan_id: VLAN Identifier (1-4094). Used in "no endpoint" builds. Defaults to 2.
# vlan_id = 2
+current_sampling_rate = 48000
+
+sampling_rates = 44100,48000,96000
+
#####################################################################
# Mapping module configuration
#####################################################################
@@ -142,17 +152,19 @@ intf_fn = openavbIntfAlsaInitialize
intf_nv_device_name = default
# intf_nv_audio_rate: Valid values that are supported by AAF are:
-# 8000, 16000, 32000, 44100, 48000, 88200, 96000, 176400 and 192000
+# 8000, 16000, 24000, 32000, 44100, 48000, 88200, 96000, 176400 and 192000
intf_nv_audio_rate = 48000
# intf_nv_audio_bit_depth: Valid values that are supported by AAF are:
-# 8, 16, 32
+# 16, 24, 32
intf_nv_audio_bit_depth = 32
-# intf_nv_audio_channels: Valid values that are supported by AAF are:
-# 1 - 8
+# intf_nv_audio_channels
intf_nv_audio_channels = 2
# intf_nv_allow_resampling: 0 = disable software resampling. 1 = allow software resampling. Default is disable.
intf_nv_allow_resampling = 1
+# AAF is defined to be big-endian.
+intf_nv_audio_endian = big
+
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_intf.md b/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_intf.md
index cd97cf1a..123c4366 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_intf.md
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_intf.md
@@ -10,26 +10,17 @@ ALSA interface module. An interface to connect AVTP streams to ALSA either as an
Name | Description
--------------------------|---------------------------
-intf_nv_ignore_timestamp | If set to 1 timestamps will be ignored during \
- processing of frames. This also means stale (old) \
- Media Queue items will not be purged.
-intf_nv_device_name |ALSA device name. Commonly "default" or "plug:dmix"
-intf_nv_audio_rate |Audio rate, numberic values defined by \
- @ref avb_audio_rate_t
-intf_nv_audio_bit_depth |Bit depth of audio, numeric values defined by \
- @ref avb_audio_bit_depth_t
-intf_nv_audio_type |Type of data samples, possible values <ul><li>float \
- </li><li>sign</li><li>unsign</li><li>int</li><li> \
- uint</li></ul>
-intf_nv_audio_endian |Data endianess possible values <ul><li>big</li><li> \
- little</li></ul>
-intf_nv_audio_channels |Number of audio channels, numeric values should be \
- within range of values in @ref avb_audio_channels_t
-intf_nv_allow_resampling |If 1 software resampling allowed, disallowed \
- otherwise (by default allowed)
-intf_nv_start_threshold_periods|Playback start threshold measured in ALSA \
- periods (2 by default)
-intf_nv_period_time |Approximate ALSA period duration in microseconds
+intf_nv_ignore_timestamp | If set to 1 timestamps will be ignored during processing of frames. This also means stale (old) Media Queue items will not be purged.
+intf_nv_device_name | ALSA device name. Commonly "default" or "plug:dmix"
+intf_nv_audio_rate | Audio rate, numberic values defined by @ref avb_audio_rate_t
+intf_nv_audio_bit_depth | Bit depth of audio, numeric values defined by @ref avb_audio_bit_depth_t
+intf_nv_audio_type | Type of data samples, possible values <ul><li>float</li><li>sign</li><li>unsign</li><li>int</li><li>uint</li></ul>
+intf_nv_audio_endian | Data endianess possible values <ul><li>big</li><li>little</li></ul>
+intf_nv_audio_channels | Number of audio channels, numeric values should be within range of values in @ref avb_audio_channels_t
+intf_nv_allow_resampling | If 1 software resampling allowed, disallowed otherwise (by default allowed)
+intf_nv_start_threshold_periods | Playback start threshold measured in ALSA periods (2 by default)
+intf_nv_period_time | Approximate ALSA period duration in microseconds
+intf_nv_clock_skew_ppb | Estimate of media clock skew in Parts Per Billion (nanoseconds per second)
<br>
# Notes
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_listener.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_listener.ini
index 944616d1..545d8943 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_listener.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_listener.ini
@@ -9,6 +9,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 08:00:28:31:E6:6E
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_talker.ini
index e5908906..fc94f7f2 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_talker.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_talker.ini
@@ -9,6 +9,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/openavb_intf_alsa.c b/lib/avtp_pipeline/platform/Linux/intf_alsa/openavb_intf_alsa.c
index 7685db93..37d29140 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_alsa/openavb_intf_alsa.c
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/openavb_intf_alsa.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -42,11 +43,12 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_map_uncmp_audio_pub.h"
#include "openavb_map_aaf_audio_pub.h"
#include "openavb_intf_pub.h"
+#include "openavb_mcs.h"
#define AVB_LOG_COMPONENT "ALSA Interface"
#include "openavb_log_pub.h"
-// The asoundlib.h header needs to appear after openavb_trace_pub.h otherwise an incompatibtily version of time.h gets pulled in.
+// The asoundlib.h header needs to appear after openavb_trace_pub.h otherwise an incompatible version of time.h gets pulled in.
#include <alsa/asoundlib.h>
#define PCM_DEVICE_NAME_DEFAULT "default"
@@ -95,6 +97,15 @@ typedef struct {
// ALSA read/write interval
U32 intervalCounter;
+
+ // Media clock synthesis for precise timestamps
+ mcs_t mcs;
+
+ // Estimate of media clock skew in Parts Per Billion (ns per second)
+ S32 clockSkewPPB;
+
+ // Use Media Clock Synth module instead of timestamps taken during Tx callback
+ bool fixedTimestampEnabled;
} pvt_data_t;
@@ -217,7 +228,7 @@ static snd_pcm_format_t x_AVBAudioFormatToAlsaFormat(avb_audio_type_t type,
// Each configuration name value pair for this mapping will result in this callback being called.
-void openavbIntfAlsaCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+void openavbIntfAlsaCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
if (pMediaQ) {
@@ -279,7 +290,7 @@ void openavbIntfAlsaCfgCB(media_q_t *pMediaQ, const char *name, const char *valu
// TODO: Should check for specific values
if (val >= AVB_AUDIO_BIT_DEPTH_1BIT && val <= AVB_AUDIO_BIT_DEPTH_64BIT) {
pPvtData->audioBitDepth = val;
- }
+ }
else {
AVB_LOG_ERROR("Invalid audio type configured for intf_nv_audio_bits.");
pPvtData->audioBitDepth = AVB_AUDIO_BIT_DEPTH_24BIT;
@@ -380,12 +391,16 @@ void openavbIntfAlsaCfgCB(media_q_t *pMediaQ, const char *name, const char *valu
pPvtData->periodTimeUsec = strtol(value, &pEnd, 10);
}
+ else if (strcmp(name, "intf_nv_clock_skew_ppb") == 0) {
+ pPvtData->clockSkewPPB = strtol(value, &pEnd, 10);
+ }
+
}
AVB_TRACE_EXIT(AVB_TRACE_INTF);
}
-void openavbIntfAlsaGenInitCB(media_q_t *pMediaQ)
+void openavbIntfAlsaGenInitCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
AVB_TRACE_EXIT(AVB_TRACE_INTF);
@@ -393,7 +408,7 @@ void openavbIntfAlsaGenInitCB(media_q_t *pMediaQ)
// A call to this callback indicates that this interface module will be
// a talker. Any talker initialization can be done in this function.
-void openavbIntfAlsaTxInitCB(media_q_t *pMediaQ)
+void openavbIntfAlsaTxInitCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
@@ -427,7 +442,7 @@ void openavbIntfAlsaTxInitCB(media_q_t *pMediaQ)
return;
}
- // Initialize the hardware paramneters
+ // Initialize the hardware parameters
rslt = snd_pcm_hw_params_any(pPvtData->pcmHandle, hwParams);
if (rslt < 0) {
AVB_LOGF_ERROR("snd_pcm_hw_params_any() error: %s", snd_strerror(rslt));
@@ -466,7 +481,7 @@ void openavbIntfAlsaTxInitCB(media_q_t *pMediaQ)
// Set the sample format
int fmt = x_AVBAudioFormatToAlsaFormat(pPvtData->audioType,
pPvtData->audioBitDepth,
- pPvtData->audioEndian,
+ pPvtData->audioEndian,
pMediaQ->pMediaQDataFormat);
rslt = snd_pcm_hw_params_set_format(pPvtData->pcmHandle, hwParams, fmt);
if (rslt < 0) {
@@ -537,14 +552,23 @@ void openavbIntfAlsaTxInitCB(media_q_t *pMediaQ)
snd_output_t* out;
snd_output_stdio_attach(&out, stderr, 0);
snd_pcm_dump(pPvtData->pcmHandle, out);
- }
+ snd_output_close(out);
+ // Start capture
+ snd_pcm_start(pPvtData->pcmHandle);
+ {
+ media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo = pMediaQ->pPubMapInfo;
+
+ AVB_LOGF_INFO("Finished ALSA Setup: packingFactor %d", pPubMapUncmpAudioInfo->packingFactor);
+ }
+ }
AVB_TRACE_EXIT(AVB_TRACE_INTF);
}
-// This callback will be called for each AVB transmit interval.
+// This callback will be called for each AVB transmit interval.
bool openavbIntfAlsaTxCB(media_q_t *pMediaQ)
{
+ bool moreItems = TRUE;
AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
S32 rslt;
@@ -555,72 +579,77 @@ bool openavbIntfAlsaTxCB(media_q_t *pMediaQ)
media_q_item_t *pMediaQItem = NULL;
if (!pPvtData) {
AVB_LOG_ERROR("Private interface module data not allocated.");
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
return FALSE;
}
- //put current wall time into tail item used by AAF mapping module
- if ((pPubMapUncmpAudioInfo->sparseMode != TS_SPARSE_MODE_UNSPEC)) {
- pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
- if ((pMediaQItem) && (pPvtData->intervalCounter % pPubMapUncmpAudioInfo->sparseMode == 0)) {
- openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
- }
- openavbMediaQTailUnlock(pMediaQ);
- pMediaQItem = NULL;
- }
- if (pPvtData->intervalCounter++ % pPubMapUncmpAudioInfo->packingFactor != 0)
+ if (pPvtData->intervalCounter++ % pPubMapUncmpAudioInfo->packingFactor != 0) {
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
return TRUE;
+ }
- pMediaQItem = openavbMediaQHeadLock(pMediaQ);
- if (pMediaQItem) {
- if (pMediaQItem->itemSize < pPubMapUncmpAudioInfo->itemSize) {
- AVB_LOG_ERROR("Media queue item not large enough for samples");
- }
+ while (moreItems) {
+ pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ if (pMediaQItem->itemSize < pPubMapUncmpAudioInfo->itemSize) {
+ AVB_LOG_ERROR("Media queue item not large enough for samples");
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+ }
- rslt = snd_pcm_readi(pPvtData->pcmHandle, pMediaQItem->pPubData + pMediaQItem->dataLen, pPubMapUncmpAudioInfo->framesPerItem - (pMediaQItem->dataLen / pPubMapUncmpAudioInfo->itemFrameSizeBytes));
+ rslt = snd_pcm_readi(pPvtData->pcmHandle, pMediaQItem->pPubData + pMediaQItem->dataLen, pPubMapUncmpAudioInfo->framesPerItem - (pMediaQItem->dataLen / pPubMapUncmpAudioInfo->itemFrameSizeBytes));
- if (rslt == -EPIPE) {
- AVB_LOGF_ERROR("snd_pcm_readi() error: %s", snd_strerror(rslt));
- rslt = snd_pcm_recover(pPvtData->pcmHandle, rslt, 0);
if (rslt < 0) {
- AVB_LOGF_ERROR("snd_pcm_recover: %s", snd_strerror(rslt));
+ switch(rslt) {
+ case -EPIPE:
+ AVB_LOGF_ERROR("snd_pcm_readi() error: %s", snd_strerror(rslt));
+ rslt = snd_pcm_recover(pPvtData->pcmHandle, rslt, 0);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_recover: %s", snd_strerror(rslt));
+ }
+ break;
+ case -EAGAIN:
+ { IF_LOG_INTERVAL(1000) AVB_LOG_DEBUG("snd_pcm_readi() had no data available"); }
+ break;
+ default:
+ AVB_LOGF_ERROR("Unhandled snd_pcm_readi() error: %s", snd_strerror(rslt));
+ break;
+ }
+
+ if (rslt < 0) {
+ openavbMediaQHeadUnlock(pMediaQ);
+ break;
+ }
}
- openavbMediaQHeadUnlock(pMediaQ);
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
- return FALSE;
- }
- if (rslt < 0) {
- openavbMediaQHeadUnlock(pMediaQ);
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
- return FALSE;
- }
- pMediaQItem->dataLen += rslt * pPubMapUncmpAudioInfo->itemFrameSizeBytes;
- if (pMediaQItem->dataLen != pPubMapUncmpAudioInfo->itemSize) {
- openavbMediaQHeadUnlock(pMediaQ);
- AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
- return TRUE;
+ pMediaQItem->dataLen += rslt * pPubMapUncmpAudioInfo->itemFrameSizeBytes;
+ if (pMediaQItem->dataLen != pPubMapUncmpAudioInfo->itemSize) {
+ openavbMediaQHeadUnlock(pMediaQ);
+ }
+ else {
+ // Always get the timestamp. Protocols such as AAF can choose to ignore them if not needed.
+ if (!pPvtData->fixedTimestampEnabled) {
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ } else {
+ openavbMcsAdvance(&pPvtData->mcs);
+ openavbAvtpTimeSetToTimestampNS(pMediaQItem->pAvtpTime, pPvtData->mcs.edgeTime);
+ }
+ openavbMediaQHeadPush(pMediaQ);
+ }
}
else {
- openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
- openavbMediaQHeadPush(pMediaQ);
-
- AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
- return TRUE;
+ moreItems = FALSE;
}
}
- else {
- AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
- return FALSE; // Media queue full
- }
}
AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
- return FALSE;
+ return !moreItems;
}
// A call to this callback indicates that this interface module will be
// a listener. Any listener initialization can be done in this function.
-void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
+void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
@@ -656,7 +685,7 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
return;
}
- // Initialize the hardware paramneters
+ // Initialize the hardware parameters
rslt = snd_pcm_hw_params_any(pPvtData->pcmHandle, hwParams);
if (rslt < 0) {
AVB_LOGF_ERROR("snd_pcm_hw_params_any() error: %s", snd_strerror(rslt));
@@ -695,7 +724,7 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
// Set the sample format
int fmt = x_AVBAudioFormatToAlsaFormat(pPvtData->audioType,
pPvtData->audioBitDepth,
- pPvtData->audioEndian,
+ pPvtData->audioEndian,
pMediaQ->pMediaQDataFormat);
rslt = snd_pcm_hw_params_set_format(pPvtData->pcmHandle, hwParams, fmt);
if (rslt < 0) {
@@ -764,7 +793,7 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
buffer_time = (max / usec_round) * usec_round;
}
- // Check for maximum perioid time and adjust ours down if necessary
+ // Check for maximum period time and adjust ours down if necessary
rslt = snd_pcm_hw_params_get_period_time_max(hwParams, &max, &dir);
if (rslt < 0) {
AVB_LOGF_ERROR("snd_pcm_hw_params_get_period_time_max() error: %s", snd_strerror(rslt));
@@ -849,6 +878,8 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
AVB_LOGF_ERROR("snd_pcm_sw_params_malloc error(): %s", snd_strerror(rslt));
snd_pcm_close(pPvtData->pcmHandle);
pPvtData->pcmHandle = NULL;
+ snd_pcm_sw_params_free(swParams);
+ swParams = NULL;
AVB_TRACE_EXIT(AVB_TRACE_INTF);
return;
}
@@ -858,6 +889,8 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
AVB_LOGF_ERROR("snd_pcm_sw_params_current error(): %s", snd_strerror(rslt));
snd_pcm_close(pPvtData->pcmHandle);
pPvtData->pcmHandle = NULL;
+ snd_pcm_sw_params_free(swParams);
+ swParams = NULL;
AVB_TRACE_EXIT(AVB_TRACE_INTF);
return;
}
@@ -867,6 +900,8 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
AVB_LOGF_ERROR("snd_pcm_sw_params_set_start_threshold error(): %s", snd_strerror(rslt));
snd_pcm_close(pPvtData->pcmHandle);
pPvtData->pcmHandle = NULL;
+ snd_pcm_sw_params_free(swParams);
+ swParams = NULL;
AVB_TRACE_EXIT(AVB_TRACE_INTF);
return;
}
@@ -876,6 +911,8 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
AVB_LOGF_ERROR("snd_pcm_sw_params_set_avail_min error(): %s", snd_strerror(rslt));
snd_pcm_close(pPvtData->pcmHandle);
pPvtData->pcmHandle = NULL;
+ snd_pcm_sw_params_free(swParams);
+ swParams = NULL;
AVB_TRACE_EXIT(AVB_TRACE_INTF);
return;
}
@@ -885,6 +922,8 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
AVB_LOGF_ERROR("snd_pcm_sw_params_set_period_event error(): %s", snd_strerror(rslt));
snd_pcm_close(pPvtData->pcmHandle);
pPvtData->pcmHandle = NULL;
+ snd_pcm_sw_params_free(swParams);
+ swParams = NULL;
AVB_TRACE_EXIT(AVB_TRACE_INTF);
return;
}
@@ -894,6 +933,8 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
AVB_LOGF_ERROR("snd_pcm_sw_params error(): %s", snd_strerror(rslt));
snd_pcm_close(pPvtData->pcmHandle);
pPvtData->pcmHandle = NULL;
+ snd_pcm_sw_params_free(swParams);
+ swParams = NULL;
AVB_TRACE_EXIT(AVB_TRACE_INTF);
return;
}
@@ -917,13 +958,14 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
snd_output_t* out;
snd_output_stdio_attach(&out, stderr, 0);
snd_pcm_dump(pPvtData->pcmHandle, out);
+ snd_output_close(out);
}
AVB_TRACE_EXIT(AVB_TRACE_INTF);
}
// This callback is called when acting as a listener.
-bool openavbIntfAlsaRxCB(media_q_t *pMediaQ)
+bool openavbIntfAlsaRxCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
@@ -932,6 +974,7 @@ bool openavbIntfAlsaRxCB(media_q_t *pMediaQ)
pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
if (!pPvtData) {
AVB_LOG_ERROR("Private interface module data not allocated.");
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
return FALSE;
}
@@ -975,9 +1018,9 @@ bool openavbIntfAlsaRxCB(media_q_t *pMediaQ)
return TRUE;
}
-// This callback will be called when the interface needs to be closed. All shutdown should
+// This callback will be called when the interface needs to be closed. All shutdown should
// occur in this function.
-void openavbIntfAlsaEndCB(media_q_t *pMediaQ)
+void openavbIntfAlsaEndCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
@@ -991,18 +1034,56 @@ void openavbIntfAlsaEndCB(media_q_t *pMediaQ)
if (pPvtData->pcmHandle) {
snd_pcm_close(pPvtData->pcmHandle);
pPvtData->pcmHandle = NULL;
+
+#if 0
+ // Optional call when using Valgrind to stop reports of memory leaks.
+ snd_config_update_free_global();
+#endif
}
}
AVB_TRACE_EXIT(AVB_TRACE_INTF);
}
-void openavbIntfAlsaGenEndCB(media_q_t *pMediaQ)
+void openavbIntfAlsaGenEndCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
AVB_TRACE_EXIT(AVB_TRACE_INTF);
}
+void openavbIntfAlsaEnableFixedTimestamp(media_q_t *pMediaQ, bool enabled, U32 transmitInterval, U32 batchFactor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ if (pMediaQ && pMediaQ->pPvtIntfInfo && pMediaQ->pPubMapInfo) {
+ media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo = pMediaQ->pPubMapInfo;
+ pvt_data_t *pPvtData = (pvt_data_t *)pMediaQ->pPvtIntfInfo;
+
+ pPvtData->fixedTimestampEnabled = enabled;
+ if (pPvtData->fixedTimestampEnabled) {
+ U32 per, rate, rem;
+ S32 skewEst = pPvtData->clockSkewPPB;
+ /* Ignore passed in transmit interval and use framesPerItem and audioRate so
+ we work with both AAF and 61883-6 */
+ /* Carefully scale values to avoid U32 overflow or loss of precision */
+ per = MICROSECONDS_PER_SECOND * pPubMapUncmpAudioInfo->framesPerItem * 10;
+ per += (skewEst/10);
+ rate = pPvtData->audioRate/100;
+ transmitInterval = per/rate;
+ rem = per % rate;
+ if (rem != 0) {
+ rem *= 10;
+ rem /= rate;
+ }
+ openavbMcsInit(&pPvtData->mcs, transmitInterval, rem, 10);
+ AVB_LOGF_INFO("Fixed timestamping enabled: %d %d/%d", transmitInterval, rem, 10);
+ }
+
+ }
+
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
// Main initialization entry point into the interface module
extern DLL_EXPORT bool openavbIntfAlsaInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
{
@@ -1026,6 +1107,7 @@ extern DLL_EXPORT bool openavbIntfAlsaInitialize(media_q_t *pMediaQ, openavb_int
pIntfCB->intf_rx_cb = openavbIntfAlsaRxCB;
pIntfCB->intf_end_cb = openavbIntfAlsaEndCB;
pIntfCB->intf_gen_end_cb = openavbIntfAlsaGenEndCB;
+ pIntfCB->intf_enable_fixed_timestamp = openavbIntfAlsaEnableFixedTimestamp;
pPvtData->ignoreTimestamp = FALSE;
pPvtData->pDeviceName = strdup(PCM_DEVICE_NAME_DEFAULT);
@@ -1034,6 +1116,8 @@ extern DLL_EXPORT bool openavbIntfAlsaInitialize(media_q_t *pMediaQ, openavb_int
pPvtData->startThresholdPeriods = 2; // Default to 2 periods of frames as the start threshold
pPvtData->periodTimeUsec = 100000;
+ pPvtData->fixedTimestampEnabled = FALSE;
+ pPvtData->clockSkewPPB = 0;
}
AVB_TRACE_EXIT(AVB_TRACE_INTF);
diff --git a/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_listener.ini b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_listener.ini
index 9817900c..6de30dc5 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_listener.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_listener.ini
@@ -5,6 +5,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = ba:bc:1a:ba:bc:1a
diff --git a/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_talker.ini
index 87569675..e69bf5bf 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_talker.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = ba:bc:1a:ba:bc:1a
diff --git a/lib/avtp_pipeline/platform/Linux/intf_h264_gst/openavb_intf_h264_gst.c b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/openavb_intf_h264_gst.c
index 35af240f..1be182d1 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_h264_gst/openavb_intf_h264_gst.c
+++ b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/openavb_intf_h264_gst.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -70,6 +71,8 @@ typedef struct pvt_data_t
bool blockingRx;
gint nWaiting;
+ bool firstSample;
+ U16 stream_uid;
} pvt_data_t;
// Each configuration name value pair for this mapping will result in this callback being called.
@@ -144,6 +147,11 @@ static GstFlowReturn sinkNewBufferSample(GstAppSink *sink, gpointer pv)
media_q_t *pMediaQ = (media_q_t *)pv;
pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (pPvtData->firstSample) {
+ AVB_LOGF_WARNING("UID: %d: First sample to send", pPvtData->stream_uid);
+ pPvtData->firstSample = false;
+ }
+
g_atomic_int_add(&pPvtData->nWaiting, 1);
return GST_FLOW_OK;
@@ -252,6 +260,8 @@ void openavbIntfH264RtpGstTxInitCB(media_q_t *pMediaQ)
return;
}
+ pPvtData->firstSample = true;
+
createTxPipeline(pMediaQ);
AVB_TRACE_EXIT(AVB_TRACE_INTF);
@@ -430,6 +440,8 @@ void openavbIntfH264RtpGstRxInitCB(media_q_t *pMediaQ)
return;
}
+ pPvtData->firstSample = true;
+
GError *error = NULL;
pPvtData->pipe = gst_parse_launch(pPvtData->pPipelineStr, &error);
if (error)
@@ -504,6 +516,12 @@ bool openavbIntfH264RtpGstRxCB(media_q_t *pMediaQ)
openavbMediaQTailPull(pMediaQ);
continue;
}
+
+ if (pPvtData->firstSample) {
+ AVB_LOGF_WARNING("UID: %d: First packet RX", pPvtData->stream_uid);
+ pPvtData->firstSample = false;
+ }
+
if (pPvtData->asyncRx)
{
U32 bufwr = pPvtData->bufwr;
@@ -587,6 +605,19 @@ void openavbIntfH264RtpGstGenEndCB(media_q_t *pMediaQ)
AVB_TRACE_EXIT(AVB_TRACE_INTF);
}
+void openavbIntfH264RtpGstSetStreamUidCB(media_q_t *pMediaQ, U16 stream_uid)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+ pPvtData->stream_uid = stream_uid;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
// Main initialization entry point into the interface module
extern DLL_EXPORT bool openavbIntfH264RtpGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
{
@@ -611,6 +642,7 @@ extern DLL_EXPORT bool openavbIntfH264RtpGstInitialize(media_q_t *pMediaQ, opena
pIntfCB->intf_rx_cb = openavbIntfH264RtpGstRxCB;
pIntfCB->intf_end_cb = openavbIntfH264RtpGstEndCB;
pIntfCB->intf_gen_end_cb = openavbIntfH264RtpGstGenEndCB;
+ pIntfCB->intf_set_stream_uid_cb = openavbIntfH264RtpGstSetStreamUidCB;
pPvtData->ignoreTimestamp = FALSE;
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_listener.ini b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_listener.ini
index 80b742ca..07ebc7fb 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_listener.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_listener.ini
@@ -5,6 +5,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = 00:50:56:c0:00:08
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_talker.ini
index 7e906a76..2fb8810d 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_talker.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/openavb_intf_mjpeg_gst.c b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/openavb_intf_mjpeg_gst.c
index db2aafa6..9c190579 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/openavb_intf_mjpeg_gst.c
+++ b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/openavb_intf_mjpeg_gst.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_listener.ini b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_listener.ini
index eb76cb7d..691b8bb1 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_listener.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_listener.ini
@@ -5,6 +5,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = 00:0c:29:f8:3e:c6
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_talker.ini
index b5bf26d0..8756dbea 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_talker.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/openavb_intf_mpeg2ts_file.c b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/openavb_intf_mpeg2ts_file.c
index 311ec767..5ab9f5b9 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/openavb_intf_mpeg2ts_file.c
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/openavb_intf_mpeg2ts_file.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_listener.ini b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_listener.ini
index bf7ef6b7..9c40b574 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_listener.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_listener.ini
@@ -5,6 +5,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = 84:7E:40:2B:73:D6
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_talker.ini
index 0cc3299b..63a7d5da 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_talker.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/openavb_intf_mpeg2ts_gst.c b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/openavb_intf_mpeg2ts_gst.c
index 0c12af20..6c06b574 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/openavb_intf_mpeg2ts_gst.c
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/openavb_intf_mpeg2ts_gst.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/intf_wav_file/openavb_intf_wav_file.c b/lib/avtp_pipeline/platform/Linux/intf_wav_file/openavb_intf_wav_file.c
index c038c95c..e598bb94 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_wav_file/openavb_intf_wav_file.c
+++ b/lib/avtp_pipeline/platform/Linux/intf_wav_file/openavb_intf_wav_file.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,19 +22,19 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
/*
* MODULE SUMMARY : wav File interface module. Talker only.
-*
+*
* This interface module is narrowly focused to read a common wav file format
* and send the data samples to mapping modules.
-*
+*
*/
#include <stdlib.h>
@@ -48,7 +49,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_intf_pub.h"
#define AVB_LOG_COMPONENT "Wav File Interface"
-#include "openavb_log_pub.h"
+#include "openavb_log_pub.h"
typedef struct {
// RIFF Chunk descriptor
@@ -103,6 +104,12 @@ typedef struct {
// intf_nv_number_of_data_bytes
U32 numberOfDataBytes;
+ //total number of data bytes stored in file so far
+ U32 numOfStoredDataBytes;
+
+ //set when writing to file is finished
+ bool fileReady;
+
} pvt_data_t;
// fread that (mostly) ignores return value - to silence compiler warnings
@@ -251,7 +258,7 @@ static void passParamToMapModule(media_q_t *pMediaQ)
}
}
-// CORE_TODO : this version of convertEndianess is in the commit process but didn't appear to work as expected.
+// CORE_TODO : this version of convertEndianess is in the commit process but didn't appear to work as expected.
// As part of a separate merge the function below this one was pulled in which does work as expected.
#if 0
// little <-> big endian conversion: copy bytes of each
@@ -299,7 +306,7 @@ static void convertEndianness(uint8_t *pData, U32 dataLen, U32 sampleSize)
}
// Each configuration name value pair for this mapping will result in this callback being called.
-void openavbIntfWavFileCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+void openavbIntfWavFileCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
@@ -375,7 +382,7 @@ void openavbIntfWavFileCfgCB(media_q_t *pMediaQ, const char *name, const char *v
AVB_TRACE_EXIT(AVB_TRACE_INTF);
}
-void openavbIntfWavFileGenInitCB(media_q_t *pMediaQ)
+void openavbIntfWavFileGenInitCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
@@ -400,7 +407,7 @@ void openavbIntfWavFileGenInitCB(media_q_t *pMediaQ)
// A call to this callback indicates that this interface module will be
// a talker. Any talker initialization can be done in this function.
-void openavbIntfWavFileTxInitCB(media_q_t *pMediaQ)
+void openavbIntfWavFileTxInitCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
@@ -443,16 +450,6 @@ bool openavbIntfWavFileTxCB(media_q_t *pMediaQ)
return FALSE;
}
- //put current wall time into tail item used by AAF maping module
- if ((pPubMapUncmpAudioInfo->sparseMode != TS_SPARSE_MODE_UNSPEC)) {
- pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
- if ((pMediaQItem) && (pPvtData->intervalCounter % pPubMapUncmpAudioInfo->sparseMode == 0)) {
- openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
- }
- openavbMediaQTailUnlock(pMediaQ);
- pMediaQItem = NULL;
- }
-
if (pPvtData->intervalCounter++ % pPubMapUncmpAudioInfo->packingFactor != 0)
return TRUE;
@@ -502,7 +499,7 @@ bool openavbIntfWavFileTxCB(media_q_t *pMediaQ)
// A call to this callback indicates that this interface module will be
// a listener. Any listener initialization can be done in this function.
-void openavbIntfWavFileRxInitCB(media_q_t *pMediaQ)
+void openavbIntfWavFileRxInitCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
@@ -565,7 +562,7 @@ void openavbIntfWavFileRxInitCB(media_q_t *pMediaQ)
}
// This callback is called when acting as a listener.
-bool openavbIntfWavFileRxCB(media_q_t *pMediaQ)
+bool openavbIntfWavFileRxCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
@@ -580,17 +577,15 @@ bool openavbIntfWavFileRxCB(media_q_t *pMediaQ)
bool moreData = TRUE;
size_t written;
- static U32 numOfStoredDataBytes = 0; //total number of data bytes stored in file so far
- static bool fileReady = FALSE; //set when writing to file is finished
bool expectedNumberOfDataReceived = FALSE; //set when expected number of data bytes has been received
while (moreData) {
media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
- if ((pMediaQItem) && (fileReady == FALSE)) {
+ if ((pMediaQItem) && (pPvtData->fileReady == FALSE)) {
if (pPvtData->pFile && pMediaQItem->dataLen > 0) {
if (expectedNumberOfDataReceived == FALSE) {
- if ((numOfStoredDataBytes + pMediaQItem->dataLen ) > pPvtData->numberOfDataBytes) {
- pMediaQItem->dataLen = pPvtData->numberOfDataBytes - numOfStoredDataBytes;
+ if ((pPvtData->numOfStoredDataBytes + pMediaQItem->dataLen ) > pPvtData->numberOfDataBytes) {
+ pMediaQItem->dataLen = pPvtData->numberOfDataBytes - pPvtData->numOfStoredDataBytes;
expectedNumberOfDataReceived = TRUE;
}
}
@@ -606,9 +601,9 @@ bool openavbIntfWavFileRxCB(media_q_t *pMediaQ)
}
else {
pMediaQItem->dataLen = 0;
- numOfStoredDataBytes += written;
+ pPvtData->numOfStoredDataBytes += written;
if (expectedNumberOfDataReceived == TRUE) {
- fileReady = TRUE;
+ pPvtData->fileReady = TRUE;
AVB_LOG_INFO("Wav file ready.");
}
}
@@ -624,9 +619,9 @@ bool openavbIntfWavFileRxCB(media_q_t *pMediaQ)
return TRUE;
}
-// This callback will be called when the interface needs to be closed. All shutdown should
+// This callback will be called when the interface needs to be closed. All shutdown should
// occur in this function.
-void openavbIntfWavFileEndCB(media_q_t *pMediaQ)
+void openavbIntfWavFileEndCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
@@ -646,7 +641,7 @@ void openavbIntfWavFileEndCB(media_q_t *pMediaQ)
AVB_TRACE_EXIT(AVB_TRACE_INTF);
}
-void openavbIntfWavFileGenEndCB(media_q_t *pMediaQ)
+void openavbIntfWavFileGenEndCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
@@ -691,6 +686,8 @@ extern DLL_EXPORT bool openavbIntfWavFileInitialize(media_q_t *pMediaQ, openavb_
pPvtData->audioEndian = AVB_AUDIO_ENDIAN_LITTLE; //wave file default
pPvtData->intervalCounter = 0;
+ pPvtData->numOfStoredDataBytes = 0;
+ pPvtData->fileReady = FALSE;
}
AVB_TRACE_EXIT(AVB_TRACE_INTF);
diff --git a/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_listener.ini b/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_listener.ini
index f1b6d595..afd32636 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_listener.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_listener.ini
@@ -5,6 +5,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = 84:7E:40:2C:1b:3a
diff --git a/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_talker.ini
index 9abe8167..4e10cdd8 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_talker.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal.c b/lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal.c
new file mode 100644
index 00000000..7acbf76d
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal.c
@@ -0,0 +1,152 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include <inttypes.h>
+#include <linux/ptp_clock.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include "avb_gptp.h"
+
+#include "openavb_platform.h"
+#include "openavb_grandmaster_osal.h"
+#include "openavb_trace.h"
+
+#define AVB_LOG_COMPONENT "osalGrandmaster"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+static pthread_mutex_t gOSALGrandmasterInitMutex = PTHREAD_MUTEX_INITIALIZER;
+#define LOCK() pthread_mutex_lock(&gOSALGrandmasterInitMutex)
+#define UNLOCK() pthread_mutex_unlock(&gOSALGrandmasterInitMutex)
+
+static bool bInitialized = FALSE;
+static int gShmFd = -1;
+static char *gMmap = NULL;
+gPtpTimeData gPtpTD;
+
+static bool x_grandmasterInit(void) {
+ AVB_TRACE_ENTRY(AVB_TRACE_GRANDMASTER);
+
+ if (gptpinit(&gShmFd, &gMmap) < 0) {
+ AVB_LOG_ERROR("Grandmaster init failed");
+ AVB_TRACE_EXIT(AVB_TRACE_GRANDMASTER);
+ return FALSE;
+ }
+
+ if (gptpgetdata(gMmap, &gPtpTD) < 0) {
+ AVB_LOG_ERROR("Grandmaster data fetch failed");
+ AVB_TRACE_EXIT(AVB_TRACE_GRANDMASTER);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_GRANDMASTER);
+ return TRUE;
+}
+
+bool osalAVBGrandmasterInit(void) {
+ AVB_TRACE_ENTRY(AVB_TRACE_GRANDMASTER);
+
+ LOCK();
+ if (!bInitialized) {
+ if (x_grandmasterInit())
+ bInitialized = TRUE;
+ }
+ UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_GRANDMASTER);
+ return bInitialized;
+}
+
+bool osalAVBGrandmasterClose(void) {
+ AVB_TRACE_ENTRY(AVB_TRACE_GRANDMASTER);
+
+ gptpdeinit(&gShmFd, &gMmap);
+
+ AVB_TRACE_EXIT(AVB_TRACE_GRANDMASTER);
+ return TRUE;
+}
+
+bool osalAVBGrandmasterGetCurrent(
+ uint8_t gptp_grandmaster_id[],
+ uint8_t * gptp_domain_number )
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_GRANDMASTER);
+
+ if (gptpgetdata(gMmap, &gPtpTD) < 0) {
+ AVB_LOG_ERROR("Grandmaster data fetch failed");
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+ }
+
+ if (gptp_grandmaster_id != NULL) { memcpy(gptp_grandmaster_id, gPtpTD.gptp_grandmaster_id, 8); }
+ if (gptp_domain_number != NULL) { *gptp_domain_number = gPtpTD.gptp_domain_number; }
+
+ AVB_TRACE_EXIT(AVB_TRACE_GRANDMASTER);
+ return TRUE;
+}
+
+bool osalClockGrandmasterGetInterface(
+ uint8_t clock_identity[],
+ uint8_t * priority1,
+ uint8_t * clock_class,
+ int16_t * offset_scaled_log_variance,
+ uint8_t * clock_accuracy,
+ uint8_t * priority2,
+ uint8_t * domain_number,
+ int8_t * log_sync_interval,
+ int8_t * log_announce_interval,
+ int8_t * log_pdelay_interval,
+ uint16_t * port_number)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_GRANDMASTER);
+
+ if (gptpgetdata(gMmap, &gPtpTD) < 0) {
+ AVB_LOG_ERROR("Grandmaster data fetch failed");
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+ }
+
+ if (clock_identity != NULL) { memcpy(clock_identity, gPtpTD.clock_identity, 8); }
+ if (priority1 != NULL) { *priority1 = gPtpTD.priority1; }
+ if (clock_class != NULL) { *clock_class = gPtpTD.clock_class; }
+ if (offset_scaled_log_variance != NULL) { *offset_scaled_log_variance = gPtpTD.offset_scaled_log_variance; }
+ if (clock_accuracy != NULL) { *clock_accuracy = gPtpTD.clock_accuracy; }
+ if (priority2 != NULL) { *priority2 = gPtpTD.priority2; }
+ if (domain_number != NULL) { *domain_number = gPtpTD.domain_number; }
+ if (log_sync_interval != NULL) { *log_sync_interval = gPtpTD.log_sync_interval; }
+ if (log_announce_interval != NULL) { *log_announce_interval = gPtpTD.log_announce_interval; }
+ if (log_pdelay_interval != NULL) { *log_pdelay_interval = gPtpTD.log_pdelay_interval; }
+ if (port_number != NULL) { *port_number = gPtpTD.port_number; }
+
+ AVB_TRACE_EXIT(AVB_TRACE_GRANDMASTER);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal.h b/lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal.h
new file mode 100644
index 00000000..cdd01b7a
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal.h
@@ -0,0 +1,37 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef _OPENAVB_GRANDMASTER_OSAL_H
+#define _OPENAVB_GRANDMASTER_OSAL_H
+
+#include "openavb_grandmaster_osal_pub.h"
+
+#endif // _OPENAVB_GRANDMASTER_OSAL_H
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal_pub.h b/lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal_pub.h
new file mode 100644
index 00000000..795ad8a7
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal_pub.h
@@ -0,0 +1,62 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef _OPENAVB_GRANDMASTER_OSAL_PUB_H
+#define _OPENAVB_GRANDMASTER_OSAL_PUB_H
+
+// Initialize the AVB Grandmaster system for client usage
+bool osalAVBGrandmasterInit(void);
+
+// Close the AVB Grandmaster system for client usage
+bool osalAVBGrandmasterClose(void);
+
+/* Get the current grandmaster information */
+/* Referenced by the IEEE Std 1722.1-2013 AVDECC Discovery Protocol Data Unit (ADPDU) */
+bool osalAVBGrandmasterGetCurrent(
+ uint8_t gptp_grandmaster_id[],
+ uint8_t * gptp_domain_number );
+
+/* Get the grandmaster support for the network interface */
+/* Referenced by the IEEE Std 1722.1-2013 AVDECC AVB_INTERFACE descriptor */
+bool osalClockGrandmasterGetInterface(
+ uint8_t clock_identity[],
+ uint8_t * priority1,
+ uint8_t * clock_class,
+ int16_t * offset_scaled_log_variance,
+ uint8_t * clock_accuracy,
+ uint8_t * priority2,
+ uint8_t * domain_number,
+ int8_t * log_sync_interval,
+ int8_t * log_announce_interval,
+ int8_t * log_pdelay_interval,
+ uint16_t * port_number);
+
+#endif // _OPENAVB_GRANDMASTER_OSAL_PUB_H
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal.h b/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal.h
index 5619e946..a0d399d0 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -179,7 +180,7 @@ thread##_type thread##_ThreadData
#define SEM_POST(sem, err) err = sem_post(&sem);
#define SEM_DESTROY(sem, err) err = sem_destroy(&sem);
#define SEM_IS_ERR_NONE(err) (0 == err)
-#define SEM_IS_ERR_TIMEOUT(err) (ETIMEDOUT == err)
+#define SEM_IS_ERR_TIMEOUT(err) (ETIMEDOUT == err || ((-1 == err) && (ETIMEDOUT == errno)))
#define SEM_LOG_ERR(err) if (0 != err) AVB_LOGF_ERROR("Semaphore error code: %d", err);
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal_pub.h b/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal_pub.h
index fe235104..efe079bb 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal_pub.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -34,6 +35,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#define LINUX 1 // !!! FIX ME !!! THIS IS A HACK TO SUPPORT ANOTHER HACK IN openavb_avtp_time.c. REMOVE THIS WHEN openavb_avtp_time.c GETS FIXED !!!
#include "openavb_time_osal_pub.h"
+#include "openavb_grandmaster_osal_pub.h"
#define INLINE_VARIABLE_NUM_OF_ARGUMENTS inline // must be okay of gcc
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_osal.c b/lib/avtp_pipeline/platform/Linux/openavb_osal.c
index 9c3c7c2e..f2568c54 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_osal.c
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -36,9 +37,23 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_pub.h"
#include "openavb_log.h"
-extern DLL_EXPORT bool osalAVBInitialize(const char* ifname)
+static FILE *s_logfile = NULL;
+
+extern DLL_EXPORT bool osalAVBInitialize(const char* logfilename, const char* ifname)
{
- avbLogInit();
+ // Open the log file, if requested.
+ if (s_logfile) {
+ fclose(s_logfile);
+ s_logfile = NULL;
+ }
+ if (logfilename) {
+ s_logfile = fopen(logfilename, "w");
+ if (s_logfile == NULL) {
+ fprintf(stderr, "Error opening log file: %s\n", logfilename);
+ }
+ }
+
+ avbLogInitEx(s_logfile);
osalAVBTimeInit();
openavbQmgrInitialize(FQTSS_MODE_HW_CLASS, 0, ifname, 0, 0, 0);
return TRUE;
@@ -49,6 +64,13 @@ extern DLL_EXPORT bool osalAVBFinalize(void)
openavbQmgrFinalize();
osalAVBTimeClose();
avbLogExit();
+
+ // Done with the log file.
+ if (s_logfile) {
+ fclose(s_logfile);
+ s_logfile = NULL;
+ }
+
return TRUE;
}
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_osal.h b/lib/avtp_pipeline/platform/Linux/openavb_osal.h
index dc1e4463..cbfd349c 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_osal.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_osal_avdecc.c b/lib/avtp_pipeline/platform/Linux/openavb_osal_avdecc.c
new file mode 100644
index 00000000..b8f056a9
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal_avdecc.c
@@ -0,0 +1,79 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include "openavb_platform.h"
+#include "openavb_osal.h"
+#include "openavb_qmgr.h"
+#include "openavb_avdecc.h"
+
+#define AVB_LOG_COMPONENT "osal"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+static FILE *s_logfile = NULL;
+
+extern DLL_EXPORT bool osalAvdeccInitialize(const char* logfilename, const char* ifname, const char **inifiles, int numfiles)
+{
+ // Open the log file, if requested.
+ if (s_logfile) {
+ fclose(s_logfile);
+ s_logfile = NULL;
+ }
+ if (logfilename) {
+ s_logfile = fopen(logfilename, "w");
+ if (s_logfile == NULL) {
+ fprintf(stderr, "Error opening log file: %s\n", logfilename);
+ }
+ }
+
+ avbLogInitEx(s_logfile);
+ osalAVBTimeInit();
+ if (!osalAVBGrandmasterInit()) { return FALSE; }
+ if (!startAvdecc(ifname, inifiles, numfiles)) { return FALSE; }
+ return TRUE;
+}
+
+extern DLL_EXPORT bool osalAvdeccFinalize(void)
+{
+ stopAvdecc();
+ osalAVBGrandmasterClose();
+ osalAVBTimeClose();
+ avbLogExit();
+
+ // Done with the log file.
+ if (s_logfile) {
+ fclose(s_logfile);
+ s_logfile = NULL;
+ }
+
+ return TRUE;
+}
+
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c b/lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c
index 51dc7087..5e661167 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -37,9 +38,23 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_pub.h"
#include "openavb_log.h"
-extern DLL_EXPORT bool osalAVBInitialize(const char* ifname)
+static FILE *s_logfile = NULL;
+
+extern DLL_EXPORT bool osalAVBInitialize(const char* logfilename, const char* ifname)
{
- avbLogInit();
+ // Open the log file, if requested.
+ if (s_logfile) {
+ fclose(s_logfile);
+ s_logfile = NULL;
+ }
+ if (logfilename) {
+ s_logfile = fopen(logfilename, "w");
+ if (s_logfile == NULL) {
+ fprintf(stderr, "Error opening log file: %s\n", logfilename);
+ }
+ }
+
+ avbLogInitEx(s_logfile);
osalAVBTimeInit();
startEndpoint(FQTSS_MODE_HW_CLASS, 0, ifname, 0, 0, 0);
return TRUE;
@@ -50,6 +65,13 @@ extern DLL_EXPORT bool osalAVBFinalize(void)
stopEndpoint();
osalAVBTimeClose();
avbLogExit();
+
+ // Done with the log file.
+ if (s_logfile) {
+ fclose(s_logfile);
+ s_logfile = NULL;
+ }
+
return TRUE;
}
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h b/lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h
index 0cae719d..843d192e 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -36,9 +37,14 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_os_services_osal_pub.h"
-bool osalAVBInitialize(const char *ifname);
+bool osalAVBInitialize(const char* logfilename, const char *ifname);
bool osalAVBFinalize(void);
+
+bool osalAvdeccInitialize(const char* logfilename, const char *ifname, const char **inifiles, int numfiles);
+
+bool osalAvdeccFinalize(void);
+
#endif // _OPENAVB_OSAL_PUB_H
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_poll_osal.h b/lib/avtp_pipeline/platform/Linux/openavb_poll_osal.h
index bd4e925f..84866cbf 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_poll_osal.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_poll_osal.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_tasks.h b/lib/avtp_pipeline/platform/Linux/openavb_tasks.h
index d456b4f9..01969f09 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_tasks.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_tasks.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -62,6 +63,9 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
//task ListenerThread
#define listenerThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+//task avdeccMsgThread
+#define avdeccMsgThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
//task openavbAecpSMEntityModelEntityThread
#define openavbAecpSMEntityModelEntityThread_THREAD_STK_SIZE THREAD_STACK_SIZE
@@ -86,8 +90,8 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
//task openavbAcmpSmTalkerThread
#define openavbAcmpSmTalkerThread_THREAD_STK_SIZE THREAD_STACK_SIZE
-//task openavbAcmpSmTalkerThread
-#define openavbAcmpSmTalkerThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+//task openavbAcmpSmControllerThread
+#define openavbAcmpSmControllerThread_THREAD_STK_SIZE THREAD_STACK_SIZE
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_time_osal.c b/lib/avtp_pipeline/platform/Linux/openavb_time_osal.c
index d5b0fff9..9f2239b6 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_time_osal.c
+++ b/lib/avtp_pipeline/platform/Linux/openavb_time_osal.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -43,8 +44,6 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_pub.h"
#include "openavb_log.h"
-//#include "openavb_time_util_osal.h"
-
static pthread_mutex_t gOSALTimeInitMutex = PTHREAD_MUTEX_INITIALIZER;
#define LOCK() pthread_mutex_lock(&gOSALTimeInitMutex)
#define UNLOCK() pthread_mutex_unlock(&gOSALTimeInitMutex)
@@ -116,7 +115,7 @@ bool osalAVBTimeInit(void) {
UNLOCK();
AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return TRUE;
+ return bInitialized;
}
bool osalAVBTimeClose(void) {
@@ -131,7 +130,8 @@ bool osalAVBTimeClose(void) {
bool osalClockGettime(openavb_clockId_t openavbClockId, struct timespec *getTime) {
AVB_TRACE_ENTRY(AVB_TRACE_TIME);
- if (openavbClockId < OPENAVB_CLOCK_WALLTIME) {
+ if (openavbClockId < OPENAVB_CLOCK_WALLTIME)
+ {
clockid_t clockId = CLOCK_MONOTONIC;
switch (openavbClockId) {
case OPENAVB_CLOCK_REALTIME:
@@ -164,7 +164,8 @@ bool osalClockGettime(openavb_clockId_t openavbClockId, struct timespec *getTime
}
bool osalClockGettime64(openavb_clockId_t openavbClockId, U64 *timeNsec) {
- if (openavbClockId < OPENAVB_CLOCK_WALLTIME) {
+ if (openavbClockId < OPENAVB_CLOCK_WALLTIME)
+ {
clockid_t clockId = CLOCK_MONOTONIC;
switch (openavbClockId) {
case OPENAVB_CLOCK_REALTIME:
@@ -193,3 +194,4 @@ bool osalClockGettime64(openavb_clockId_t openavbClockId, U64 *timeNsec) {
AVB_TRACE_EXIT(AVB_TRACE_TIME);
return FALSE;
}
+
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_time_osal.h b/lib/avtp_pipeline/platform/Linux/openavb_time_osal.h
index 293f7c3c..a6879862 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_time_osal.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_time_osal.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_time_osal_pub.h b/lib/avtp_pipeline/platform/Linux/openavb_time_osal_pub.h
index 1f2c243f..ba693da9 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_time_osal_pub.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_time_osal_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -42,7 +43,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#define TIMERFD_SETTIME(arg1, arg2, arg3, arg4) timerfd_settime(arg1, arg2, arg3, arg4)
#define TIMER_CLOSE(arg1) close(arg1)
-// In this Linux port all clock IDs preceeding OPENAVB_CLOCK_WALLTIME will be set to clock_gettime()
+// In this Linux port all clock IDs preceding OPENAVB_CLOCK_WALLTIME will be set to clock_gettime()
typedef enum {
OPENAVB_CLOCK_REALTIME,
OPENAVB_CLOCK_MONOTONIC,
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/avtp_rx.c b/lib/avtp_pipeline/platform/Linux/rawsock/avtp_rx.c
index e451fab9..80adbb59 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/avtp_rx.c
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/avtp_rx.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.c b/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.c
index 918d1006..a9cf5ac2 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.c
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.h b/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.h
index e542e1c1..70215981 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.h
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock.c b/lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock.c
index 0e195ad6..c05053a5 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock.c
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -28,27 +29,25 @@ Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
-#include "openavb_rawsock.h"
-#include <malloc.h>
+#include "sendmmsg_rawsock.h"
#include "simple_rawsock.h"
#include "ring_rawsock.h"
-
+#if AVB_FEATURE_PCAP
+#include "pcap_rawsock.h"
#if AVB_FEATURE_IGB
#include "igb_rawsock.h"
-#define DEFAULT_PROTO "igb"
-#else
-#define DEFAULT_PROTO "simple"
#endif
-
-#if AVB_FEATURE_PCAP
-#include "pcap_rawsock.h"
#endif
+#include "openavb_rawsock.h"
+
#include "openavb_trace.h"
#define AVB_LOG_COMPONENT "Raw Socket"
#include "openavb_log.h"
+#include <malloc.h>
+
// Get information about an interface
bool openavbCheckInterface(const char *ifname_uri, if_info_t *info)
@@ -77,11 +76,21 @@ void *openavbRawsockOpen(const char *ifname_uri, bool rx_mode, bool tx_mode, U16
AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
const char* ifname = ifname_uri;
- char proto[IF_NAMESIZE] = DEFAULT_PROTO;
+#if AVB_FEATURE_PCAP
+#if AVB_FEATURE_IGB
+ char proto[IF_NAMESIZE] = "igb";
+#else
+ char proto[IF_NAMESIZE] = "pcap";
+#endif
+#else
+ char proto[IF_NAMESIZE] = "simple";
+#endif
+
char *colon = strchr(ifname_uri, ':');
if (colon) {
ifname = colon + 1;
strncpy(proto, ifname_uri, colon - ifname_uri);
+ proto[colon - ifname_uri] = '\0';
}
AVB_LOGF_DEBUG("%s ifname_uri %s ifname %s proto %s", __func__, ifname_uri, ifname, proto);
@@ -107,7 +116,7 @@ void *openavbRawsockOpen(const char *ifname_uri, bool rx_mode, bool tx_mode, U16
AVB_LOG_INFO("Using *simple* implementation");
// allocate memory for rawsock object
- simple_rawsock_t *rawsock = calloc(1, sizeof(simple_rawsock_t));
+ simple_rawsock_t *rawsock = calloc(1, sizeof(simple_rawsock_t) + 4 /* Just in case */);
if (!rawsock) {
AVB_LOG_ERROR("Creating rawsock; malloc failed");
return NULL;
@@ -115,6 +124,19 @@ void *openavbRawsockOpen(const char *ifname_uri, bool rx_mode, bool tx_mode, U16
// call constructor
pvRawsock = simpleRawsockOpen(rawsock, ifname, rx_mode, tx_mode, ethertype, frame_size, num_frames);
+ } else if (strcmp(proto, "sendmmsg") == 0) {
+
+ AVB_LOG_INFO("Using *sendmmsg* implementation");
+
+ // allocate memory for rawsock object
+ sendmmsg_rawsock_t *rawsock = calloc(1, sizeof(sendmmsg_rawsock_t));
+ if (!rawsock) {
+ AVB_LOG_ERROR("Creating rawsock; malloc failed");
+ return NULL;
+ }
+
+ // call constructor
+ pvRawsock = sendmmsgRawsockOpen(rawsock, ifname, rx_mode, tx_mode, ethertype, frame_size, num_frames);
#if AVB_FEATURE_PCAP
} else if (strcmp(proto, "pcap") == 0) {
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.c b/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.c
index 1f87c043..de0d7967 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.c
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -38,6 +39,36 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#define AVB_LOG_COMPONENT "Raw Socket"
#include "openavb_log.h"
+static pcap_t* open_pcap_dev(const char* ifname, int frameSize, char* errbuf)
+{
+ pcap_t* handle = pcap_create(ifname, errbuf);
+ if (handle) {
+ int err;
+ err = pcap_set_snaplen(handle, frameSize);
+ if (err) AVB_LOGF_WARNING("Cannot set snap len %d", err);
+
+ err = pcap_set_promisc(handle, 1);
+ if (err) AVB_LOGF_WARNING("Cannot set promisc %d", err);
+
+ err = pcap_set_immediate_mode(handle, 1);
+ if (err) AVB_LOGF_WARNING("Cannot set immediate mode %d", err);
+
+ // we need timeout (here 100ms) otherwise we could block for ever
+ err = pcap_set_timeout(handle, 100);
+ if (err) AVB_LOGF_WARNING("Cannot set timeout %d", err);
+
+ err = pcap_set_tstamp_precision(handle, PCAP_TSTAMP_PRECISION_NANO);
+ if (err) AVB_LOGF_WARNING("Cannot set tstamp nano precision %d", err);
+
+ err = pcap_set_tstamp_type(handle, PCAP_TSTAMP_ADAPTER_UNSYNCED);
+ if (err) AVB_LOGF_WARNING("Cannot set tstamp adapter unsynced %d", err);
+
+ err = pcap_activate(handle);
+ if (err) AVB_LOGF_WARNING("Cannot activate pcap %d", err);
+ }
+ return handle;
+}
+
// Open a rawsock for TX or RX
void *pcapRawsockOpen(pcap_rawsock_t* rawsock, const char *ifname, bool rx_mode, bool tx_mode, U16 ethertype, U32 frame_size, U32 num_frames)
{
@@ -67,14 +98,14 @@ void *pcapRawsockOpen(pcap_rawsock_t* rawsock, const char *ifname, bool rx_mode,
rawsock->base.frameSize = rawsock->base.ifInfo.mtu + ETH_HLEN + VLAN_HLEN;
}
else if (rawsock->base.frameSize > rawsock->base.ifInfo.mtu + ETH_HLEN + VLAN_HLEN) {
- AVB_LOG_ERROR("Creating raswsock; requested frame size exceeds MTU");
+ AVB_LOG_ERROR("Creating rawsock; requested frame size exceeds MTU");
free(rawsock);
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
return NULL;
}
char errbuf[PCAP_ERRBUF_SIZE];
- rawsock->handle = pcap_open_live(ifname, rawsock->base.frameSize, 1, 1, errbuf);
+ rawsock->handle = open_pcap_dev(ifname, rawsock->base.frameSize, errbuf);
if (!rawsock->handle) {
AVB_LOGF_ERROR("Cannot open device %s: %s", ifname, errbuf);
free(rawsock);
@@ -87,8 +118,10 @@ void *pcapRawsockOpen(pcap_rawsock_t* rawsock, const char *ifname, bool rx_mode,
cb->close = pcapRawsockClose;
cb->getTxFrame = pcapRawsockGetTxFrame;
cb->txFrameReady = pcapRawsockTxFrameReady;
+ cb->send = pcapRawsockSend;
cb->getRxFrame = pcapRawsockGetRxFrame;
cb->rxMulticast = pcapRawsockRxMulticast;
+ cb->rxParseHdr = pcapRawsockRxParseHdr;
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
return rawsock;
@@ -136,20 +169,28 @@ bool pcapRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64
return ret == 0;
}
+// Send all packets that are ready (i.e. tell kernel to send them)
+int pcapRawsockSend(void *pvRawsock)
+{
+ // pcapRawsock sends frames in pcapRawsockTxFrameReady
+
+ return 1;
+}
+
U8 *pcapRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len)
{
pcap_rawsock_t *rawsock = (pcap_rawsock_t*)pvRawsock;
- struct pcap_pkthdr *header = 0;
+ rawsock->rxHeader = 0;
const u_char *packet = 0;
int ret;
if (rawsock) {
- ret = pcap_next_ex(rawsock->handle, &header, &packet);
+ ret = pcap_next_ex(rawsock->handle, &rawsock->rxHeader, &packet);
switch(ret) {
case 1:
*offset = 0;
- *len = header->caplen;
+ *len = rawsock->rxHeader->caplen;
return (U8*)packet;
case -1:
AVB_LOGF_ERROR("pcap_next_ex failed: %s", pcap_geterr(rawsock->handle));
@@ -159,7 +200,7 @@ U8 *pcapRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, un
break;
case -2:
// no packets to be read from savefile
- // this should not happend
+ // this should not happened
break;
default:
break;
@@ -169,6 +210,19 @@ U8 *pcapRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, un
return NULL;
}
+int pcapRawsockRxParseHdr(void* pvRawsock, U8* pBuffer, hdr_info_t* pInfo)
+{
+ int hdrLen = baseRawsockRxParseHdr(pvRawsock, pBuffer, pInfo);
+
+ pcap_rawsock_t *rawsock = (pcap_rawsock_t*)pvRawsock;
+ if (rawsock && rawsock->rxHeader) {
+ pInfo->ts.tv_sec = rawsock->rxHeader->ts.tv_sec;
+ // we requested nanosecond timestamp precision, so probably we don't have to scale here
+ pInfo->ts.tv_nsec = rawsock->rxHeader->ts.tv_usec;
+ }
+ return hdrLen;
+}
+
// Setup the rawsock to receive multicast packets
bool pcapRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[ETH_ALEN])
{
@@ -177,7 +231,7 @@ bool pcapRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[
struct bpf_program comp_filter_exp;
char filter_exp[30];
- sprintf(filter_exp, "ether dst %x:%x:%x:%x:%x:%x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+ sprintf(filter_exp, "ether dst %02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
AVB_LOGF_DEBUG("%s %d %s", __func__, (int)add_membership, filter_exp);
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.h b/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.h
index 9e5fe12e..32b01854 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.h
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -38,6 +39,7 @@ typedef struct {
base_rawsock_t base;
pcap_t* handle;
U8 txBuffer[1518];
+ struct pcap_pkthdr *rxHeader;
} pcap_rawsock_t;
void *pcapRawsockOpen(pcap_rawsock_t* rawsock, const char *ifname, bool rx_mode, bool tx_mode, U16 ethertype, U32 frame_size, U32 num_frames);
@@ -48,8 +50,12 @@ U8 *pcapRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len);
bool pcapRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec);
+int pcapRawsockSend(void *pvRawsock);
+
U8 *pcapRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len);
+int pcapRawsockRxParseHdr(void* pvRawsock, U8* pBuffer, hdr_info_t* pInfo);
+
bool pcapRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[ETH_ALEN]);
#endif
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_rx.c b/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_rx.c
index 4fa4682f..7e78516a 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_rx.c
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_rx.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_tx.c b/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_tx.c
index 4db5b6e3..20a41a94 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_tx.c
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_tx.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -34,6 +35,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include <string.h>
#include <glib.h>
#include "./openavb_rawsock.h"
+#include "openavb_log.h"
//Common usage: ./rawsock_tx -i eth0 -t 8944 -r 8000 -s 1 -c 1 -m 1 -l 100
@@ -150,6 +152,8 @@ int main(int argc, char* argv[])
U32 buflen, hdrlen, datalen;
hdr_info_t hdr;
+ avbLogInit();
+
memset(&hdr, 0, sizeof(hdr_info_t));
openavbRawsockTxSetHdr(rs, &hdr);
@@ -165,6 +169,7 @@ int main(int argc, char* argv[])
nextReportInterval = TIMESPEC_TO_NSEC(now) + (NANOSECONDS_PER_SECOND * reportSec);
while (1) {
+ int remainder = 0;
pBuf = (U8*)openavbRawsockGetTxFrame(rs, TRUE, &buflen);
if (!pBuf) {
printf("failed to get TX frame buffer\n");
@@ -204,8 +209,9 @@ int main(int argc, char* argv[])
U64 nowNSec = TIMESPEC_TO_NSEC(now);;
if (nowNSec > nextReportInterval) {
- printf("TX Packets: %d\n", packetCnt);
- packetCnt = 0;
+ printf("TX Packets: %d\n", packetCnt-remainder);
+ packetCnt %= chunkSize;
+ remainder = packetCnt;
nextReportInterval = nowNSec + (NANOSECONDS_PER_SECOND * reportSec);
}
@@ -215,5 +221,6 @@ int main(int argc, char* argv[])
}
openavbRawsockClose(rs);
+ avbLogExit();
return 0;
}
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.c b/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.c
index de03d4a6..f66878c1 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.c
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -218,9 +219,9 @@ U8* ringRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len)
// And pointer to portion of buffer to be filled with frame
volatile U8 *pBuffer = (U8*)pHdr + rawsock->bufHdrSize;
- AVB_LOGF_VERBOSE("block=%d, buffer=%d, out=%d, pHdr=%p, pBuffer=%p",
+ AVB_LOGF_VERBOSE("block=%d, buffer=%d, out=%d, pBuffer=%p, pHdr=%p",
rawsock->blockIndex, rawsock->bufferIndex, rawsock->buffersOut,
- pHdr, pBuffer);
+ pBuffer, pHdr);
// Check if buffer ready for user
// In send mode, we want to see TP_STATUS_AVAILABLE
@@ -484,9 +485,9 @@ U8* ringRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, un
+ (rawsock->bufferIndex * rawsock->bufferSize));
volatile U8 *pBuffer = (U8*)pHdr + rawsock->bufHdrSize;
- AVB_LOGF_VERBOSE("block=%d, buffer=%d, out=%d, pHdr=%p, pBuffer=%p",
+ AVB_LOGF_VERBOSE("block=%d, buffer=%d, out=%d, pBuffer=%p, pHdr=%p",
rawsock->blockIndex, rawsock->bufferIndex, rawsock->buffersOut,
- pHdr, pBuffer);
+ pBuffer, pHdr);
// Check if buffer ready for user
// In receive mode, we want TP_STATUS_USER flag set
@@ -600,7 +601,12 @@ U8* ringRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, un
rawsock->buffersOut += 1;
if (pHdr->tp_snaplen < pHdr->tp_len) {
+#if (AVB_LOG_LEVEL >= AVB_LOG_LEVEL_VERBOSE)
+ AVB_LOGF_WARNING("Getting RX frame; partial frame ignored (len %d, snaplen %d)", pHdr->tp_len, pHdr->tp_snaplen);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_VERBOSE, (const U8 *) pBuffer + (pHdr->tp_mac - rawsock->bufHdrSize), pHdr->tp_len, 16);
+#else
IF_LOG_INTERVAL(1000) AVB_LOGF_WARNING("Getting RX frame; partial frame ignored (len %d, snaplen %d)", pHdr->tp_len, pHdr->tp_snaplen);
+#endif
ringRawsockRelRxFrame(rawsock, (U8*)pBuffer);
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
return NULL;
@@ -609,6 +615,7 @@ U8* ringRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, un
// Return pointer to the buffer and length
*offset = pHdr->tp_mac - rawsock->bufHdrSize;
*len = pHdr->tp_snaplen;
+ AVB_LOGF_VERBOSE("Good RX frame (len %d, snaplen %d)", pHdr->tp_len, pHdr->tp_snaplen);
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
return (U8*)pBuffer;
@@ -627,7 +634,7 @@ int ringRawsockRxParseHdr(void *pvRawsock, U8 *pBuffer, hdr_info_t *pInfo)
}
volatile struct tpacket2_hdr *pHdr = (struct tpacket2_hdr*)(pBuffer - rawsock->bufHdrSize);
- AVB_LOGF_VERBOSE("pBuffer=%p, pHdr=%p", pBuffer, pHdr);
+ AVB_LOGF_VERBOSE("ringRawsockRxParseHdr: pBuffer=%p, pHdr=%p", pBuffer, pHdr);
memset(pInfo, 0, sizeof(hdr_info_t));
@@ -636,6 +643,8 @@ int ringRawsockRxParseHdr(void *pvRawsock, U8 *pBuffer, hdr_info_t *pInfo)
pInfo->shost = pNoTag->shost;
pInfo->dhost = pNoTag->dhost;
pInfo->ethertype = ntohs(pNoTag->ethertype);
+ pInfo->ts.tv_sec = pHdr->tp_sec;
+ pInfo->ts.tv_nsec = pHdr->tp_nsec;
if (pInfo->ethertype == ETHERTYPE_8021Q) {
pInfo->vlan = TRUE;
@@ -662,7 +671,7 @@ bool ringRawsockRelRxFrame(void *pvRawsock, U8 *pBuffer)
}
volatile struct tpacket2_hdr *pHdr = (struct tpacket2_hdr*)(pBuffer - rawsock->bufHdrSize);
- AVB_LOGF_VERBOSE("pBuffer=%p, pHdr=%p", pBuffer, pHdr);
+ AVB_LOGF_VERBOSE("ringRawsockRelRxFrame: pBuffer=%p, pHdr=%p", pBuffer, pHdr);
pHdr->tp_status = TP_STATUS_KERNEL;
rawsock->buffersOut -= 1;
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.h b/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.h
index d95e94e9..aa98ff7f 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.h
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/sendmmsg_rawsock.c b/lib/avtp_pipeline/platform/Linux/rawsock/sendmmsg_rawsock.c
new file mode 100644
index 00000000..2a2be5c3
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/sendmmsg_rawsock.c
@@ -0,0 +1,503 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include "sendmmsg_rawsock.h"
+
+#include "simple_rawsock.h"
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/if_packet.h>
+#include <linux/filter.h>
+
+#define AVB_LOG_LEVEL AVB_LOG_LEVEL_INFO
+
+#include "openavb_trace.h"
+
+#define AVB_LOG_COMPONENT "Raw Socket"
+#include "openavb_log.h"
+
+
+#if USE_LAUNCHTIME
+
+#ifndef SCM_TIMEDLAUNCH
+#define SCM_TIMEDLAUNCH 0x04
+#endif
+
+#endif /* if USE_LAUNCHTIME */
+
+
+static void fillmsghdr(struct msghdr *msg, struct iovec *iov,
+#if USE_LAUNCHTIME
+ unsigned char *cmsgbuf, uint64_t time,
+#endif
+ void *pktdata, size_t pktlen)
+{
+ msg->msg_name = NULL;
+ msg->msg_namelen = 0;
+
+ iov->iov_base = pktdata;
+ iov->iov_len = pktlen;
+ msg->msg_iov = iov;
+ msg->msg_iovlen = 1;
+
+#if USE_LAUNCHTIME
+ {
+ struct cmsghdr *cmsg;
+ uint64_t *tsptr;
+
+ msg->msg_control = cmsgbuf;
+ msg->msg_controllen = CMSG_LEN(sizeof time);
+
+ cmsg = CMSG_FIRSTHDR(msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_TIMEDLAUNCH;
+ cmsg->cmsg_len = CMSG_LEN(sizeof time);
+
+ tsptr = (uint64_t *)CMSG_DATA(cmsg);
+ *tsptr = time;
+ }
+#else
+ msg->msg_control = NULL;
+ msg->msg_controllen = 0;
+#endif
+
+ msg->msg_flags = 0;
+}
+
+// Open a rawsock for TX or RX
+void* sendmmsgRawsockOpen(sendmmsg_rawsock_t* rawsock, const char *ifname, bool rx_mode, bool tx_mode, U16 ethertype, U32 frame_size, U32 num_frames)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+
+ AVB_LOGF_DEBUG("Open, ifname=%s, rx=%d, tx=%d, ethertype=%x size=%d, num=%d",
+ ifname, rx_mode, tx_mode, ethertype, frame_size, num_frames);
+
+ baseRawsockOpen(&rawsock->base, ifname, rx_mode, tx_mode, ethertype, frame_size, num_frames);
+
+ rawsock->sock = -1;
+
+ // Get info about the network device
+ if (!simpleAvbCheckInterface(ifname, &(rawsock->base.ifInfo))) {
+ AVB_LOGF_ERROR("Creating rawsock; bad interface name: %s", ifname);
+ free(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+
+ // Deal with frame size.
+ if (rawsock->base.frameSize == 0) {
+ // use interface MTU as max frames size, if none specified
+ rawsock->base.frameSize = rawsock->base.ifInfo.mtu + ETH_HLEN + VLAN_HLEN;
+ }
+ else if (rawsock->base.frameSize > rawsock->base.ifInfo.mtu + ETH_HLEN + VLAN_HLEN) {
+ AVB_LOG_ERROR("Creating raswsock; requested frame size exceeds MTU");
+ free(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+ rawsock->base.frameSize = TPACKET_ALIGN(rawsock->base.frameSize);
+ assert(rawsock->base.frameSize <= MAX_FRAME_SIZE);
+
+ // Prepare default Ethernet header.
+ rawsock->base.ethHdrLen = sizeof(eth_hdr_t);
+ memset(&(rawsock->base.ethHdr.notag.dhost), 0xFF, ETH_ALEN);
+ memcpy(&(rawsock->base.ethHdr.notag.shost), &(rawsock->base.ifInfo.mac), ETH_ALEN);
+ rawsock->base.ethHdr.notag.ethertype = htons(rawsock->base.ethertype);
+
+ // Create socket
+ rawsock->sock = socket(PF_PACKET, SOCK_RAW, htons(rawsock->base.ethertype));
+ if (rawsock->sock == -1) {
+ AVB_LOGF_ERROR("Creating rawsock; opening socket: %s", strerror(errno));
+ sendmmsgRawsockClose(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+
+ // Allow address reuse
+ int temp = 1;
+ if(setsockopt(rawsock->sock, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(int)) < 0) {
+ AVB_LOG_ERROR("Creating rawsock; failed to set reuseaddr");
+ sendmmsgRawsockClose(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+
+ // Bind to interface
+ struct sockaddr_ll my_addr;
+ memset(&my_addr, 0, sizeof(my_addr));
+ my_addr.sll_family = PF_PACKET;
+ my_addr.sll_protocol = htons(rawsock->base.ethertype);
+ my_addr.sll_ifindex = rawsock->base.ifInfo.index;
+
+ if (bind(rawsock->sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == -1) {
+ AVB_LOGF_ERROR("Creating rawsock; bind socket: %s", strerror(errno));
+ sendmmsgRawsockClose(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+
+ // Clear our buffers and other tracking data
+ memset(rawsock->mmsg, 0, sizeof(rawsock->mmsg));
+ memset(rawsock->miov, 0, sizeof(rawsock->miov));
+ memset(rawsock->pktbuf, 0, sizeof(rawsock->pktbuf));
+#if USE_LAUNCHTIME
+ memset(rawsock->cmsgbuf, 0, sizeof(rawsock->cmsgbuf));
+#endif
+
+ rawsock->buffersOut = 0;
+ rawsock->buffersReady = 0;
+ rawsock->frameCount = MSG_COUNT;
+
+ // fill virtual functions table
+ rawsock_cb_t *cb = &rawsock->base.cb;
+ cb->close = sendmmsgRawsockClose;
+ cb->getTxFrame = sendmmsgRawsockGetTxFrame;
+ cb->txSetMark = sendmmsgRawsockTxSetMark;
+ cb->txSetHdr = sendmmsgRawsockTxSetHdr;
+ cb->txFrameReady = sendmmsgRawsockTxFrameReady;
+ cb->send = sendmmsgRawsockSend;
+ cb->getRxFrame = sendmmsgRawsockGetRxFrame;
+ cb->rxMulticast = sendmmsgRawsockRxMulticast;
+ cb->getSocket = sendmmsgRawsockGetSocket;
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return rawsock;
+}
+
+// Close the rawsock
+void sendmmsgRawsockClose(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ sendmmsg_rawsock_t *rawsock = (sendmmsg_rawsock_t*)pvRawsock;
+
+ if (rawsock) {
+ if (rawsock->sock != -1) {
+ close(rawsock->sock);
+ rawsock->sock = -1;
+ }
+ }
+
+ baseRawsockClose(rawsock);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+}
+
+// Get a buffer from the ring to use for TX
+U8* sendmmsgRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ sendmmsg_rawsock_t *rawsock = (sendmmsg_rawsock_t*)pvRawsock;
+
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Getting TX frame; bad arguments");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+ if (rawsock->buffersOut >= rawsock->frameCount) {
+ AVB_LOG_ERROR("Getting TX frame; too many TX buffers in use");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+
+ U8 *pBuffer = rawsock->pktbuf[rawsock->buffersOut];
+ rawsock->buffersOut += 1;
+
+ // Remind client how big the frame buffer is
+ if (len)
+ *len = rawsock->base.frameSize;
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return pBuffer;
+}
+
+// Set the Firewall MARK on the socket
+// The mark is used by FQTSS to identify AVTP packets in kernel.
+// FQTSS creates a mark that includes the AVB class and stream index.
+bool sendmmsgRawsockTxSetMark(void *pvRawsock, int mark)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ sendmmsg_rawsock_t *rawsock = (sendmmsg_rawsock_t*)pvRawsock;
+ bool retval = FALSE;
+
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Setting TX mark; invalid argument passed");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ if (setsockopt(rawsock->sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) {
+ AVB_LOGF_ERROR("Setting TX mark; setsockopt failed: %s", strerror(errno));
+ }
+ else {
+ AVB_LOGF_DEBUG("SO_MARK=%d OK", mark);
+ retval = TRUE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return retval;
+}
+
+// Pre-set the ethernet header information that will be used on TX frames
+bool sendmmsgRawsockTxSetHdr(void *pvRawsock, hdr_info_t *pHdr)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ sendmmsg_rawsock_t *rawsock = (sendmmsg_rawsock_t*)pvRawsock;
+
+ bool ret = baseRawsockTxSetHdr(pvRawsock, pHdr);
+ if (ret && pHdr->vlan) {
+ // set the class'es priority on the TX socket
+ // (required by Telechips platform for FQTSS Credit Based Shaper to work)
+ U32 pcp = pHdr->vlan_pcp;
+ if (setsockopt(rawsock->sock, SOL_SOCKET, SO_PRIORITY, (char *)&pcp, sizeof(pcp)) < 0) {
+ AVB_LOGF_ERROR("openavbRawsockTxSetHdr; SO_PRIORITY setsockopt failed (%d: %s)\n", errno, strerror(errno));
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return ret;
+}
+
+// Release a TX frame, mark it ready to send
+bool sendmmsgRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ sendmmsg_rawsock_t *rawsock = (sendmmsg_rawsock_t*)pvRawsock;
+ int bufidx;
+
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Marking TX frame ready; invalid argument");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ bufidx = rawsock->buffersReady;
+ assert(pBuffer == rawsock->pktbuf[bufidx]);
+
+#if USE_LAUNCHTIME
+ if (!timeNsec) {
+ IF_LOG_INTERVAL(1000) AVB_LOG_WARNING("launch time is enabled but not passed to TxFrameReady");
+ }
+ fillmsghdr(&(rawsock->mmsg[bufidx].msg_hdr), &(rawsock->miov[bufidx]), rawsock->cmsgbuf[bufidx],
+ timeNsec, rawsock->pktbuf[bufidx], len);
+#else
+ if (timeNsec) {
+ IF_LOG_INTERVAL(1000) AVB_LOG_WARNING("launch time is not enabled but was passed to TxFrameReady");
+ }
+ fillmsghdr(&(rawsock->mmsg[bufidx].msg_hdr), &(rawsock->miov[bufidx]), rawsock->pktbuf[bufidx], len);
+#endif
+
+
+ rawsock->buffersReady += 1;
+
+ if (rawsock->buffersReady >= rawsock->frameCount) {
+ AVB_LOG_DEBUG("All TxFrame slots marked ready");
+ //sendmmsgRawsockSend(rawsock);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return TRUE;
+}
+
+// Send all packets that are ready (i.e. tell kernel to send them)
+int sendmmsgRawsockSend(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ sendmmsg_rawsock_t *rawsock = (sendmmsg_rawsock_t*)pvRawsock;
+ int sz, bytes;
+
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Marking TX frame ready; invalid argument");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return -1;
+ }
+
+ if (rawsock->buffersOut != rawsock->buffersReady) {
+ AVB_LOGF_ERROR("Tried to send with %d bufs out, %d bufs ready", rawsock->buffersOut, rawsock->buffersReady);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return -1;
+ }
+
+ IF_LOG_INTERVAL(1000) AVB_LOGF_DEBUG("Send with %d of %d buffers ready", rawsock->buffersReady, rawsock->frameCount);
+ sz = sendmmsg(rawsock->sock, rawsock->mmsg, rawsock->buffersReady, 0);
+ if (sz < 0) {
+ AVB_LOGF_ERROR("Call to sendmmsg failed! Error code was %d", sz);
+ bytes = sz;
+ } else {
+ int i;
+ for (i = 0, bytes = 0; i < sz; i++) {
+ bytes += rawsock->mmsg[i].msg_len;
+ }
+ if (sz < rawsock->buffersReady) {
+ AVB_LOGF_WARNING("Only sent %ld of %d messages; dropping others", sz, rawsock->buffersReady);
+ }
+ }
+
+ rawsock->buffersOut = rawsock->buffersReady = 0;
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return bytes;
+}
+
+// Get a RX frame
+U8* sendmmsgRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ sendmmsg_rawsock_t *rawsock = (sendmmsg_rawsock_t*)pvRawsock;
+ if (!VALID_RX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Getting RX frame; invalid arguments");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+// For switching to recvmmsg eventually
+// if (rawsock->rxbuffersOut >= rawsock->rxframeCount) {
+// AVB_LOG_ERROR("Too many RX buffers in use");
+// AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+// return NULL;
+// }
+
+ int flags = 0;
+
+ U8 *pBuffer = rawsock->rxBuffer;
+ *offset = 0;
+ *len = recv(rawsock->sock, pBuffer, rawsock->base.frameSize, flags);
+
+ if (*len == (unsigned int)(-1)) {
+ AVB_LOGF_ERROR("%s %s", __func__, strerror(errno));
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return pBuffer;
+}
+
+// Setup the rawsock to receive multicast packets
+bool sendmmsgRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[ETH_ALEN])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+
+ sendmmsg_rawsock_t *rawsock = (sendmmsg_rawsock_t*)pvRawsock;
+ if (!VALID_RX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Setting multicast; invalid arguments");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ struct ether_addr mcast_addr;
+ memcpy(mcast_addr.ether_addr_octet, addr, ETH_ALEN);
+
+ // Fill in the structure for the multicast ioctl
+ struct packet_mreq mreq;
+ memset(&mreq, 0, sizeof(struct packet_mreq));
+ mreq.mr_ifindex = rawsock->base.ifInfo.index;
+ mreq.mr_type = PACKET_MR_MULTICAST;
+ mreq.mr_alen = ETH_ALEN;
+ memcpy(&mreq.mr_address, &mcast_addr.ether_addr_octet, ETH_ALEN);
+
+ // And call the ioctl to add/drop the multicast address
+ int action = (add_membership ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP);
+ if (setsockopt(rawsock->sock, SOL_PACKET, action,
+ (void*)&mreq, sizeof(struct packet_mreq)) < 0) {
+ AVB_LOGF_ERROR("Setting multicast; setsockopt(%s) failed: %s",
+ (add_membership ? "PACKET_ADD_MEMBERSHIP" : "PACKET_DROP_MEMBERSHIP"),
+ strerror(errno));
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ // In addition to adding the multicast membership, we also want to
+ // add a packet filter to restrict the packets that we'll receive
+ // on this socket. Multicast memeberships are global - not
+ // per-socket, so without the filter, this socket would receieve
+ // packets for all the multicast addresses added by all other
+ // sockets.
+ //
+ if (add_membership)
+ {
+ // Here's the template packet filter code.
+ // It was produced by running:
+ // tcpdump -dd ether dest host 91:e0:01:02:03:04
+ struct sock_filter bpfCode[] = {
+ { 0x20, 0, 0, 0x00000002 },
+ { 0x15, 0, 3, 0x01020304 }, // last 4 bytes of dest mac
+ { 0x28, 0, 0, 0x00000000 },
+ { 0x15, 0, 1, 0x000091e0 }, // first 2 bytes of dest mac
+ { 0x06, 0, 0, 0x0000ffff },
+ { 0x06, 0, 0, 0x00000000 }
+ };
+
+ // We need to graft our multicast dest address into bpfCode
+ U32 tmp; U8 *buf = (U8*)&tmp;
+ memcpy(buf, mcast_addr.ether_addr_octet + 2, 4);
+ bpfCode[1].k = ntohl(tmp);
+ memset(buf, 0, 4);
+ memcpy(buf + 2, mcast_addr.ether_addr_octet, 2);
+ bpfCode[3].k = ntohl(tmp);
+
+ // Now wrap the filter code in the appropriate structure
+ struct sock_fprog filter;
+ memset(&filter, 0, sizeof(filter));
+ filter.len = 6;
+ filter.filter = bpfCode;
+
+ // And attach it to our socket
+ if (setsockopt(rawsock->sock, SOL_SOCKET, SO_ATTACH_FILTER,
+ &filter, sizeof(filter)) < 0) {
+ AVB_LOGF_ERROR("Setting multicast; setsockopt(SO_ATTACH_FILTER) failed: %s", strerror(errno));
+ }
+ }
+ else {
+ if (setsockopt(rawsock->sock, SOL_SOCKET, SO_DETACH_FILTER, NULL, 0) < 0) {
+ AVB_LOGF_ERROR("Setting multicast; setsockopt(SO_DETACH_FILTER) failed: %s", strerror(errno));
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return TRUE;
+}
+
+// Get the socket used for this rawsock; can be used for poll/select
+int sendmmsgRawsockGetSocket(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ sendmmsg_rawsock_t *rawsock = (sendmmsg_rawsock_t*)pvRawsock;
+ if (!rawsock) {
+ AVB_LOG_ERROR("Getting socket; invalid arguments");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return -1;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return rawsock->sock;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/sendmmsg_rawsock.h b/lib/avtp_pipeline/platform/Linux/rawsock/sendmmsg_rawsock.h
new file mode 100644
index 00000000..05cf4b54
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/sendmmsg_rawsock.h
@@ -0,0 +1,110 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef SENDMMSG_RAWSOCK_H
+#define SENDMMSG_RAWSOCK_H
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <sys/socket.h>
+
+#include "rawsock_impl.h"
+
+#define MSG_COUNT 8
+#define MAX_FRAME_SIZE 1024
+#define USE_LAUNCHTIME 0
+
+
+// State information for raw socket
+//
+typedef struct {
+ base_rawsock_t base;
+
+ // the underlying socket
+ int sock;
+
+ // count of total buffers available for messages
+ int frameCount;
+
+ // count of buffers taken by senders
+ int buffersOut;
+
+ // count of buffers ready to send
+ int buffersReady;
+
+ // buffer for receiving frames
+ U8 rxBuffer[1518];
+
+ struct mmsghdr mmsg[MSG_COUNT];
+
+ struct iovec miov[MSG_COUNT];
+
+ unsigned char pktbuf[MSG_COUNT][MAX_FRAME_SIZE];
+#if USE_LAUNCHTIME
+ unsigned char cmsgbuf[MSG_COUNT][CMSG_SPACE(sizeof(uint64_t))];
+#endif
+} sendmmsg_rawsock_t;
+
+// Open a rawsock for TX or RX
+void* sendmmsgRawsockOpen(sendmmsg_rawsock_t *rawsock, const char *ifname, bool rx_mode, bool tx_mode, U16 ethertype, U32 frame_size, U32 num_frames);
+
+// Close the rawsock
+void sendmmsgRawsockClose(void *pvRawsock);
+
+// Get a buffer from the simple to use for TX
+U8* sendmmsgRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len);
+
+// Set the Firewall MARK on the socket
+// The mark is used by FQTSS to identify AVTP packets in kernel.
+// FQTSS creates a mark that includes the AVB class and stream index.
+bool sendmmsgRawsockTxSetMark(void *pvRawsock, int mark);
+
+// Pre-set the ethernet header information that will be used on TX frames
+bool sendmmsgRawsockTxSetHdr(void *pvRawsock, hdr_info_t *pHdr);
+
+// Release a TX frame, and mark it as ready to send
+bool sendmmsgRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec);
+
+// Send all packets that are ready (i.e. tell kernel to send them)
+int sendmmsgRawsockSend(void *pvRawsock);
+
+// Get a RX frame
+U8* sendmmsgRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len);
+
+// Setup the rawsock to receive multicast packets
+bool sendmmsgRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[ETH_ALEN]);
+
+// Get the socket used for this rawsock; can be used for poll/select
+int sendmmsgRawsockGetSocket(void *pvRawsock);
+
+#endif
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.c b/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.c
index 644a6011..c903ae43 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.c
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -54,7 +55,7 @@ bool simpleAvbCheckInterface(const char *ifname, if_info_t *info)
memset(info, 0, sizeof(if_info_t));
AVB_LOGF_DEBUG("ifname=%s", ifname);
- strncpy(info->name, ifname, IFNAMSIZ - 1);
+ strncpy(info->name, ifname, sizeof(info->name) - 1);
// open a throw-away socket - used for our ioctls
int sk = socket(AF_INET, SOCK_STREAM, 0);
@@ -137,7 +138,7 @@ void* simpleRawsockOpen(simple_rawsock_t* rawsock, const char *ifname, bool rx_m
// Get info about the network device
if (!simpleAvbCheckInterface(ifname, &(rawsock->base.ifInfo))) {
AVB_LOGF_ERROR("Creating rawsock; bad interface name: %s", ifname);
- free(rawsock);
+ simpleRawsockClose(rawsock);
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
return NULL;
}
@@ -149,7 +150,7 @@ void* simpleRawsockOpen(simple_rawsock_t* rawsock, const char *ifname, bool rx_m
}
else if (rawsock->base.frameSize > rawsock->base.ifInfo.mtu + ETH_HLEN + VLAN_HLEN) {
AVB_LOG_ERROR("Creating raswsock; requested frame size exceeds MTU");
- free(rawsock);
+ simpleRawsockClose(rawsock);
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
return NULL;
}
@@ -201,9 +202,12 @@ void* simpleRawsockOpen(simple_rawsock_t* rawsock, const char *ifname, bool rx_m
cb->txSetMark = simpleRawsockTxSetMark;
cb->txSetHdr = simpleRawsockTxSetHdr;
cb->txFrameReady = simpleRawsockTxFrameReady;
+ cb->send = simpleRawsockSend;
cb->getRxFrame = simpleRawsockGetRxFrame;
cb->rxMulticast = simpleRawsockRxMulticast;
+ cb->rxAVTPSubtype = simpleRawsockRxAVTPSubtype;
cb->getSocket = simpleRawsockGetSocket;
+ cb->relRxFrame = simpleRawsockRelRxFrame;
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
return rawsock;
@@ -327,6 +331,17 @@ bool simpleRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U
return TRUE;
}
+// Send all packets that are ready (i.e. tell kernel to send them)
+int simpleRawsockSend(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+
+ // simpleRawsock sends frames in simpleRawsockTxFrameReady
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return 1;
+}
+
// Get a RX frame
U8* simpleRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len)
{
@@ -343,10 +358,23 @@ U8* simpleRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset,
// return NULL;
// }
+ *offset = 0;
+ *len = 0;
+
+ // Wait until a packet is available, or a timeout occurs.
+ struct timeval tv_timeout = { timeout / MICROSECONDS_PER_SECOND, timeout % MICROSECONDS_PER_SECOND };
+ fd_set readfds;
+ FD_ZERO( &readfds );
+ FD_SET( rawsock->sock, &readfds );
+ int err = select( rawsock->sock + 1, &readfds, NULL, NULL, &tv_timeout );
+ if (err <= 0) {
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+
int flags = 0;
U8 *pBuffer = rawsock->rxBuffer;
- *offset = 0;
*len = recv(rawsock->sock, pBuffer, rawsock->base.frameSize, flags);
if (*len == -1) {
@@ -396,8 +424,8 @@ bool simpleRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 add
// In addition to adding the multicast membership, we also want to
// add a packet filter to restrict the packets that we'll receive
- // on this socket. Multicast memeberships are global - not
- // per-socket, so without the filter, this socket would receieve
+ // on this socket. Multicast memberships are global - not
+ // per-socket, so without the filter, this socket would receive
// packets for all the multicast addresses added by all other
// sockets.
//
@@ -445,6 +473,11 @@ bool simpleRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 add
return TRUE;
}
+bool simpleRawsockRxAVTPSubtype(void *rawsock, U8 subtype)
+{
+ return true; //TODO: implement as BPF to improve performance
+}
+
// Get the socket used for this rawsock; can be used for poll/select
int simpleRawsockGetSocket(void *pvRawsock)
{
@@ -459,3 +492,8 @@ int simpleRawsockGetSocket(void *pvRawsock)
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
return rawsock->sock;
}
+
+bool simpleRawsockRelRxFrame(void *pvRawsock, U8 *pFrame)
+{
+ return true;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.h b/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.h
index 48b9003b..2bbf8649 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.h
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -70,13 +71,22 @@ bool simpleRawsockTxSetHdr(void *pvRawsock, hdr_info_t *pHdr);
// Release a TX frame, and mark it as ready to send
bool simpleRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec);
+// Send all packets that are ready (i.e. tell kernel to send them)
+int simpleRawsockSend(void *pvRawsock);
+
// Get a RX frame
U8* simpleRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len);
// Setup the rawsock to receive multicast packets
bool simpleRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[ETH_ALEN]);
+// Allows for filtering of AVTP subtypes at the rawsock level for rawsock implementations that aren't able to
+// delivery the same packet to multiple sockets.
+bool simpleRawsockRxAVTPSubtype(void *rawsock, U8 subtype);
+
// Get the socket used for this rawsock; can be used for poll/select
int simpleRawsockGetSocket(void *pvRawsock);
+bool simpleRawsockRelRxFrame(void *pvRawsock, U8 *pFrame);
+
#endif
diff --git a/lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c b/lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c
index ed7b78f3..8f3cf82b 100644
--- a/lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c
+++ b/lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -48,6 +49,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_rawsock.h"
#include "openavb_mediaq.h"
#include "openavb_tl.h"
+#include "openavb_avtp.h"
#define AVB_LOG_COMPONENT "Talker / Listener"
#include "openavb_log.h"
@@ -61,7 +63,7 @@ typedef struct {
openavb_tl_cfg_name_value_t *pNVCfg;
} parse_ini_data_t;
-bool parse_mac(const char *str, cfg_mac_t *mac)
+static bool parse_mac(const char *str, cfg_mac_t *mac)
{
memset(&mac->buffer, 0, sizeof(struct ether_addr));
@@ -173,6 +175,16 @@ static int openavbTLCfgCallback(void *user, const char *tlSection, const char *n
valOK = TRUE;
}
}
+ else if (MATCH(name, "initial_state")) {
+ if (MATCH(value, "running")) {
+ pCfg->initial_state = TL_INIT_STATE_RUNNING;
+ valOK = TRUE;
+ }
+ else if (MATCH(value, "stopped")) {
+ pCfg->initial_state = TL_INIT_STATE_STOPPED;
+ valOK = TRUE;
+ }
+ }
else if (MATCH(name, "dest_addr")) {
valOK = parse_mac(value, &pCfg->dest_addr);
}
@@ -283,6 +295,14 @@ static int openavbTLCfgCallback(void *user, const char *tlSection, const char *n
&& pCfg->report_seconds <= INT32_MAX)
valOK = TRUE;
}
+ else if (MATCH(name, "report_frames")) {
+ errno = 0;
+ pCfg->report_frames = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && (int)pCfg->report_frames >= 0
+ && pCfg->report_frames <= INT32_MAX)
+ valOK = TRUE;
+ }
else if (MATCH(name, "start_paused")) {
// ignore this item - tl_host doesn't use it because
// it pauses before reading any of its streams.
@@ -297,7 +317,7 @@ static int openavbTLCfgCallback(void *user, const char *tlSection, const char *n
}
}
else if (MATCH(name, "ifname")) {
- strncpy(pCfg->ifname, value, IFNAMSIZ - 1);
+ strncpy(pCfg->ifname, value, sizeof(pCfg->ifname) - 1);
valOK = TRUE;
}
else if (MATCH(name, "vlan_id")) {
@@ -321,6 +341,15 @@ static int openavbTLCfgCallback(void *user, const char *tlSection, const char *n
valOK = TRUE;
}
}
+ else if (MATCH(name, "spin_wait")) {
+ errno = 0;
+ long tmp;
+ tmp = strtol(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0) {
+ pCfg->spin_wait = (tmp == 1);
+ valOK = TRUE;
+ }
+ }
else if (MATCH(name, "tx_blocking_in_intf")) {
errno = 0;
long tmp;
@@ -349,6 +378,11 @@ static int openavbTLCfgCallback(void *user, const char *tlSection, const char *n
}
}
+ else if (MATCH(name, "friendly_name")) {
+ strncpy(pCfg->friendly_name, value, FRIENDLY_NAME_SIZE - 1);
+ valOK = TRUE;
+ }
+
else if (MATCH(name, "map_lib")) {
if (pTLState->mapLib.libName)
free(pTLState->mapLib.libName);
@@ -405,12 +439,14 @@ static int openavbTLCfgCallback(void *user, const char *tlSection, const char *n
else {
// unmatched item, fail
AVB_LOGF_ERROR("Unrecognized configuration item: name=%s", name);
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
return 0;
}
if (!valOK) {
// bad value
AVB_LOGF_ERROR("Invalid value: name=%s, value=%s", name, value);
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
return 0;
}
@@ -425,9 +461,6 @@ bool openavbTLThreadFnOsal(tl_state_t *pTLState)
}
-
-
-
EXTERN_DLL_EXPORT bool openavbTLReadIniFileOsal(tl_handle_t TLhandle, const char *fileName, openavb_tl_cfg_t *pCfg, openavb_tl_cfg_name_value_t *pNVCfg)
{
AVB_TRACE_ENTRY(AVB_TRACE_TL);
@@ -437,23 +470,62 @@ EXTERN_DLL_EXPORT bool openavbTLReadIniFileOsal(tl_handle_t TLhandle, const char
parseIniData.pCfg = pCfg;
parseIniData.pNVCfg = pNVCfg;
+ // Use the .INI file name as the default friendly name.
+ strncpy(parseIniData.pCfg->friendly_name, fileName, FRIENDLY_NAME_SIZE - 1);
+ char * pszComma = strchr(parseIniData.pCfg->friendly_name, ',');
+ if (pszComma) {
+ // Get rid of anything following the file name.
+ *pszComma = '\0';
+ }
+ char * pszExtension = strrchr(parseIniData.pCfg->friendly_name, '.');
+ if (pszExtension && strcasecmp(pszExtension, ".ini") == 0) {
+ // Get rid of the .INI file extension.
+ *pszExtension = '\0';
+ }
+
int result = ini_parse(fileName, openavbTLCfgCallback, &parseIniData);
if (result == 0) {
if_info_t ifinfo;
- if (!openavbCheckInterface(parseIniData.pCfg->ifname, &ifinfo)) {
+ if (pCfg->ifname[0] && !openavbCheckInterface(parseIniData.pCfg->ifname, &ifinfo)) {
AVB_LOGF_ERROR("Invalid value: name=%s, value=%s", "ifname", parseIniData.pCfg->ifname);
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
return FALSE;
}
}
if (result < 0) {
AVB_LOGF_ERROR("Couldn't parse INI file: %s", fileName);
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
return FALSE;
}
if (result > 0) {
AVB_LOGF_ERROR("Error in INI file: %s, line %d", fileName, result);
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
return FALSE;
}
+ // For a Talker, use the adapter MAC Address as the stream address when one was not supplied.
+ if (parseIniData.pCfg->role == AVB_ROLE_TALKER &&
+ (!parseIniData.pCfg->stream_addr.mac || memcmp(parseIniData.pCfg->stream_addr.mac, "\x00\x00\x00\x00\x00\x00", 6) == 0))
+ {
+ // Open a rawsock may be the easiest cross platform way to get the MAC address.
+ void *txSock = openavbRawsockOpen(parseIniData.pCfg->ifname, FALSE, TRUE, ETHERTYPE_AVTP, 100, 1);
+ if (txSock) {
+ if (openavbRawsockGetAddr(txSock, parseIniData.pCfg->stream_addr.buffer.ether_addr_octet)) {
+ parseIniData.pCfg->stream_addr.mac = &(parseIniData.pCfg->stream_addr.buffer); // Indicate that the MAC Address is valid.
+ }
+ openavbRawsockClose(txSock);
+ txSock = NULL;
+ }
+
+ if (!parseIniData.pCfg->stream_addr.mac || memcmp(parseIniData.pCfg->stream_addr.mac, "\x00\x00\x00\x00\x00\x00", 6) == 0) {
+ AVB_LOG_ERROR("stream_addr required, but not specified.");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+ AVB_LOGF_DEBUG("Detected stream_addr: " ETH_FORMAT,
+ ETH_OCTETS(parseIniData.pCfg->stream_addr.buffer.ether_addr_octet));
+ }
+
AVB_TRACE_EXIT(AVB_TRACE_TL);
return TRUE;
}
@@ -465,12 +537,14 @@ bool openavbTLOpenLinkLibsOsal(tl_state_t *pTLState)
if (!pTLState->cfg.pMapInitFn) {
if (!openMapLib(pTLState)) {
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
return FALSE;
}
}
if (!pTLState->cfg.pIntfInitFn) {
if (!openIntfLib(pTLState)) {
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
return FALSE;
}
}
diff --git a/lib/avtp_pipeline/platform/Linux/x86_i210_linux.cmake b/lib/avtp_pipeline/platform/Linux/x86_i210_linux.cmake
index ae9ce67a..48e62223 100644
--- a/lib/avtp_pipeline/platform/Linux/x86_i210_linux.cmake
+++ b/lib/avtp_pipeline/platform/Linux/x86_i210_linux.cmake
@@ -1,3 +1,16 @@
+
+if (AVB_FEATURE_AVDECC)
+ set ( AVB_FEATURE_GSTREAMER 0 )
+ set ( AVB_FEATURE_PCAP 0 )
+ set ( AVB_FEATURE_IGB 0 )
+else ()
+ set ( AVB_FEATURE_PCAP 1 )
+ set ( AVB_FEATURE_IGB 1 )
+
+ set ( GSTREAMER_1_0 0 )
+endif ()
+
+
# and another kernel sources
#set ( LINUX_KERNEL_DIR "/usr/src/kernel" )
@@ -8,26 +21,30 @@ set ( OPENAVB_TCAL "GNU" )
set ( OPENAVB_PLATFORM "${OPENAVB_HAL}-${OPENAVB_OSAL}" )
# Platform Additions
-set ( PLATFORM_INCLUDE_DIRECTORIES
- ${CMAKE_SOURCE_DIR}/platform/x86_i210/include
- ${CMAKE_SOURCE_DIR}/../igb
+set ( PLATFORM_INCLUDE_DIRECTORIES
+ ${CMAKE_SOURCE_DIR}/platform/x86_i210/include
+if (AVB_FEATURE_IGB)
+ ${CMAKE_SOURCE_DIR}/../igb
+endif ()
${CMAKE_SOURCE_DIR}/openavb_common
${CMAKE_SOURCE_DIR}/../../daemons/common
${CMAKE_SOURCE_DIR}/../../daemons/mrpd
+ ${CMAKE_SOURCE_DIR}/../../daemons/maap/common
)
-set ( PLATFORM_LINK_DIRECTORIES
- ${CMAKE_SOURCE_DIR}/../igb
-)
-
-set ( PLATFORM_LINK_LIBRARIES
- igb
-)
+if (AVB_FEATURE_IGB)
+ set ( PLATFORM_LINK_DIRECTORIES
+ ${CMAKE_SOURCE_DIR}/../igb
+ )
+endif ()
+if (AVB_FEATURE_IGB)
+ set ( PLATFORM_LINK_LIBRARIES
+ igb
+ pci
+ )
+endif ()
# TODO_OPENAVB : need this?
# Set platform specific define
#set ( PLATFORM_DEFINE "AVB_DELAY_TWEAK_USEC=15" )
-
-set ( GSTREAMER_1_0 0 )
-set ( AVB_FEATURE_PCAP 1 )