summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandrew-elder <aelder@audioscience.com>2017-10-07 16:33:38 -0400
committerGitHub <noreply@github.com>2017-10-07 16:33:38 -0400
commit21422721301a409209f9dbb04d0c102a2e072b7a (patch)
treea17c45107028ff33055aefa25e14e5bc195e5ff1
parentbffc91619ffff1990d81e7326d7d5879a705f523 (diff)
parent67cee412de055c7a49a8e37f1ee870269d3f5abb (diff)
downloadOpen-AVB-feature-appveyor.tar.gz
Merge pull request #701 from andrew-elder/feature/appveyorfeature-appveyor
appveyor - working
-rw-r--r--.gitignore1
-rw-r--r--.gitmodules2
-rw-r--r--.travis.yml12
-rw-r--r--CMakeLists.txt36
-rw-r--r--Makefile28
-rw-r--r--appveyor.yml24
-rw-r--r--daemons/gptp/CMakeLists.txt12
-rw-r--r--daemons/gptp/common/common_port.cpp13
-rw-r--r--daemons/gptp/common/common_port.hpp26
-rw-r--r--daemons/gptp/common/ether_port.cpp9
-rw-r--r--daemons/gptp/common/ether_port.hpp16
-rw-r--r--daemons/gptp/common/gptp_cfg.cpp2
-rw-r--r--daemons/maap/common/maap_log.h10
-rw-r--r--daemons/maap/linux/src/maap_helper_linux.h2
-rw-r--r--daemons/maap/windows/src/maap_main.c29
-rw-r--r--daemons/mrpd/mrpctl.c6
-rw-r--r--daemons/shaper/LICENSE25
-rw-r--r--daemons/shaper/Makefile37
-rw-r--r--daemons/shaper/README.rst38
-rw-r--r--daemons/shaper/src/platform.h74
-rw-r--r--daemons/shaper/src/shaper_daemon.c986
-rw-r--r--daemons/shaper/src/shaper_helper_linux.h182
-rw-r--r--daemons/shaper/src/shaper_log.h267
-rw-r--r--daemons/shaper/src/shaper_log_linux.c445
-rw-r--r--daemons/shaper/src/shaper_log_queue.c200
-rw-r--r--daemons/shaper/src/shaper_log_queue.h78
-rw-r--r--kmod/igb/igb_main.c22
-rw-r--r--lib/avtp_pipeline/LICENSE15
-rw-r--r--lib/avtp_pipeline/README.md38
-rw-r--r--lib/avtp_pipeline/acmp/CMakeLists.txt9
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp.c147
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp.h195
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp_message.c424
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp_message.h50
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp_pub.h42
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp_sm_controller.c435
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp_sm_controller.h67
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp_sm_listener.c982
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp_sm_listener.h94
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp_sm_talker.c682
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp_sm_talker.h76
-rw-r--r--lib/avtp_pipeline/adp/CMakeLists.txt9
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp.c181
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp.h93
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp_message.c464
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp_message.h50
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp_pub.h90
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp_sm_advertise_entity.c252
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp_sm_advertise_entity.h63
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp_sm_advertise_interface.c341
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp_sm_advertise_interface.h73
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp_sm_discovery.c45
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp_sm_discovery.h48
-rw-r--r--lib/avtp_pipeline/aecp/CMakeLists.txt8
-rw-r--r--lib/avtp_pipeline/aecp/openavb_aecp.c98
-rw-r--r--lib/avtp_pipeline/aecp/openavb_aecp.h408
-rw-r--r--lib/avtp_pipeline/aecp/openavb_aecp_cmd_get_counters.c223
-rw-r--r--lib/avtp_pipeline/aecp/openavb_aecp_cmd_get_counters.h103
-rw-r--r--lib/avtp_pipeline/aecp/openavb_aecp_message.c1049
-rw-r--r--lib/avtp_pipeline/aecp/openavb_aecp_message.h50
-rw-r--r--lib/avtp_pipeline/aecp/openavb_aecp_pub.h42
-rw-r--r--lib/avtp_pipeline/aecp/openavb_aecp_sm_entity_model_entity.c1378
-rw-r--r--lib/avtp_pipeline/aecp/openavb_aecp_sm_entity_model_entity.h71
-rw-r--r--lib/avtp_pipeline/aem/CMakeLists.txt21
-rw-r--r--lib/avtp_pipeline/aem/openavb_aem.c534
-rw-r--r--lib/avtp_pipeline/aem/openavb_aem.h103
-rw-r--r--lib/avtp_pipeline/aem/openavb_aem_pub.h80
-rw-r--r--lib/avtp_pipeline/aem/openavb_aem_types_pub.h1339
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster.c179
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster_pub.h65
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_audio_map.c180
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_audio_map.h47
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_audio_map_pub.h69
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_audio_unit.c297
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_audio_unit.h47
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_audio_unit_pub.h99
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_avb_interface.c244
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_avb_interface.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_avb_interface_pub.h73
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_clock_domain.c209
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_clock_domain.h47
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_clock_domain_pub.h66
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_clock_source.c205
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_clock_source.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_clock_source_pub.h65
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_configuration.c197
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_configuration.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_configuration_pub.h70
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_control.c502
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_control.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_control_pub.h111
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_entity.c411
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_entity.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_entity_pub.h108
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_external_port_io.c209
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_external_port_io.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_external_port_io_pub.h66
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_jack_io.c235
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_jack_io.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_jack_io_pub.h66
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_locale.c208
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_locale.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_locale_pub.h69
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler.c230
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler.h44
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler_pub.h91
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_stream_io.c572
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_stream_io.h47
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_stream_io_pub.h111
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io.c207
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io_pub.h65
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_strings.c193
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_strings.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_strings_pub.h65
-rw-r--r--lib/avtp_pipeline/avdecc/CMakeLists.txt12
-rw-r--r--lib/avtp_pipeline/avdecc/avdecc.ini82
-rw-r--r--lib/avtp_pipeline/avdecc/openavb_avdecc.c509
-rw-r--r--lib/avtp_pipeline/avdecc/openavb_avdecc.h210
-rw-r--r--lib/avtp_pipeline/avdecc/openavb_avdecc_pipeline_interaction_pub.h71
-rw-r--r--lib/avtp_pipeline/avdecc/openavb_avdecc_pub.h145
-rw-r--r--lib/avtp_pipeline/avdecc/openavb_avdecc_read_ini_pub.h197
-rwxr-xr-xlib/avtp_pipeline/avdecc/shutdown_openavb_avdecc.sh18
-rw-r--r--lib/avtp_pipeline/avdecc_msg/CMakeLists.txt2
-rw-r--r--lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg.c192
-rw-r--r--lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg.h216
-rw-r--r--lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_client.c723
-rw-r--r--lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_client.h60
-rw-r--r--lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.c470
-rw-r--r--lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.h57
-rw-r--r--lib/avtp_pipeline/avtp/openavb_avtp.c76
-rw-r--r--lib/avtp_pipeline/avtp/openavb_avtp.h6
-rw-r--r--lib/avtp_pipeline/avtp/openavb_avtp_time.c1
-rw-r--r--lib/avtp_pipeline/avtp/openavb_avtp_time_pub.h1
-rw-r--r--lib/avtp_pipeline/avtp_avdecc.mk23
-rw-r--r--lib/avtp_pipeline/avtp_pipeline.mk2
-rw-r--r--lib/avtp_pipeline/documents/sdk_avtp_interface_module_dev.md7
-rw-r--r--lib/avtp_pipeline/documents/sdk_avtp_stream_cfg.md163
-rw-r--r--lib/avtp_pipeline/documents/sdk_eavb_integration.md2
-rw-r--r--lib/avtp_pipeline/documents/sdk_notes_media_queue_usage.md6
-rw-r--r--lib/avtp_pipeline/documents/sdk_overview.md17
-rw-r--r--lib/avtp_pipeline/endpoint/CMakeLists.txt4
-rw-r--r--lib/avtp_pipeline/endpoint/endpoint.ini29
-rw-r--r--lib/avtp_pipeline/endpoint/openavb_endpoint.c60
-rw-r--r--lib/avtp_pipeline/endpoint/openavb_endpoint.h46
-rw-r--r--lib/avtp_pipeline/endpoint/openavb_endpoint_client.c35
-rw-r--r--lib/avtp_pipeline/endpoint/openavb_endpoint_server.c79
-rw-r--r--lib/avtp_pipeline/include/avb_sched.h1
-rw-r--r--lib/avtp_pipeline/include/openavb_audio_pub.h17
-rwxr-xr-xlib/avtp_pipeline/include/openavb_intf_pub.h28
-rw-r--r--lib/avtp_pipeline/include/openavb_log.h1
-rw-r--r--lib/avtp_pipeline/include/openavb_log_pub.h80
-rwxr-xr-xlib/avtp_pipeline/include/openavb_map_pub.h19
-rw-r--r--lib/avtp_pipeline/include/openavb_platform.h1
-rw-r--r--lib/avtp_pipeline/include/openavb_platform_pub.h1
-rw-r--r--lib/avtp_pipeline/include/openavb_pub.h13
-rw-r--r--lib/avtp_pipeline/include/openavb_trace.h1
-rw-r--r--lib/avtp_pipeline/include/openavb_trace_pub.h1
-rw-r--r--lib/avtp_pipeline/include/openavb_types.h1
-rw-r--r--lib/avtp_pipeline/include/openavb_types_base.h1
-rw-r--r--lib/avtp_pipeline/include/openavb_types_base_pub.h1
-rw-r--r--lib/avtp_pipeline/include/openavb_types_pub.h1
-rw-r--r--lib/avtp_pipeline/inih/ini.c12
-rw-r--r--lib/avtp_pipeline/intf_ctrl/ctrl_listener.ini6
-rw-r--r--lib/avtp_pipeline/intf_ctrl/ctrl_mux_listener.ini6
-rw-r--r--lib/avtp_pipeline/intf_ctrl/ctrl_mux_talker.ini6
-rw-r--r--lib/avtp_pipeline/intf_ctrl/ctrl_talker.ini6
-rwxr-xr-xlib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl.c1
-rwxr-xr-xlib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl_pub.h1
-rw-r--r--lib/avtp_pipeline/intf_echo/echo_listener.ini6
-rw-r--r--lib/avtp_pipeline/intf_echo/echo_listener_auto.ini6
-rw-r--r--lib/avtp_pipeline/intf_echo/echo_talker.ini6
-rw-r--r--lib/avtp_pipeline/intf_echo/echo_talker_auto.ini6
-rwxr-xr-xlib/avtp_pipeline/intf_echo/openavb_intf_echo.c3
-rw-r--r--lib/avtp_pipeline/intf_logger/openavb_intf_logger.c1
-rw-r--r--lib/avtp_pipeline/intf_null/null_listener.ini6
-rw-r--r--lib/avtp_pipeline/intf_null/null_talker.ini6
-rwxr-xr-xlib/avtp_pipeline/intf_null/openavb_intf_null.c1
-rw-r--r--lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.c94
-rw-r--r--lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.md22
-rw-r--r--lib/avtp_pipeline/intf_tonegen/tonegen_talker.ini8
-rw-r--r--lib/avtp_pipeline/intf_tonegen/tonegen_talker_lowlatency.ini8
-rw-r--r--lib/avtp_pipeline/intf_viewer/latency_listener.ini6
-rw-r--r--lib/avtp_pipeline/intf_viewer/latency_talker.ini6
-rwxr-xr-xlib/avtp_pipeline/intf_viewer/openavb_intf_viewer.c1
-rw-r--r--lib/avtp_pipeline/intf_viewer/viewer_listener.ini6
-rw-r--r--lib/avtp_pipeline/maap/openavb_maap.h27
-rwxr-xr-xlib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c296
-rwxr-xr-xlib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio_pub.h17
-rwxr-xr-xlib/avtp_pipeline/map_ctrl/openavb_map_ctrl.c1
-rwxr-xr-xlib/avtp_pipeline/map_ctrl/openavb_map_ctrl_pub.h1
-rwxr-xr-xlib/avtp_pipeline/map_h264/openavb_map_h264.c1
-rwxr-xr-xlib/avtp_pipeline/map_h264/openavb_map_h264_pub.h1
-rwxr-xr-xlib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg.c1
-rwxr-xr-xlib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg_pub.h1
-rw-r--r--lib/avtp_pipeline/map_mpeg2ts/demo_listener.ini6
-rw-r--r--lib/avtp_pipeline/map_mpeg2ts/demo_talker.ini6
-rwxr-xr-xlib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts.c1
-rwxr-xr-xlib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts_pub.h1
-rw-r--r--lib/avtp_pipeline/map_mpeg2ts/ts_packet_size.c1
-rwxr-xr-xlib/avtp_pipeline/map_null/openavb_map_null.c1
-rwxr-xr-xlib/avtp_pipeline/map_null/openavb_map_null_pub.h1
-rwxr-xr-xlib/avtp_pipeline/map_pipe/openavb_map_pipe.c3
-rwxr-xr-xlib/avtp_pipeline/map_pipe/openavb_map_pipe_pub.h1
-rwxr-xr-xlib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio.c64
-rwxr-xr-xlib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio_pub.h41
-rw-r--r--lib/avtp_pipeline/map_uncmp_audio/uncmp_audio_map.md2
-rw-r--r--lib/avtp_pipeline/mcr/openavb_mcr_hal_pub.h1
-rw-r--r--lib/avtp_pipeline/mcs/openavb_mcs.c56
-rw-r--r--lib/avtp_pipeline/mcs/openavb_mcs.h20
-rw-r--r--lib/avtp_pipeline/mediaq/openavb_mediaq.c79
-rw-r--r--lib/avtp_pipeline/mediaq/openavb_mediaq.h1
-rw-r--r--lib/avtp_pipeline/mediaq/openavb_mediaq_pub.h27
-rw-r--r--lib/avtp_pipeline/openavb_common/mrp_client.c391
-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
-rw-r--r--lib/avtp_pipeline/platform/generic/mcr/openavb_mcr_hal.c1
-rw-r--r--lib/avtp_pipeline/platform/generic/mcr/openavb_mcr_hal.h1
-rw-r--r--lib/avtp_pipeline/platform/generic/openavb_hal.h1
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.c1
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.h1
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal_pub.h1
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_tcal_pub.h1
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_time_tcal_pub.h1
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_types_base_tcal_pub.h1
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_warnings_tcal.h1
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/rawsock/openavb_rawsock_tcal.h1
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.c1
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.h1
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/openavb_hal.h1
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/openavb_igb.c3
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/openavb_igb.h1
-rw-r--r--lib/avtp_pipeline/qmgr/openavb_qmgr.c22
-rw-r--r--lib/avtp_pipeline/qmgr/openavb_qmgr.h1
-rw-r--r--lib/avtp_pipeline/rawsock/CMakeLists.txt1
-rw-r--r--lib/avtp_pipeline/rawsock/openavb_rawsock.h2
-rw-r--r--lib/avtp_pipeline/rawsock/rawsock_impl.c23
-rw-r--r--lib/avtp_pipeline/rawsock/rawsock_impl.h1
-rw-r--r--lib/avtp_pipeline/shaper/openavb_shaper.h49
-rwxr-xr-xlib/avtp_pipeline/srp/openavb_srp.h21
-rwxr-xr-xlib/avtp_pipeline/srp/openavb_srp_api.h7
-rw-r--r--lib/avtp_pipeline/tl/CMakeLists.txt1
-rw-r--r--lib/avtp_pipeline/tl/openavb_listener.c88
-rw-r--r--lib/avtp_pipeline/tl/openavb_listener.h4
-rw-r--r--lib/avtp_pipeline/tl/openavb_listener_endpoint.c39
-rw-r--r--lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c19
-rw-r--r--lib/avtp_pipeline/tl/openavb_talker.c92
-rw-r--r--lib/avtp_pipeline/tl/openavb_talker.h21
-rw-r--r--lib/avtp_pipeline/tl/openavb_talker_endpoint.c68
-rw-r--r--lib/avtp_pipeline/tl/openavb_talker_no_endpoint.c52
-rwxr-xr-xlib/avtp_pipeline/tl/openavb_tl.c93
-rwxr-xr-xlib/avtp_pipeline/tl/openavb_tl.h31
-rw-r--r--lib/avtp_pipeline/tl/openavb_tl_endpoint.c126
-rw-r--r--lib/avtp_pipeline/tl/openavb_tl_no_endpoint.c3
-rwxr-xr-xlib/avtp_pipeline/tl/openavb_tl_pub.h86
-rw-r--r--lib/avtp_pipeline/util/openavb_array.c1
-rw-r--r--lib/avtp_pipeline/util/openavb_array.h1
-rw-r--r--lib/avtp_pipeline/util/openavb_debug.c1
-rw-r--r--lib/avtp_pipeline/util/openavb_debug.h1
-rw-r--r--lib/avtp_pipeline/util/openavb_list.c1
-rw-r--r--lib/avtp_pipeline/util/openavb_list.h21
-rw-r--r--lib/avtp_pipeline/util/openavb_log.c263
-rw-r--r--lib/avtp_pipeline/util/openavb_plugin.c1
-rw-r--r--lib/avtp_pipeline/util/openavb_plugin.h1
-rw-r--r--lib/avtp_pipeline/util/openavb_printbuf.c1
-rw-r--r--lib/avtp_pipeline/util/openavb_printbuf.h1
-rw-r--r--lib/avtp_pipeline/util/openavb_queue.c1
-rw-r--r--lib/avtp_pipeline/util/openavb_queue.h1
-rwxr-xr-xlib/avtp_pipeline/util/openavb_result_codes.c2
-rw-r--r--lib/avtp_pipeline/util/openavb_result_codes.h14
-rw-r--r--lib/avtp_pipeline/util/openavb_time.c32
-rw-r--r--lib/avtp_pipeline/util/openavb_time.h5
-rw-r--r--lib/avtp_pipeline/util/openavb_timestamp.c1
-rw-r--r--lib/avtp_pipeline/util/openavb_timestamp.h1
-rw-r--r--lib/igb/igb.c12
-rwxr-xr-xrun_maap.sh10
-rwxr-xr-xrun_shaper.sh4
-rwxr-xr-xrun_srp.sh2
m---------thirdparty/cpputest0
-rwxr-xr-xtravis.sh1
368 files changed, 30704 insertions, 2227 deletions
diff --git a/.gitignore b/.gitignore
index e2c8c5fb..d328bdcc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
*.o
*.swp
*build/
+*build_avdecc/
*CMakeFiles/
CMakeCache.txt
diff --git a/.gitmodules b/.gitmodules
index 3254bb8a..6494de60 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,6 @@
[submodule "thirdparty/cpputest"]
path = thirdparty/cpputest
- url = ../../cpputest/cpputest.git
+ url = ../../AVnu/cpputest.git
[submodule "avdecc-lib"]
path = avdecc-lib
url = ../../AVnu/avdecc-lib
diff --git a/.travis.yml b/.travis.yml
index a8749dac..ecc2b9d6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -23,20 +23,16 @@ compiler:
- gcc
env:
- BUILD_KERNEL=4.4.0-75-generic
- - DEPS_DIR=${TRAVIS_BUILD_DIR}/deps
install:
- sudo apt-get update -qq
- sudo apt-get install -y libpcap-dev libpci-dev libsndfile1-dev libjack-dev linux-headers-4.4.0-75-generic
- sudo apt-get install -y libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev libasound2-dev
- sudo cp /usr/src/linux-headers-4.4.0-75/include/uapi/linux/ethtool.h /usr/include/linux
- sudo cp /usr/src/linux-headers-4.4.0-75/include/uapi/linux/ptp_clock.h /usr/include/linux
- - |
- if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then
- CMAKE_URL="http://www.cmake.org/files/v3.4/cmake-3.4.3-Linux-x86_64.tar.gz"
- mkdir -p ${DEPS_DIR}/cmake
- travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C ${DEPS_DIR}/cmake
- export PATH=${DEPS_DIR}/cmake/bin:${PATH}
- fi
+ - CMAKE_URL="https://cmake.org/files/v3.9/cmake-3.9.4-Linux-x86_64.tar.gz"
+ - mkdir -p ${TRAVIS_BUILD_DIR}/deps/cmake
+ - travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C ${TRAVIS_BUILD_DIR}/deps/cmake
+ - export PATH=${TRAVIS_BUILD_DIR}/deps/cmake/bin:${PATH}
script: ./travis.sh
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a9244229..eccb62eb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,9 +2,43 @@ cmake_minimum_required (VERSION 2.8)
project (open-avb)
enable_testing()
-set(C++11 ON CACHE BOOL "Compile with C++11 support" FORCE)
+include(CheckCXXCompilerFlag)
+CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
+CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
+if(COMPILER_SUPPORTS_CXX11)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+elseif(COMPILER_SUPPORTS_CXX0X)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
+else()
+ message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
+endif()
+
add_subdirectory("thirdparty/cpputest")
add_subdirectory("daemons/common/tests")
add_subdirectory("daemons/mrpd")
add_subdirectory("daemons/maap")
add_subdirectory("daemons/gptp")
+
+message("
+-------------------------------------------------------
+OpenAvnu Build information
+
+Current compiler options:
+ CC: ${CMAKE_C_COMPILER}
+ CXX: ${CMAKE_CXX_COMPILER}
+ OpenAvnu CFLAGS: ${CMAKE_C_FLAGS}
+ OpenAvnu CXXFLAGS: ${CMAKE_CXX_FLAGS}
+ OpenAvnu LDFLAGS: ${CMAKE_LD_FLAGS}
+
+Features configured in OpenAvnu root CMakeFile.txt:
+ Memory Leak Detection: ${MEMORY_LEAK_DETECTION}
+ Compiling Extensions: ${EXTENSIONS}
+ Support Long Long: ${LONGLONG}
+ Use OpenAvnu flags: ${CMAKE_FLAGS}
+
+ Using Standard C library: ${STD_C}
+ Using Standard C++ library: ${STD_CPP}
+ Using C++11 library: ${C++11}
+
+-------------------------------------------------------
+")
diff --git a/Makefile b/Makefile
index 51537c1a..2a931c3a 100644
--- a/Makefile
+++ b/Makefile
@@ -9,13 +9,16 @@ help:
@echo ''
@echo ' lib - igb library'
@echo ''
- @echo ' daemons_all - build all daemons (mrpd gptp maap)'
+ @echo ' daemons_all - build all daemons (mrpd gptp maap shaper)'
@echo ' mrpd - mrpd daemon'
@echo ' gptp - gptp daemon for linux'
@echo ' maap - maap daemon'
+ @echo ' shaper - shaper daemon for linux'
@echo ''
@echo ' avtp_pipeline - AVTP pipeline'
@echo ' avtp_pipeline_doc - AVTP pipeline doc'
+ @echo ' avtp_avdecc - AVTP avdecc'
+ @echo ' avtp_avdecc_doc - AVTP avdecc doc'
@echo ''
@echo ' examples_all - build all examples (simple_talker simple_listener mrp_client live_stream jackd-talker jackd-listener)'
@echo ' simple_talker - simple_talker application'
@@ -64,9 +67,15 @@ maap:
maap_clean:
$(call descend,daemons/maap/linux/build/,clean)
-daemons_all: mrpd maap gptp
+shaper:
+ $(call descend,daemons/$@)
+
+shaper_clean:
+ $(call descend,daemons/shaper/,clean)
+
+daemons_all: mrpd maap gptp shaper
-daemons_all_clean: mrpd_clean gptp_clean maap_clean
+daemons_all_clean: mrpd_clean gptp_clean maap_clean shaper_clean
examples_common:
$(call descend,examples/common)
@@ -131,14 +140,23 @@ avtp_pipeline_clean:
avtp_pipeline_doc: lib
$(MAKE) -s -C lib/avtp_pipeline -f avtp_pipeline.mk doc
+avtp_avdecc: lib
+ $(MAKE) -s -C lib/avtp_pipeline -f avtp_avdecc.mk
+
+avtp_avdecc_clean:
+ $(MAKE) -s -C lib/avtp_pipeline -f avtp_avdecc.mk clean
+
+avtp_avdecc_doc: lib
+ $(MAKE) -s -C lib/avtp_pipeline -f avtp_avdecc.mk doc
+
examples_all: examples_common simple_talker simple_listener mrp_client live_stream jackd-talker \
jackd-listener simple_rx
examples_all_clean: examples_common_clean simple_talker_clean simple_listener_clean mrp_client_clean \
jackd-talker_clean jackd-listener_clean live_stream_clean simple_rx_clean
-all: igb lib daemons_all examples_all avtp_pipeline
+all: igb lib daemons_all examples_all avtp_pipeline avtp_avdecc
-clean: igb_clean lib_clean daemons_all_clean examples_all_clean avtp_pipeline_clean
+clean: igb_clean lib_clean daemons_all_clean examples_all_clean avtp_pipeline_clean avtp_avdecc_clean
.PHONY: FORCE
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 00000000..be1355c1
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,24 @@
+version: '1.0.{build}'
+
+clone_folder: c:\oavb
+clone_depth: 20
+
+environment:
+ # Config for mrp Windows build
+ WPCAP_DIR: c:\oavb\WpdPack
+
+install:
+ - git submodule update --init --recursive
+ # download WinPcap developer module and unzip it
+ - ps: Start-FileDownload 'https://www.winpcap.org/install/bin/WpdPack_4_1_2.zip'
+ - ps: 7z x WpdPack_4_1_2.zip
+
+before_build:
+ # cmake
+ - choco upgrade cmake
+ - set path=C:\Program Files\CMake\bin;%path%
+
+build_script:
+ - cd c:\oavb
+ - cmake CMakeLists.txt -G "Visual Studio 12 2013"
+ - cmake --build . --config Release
diff --git a/daemons/gptp/CMakeLists.txt b/daemons/gptp/CMakeLists.txt
index 4935e665..fb7d19b3 100644
--- a/daemons/gptp/CMakeLists.txt
+++ b/daemons/gptp/CMakeLists.txt
@@ -6,8 +6,16 @@ file(GLOB GPTP_COMMON "./common/*.cpp" "./common/*.c")
if(UNIX)
include_directories( include "./linux/src" )
- file(GLOB GPTP_OS "./linux/src/*.cpp")
- target_link_libraries(gptp pthread)
+ file(GLOB GPTP_OS
+ "./linux/src/daemon_cl.cpp"
+ "./linux/src/linux_ipc.cpp"
+ "./linux/src/platform.cpp"
+ "./linux/src/linux_hal_persist_file.cpp"
+ "./linux/src/linux_hal_generic.cpp"
+ "./linux/src/linux_hal_generic_adj.cpp"
+ "./linux/src/linux_hal_common.cpp")
+ add_executable (gptp ${GPTP_COMMON} ${GPTP_OS})
+ target_link_libraries(gptp pthread rt)
elseif(WIN32)
if( CMAKE_SIZEOF_VOID_P EQUAL 8 )
link_directories($ENV{WPCAP_DIR}/Lib/x64)
diff --git a/daemons/gptp/common/common_port.cpp b/daemons/gptp/common/common_port.cpp
index 512c579b..d8ba54f6 100644
--- a/daemons/gptp/common/common_port.cpp
+++ b/daemons/gptp/common/common_port.cpp
@@ -311,7 +311,7 @@ void CommonPort::stopSyncReceiptTimer( void )
void CommonPort::startSyncIntervalTimer
( long long unsigned int waitTime )
{
- syncIntervalTimerLock->lock();
+ if( syncIntervalTimerLock->trylock() == oslock_fail ) return;
clock->deleteEventTimerLocked(this, SYNC_INTERVAL_TIMEOUT_EXPIRES);
clock->addEventTimerLocked
(this, SYNC_INTERVAL_TIMEOUT_EXPIRES, waitTime);
@@ -550,7 +550,7 @@ bool CommonPort::processEvent( Event e )
// If port has been configured as master or slave, run media
// specific configuration. If it hasn't been configured
- // start announce message time
+ // start listening for announce messages
if( clock->getPriority1() == 255 ||
port_state == PTP_SLAVE )
{
@@ -562,7 +562,8 @@ bool CommonPort::processEvent( Event e )
}
else
{
- startAnnounce();
+ clock->addEventTimerLocked(this, ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES,
+ ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER * pow(2.0, getAnnounceInterval()) * 1000000000.0);
}
// Do any media specific initialization
@@ -597,13 +598,9 @@ bool CommonPort::processEvent( Event e )
case ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES:
GPTP_LOG_DEBUG("ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES occured");
- if( !asCapable )
- {
- ret = true;
- break;
- }
// Send an announce message
+ if ( asCapable)
{
PTPMessageAnnounce *annc =
new PTPMessageAnnounce(this);
diff --git a/daemons/gptp/common/common_port.hpp b/daemons/gptp/common/common_port.hpp
index 27800ad2..d5d0adda 100644
--- a/daemons/gptp/common/common_port.hpp
+++ b/daemons/gptp/common/common_port.hpp
@@ -230,16 +230,16 @@ typedef struct {
bool linkUp;
/* gPTP 10.2.4.4 */
- char initialLogSyncInterval;
+ signed char initialLogSyncInterval;
/* gPTP 11.5.2.2 */
- char initialLogPdelayReqInterval;
+ signed char initialLogPdelayReqInterval;
/* CDS 6.2.1.5 */
- char operLogPdelayReqInterval;
+ signed char operLogPdelayReqInterval;
/* CDS 6.2.1.6 */
- char operLogSyncInterval;
+ signed char operLogSyncInterval;
/* condition_factory OSConditionFactory instance */
OSConditionFactory * condition_factory;
@@ -314,9 +314,9 @@ private:
PortState port_state;
bool testMode;
- char log_mean_sync_interval;
- char log_mean_announce_interval;
- char initialLogSyncInterval;
+ signed char log_mean_sync_interval;
+ signed char log_mean_announce_interval;
+ signed char initialLogSyncInterval;
/*Sync threshold*/
unsigned int sync_receipt_thresh;
@@ -1219,7 +1219,7 @@ public:
* @brief Gets the sync interval value
* @return Sync Interval
*/
- char getSyncInterval( void )
+ signed char getSyncInterval( void )
{
return log_mean_sync_interval;
}
@@ -1229,7 +1229,7 @@ public:
* @param val time interval
* @return none
*/
- void setSyncInterval( char val )
+ void setSyncInterval( signed char val )
{
log_mean_sync_interval = val;
}
@@ -1247,7 +1247,7 @@ public:
* @brief Sets the sync interval
* @return none
*/
- void setInitSyncInterval( char interval )
+ void setInitSyncInterval( signed char interval )
{
initialLogSyncInterval = interval;
}
@@ -1256,7 +1256,7 @@ public:
* @brief Gets the sync interval
* @return sync interval
*/
- char getInitSyncInterval( void )
+ signed char getInitSyncInterval( void )
{
return initialLogSyncInterval;
}
@@ -1265,7 +1265,7 @@ public:
* @brief Gets the announce interval
* @return Announce interval
*/
- char getAnnounceInterval( void ) {
+ signed char getAnnounceInterval( void ) {
return log_mean_announce_interval;
}
@@ -1274,7 +1274,7 @@ public:
* @param val time interval
* @return none
*/
- void setAnnounceInterval(char val) {
+ void setAnnounceInterval(signed char val) {
log_mean_announce_interval = val;
}
/**
diff --git a/daemons/gptp/common/ether_port.cpp b/daemons/gptp/common/ether_port.cpp
index f517c181..2325fb99 100644
--- a/daemons/gptp/common/ether_port.cpp
+++ b/daemons/gptp/common/ether_port.cpp
@@ -403,6 +403,15 @@ bool EtherPort::_processEvent( Event e )
GPTP_LOG_STATUS("LINKUP");
}
+ if( clock->getPriority1() == 255 || getPortState() == PTP_SLAVE ) {
+ becomeSlave( true );
+ } else if( getPortState() == PTP_MASTER ) {
+ becomeMaster( true );
+ } else {
+ clock->addEventTimerLocked(this, ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES,
+ ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER * pow(2.0, getAnnounceInterval()) * 1000000000.0);
+ }
+
if (automotive_profile) {
setAsCapable( true );
diff --git a/daemons/gptp/common/ether_port.hpp b/daemons/gptp/common/ether_port.hpp
index 9d621e39..32968dc4 100644
--- a/daemons/gptp/common/ether_port.hpp
+++ b/daemons/gptp/common/ether_port.hpp
@@ -96,9 +96,9 @@ class EtherPort : public CommonPort
bool linkUp;
/* Port Configuration */
- char log_mean_unicast_sync_interval;
- char log_min_mean_delay_req_interval;
- char log_min_mean_pdelay_req_interval;
+ signed char log_mean_unicast_sync_interval;
+ signed char log_min_mean_delay_req_interval;
+ signed char log_min_mean_pdelay_req_interval;
unsigned int duplicate_resp_counter;
uint16_t last_invalid_seqid;
@@ -107,9 +107,9 @@ class EtherPort : public CommonPort
// port_state : already defined as port_state
bool isGM;
// asCapable : already defined as asCapable
- char operLogPdelayReqInterval;
- char operLogSyncInterval;
- char initialLogPdelayReqInterval;
+ signed char operLogPdelayReqInterval;
+ signed char operLogSyncInterval;
+ signed char initialLogPdelayReqInterval;
bool automotive_profile;
// Test Status variables
@@ -306,7 +306,7 @@ protected:
* @brief Gets the pDelay minimum interval
* @return PDelay interval
*/
- char getPDelayInterval(void) {
+ signed char getPDelayInterval(void) {
return log_min_mean_pdelay_req_interval;
}
@@ -315,7 +315,7 @@ protected:
* @param val time interval
* @return none
*/
- void setPDelayInterval(char val) {
+ void setPDelayInterval(signed char val) {
log_min_mean_pdelay_req_interval = val;
}
diff --git a/daemons/gptp/common/gptp_cfg.cpp b/daemons/gptp/common/gptp_cfg.cpp
index fae8e6c0..8b9db0dc 100644
--- a/daemons/gptp/common/gptp_cfg.cpp
+++ b/daemons/gptp/common/gptp_cfg.cpp
@@ -253,7 +253,7 @@ void GptpIniParser::print_phy_delay( void )
tx = i->second.get_tx_delay();
rx = i->second.get_rx_delay();
- snprintf( phy_delay_desc, PHY_DELAY_DESC_LEN+1,
+ PLAT_snprintf( phy_delay_desc, PHY_DELAY_DESC_LEN+1,
"TX: %hu | RX: %hu", tx, rx );
speed_name = findNameBySpeed( speed );
diff --git a/daemons/maap/common/maap_log.h b/daemons/maap/common/maap_log.h
index 7d36c1a1..eb9ca01f 100644
--- a/daemons/maap/common/maap_log.h
+++ b/daemons/maap/common/maap_log.h
@@ -162,11 +162,11 @@ typedef enum {
#define LOG_VARX(x, y) x ## y
#define LOG_VAR(x, y) LOG_VARX(x, y)
-// Log a message once. Technically once every 4.2 billion attempts. Usage: LOG_ONCE MAAP_LOG_INFO(...)
-#define IF_LOG_ONCE() static uint32_t LOG_VAR(logOnce,__LINE__); if (!LOG_VAR(logOnce,__LINE__)++)
+// Log a message once. Technically once every 4.2 billion attempts. Usage: IF_LOG_ONCE() MAAP_LOG_INFO(...)
+#define IF_LOG_ONCE() static uint32_t LOG_VAR(logOnce,__LINE__) = 0; if (!LOG_VAR(logOnce,__LINE__)++)
-// Log a message at an interval. Usage: LOG_INTERVAL(100) MAAP_LOG_INFO(...)
-#define IF_LOG_INTERVAL(x) static uint32_t LOG_VAR(logOnce,__LINE__); if (!(LOG_VAR(logOnce,__LINE__)++ % (x - 1)))
+// Log a message at an interval. Usage: IF_LOG_INTERVAL(100) MAAP_LOG_INFO(...)
+#define IF_LOG_INTERVAL(x) static uint32_t LOG_VAR(logOnce,__LINE__) = 0; if (!(LOG_VAR(logOnce,__LINE__)++ % (x)))
#define ETH_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x"
@@ -221,7 +221,7 @@ void maapLogBuffer(
#define MAAP_LOGRT_STATUS(BEGIN, ITEM, END, FMT, TYPE, VAL) maapLogRT(MAAP_LOG_LEVEL_STATUS, BEGIN, ITEM, END, FMT, TYPE, VAL)
#define MAAP_LOGRT_DEBUG(BEGIN, ITEM, END, FMT, TYPE, VAL) maapLogRT(MAAP_LOG_LEVEL_DEBUG, BEGIN, ITEM, END, FMT, TYPE, VAL)
#define MAAP_LOGRT_VERBOSE(BEGIN, ITEM, END, FMT, TYPE, VAL) maapLogRT(MAAP_LOG_LEVEL_VERBOSE, BEGIN, ITEM, END, FMT, TYPE, VAL)
-#define MAAP_LOG_BUFFER(LEVEL, DATA, DATALEN, LINELINE) maapLogBuffer(LEVEL, DATA, DATALEN, LINELINE, MAAP_LOG_COMPANY, MAAP_LOG_COMPONENT, __FILE__, __LINE__)
+#define MAAP_LOG_BUFFER(LEVEL, DATA, DATALEN, LINELINE) do { if (LEVEL <= MAAP_LOG_LEVEL) maapLogBuffer(0, DATA, DATALEN, LINELINE, MAAP_LOG_COMPANY, MAAP_LOG_COMPONENT, __FILE__, __LINE__); } while(0)
#else
#define MAAP_LOGF_DEV(LEVEL, FMT, ...)
#define MAAP_LOGF_ERROR(FMT, ...)
diff --git a/daemons/maap/linux/src/maap_helper_linux.h b/daemons/maap/linux/src/maap_helper_linux.h
index 251d7e8f..e5b3b3d1 100644
--- a/daemons/maap/linux/src/maap_helper_linux.h
+++ b/daemons/maap/linux/src/maap_helper_linux.h
@@ -153,7 +153,7 @@ typedef struct \
#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 || -1 == err)
+#define SEM_IS_ERR_TIMEOUT(err) (ETIMEDOUT == err || ((-1 == err) && (ETIMEDOUT == errno)))
#define SEM_LOG_ERR(err) if (0 != err) MAAP_LOGF_ERROR("Semaphore error code: %d", err);
#define MUTEX_ATTR_TYPE_DEFAULT PTHREAD_MUTEX_DEFAULT
diff --git a/daemons/maap/windows/src/maap_main.c b/daemons/maap/windows/src/maap_main.c
index 6c817d71..dce75312 100644
--- a/daemons/maap/windows/src/maap_main.c
+++ b/daemons/maap/windows/src/maap_main.c
@@ -1,3 +1,32 @@
+/*************************************************************************************
+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.
+*************************************************************************************/
+
/*
* TODO: This code still needs to be added!
*/
+
+int main(int argc, char *argv[])
+{
+}
diff --git a/daemons/mrpd/mrpctl.c b/daemons/mrpd/mrpctl.c
index 5ebe77a2..3a3e2add 100644
--- a/daemons/mrpd/mrpctl.c
+++ b/daemons/mrpd/mrpctl.c
@@ -261,8 +261,10 @@ int main(int argc, char *argv[])
if (-1 == rc) goto out;
/* yield replies */
- rc = mrpdclient_recv(mrpd_sock, process_ctl_msg);
- if (-1 == rc) goto out;
+ do {
+ rc = mrpdclient_recv(mrpd_sock, process_ctl_msg);
+ if (-1 == rc) goto out;
+ } while (rc >=0);
sleep(1);
} while (1);
diff --git a/daemons/shaper/LICENSE b/daemons/shaper/LICENSE
new file mode 100644
index 00000000..9a67d06a
--- /dev/null
+++ b/daemons/shaper/LICENSE
@@ -0,0 +1,25 @@
+/*************************************************************************************************************
+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.
+*************************************************************************************************************/
+
diff --git a/daemons/shaper/Makefile b/daemons/shaper/Makefile
new file mode 100644
index 00000000..13e4b037
--- /dev/null
+++ b/daemons/shaper/Makefile
@@ -0,0 +1,37 @@
+CC ?= gcc
+OPT = -O2 -g
+CFLAGS = $(OPT) -Wall -Wextra
+INCFLAGS =
+LDLIBS = -lm -pthread
+
+SRC_DIR = src
+OUT_O_DIR = build
+
+all: shaper_daemon
+
+shaper_daemon: \
+ $(OUT_O_DIR)/shaper_daemon.o \
+ $(OUT_O_DIR)/shaper_log_queue.o \
+ $(OUT_O_DIR)/shaper_log_linux.o
+
+$(OUT_O_DIR)/shaper_daemon.o: $(SRC_DIR)/shaper_daemon.c \
+ $(SRC_DIR)/shaper_log.h
+ @mkdir -p $(@D)
+ $(CC) $(CFLAGS) $(INCFLAGS) -c $(SRC_DIR)/shaper_daemon.c -o $(OUT_O_DIR)/shaper_daemon.o
+
+$(OUT_O_DIR)/shaper_log_queue.o: $(SRC_DIR)/shaper_log_queue.c \
+ $(SRC_DIR)/shaper_log.h $(SRC_DIR)/shaper_log_queue.h
+ @mkdir -p $(@D)
+ $(CC) $(CFLAGS) $(INCFLAGS) -c $(SRC_DIR)/shaper_log_queue.c -o $(OUT_O_DIR)/shaper_log_queue.o
+
+$(OUT_O_DIR)/shaper_log_linux.o: $(SRC_DIR)/shaper_log_linux.c \
+ $(SRC_DIR)/platform.h $(SRC_DIR)/shaper_log.h $(SRC_DIR)/shaper_log_queue.h $(SRC_DIR)/shaper_helper_linux.h
+ @mkdir -p $(@D)
+ $(CC) $(CFLAGS) $(INCFLAGS) -c $(SRC_DIR)/shaper_log_linux.c -o $(OUT_O_DIR)/shaper_log_linux.o
+
+%: $(OUT_O_DIR)/%.o
+ $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
+
+clean:
+ $(RM) shaper_daemon
+ $(RM) -r $(OUT_O_DIR)
diff --git a/daemons/shaper/README.rst b/daemons/shaper/README.rst
new file mode 100644
index 00000000..370ae1b7
--- /dev/null
+++ b/daemons/shaper/README.rst
@@ -0,0 +1,38 @@
+OpenAvnu Traffic Shaping Daemon
+===============================
+
+.. contents::
+..
+ 1 Introduction
+ 2 Support
+ 3 Future Updates
+
+Introduction
+------------
+
+The shaper daemon is an interface to use the tc (Traffic Control) command to
+configure the kernel traffic shaping with the Hierarchy Token Bucket. While
+tc could be called directly, using the daemon allows for a simpler interface
+and keeps track of the current traffic shaping configurations in use.
+
+Support
+-------
+
+To enable the Shaper daemon support for AVTP Pipeline, edit the endpoint.ini
+file and uncomment the port=15365 line of the shaper section.
+
+The Shaper daemon does not work (i.e. no shaping occurs) if the Intel IGB
+support is loaded for the adapter being used. You may also need to compile
+the AVTP Pipeline with PLATFORM_TOOLCHAIN=generic to not include the IGB
+features.
+
+Future Updates
+--------------
+
+- Have the daemon verify that tc is installed
+- Have the daemon verify that the kernel is configured to support Hierarchy
+ Token Bucket traffic shaping
+- Add a method to interlace frames from multiple streams of the same class
+ (perhaps using multiple layers of queues)
+- Add updates to support IEEE 802.1Qcc configurable classes
+
diff --git a/daemons/shaper/src/platform.h b/daemons/shaper/src/platform.h
new file mode 100644
index 00000000..3691d584
--- /dev/null
+++ b/daemons/shaper/src/platform.h
@@ -0,0 +1,74 @@
+/*************************************************************************************************************
+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.
+*************************************************************************************************************/
+
+#ifndef MAAP_PLATFORM_H
+#define MAAP_PLATFORM_H
+
+#if defined(__linux__)
+
+#include <endian.h>
+#include <time.h>
+
+#define OS_TIME_TYPE struct timespec
+
+#elif defined(__APPLE__)
+
+#include <libkern/OSByteOrder.h>
+#include <sys/time.h>
+
+#define htobe16(x) OSSwapHostToBigInt16(x)
+#define be16toh(x) OSSwapBigToHostInt16(x)
+#define htobe64(x) OSSwapHostToBigInt64(x)
+#define be64toh(x) OSSwapBigToHostInt64(x)
+
+#define ETH_ALEN 6
+
+#define OS_TIME_TYPE struct timeval
+
+#elif defined(_WIN32)
+
+#include <Winsock2.h>
+
+#define htobe16(x) htons(x)
+#define be16toh(x) ntohs(x)
+#define htobe64(x) ((htonl(1) == 1) ? x : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
+#define be64toh(x) ((ntohl(1) == 1) ? x : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
+
+#define OS_TIME_TYPE struct timeval
+
+#else
+
+#error Please create the platform support definitions for this platform
+
+#endif
+
+
+#define HTOBE16(x) htobe16(x)
+#define BE16TOH(x) be16toh(x)
+#define HTOBE64(x) htobe64(x)
+#define BE64TOH(x) be64toh(x)
+
+
+#endif
diff --git a/daemons/shaper/src/shaper_daemon.c b/daemons/shaper/src/shaper_daemon.c
new file mode 100644
index 00000000..1ef6a69c
--- /dev/null
+++ b/daemons/shaper/src/shaper_daemon.c
@@ -0,0 +1,986 @@
+/*************************************************************************************************************
+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.
+*************************************************************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include <net/if.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#define SHAPER_LOG_COMPONENT "Main"
+#include "shaper_log.h"
+
+#define STREAMDA_LENGTH 18
+#define SHAPER_PORT 15365 /* Unassigned at https://www.iana.org/assignments/port-numbers */
+#define MAX_CLIENT_CONNECTIONS 10
+#define USER_COMMAND_PROMPT "\nEnter the command: "
+
+typedef struct cmd_ip
+{
+ int reserve_bw;
+ int unreserve_bw;
+ char interface[IFNAMSIZ];
+ int class_a, class_b;
+ int measurement_interval;//usec
+ int max_frame_size;
+ int max_frame_interval;
+ char stream_da[STREAMDA_LENGTH];
+ int delete_qdisc;
+ int quit;
+} cmd_ip;
+
+typedef struct stream_da
+{
+ char dest_addr[STREAMDA_LENGTH];
+ int bandwidth;
+ char class_id[5];
+ int filter_handle;
+ struct stream_da *next;
+} stream_da;
+
+stream_da *head = NULL;
+int sr_classa=0, sr_classb=0;
+int classa_48=0, classa_44=0, classb_48=0, classb_44=0;
+int classa_bw_48=0, classa_bw_44=0, classb_bw_48=0, classb_bw_44=0;
+int daemonize=0,c=0;
+int filterhandle_classa=1,filterhandle_classb=20;
+char classid_a_48[]="2:10";
+char classid_a_44[]="2:20";
+char classid_b_48[]="3:30";
+char classid_b_44[]="3:40";
+char interface[IFNAMSIZ] = {0};
+int bandwidth = 0;
+int classa_parent = 2, classb_parent=3;
+int exit_received = 0;
+
+static void signal_handler(int signal)
+{
+ if (signal == SIGINT || signal == SIGTERM) {
+ if (!exit_received) {
+ SHAPER_LOG_INFO("Shutdown signal received");
+ exit_received = 1;
+ }
+ else {
+ // Force shutdown
+ exit(2);
+ }
+ }
+ else if (signal == SIGUSR1) {
+ SHAPER_LOG_DEBUG("Waking up streaming thread");
+ }
+ else {
+ SHAPER_LOG_ERROR("Unexpected signal");
+ }
+}
+
+void log_client_error_message(int sockfd, const char *fmt, ...)
+{
+ static char error_msg[200], combined_error_msg[250];
+ va_list args;
+
+ if (SHAPER_LOG_LEVEL_ERROR > SHAPER_LOG_LEVEL)
+ {
+ return;
+ }
+
+ /* Get the error message. */
+ va_start(args, fmt);
+ vsprintf(error_msg, fmt, args);
+ va_end(args);
+
+ if (sockfd < 0)
+ {
+ /* Received from stdin. Just log this error. */
+ SHAPER_LOG_ERROR(error_msg);
+ }
+ else
+ {
+ /* Log this as a remote client error. */
+ sprintf(combined_error_msg, "Client %d: %s", sockfd, error_msg);
+ SHAPER_LOG_ERROR(combined_error_msg);
+
+ /* Send the error message to the client. */
+ sprintf(combined_error_msg, "ERROR: %s\n", error_msg);
+ send(sockfd, combined_error_msg, strlen(combined_error_msg), 0);
+ }
+}
+
+void log_client_debug_message(int sockfd, const char *fmt, ...)
+{
+ static char debug_msg[200], combined_debug_msg[250];
+ va_list args;
+
+ if (SHAPER_LOG_LEVEL_DEBUG > SHAPER_LOG_LEVEL)
+ {
+ return;
+ }
+
+ /* Get the debug message. */
+ va_start(args, fmt);
+ vsprintf(debug_msg, fmt, args);
+ va_end(args);
+
+ if (sockfd < 0)
+ {
+ /* Received from stdin. Just log this message. */
+ SHAPER_LOG_DEBUG(debug_msg);
+ }
+ else
+ {
+ /* Log this as a remote client message. */
+ sprintf(combined_debug_msg, "Client %d: %s", sockfd, debug_msg);
+ SHAPER_LOG_DEBUG(combined_debug_msg);
+
+ /* Send the message to the client. */
+ sprintf(combined_debug_msg, "DEBUG: %s\n", debug_msg);
+ send(sockfd, combined_debug_msg, strlen(combined_debug_msg), 0);
+ }
+}
+
+int is_empty()
+{
+ return head == NULL;
+}
+
+void insert_stream_da(int sockfd, char dest_addr[], int bandwidth, char class_id[], int filter_handle)
+{
+ stream_da *node = (stream_da *)malloc(sizeof(stream_da));
+ if (node == NULL)
+ {
+ log_client_error_message(sockfd, "Unable to allocate memory. Exiting program");
+ shaperLogExit();
+ exit(1);
+ }
+ strcpy(node->dest_addr,dest_addr);
+ node->bandwidth = bandwidth;
+ strcpy(node->class_id,class_id);
+ node->filter_handle=filter_handle;
+ node->next = NULL;
+ if (is_empty())
+ {
+ head = node;
+ }
+ else
+ {
+ stream_da *current = head;
+ while (current->next != NULL)
+ {
+ current = current->next;
+ }
+ current->next = node;
+ }
+}
+
+int check_stream_da(int sockfd, char dest_addr[])
+{
+ stream_da *current = head;
+ while (current != NULL)
+ {
+ if (!strcmp(current->dest_addr, dest_addr))
+ {
+ log_client_error_message(sockfd, "Stream DA already present");
+ return 1;
+ }
+ current = current->next;
+ }
+ return 0;
+}
+
+stream_da* get_stream_da(int sockfd, char dest_addr[])
+{
+ stream_da *current = head;
+ while (current != NULL)
+ {
+ if (!strcmp(current->dest_addr, dest_addr))
+ {
+
+ return current;
+ }
+ current = current->next;
+ }
+ log_client_error_message(sockfd, "Unknown Stream DA");
+ return NULL;
+}
+
+void remove_stream_da(int sockfd, char dest_addr[])
+{
+ stream_da *current = head;
+ (void) sockfd;
+
+ if (current != NULL && !strcmp(current->dest_addr, dest_addr))
+ {
+ head = current->next;
+ free(current);
+ return;
+ }
+
+ while (current->next != NULL)
+ {
+ if (!strcmp(current->next->dest_addr, dest_addr))
+ {
+ stream_da *temp = current->next;
+ current->next = current->next->next;
+ free(temp);
+ return;
+ }
+ current = current->next;
+ }
+}
+
+void delete_streamda_list()
+{
+ stream_da *current = head;
+ stream_da *next = NULL;
+ while (current != NULL)
+ {
+ next = current->next;
+ free(current);
+ current = next;
+ }
+ head = NULL;
+}
+
+void usage (int sockfd)
+{
+ const char *usage = "Usage:\n"
+ " -r Reserve Bandwidth\n"
+ " -u Unreserve Bandwidth\n"
+ " -i Interface\n"
+ " -c Class ('A' or 'B')\n"
+ " -s Measurement interval (in microseconds)\n"
+ " -b Maximum frame size (in bytes)\n"
+ " -f Maximum frame interval\n"
+ " -a Stream Destination Address\n"
+ " -d Delete qdisc\n"
+ " -q Quit Application\n"
+ "Reserving Bandwidth Example:\n"
+ " -ri eth2 -c A -s 125 -b 74 -f 1 -a ff:ff:ff:ff:ff:11\n"
+ "Unreserving Bandwidth Example:\n"
+ " -ua ff:ff:ff:ff:ff:11\n"
+ "Quit Example:\n"
+ " -q\n"
+ "Delete qdisc Example:\n"
+ " -d\n";
+ if (sockfd < 0)
+ {
+ printf("%s",usage);
+ }
+ else
+ {
+ send(sockfd, usage, strlen(usage),0);
+ }
+
+}
+
+cmd_ip parse_cmd(char command[])
+{
+ cmd_ip inputs={0};
+ int i=0;
+ char temp[100];
+ while(command[i++] != '\0')
+ {
+
+ if (command[i] == 'r')
+ {
+ inputs.reserve_bw=1;
+ i++;
+ }
+
+ if (command[i] == 'u')
+ {
+ inputs.unreserve_bw=1;
+ i++;
+ }
+
+ if (command[i] == 'i')
+ {
+ int k=0;
+ i = i+2;
+ while (command[i] != ' ' && k < IFNAMSIZ-1)
+ {
+ inputs.interface[k] = command[i];
+ k++;i++;
+ }
+ inputs.interface[k] = '\0';
+ }
+
+ if (command[i] == 'c')
+ {
+ i = i+2;
+ if (command[i] == 'A' || command[i] == 'a')
+ {
+ inputs.class_a = 1;
+ }
+ else if (command[i] == 'B' || command[i] == 'b')
+ {
+ inputs.class_b = 1;
+ }
+ i++;
+ }
+
+ if (command[i] == 's')
+ {
+ int k=0;
+ i = i+2;
+ while (command[i] != ' ' && k < (int) sizeof(temp)-1)
+ {
+ temp[k] = command[i];
+ k++;i++;
+ }
+ temp[k] = '\0';
+ inputs.measurement_interval = atoi(temp);
+ }
+
+ if (command[i] == 'b')
+ {
+ int k=0;
+ i = i+2;
+ while (command[i] != ' ' && k < (int) sizeof(temp)-1)
+ {
+ temp[k] = command[i];
+ k++;i++;
+ }
+ temp[k] = '\0';
+ inputs.max_frame_size = atoi(temp);
+ }
+
+ if (command[i] == 'f')
+ {
+ int k=0;
+ i = i+2;
+ while (command[i] != ' ' && k < (int) sizeof(temp)-1)
+ {
+ temp[k] = command[i];
+ k++;i++;
+ }
+ temp[k] = '\0';
+ inputs.max_frame_interval = atoi(temp);
+ }
+
+ if (command[i] == 'a')
+ {
+ int k=0;
+ i = i+2;
+ while (command[i] != ' ' && k < STREAMDA_LENGTH-1)
+ {
+ inputs.stream_da[k] = command[i];
+ k++;i++;
+ }
+ inputs.stream_da[k] = '\0';
+ }
+
+ if (command[i] == 'd')
+ {
+ inputs.delete_qdisc=1;
+ i++;
+ }
+
+ if (command[i] == 'q')
+ {
+ inputs.quit = 1;
+ i++;
+ }
+ }
+ return inputs;
+}
+
+void tc_class_command(int sockfd, char command[], char class_id[], char interface[], int bandwidth, int cburst)
+{
+ char tc_command[1000]={0};
+ sprintf(tc_command, "tc class %s dev %s classid %s htb rate %dbps cburst %d",
+ command, interface, class_id, bandwidth, cburst);
+ log_client_debug_message(sockfd, "tc command: \"%s\"", tc_command);
+ if (system(tc_command) < 0)
+ {
+ log_client_error_message(sockfd, "command(\"%s\") failed", tc_command);
+ }
+}
+
+void add_filter(int sockfd, char interface[], int parent, int filter_handle, char class_id[], char dest_addr[])
+{
+ char tc_command[1000]={0};
+ sprintf(tc_command, "tc filter add dev %s prio 1 handle 800::%d parent %d: u32 classid %s match ether dst %s",
+ interface, filter_handle, parent, class_id, dest_addr);
+ log_client_debug_message(sockfd, "tc command: \"%s\"", tc_command);
+ if (system(tc_command) < 0)
+ {
+ log_client_error_message(sockfd, "command(\"%s\") failed", tc_command);
+ }
+}
+
+// Returns 1 if successful, -1 on an error, or 0 if exit requested.
+int process_command(int sockfd, char command[])
+{
+ cmd_ip input = parse_cmd(command);
+ char tc_command[1000]={0};
+ int maxburst = 0;
+
+ if (input.reserve_bw && input.unreserve_bw)
+ {
+ log_client_error_message(sockfd, "Cannot reserve and unreserve bandwidth at the same time");
+ usage(sockfd);
+ return -1;
+ }
+
+
+ if (input.reserve_bw)
+ {
+ if (input.max_frame_size == 0 || input.measurement_interval == 0 || input.max_frame_interval == 0 ||
+ (!input.class_a && !input.class_b))
+ {
+ log_client_error_message(sockfd, "class, max_frame_size, measurement_interval and max_frame_interval are mandatory inputs");
+ usage(sockfd);
+ return -1;
+ }
+
+ if (input.class_a && input.class_b)
+ {
+ log_client_error_message(sockfd, "Cannot reserve for both class A and class B");
+ usage(sockfd);
+ return -1;
+ }
+ }
+ if (input.unreserve_bw)
+ {
+ if (input.stream_da == 0)
+ {
+ log_client_error_message(sockfd, "Stream Destination Address is required to unreserve bandwidth");
+ usage(sockfd);
+ return -1;
+ }
+ }
+ if ((input.quit==1 || input.delete_qdisc==1) &&(input.reserve_bw==1 || input.unreserve_bw==1))
+ {
+ log_client_error_message(sockfd, "Quit or Delete cannot be used with other commands");
+ usage(sockfd);
+ return -1;
+ }
+
+ if (input.quit == 1 || input.delete_qdisc == 1)
+ {
+ if (sr_classa != 0 || sr_classb != 0)
+ {
+ //delete all the Stream DAs in list
+ delete_streamda_list();
+ if (strlen(interface) != 0)
+ {
+ //delete qdisc
+ sprintf(tc_command, "tc qdisc del dev %s root handle 1:", interface);
+ log_client_debug_message(sockfd, "tc command: \"%s\"", tc_command);
+ if (system(tc_command) < 0)
+ {
+ log_client_error_message(sockfd, "command(\"%s\") failed", tc_command);
+ }
+ }
+ sr_classa = sr_classb = 0;
+ classa_48 = classa_44 = classb_48 = classb_44 = 0;
+ classa_bw_48 = classa_bw_44 = classb_bw_48 = classb_bw_44 = 0;
+ }
+
+ if (input.quit == 1)
+ {
+ return 0;
+ }
+ }
+
+ if (sr_classa == 0 && sr_classb == 0)
+ {
+ //Initializing qdisc
+ if (strlen(input.interface)==0)
+ {
+ if (input.unreserve_bw || input.reserve_bw)
+ {
+ log_client_error_message(sockfd, "Interface is mandatory for the first command");
+ }
+ usage(sockfd);
+ return -1;
+ }
+ sprintf(tc_command, "tc qdisc add dev %s root handle 1: mqprio num_tc 4 map 3 3 1 0 2 2 2 2 2 2 2 2 2 2 2 2 queues 1@0 1@1 1@2 1@3 hw 0", input.interface);
+ log_client_debug_message(sockfd, "tc command: \"%s\"", tc_command);
+ if (system(tc_command) < 0)
+ {
+ log_client_error_message(sockfd, "command(\"%s\") failed", tc_command);
+ return -1;
+ }
+ strcpy(interface,input.interface);
+ }
+
+ if (input.unreserve_bw || input.reserve_bw)
+ {
+ bandwidth = ceil(((1/(input.measurement_interval*pow(10,-6))) * (input.max_frame_size*8) * input.max_frame_interval) / 8);
+ maxburst = input.max_frame_size*input.max_frame_interval*2;
+ }
+
+ if (input.reserve_bw == 1)
+ {
+ if (check_stream_da(sockfd, input.stream_da))
+ {
+ return 1;
+ }
+ if (input.class_a)
+ {
+ if (sr_classa == 0)
+ {
+ sr_classa = 1;
+ //Create qdisc for Class A traffic
+ sprintf(tc_command, "tc qdisc add dev %s handle %d: parent 1:5 htb", interface, classa_parent);
+ log_client_debug_message(sockfd, "tc command: \"%s\"", tc_command);
+ if (system(tc_command) < 0)
+ {
+ log_client_error_message(sockfd, "command(\"%s\") failed", tc_command);
+ return -1;
+ }
+ }
+
+ if (input.measurement_interval == 125)
+ {
+ classa_bw_48 = classa_bw_48 + bandwidth;
+ if (classa_48 == 0)
+ {
+ classa_48 = 1;
+ tc_class_command(sockfd, "add", classid_a_48, interface, classa_bw_48, maxburst);
+ }
+ else
+ {
+ tc_class_command(sockfd, "change", classid_a_48, interface, classa_bw_48, maxburst);
+ }
+
+ add_filter(sockfd, interface, classa_parent, filterhandle_classa, classid_a_48, input.stream_da);
+ insert_stream_da(sockfd, input.stream_da, bandwidth, classid_a_48, filterhandle_classa );
+ filterhandle_classa++;
+ }
+ else if (input.measurement_interval == 136)
+ {
+ classa_bw_44 = classa_bw_44 + bandwidth;
+ if (classa_44 == 0)
+ {
+ classa_44 = 1;
+ tc_class_command(sockfd, "add", classid_a_44, interface, classa_bw_44, maxburst);
+ }
+ else
+ {
+ tc_class_command(sockfd, "change", classid_a_44, interface, classa_bw_44, maxburst);
+ }
+
+ add_filter(sockfd, interface, classa_parent, filterhandle_classa, classid_a_44, input.stream_da);
+ insert_stream_da(sockfd, input.stream_da, bandwidth, classid_a_44, filterhandle_classa);
+ filterhandle_classa++;
+ }
+ else
+ {
+ log_client_error_message(sockfd, "Measurement Interval (%d) doesn't match that of Class A (125 or 136) traffic. "
+ "Enter a valid measurement interval",
+ input.measurement_interval);
+ return -1;
+ }
+ }
+ else
+ {
+ if (sr_classb == 0)
+ {
+ sr_classb = 1;
+ //Create qdisc for Class B traffic
+ sprintf(tc_command, "tc qdisc add dev %s handle %d: parent 1:6 htb", interface, classb_parent);
+ log_client_debug_message(sockfd, "tc command: \"%s\"", tc_command);
+ if (system(tc_command) < 0)
+ {
+ log_client_error_message(sockfd, "command(\"%s\") failed", tc_command);
+ return -1;
+ }
+ }
+
+ if (input.measurement_interval == 250)
+ {
+ classb_bw_48 = classb_bw_48 + bandwidth;
+ if (classb_48 == 0)
+ {
+ classb_48 = 1;
+ tc_class_command(sockfd, "add", classid_b_48, interface, classb_bw_48, maxburst);
+ }
+ else
+ {
+ tc_class_command(sockfd, "change", classid_b_48, interface, classb_bw_48, maxburst);
+ }
+ add_filter(sockfd, interface, classb_parent, filterhandle_classb, classid_b_48, input.stream_da);
+ insert_stream_da(sockfd, input.stream_da, bandwidth, classid_b_48, filterhandle_classb);
+ filterhandle_classb++;
+ }
+ else if (input.measurement_interval == 272)
+ {
+ classb_bw_44 = classb_bw_44 + bandwidth;
+ if (classb_44 == 0)
+ {
+ classb_44 = 1;
+ tc_class_command(sockfd, "add", classid_b_44, interface, classb_bw_44, maxburst);
+ }
+ else
+ {
+ tc_class_command(sockfd, "change", classid_b_44, interface, classb_bw_44, maxburst);
+ }
+ add_filter(sockfd, interface, classb_parent, filterhandle_classb, classid_b_44, input.stream_da);
+ insert_stream_da(sockfd, input.stream_da, bandwidth, classid_b_44, filterhandle_classb);
+ filterhandle_classb++;
+ }
+ else
+ {
+ log_client_error_message(sockfd, "Measurement Interval (%d) doesn't match that of Class B (250 or 272) traffic. "
+ "Enter a valid measurement interval",
+ input.measurement_interval);
+ return -1;
+ }
+ }
+ }
+ else if (input.unreserve_bw==1)
+ {
+ stream_da *remove_stream = get_stream_da(sockfd, input.stream_da);
+ if (remove_stream != NULL)
+ {
+ int class_bw = 0;
+ if (!strcmp(remove_stream->class_id, classid_a_48))
+ {
+ classa_bw_48 = classa_bw_48 - remove_stream->bandwidth;
+ class_bw = classa_bw_48;
+ }
+ else if (!strcmp(remove_stream->class_id, classid_a_44))
+ {
+ classa_bw_44 = classa_bw_44 - remove_stream->bandwidth;
+ class_bw = classa_bw_44;
+ }
+ else if (!strcmp(remove_stream->class_id, classid_b_48))
+ {
+ classb_bw_48 = classb_bw_48 - remove_stream->bandwidth;
+ class_bw = classb_bw_48;
+ }
+ else if (!strcmp(remove_stream->class_id, classid_b_44))
+ {
+ classb_bw_44 = classb_bw_44 - remove_stream->bandwidth;
+ class_bw = classb_bw_44;
+ }
+ if (class_bw == 0)
+ {
+ class_bw = 1;
+ }
+ tc_class_command(sockfd, "change", remove_stream->class_id, interface, class_bw, maxburst);
+ char parent[3] = {0};
+ strncpy(parent,remove_stream->class_id,2);
+ sprintf(tc_command, "tc filter del dev %s parent %s handle 800::%d prio 1 protocol all u32",
+ interface, parent, remove_stream->filter_handle);
+ log_client_debug_message(sockfd, "tc command: \"%s\"", tc_command);
+ if (system(tc_command) < 0)
+ {
+ log_client_error_message(sockfd, "command(\"%s\") failed", tc_command);
+ return -1;
+ }
+ remove_stream_da(sockfd, remove_stream->dest_addr);
+ }
+ }
+
+ return 1;
+}
+
+int init_socket()
+{
+ int socketfd = 0;
+ struct sockaddr_in serv_addr;
+ int yes=1;
+ if ((socketfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
+ {
+ SHAPER_LOGF_ERROR("Could not open socket %d. Error %d (%s)", socketfd, errno, strerror(errno));
+ return -1;
+ }
+ if (fcntl(socketfd, F_SETFL, O_NONBLOCK) < 0)
+ {
+ SHAPER_LOGF_ERROR("Could not set the socket to non-blocking. Error %d (%s)", errno, strerror(errno));
+ close(socketfd);
+ return -1;
+ }
+
+
+ memset(&serv_addr, '0', sizeof(serv_addr));
+
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ serv_addr.sin_port = htons(SHAPER_PORT);
+ setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
+
+ if (bind(socketfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr))<0)
+ {
+ SHAPER_LOGF_ERROR("bind() error %d (%s)", errno, strerror(errno));
+ return -1;
+ }
+ if (listen(socketfd, 10)<0)
+ {
+ SHAPER_LOGF_ERROR("listen() error %d (%s)", errno, strerror(errno));
+ return -1;
+ }
+
+ return socketfd;
+
+}
+
+int main (int argc, char *argv[])
+{
+ char command[100];
+ int socketfd = 0,newfd = 0;
+ int clientfd[MAX_CLIENT_CONNECTIONS];
+ int i, nextclientindex;
+ fd_set read_fds;
+ int fdmax;
+ int recvbytes;
+
+ shaperLogInit();
+
+ while((c = getopt(argc,argv,"d"))>=0)
+ {
+ switch(c)
+ {
+ case 'd':
+ daemonize = 1;
+ break;
+ }
+ }
+
+ if (daemonize == 1 && daemon(1,0) < 0)
+ {
+ SHAPER_LOGF_ERROR("Error %d (%s) starting the daemon", errno, strerror(errno));
+ shaperLogExit();
+ return 1;
+ }
+
+ if ((socketfd = init_socket())<0)
+ {
+ shaperLogExit();
+ return 1;
+ }
+
+ // Setup signal handler
+ // We catch SIGINT and shutdown cleanly
+ int err;
+ struct sigaction sa;
+ sa.sa_handler = signal_handler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ err = sigaction(SIGINT, &sa, NULL);
+ if (err)
+ {
+ SHAPER_LOG_ERROR("Failed to setup SIGINT handler");
+ shaperLogExit();
+ return 1;
+ }
+ err = sigaction(SIGTERM, &sa, NULL);
+ if (err)
+ {
+ SHAPER_LOG_ERROR("Failed to setup SIGTERM handler");
+ shaperLogExit();
+ return 1;
+ }
+ err = sigaction(SIGUSR1, &sa, NULL);
+ if (err)
+ {
+ SHAPER_LOG_ERROR("Failed to setup SIGUSR1 handler");
+ shaperLogExit();
+ return 1;
+ }
+
+ // Ignore SIGPIPE signals.
+ signal(SIGPIPE, SIG_IGN);
+
+ for (i = 0; i < MAX_CLIENT_CONNECTIONS; ++i)
+ {
+ clientfd[i] = -1;
+ }
+ nextclientindex = 0;
+
+ fputs(USER_COMMAND_PROMPT, stdout);
+ fflush(stdout);
+
+ while (!exit_received)
+ {
+ FD_ZERO(&read_fds);
+ if (!daemonize)
+ {
+ FD_SET(STDIN_FILENO, &read_fds);
+ }
+ FD_SET(socketfd, &read_fds);
+ fdmax = socketfd;
+ for (i = 0; i < MAX_CLIENT_CONNECTIONS; ++i)
+ {
+ if (clientfd[i] > 0)
+ {
+ FD_SET(clientfd[i], &read_fds);
+ if (clientfd[i] > fdmax)
+ {
+ fdmax = clientfd[i];
+ }
+ }
+ }
+ int n = select(fdmax+1, &read_fds, NULL, NULL, NULL);
+ if(n == -1)
+ {
+ if (exit_received)
+ {
+ // Assume the app received a signal to quit.
+ // Process the quit command.
+ process_command(-1, "-q");
+ }
+ else
+ {
+ SHAPER_LOGF_ERROR("select() error %d (%s)", errno, strerror(errno));
+ break;
+ }
+ }
+ else
+ {
+ /* Handle any commands received via stdin. */
+ if (FD_ISSET(STDIN_FILENO, &read_fds))
+ {
+ recvbytes = read(STDIN_FILENO, command, sizeof(command) - 1);
+ if (recvbytes <= 0)
+ {
+ SHAPER_LOGF_ERROR("Error %d reading from stdin (%s)", errno, strerror(errno));
+ }
+ else
+ {
+ command[recvbytes] = '\0';
+
+ /* Process the command data. */
+ int ret = process_command(-1, command);
+ if (!ret)
+ {
+ /* Received a command to exit. */
+ exit_received = 1;
+ }
+ else
+ {
+ /* Prompt the user again. */
+ shaperLogDisplayAll();
+ fputs(USER_COMMAND_PROMPT, stdout);
+ fflush(stdout);
+ }
+ }
+ }
+
+ if (FD_ISSET(socketfd, &read_fds))
+ {
+ newfd = accept(socketfd, (struct sockaddr*)NULL, NULL);
+ if (clientfd[nextclientindex] != -1)
+ {
+ /* Find the next available index. */
+ for (i = (nextclientindex + 1) % MAX_CLIENT_CONNECTIONS; i != nextclientindex; i = (i + 1) % MAX_CLIENT_CONNECTIONS)
+ {
+ if (clientfd[nextclientindex] == -1)
+ {
+ /* Found an empty array slot. */
+ break;
+ }
+ }
+ if (i == nextclientindex)
+ {
+ /* No more client slots available. Connection rejected. */
+ SHAPER_LOG_WARNING("Out of client connection slots. Connection rejected.");
+ close(newfd);
+ newfd = -1;
+ }
+ }
+
+
+ if (newfd != -1)
+ {
+ clientfd[nextclientindex] = newfd;
+ nextclientindex = (nextclientindex + 1) % MAX_CLIENT_CONNECTIONS; /* Next slot used for the next try. */
+
+ /* Send a prompt to the user. */
+ send(newfd, USER_COMMAND_PROMPT, strlen(USER_COMMAND_PROMPT), 0);
+ }
+ }
+
+ for (i = 0; i < MAX_CLIENT_CONNECTIONS; ++i)
+ {
+ if (clientfd[i] != -1 && FD_ISSET(clientfd[i], &read_fds))
+ {
+ recvbytes = recv(clientfd[i], command, sizeof(command) - 1, 0);
+ if (recvbytes < 0)
+ {
+ SHAPER_LOGF_ERROR("Error %d reading from socket %d (%s). Connection closed.", errno, clientfd[i], strerror(errno));
+ close(clientfd[i]);
+ clientfd[i] = -1;
+ nextclientindex = i; /* We know this slot will be empty. */
+ continue;
+ }
+ if (recvbytes == 0)
+ {
+ SHAPER_LOGF_INFO("Socket %d closed", clientfd[i]);
+ close(clientfd[i]);
+ clientfd[i] = -1;
+ nextclientindex = i; /* We know this slot will be empty. */
+ continue;
+ }
+
+ command[recvbytes] = '\0';
+ while (recvbytes > 0 && isspace(command[recvbytes - 1]))
+ {
+ /* Remove trailing whitespace. */
+ command[--recvbytes] = '\0';
+ }
+ SHAPER_LOGF_INFO("The received command is \"%s\"",command);
+ int ret = process_command(clientfd[i], command);
+ if (!ret)
+ {
+ /* Received a command to exit. */
+ exit_received = 1;
+ }
+ else
+ {
+ /* Send another prompt to the user. */
+ send(clientfd[i], USER_COMMAND_PROMPT, strlen(USER_COMMAND_PROMPT), 0);
+ }
+ }
+ }
+ }
+ }//main while loop
+
+ close(socketfd);
+
+ /* Close any connected sockets. */
+ for (i = 0; i < MAX_CLIENT_CONNECTIONS; ++i) {
+ if (clientfd[i] != -1) {
+ SHAPER_LOGF_INFO("Socket %d closed", clientfd[i]);
+ close(clientfd[i]);
+ clientfd[i] = -1;
+ }
+ }
+
+ shaperLogExit();
+
+ return 0;
+}
diff --git a/daemons/shaper/src/shaper_helper_linux.h b/daemons/shaper/src/shaper_helper_linux.h
new file mode 100644
index 00000000..14ee7dbf
--- /dev/null
+++ b/daemons/shaper/src/shaper_helper_linux.h
@@ -0,0 +1,182 @@
+/*************************************************************************************************************
+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.
+*************************************************************************************************************/
+
+#ifndef SHAPER_HELPER_LINUX_H
+#define SHAPER_HELPER_LINUX_H
+
+#include <unistd.h>
+#include <pthread.h>
+#include <signal.h>
+#include <time.h>
+#include <semaphore.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <dlfcn.h>
+
+// Uncomment to use manual data alignment adjustments. Not needed for Linux
+//#define DATA_ALIGNMENT_ADJUSTMENT 1
+
+/// Number of nanoseconds in second
+#define NANOSECONDS_PER_SECOND (1000000000ULL)
+/// Number of nanoseconds in millisecond
+#define NANOSECONDS_PER_MSEC (1000000L)
+/// Number of nanoseconds in microsecond
+#define NANOSECONDS_PER_USEC (1000L)
+/// Number of microseconds in second
+#define MICROSECONDS_PER_SECOND (1000000L)
+/// Number of microseconds in millisecond
+#define MICROSECONDS_PER_MSEC (1000L)
+
+#define SLEEP(sec) sleep(sec)
+#define SLEEP_MSEC(mSec) usleep(mSec * 1000)
+#define SLEEP_NSEC(nSec) usleep(nSec / 1000)
+#define SLEEP_UNTIL_NSEC(nSec) xSleepUntilNSec(nSec)
+inline static void xSleepUntilNSec(uint64_t nSec)
+{
+ struct timespec tmpTime;
+ tmpTime.tv_sec = nSec / NANOSECONDS_PER_SECOND;
+ tmpTime.tv_nsec = nSec % NANOSECONDS_PER_SECOND;
+ clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tmpTime, NULL);
+}
+
+#define RAND() random()
+#define SRAND(seed) srandom(seed)
+
+#define PRAGMA_ALIGN_8
+
+#define SIGNAL_CALLBACK_SETUP(__NAM, __CB) \
+ struct sigaction __NAM; \
+ __NAM.sa_handler = __CB
+
+#define SIGNAL_SIGNAL_SETUP(__SIG, __NAM, __CB, __ERR) \
+ sigemptyset(&__NAM.sa_mask); \
+ __NAM.sa_flags = 0; \
+ __ERR = sigaction(__SIG, &__NAM, NULL)
+
+
+// the following macros define thread related items
+#define THREAD_TYPE(thread) \
+typedef struct \
+{ \
+ pthread_t pthread; \
+ int err; \
+} thread##_type;
+
+#define THREAD_DEFINITON(thread) \
+thread##_type thread##_ThreadData
+
+#define THREAD_CREATE(threadName, threadhandle, thread_attr_name, thread_function, thread_function_arg) \
+ { \
+ pthread_attr_t thread_attr; \
+ do { \
+ threadhandle##_ThreadData.err = pthread_attr_init(&thread_attr); \
+ if (threadhandle##_ThreadData.err) break; \
+ threadhandle##_ThreadData.err = pthread_attr_setstacksize(&thread_attr, threadName##_THREAD_STK_SIZE); \
+ if (threadhandle##_ThreadData.err) break; \
+ threadhandle##_ThreadData.err = pthread_create( \
+ (pthread_t*)&threadhandle##_ThreadData.pthread, \
+ &thread_attr, \
+ thread_function, \
+ (void*)thread_function_arg); \
+ } while (0); \
+ pthread_attr_destroy(&thread_attr); \
+ }
+
+#define THREAD_SET_RT_PRIORITY(threadhandle, priority) \
+ { \
+ struct sched_param param; \
+ param.__sched_priority = priority; \
+ pthread_setschedparam(threadhandle##_ThreadData.pthread, SCHED_RR, &param); \
+ }
+
+#define THREAD_PIN(threadhandle, affinity) \
+ { \
+ cpu_set_t cpuset; \
+ int i1; \
+ CPU_ZERO(&cpuset); \
+ for (i1 = 0; i1 < 32; i1++) { \
+ if (affinity & (1 << i1)) CPU_SET(i1, &cpuset); \
+ } \
+ pthread_setaffinity_np(threadhandle##_ThreadData.pthread, sizeof(cpu_set_t), &cpuset); \
+ }
+
+#define THREAD_CHECK_ERROR(threadhandle, message, error) \
+ do { \
+ error=FALSE; \
+ if (threadhandle##_ThreadData.err != 0) \
+ { \
+ SHAPER_LOGF_ERROR("Thread error: %s code: %d", message, threadhandle##_ThreadData.err); \
+ error=TRUE; \
+ break; \
+ } \
+ } while (0)
+
+#define THREAD_STARTTHREAD(err)
+#define THREAD_KILL(threadhandle, signal) pthread_kill(threadhandle##_ThreadData.pthread, signal)
+#define THREAD_JOINABLE(threadhandle)
+#define THREAD_JOIN(threadhandle, signal) pthread_join(threadhandle##_ThreadData.pthread, (void**)signal)
+#define THREAD_SLEEP(threadhandle, secs) sleep(secs)
+
+#define THREAD_SELF() pthread_self()
+#define GET_PID() getpid()
+
+#define SEM_T(sem) sem_t sem;
+#define SEM_ERR_T(err) int err;
+#define SEM_INIT(sem, init, err) err = sem_init(&sem, 0, init);
+#define SEM_WAIT(sem, err) err = sem_wait(&sem);
+#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 || -1 == err)
+#define SEM_LOG_ERR(err) if (0 != err) SHAPER_LOGF_ERROR("Semaphore error code: %d", err);
+
+#define MUTEX_ATTR_TYPE_DEFAULT PTHREAD_MUTEX_DEFAULT
+#define MUTEX_ATTR_TYPE_RECURSIVE PTHREAD_MUTEX_RECURSIVE
+#define MUTEX_HANDLE(mutex_handle) pthread_mutex_t mutex_handle
+#define MUTEX_ATTR_HANDLE(mutex_attr_name) pthread_mutexattr_t mutex_attr_name
+#define MUTEX_ATTR_CREATE_ERR() static mutex_err
+#define MUTEX_ATTR_INIT(mutex_attr_name) pthread_mutexattr_init(&mutex_attr_name)
+#define MUTEX_ATTR_SET_TYPE(mutex_attr_name,type) pthread_mutexattr_settype(&mutex_attr_name, type)
+#define MUTEX_ATTR_SET_NAME(mutex_attr_name, name)
+#define MUTEX_CREATE_ERR() int mutex_err
+#define MUTEX_CREATE(mutex_handle,mutex_attr_name) mutex_err=pthread_mutex_init(&mutex_handle, &mutex_attr_name)
+#define MUTEX_LOCK(mutex_handle) mutex_err=pthread_mutex_lock(&mutex_handle)
+#define MUTEX_UNLOCK(mutex_handle) mutex_err=pthread_mutex_unlock(&mutex_handle)
+#define MUTEX_DESTROY(mutex_handle) mutex_err=pthread_mutex_destroy(&mutex_handle)
+#define MUTEX_LOG_ERR(message) if (mutex_err) SHAPER_LOG_ERROR(message);
+#define MUTEX_IS_ERR (mutex_err != 0)
+
+// Alternate simplified mutex mapping
+#define MUTEX_HANDLE_ALT(mutex_handle) pthread_mutex_t mutex_handle
+#define MUTEX_CREATE_ALT(mutex_handle) pthread_mutex_init(&mutex_handle, NULL)
+#define MUTEX_LOCK_ALT(mutex_handle) pthread_mutex_lock(&mutex_handle)
+#define MUTEX_UNLOCK_ALT(mutex_handle) pthread_mutex_unlock(&mutex_handle)
+#define MUTEX_DESTROY_ALT(mutex_handle) pthread_mutex_destroy(&mutex_handle)
+
+#endif // SHAPER_HELPER_LINUX_H
diff --git a/daemons/shaper/src/shaper_log.h b/daemons/shaper/src/shaper_log.h
new file mode 100644
index 00000000..0db3dc36
--- /dev/null
+++ b/daemons/shaper/src/shaper_log.h
@@ -0,0 +1,267 @@
+/*************************************************************************************************************
+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.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : A simple logging facility for use during
+* development.
+*/
+
+#ifndef SHAPER_LOG_H
+#define SHAPER_LOG_H 1
+
+// ********
+// Merge Issue
+// TODO: Restructure to remove #ifdef code.
+// ********
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+// Uncomment SHAPER_LOG_ON to enable logging.
+#define SHAPER_LOG_ON 1
+
+// Uncomment SHAPER_LOG_ON_OVERRIDE to override all SHAPER_LOG_ON usage in the app to ensure all logs are off.
+//#define SHAPER_LOG_ON_OVERRIDE 1
+
+#ifdef SHAPER_LOG_ON_OVERRIDE
+#ifdef SHAPER_LOG_ON
+#undef SHAPER_LOG_ON
+#endif
+#endif
+
+#define SHAPER_LOG_LEVEL_NONE 0
+#define SHAPER_LOG_LEVEL_ERROR 1
+#define SHAPER_LOG_LEVEL_WARNING 2
+#define SHAPER_LOG_LEVEL_INFO 3
+#define SHAPER_LOG_LEVEL_STATUS 4
+#define SHAPER_LOG_LEVEL_DEBUG 5
+#define SHAPER_LOG_LEVEL_VERBOSE 6
+
+// Special case development logging levels for use with SHAPER_LOGF_DEV and SHAPER_LOG_DEV
+#define SHAPER_LOG_LEVEL_DEV_ON SHAPER_LOG_LEVEL_NONE
+#define SHAPER_LOG_LEVEL_DEV_OFF SHAPER_LOG_LEVEL_VERBOSE + 1
+
+// Default log level, can override in source files
+#ifndef SHAPER_LOG_LEVEL
+//#define SHAPER_LOG_LEVEL SHAPER_LOG_LEVEL_ERROR
+//#define SHAPER_LOG_LEVEL SHAPER_LOG_LEVEL_INFO
+#define SHAPER_LOG_LEVEL SHAPER_LOG_LEVEL_STATUS
+//#define SHAPER_LOG_LEVEL SHAPER_LOG_LEVEL_DEBUG
+//#define SHAPER_LOG_LEVEL SHAPER_LOG_LEVEL_VERBOSE
+#endif
+
+#ifndef SHAPER_LOG_COMPANY
+#define SHAPER_LOG_COMPANY "SHAPER"
+#endif
+
+#ifndef SHAPER_LOG_COMPONENT
+#define SHAPER_LOG_COMPONENT "SHAPER"
+#endif
+
+// Log format options and sizes. Uncomment to include the formatted info.
+#define LOG_MSG_LEN 1024
+
+// The length of the full message
+#define LOG_FULL_MSG_LEN 1024
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+static const int SHAPER_LOG_TIME_INFO = FALSE;
+#define LOG_TIME_LEN 9
+//#define LOG_TIME_LEN 1
+
+static const int SHAPER_LOG_TIMESTAMP_INFO = TRUE;
+#define LOG_TIMESTAMP_LEN 32
+//#define LOG_TIMESTAMP_LEN 1
+
+static const int SHAPER_LOG_FILE_INFO = FALSE;
+//#define LOG_FILE_LEN 256
+#define LOG_FILE_LEN 1
+
+static const int SHAPER_LOG_PROC_INFO = FALSE;
+//#define LOG_PROC_LEN 64
+#define LOG_PROC_LEN 1
+
+static const int SHAPER_LOG_THREAD_INFO = FALSE;
+//#define LOG_THREAD_LEN 64
+#define LOG_THREAD_LEN 1
+
+#define LOG_RT_MSG_LEN 256
+//#define LOG_RT_MSG_LEN 1
+
+#define SHAPER_LOG_OUTPUT_FD stderr
+//#define SHAPER_LOG_OUTPUT_FD stdout
+
+#define SHAPER_LOG_STDOUT_CONSOLE_WIDTH 80
+
+static const int SHAPER_LOG_EXTRA_NEWLINE = TRUE;
+
+// When SHAPER_LOG_FROM_THREAD the message output will be output from a separate thread/task
+// Primary intended use is for debugging.
+// It is expected that SHAPER_LOG_PULL_MODE will not be used at the same time as this option.
+static const int SHAPER_LOG_FROM_THREAD = TRUE;
+
+// When SHAPER_LOG_PULL_MODE the messages will be queued and can be pulled using the
+// shaperLogGetMsg() call. This could be from an logger interface module or host application.
+// It is expected that SHAPER_LOG_FROM_THREAD will not be used at the same time as this option.
+static const int SHAPER_LOG_PULL_MODE = FALSE;
+
+// When using the SHAPER_LOG_FROM_THREAD option. These defines control the behavior of the msg queue
+#define LOG_QUEUE_MSG_LEN 256
+#define LOG_QUEUE_MSG_SIZE (LOG_QUEUE_MSG_LEN + 1)
+#define LOG_QUEUE_MSG_CNT 82
+#define LOG_QUEUE_SLEEP_MSEC 100
+
+// RT (RealTime logging) related defines
+#define LOG_RT_QUEUE_CNT 128
+#define LOG_RT_BEGIN TRUE
+#define LOG_RT_ITEM TRUE
+#define LOG_RT_END TRUE
+typedef enum {
+ LOG_RT_DATATYPE_NONE,
+ LOG_RT_DATATYPE_CONST_STR,
+ LOG_RT_DATATYPE_NOW_TS,
+ LOG_RT_DATATYPE_U16,
+ LOG_RT_DATATYPE_S16,
+ LOG_RT_DATATYPE_U32,
+ LOG_RT_DATATYPE_S32,
+ LOG_RT_DATATYPE_U64,
+ LOG_RT_DATATYPE_S64,
+ LOG_RT_DATATYPE_FLOAT
+} log_rt_datatype_t;
+
+
+#define LOG_VARX(x, y) x ## y
+#define LOG_VAR(x, y) LOG_VARX(x, y)
+
+// Log a message once. Technically once every 4.2 billion attempts. Usage: IF_LOG_ONCE() SHAPER_LOG_INFO(...)
+#define IF_LOG_ONCE() static uint32_t LOG_VAR(logOnce,__LINE__) = 0; if (!LOG_VAR(logOnce,__LINE__)++)
+
+// Log a message at an interval. Usage: IF_LOG_INTERVAL(100) SHAPER_LOG_INFO(...)
+#define IF_LOG_INTERVAL(x) static uint32_t LOG_VAR(logOnce,__LINE__) = 0; if (!(LOG_VAR(logOnce,__LINE__)++ % (x)))
+
+
+#define ETH_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define ETH_OCTETS(a) (a)[0],(a)[1],(a)[2],(a)[3],(a)[4],(a)[5]
+
+
+void shaperLogInit(void);
+
+void shaperLogDisplayAll(void);
+
+void shaperLogExit(void);
+
+void shaperLogFn(
+ int level,
+ const char *tag,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line,
+ const char *fmt,
+ ...);
+
+void shaperLogRT(int level, int bBegin, int bItem, int bEnd, char *pFormat, log_rt_datatype_t dataType, void *pVar);
+
+void shaperLogBuffer(
+ int level,
+ const uint8_t *pData,
+ int dataLen,
+ int lineLen,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line);
+
+
+#define shaperLogFn2(level, tag, company, component, path, line, fmt, ...) \
+ {\
+ if (level <= SHAPER_LOG_LEVEL) \
+ shaperLogFn(0, tag, company, component, path, line, fmt, __VA_ARGS__); \
+ }
+
+#define shaperLogBuffer2(level, pData, dataLen, lineLen, company, component, path, line) \
+ {\
+ if (level <= AVB_LOG_LEVEL) \
+ shaperLogBuffer(0, pData, dataLen, lineLen, company, component, path, line); \
+ }
+
+#ifdef SHAPER_LOG_ON
+#define SHAPER_LOGF_DEV(LEVEL, FMT, ...) shaperLogFn2(LEVEL, "DEV", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define SHAPER_LOGF_ERROR(FMT, ...) shaperLogFn2(SHAPER_LOG_LEVEL_ERROR, "ERROR", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define SHAPER_LOGF_WARNING(FMT, ...) shaperLogFn2(SHAPER_LOG_LEVEL_WARNING, "WARNING", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define SHAPER_LOGF_INFO(FMT, ...) shaperLogFn2(SHAPER_LOG_LEVEL_INFO, "INFO", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define SHAPER_LOGF_STATUS(FMT, ...) shaperLogFn2(SHAPER_LOG_LEVEL_STATUS, "STATUS", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define SHAPER_LOGF_DEBUG(FMT, ...) shaperLogFn2(SHAPER_LOG_LEVEL_DEBUG, "DEBUG", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define SHAPER_LOGF_VERBOSE(FMT, ...) shaperLogFn2(SHAPER_LOG_LEVEL_VERBOSE, "VERBOSE", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define SHAPER_LOG_DEV(LEVEL, MSG) shaperLogFn2(LEVEL, "DEV", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define SHAPER_LOG_ERROR(MSG) shaperLogFn2(SHAPER_LOG_LEVEL_ERROR, "ERROR", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define SHAPER_LOG_WARNING(MSG) shaperLogFn2(SHAPER_LOG_LEVEL_WARNING, "WARNING", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define SHAPER_LOG_INFO(MSG) shaperLogFn2(SHAPER_LOG_LEVEL_INFO, "INFO", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define SHAPER_LOG_STATUS(MSG) shaperLogFn2(SHAPER_LOG_LEVEL_STATUS, "STATUS", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define SHAPER_LOG_DEBUG(MSG) shaperLogFn2(SHAPER_LOG_LEVEL_DEBUG, "DEBUG", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define SHAPER_LOG_VERBOSE(MSG) shaperLogFn2(SHAPER_LOG_LEVEL_VERBOSE, "VERBOSE", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define SHAPER_LOGRT_ERROR(BEGIN, ITEM, END, FMT, TYPE, VAL) shaperLogRT(SHAPER_LOG_LEVEL_ERROR, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_WARNING(BEGIN, ITEM, END, FMT, TYPE, VAL) shaperLogRT(SHAPER_LOG_LEVEL_WARNING, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_INFO(BEGIN, ITEM, END, FMT, TYPE, VAL) shaperLogRT(SHAPER_LOG_LEVEL_INFO, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_STATUS(BEGIN, ITEM, END, FMT, TYPE, VAL) shaperLogRT(SHAPER_LOG_LEVEL_STATUS, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_DEBUG(BEGIN, ITEM, END, FMT, TYPE, VAL) shaperLogRT(SHAPER_LOG_LEVEL_DEBUG, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_VERBOSE(BEGIN, ITEM, END, FMT, TYPE, VAL) shaperLogRT(SHAPER_LOG_LEVEL_VERBOSE, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOG_BUFFER(LEVEL, DATA, DATALEN, LINELINE) shaperLogBuffer2(LEVEL, DATA, DATALEN, LINELINE, SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__)
+#else
+#define SHAPER_LOGF_DEV(LEVEL, FMT, ...)
+#define SHAPER_LOGF_ERROR(FMT, ...)
+#define SHAPER_LOGF_WARNING(FMT, ...)
+#define SHAPER_LOGF_INFO(FMT, ...)
+#define SHAPER_LOGF_STATUS(FMT, ...)
+#define SHAPER_LOGF_DEBUG(FMT, ...)
+#define SHAPER_LOGF_VERBOSE(FMT, ...)
+#define SHAPER_LOG_DEV(LEVEL, FMT, ...)
+#define SHAPER_LOG_ERROR(MSG)
+#define SHAPER_LOG_WARNING(MSG)
+#define SHAPER_LOG_INFO(MSG)
+#define SHAPER_LOG_STATUS(MSG)
+#define SHAPER_LOG_DEBUG(MSG)
+#define SHAPER_LOG_VERBOSE(MSG)
+#define SHAPER_LOGRT_ERROR(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_WARNING(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_INFO(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_STATUS(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_DEBUG(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_VERBOSE(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOG_BUFFER(LEVEL, DATA, DATALEN, LINELINE)
+#endif // SHAPER_LOG_ON
+
+// Get a queued log message. Intended to be used with the SHAPER_LOG_PULL_MODE option.
+// Message will not be null terminated.
+uint32_t shaperLogGetMsg(uint8_t *pBuf, uint32_t bufSize);
+
+#endif // SHAPER_LOG_H
diff --git a/daemons/shaper/src/shaper_log_linux.c b/daemons/shaper/src/shaper_log_linux.c
new file mode 100644
index 00000000..d68a79a2
--- /dev/null
+++ b/daemons/shaper/src/shaper_log_linux.c
@@ -0,0 +1,445 @@
+/*************************************************************************************************************
+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.
+*************************************************************************************************************/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "platform.h"
+#include "shaper_log_queue.h"
+#include "shaper_helper_linux.h"
+
+#define SHAPER_LOG_COMPONENT "Log"
+#include "shaper_log.h"
+
+typedef struct {
+ uint8_t msg[LOG_QUEUE_MSG_SIZE];
+ int bRT; // TRUE = Details are in RT queue
+} log_queue_item_t;
+
+typedef struct {
+ char *pFormat;
+ log_rt_datatype_t dataType;
+ union {
+ struct timespec nowTS;
+ uint16_t unsignedShortVar;
+ int16_t signedShortVar;
+ uint32_t unsignedLongVar;
+ int32_t signedLongVar;
+ uint64_t unsignedLongLongVar;
+ int64_t signedLongLongVar;
+ float floatVar;
+ } data;
+ int bEnd;
+} log_rt_queue_item_t;
+
+static shaper_log_queue_t logQueue;
+static shaper_log_queue_t logRTQueue;
+
+static char msg[LOG_MSG_LEN] = "";
+static char time_msg[LOG_TIME_LEN] = "";
+static char timestamp_msg[LOG_TIMESTAMP_LEN] = "";
+static char file_msg[LOG_FILE_LEN] = "";
+static char proc_msg[LOG_PROC_LEN] = "";
+static char thread_msg[LOG_THREAD_LEN] = "";
+static char full_msg[LOG_FULL_MSG_LEN] = "";
+
+static char rt_msg[LOG_RT_MSG_LEN] = "";
+
+static int loggingThreadRunning = FALSE;
+extern void *loggingThreadFn(void *pv);
+THREAD_TYPE(loggingThread);
+THREAD_DEFINITON(loggingThread);
+
+#define THREAD_STACK_SIZE 65536
+#define loggingThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
+static MUTEX_HANDLE_ALT(gLogMutex);
+#define LOG_LOCK() MUTEX_LOCK_ALT(gLogMutex)
+#define LOG_UNLOCK() MUTEX_UNLOCK_ALT(gLogMutex)
+
+void shaperLogRTRender(log_queue_item_t *pLogItem)
+{
+ if (logRTQueue) {
+ pLogItem->msg[0] = 0x00;
+ int bMore = TRUE;
+ while (bMore) {
+ shaper_log_queue_elem_t elem = shaperLogQueueTailLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)shaperLogQueueData(elem);
+
+ switch (pLogRTItem->dataType) {
+ case LOG_RT_DATATYPE_CONST_STR:
+ strcat((char *)pLogItem->msg, pLogRTItem->pFormat);
+ break;
+ case LOG_RT_DATATYPE_NOW_TS:
+ sprintf(rt_msg, "[%lu:%09lu] ", pLogRTItem->data.nowTS.tv_sec, pLogRTItem->data.nowTS.tv_nsec);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_U16:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedShortVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_S16:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedShortVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_U32:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_S32:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_U64:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_S64:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedLongLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_FLOAT:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.floatVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ default:
+ break;
+ }
+
+ if (pLogRTItem->bEnd) {
+ if (SHAPER_LOG_EXTRA_NEWLINE)
+ strcat((char *)pLogItem->msg, "\n");
+ bMore = FALSE;
+ }
+ shaperLogQueueTailPull(logRTQueue);
+ }
+ }
+ }
+}
+
+uint32_t shaperLogGetMsg(uint8_t *pBuf, uint32_t bufSize)
+{
+ uint32_t dataLen = 0;
+ if (logQueue) {
+ shaper_log_queue_elem_t elem = shaperLogQueueTailLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)shaperLogQueueData(elem);
+
+ if (pLogItem->bRT)
+ shaperLogRTRender(pLogItem);
+
+ dataLen = strlen((const char *)pLogItem->msg);
+ if (dataLen <= bufSize)
+ memcpy(pBuf, (uint8_t *)pLogItem->msg, dataLen);
+ else
+ memcpy(pBuf, (uint8_t *)pLogItem->msg, bufSize);
+ shaperLogQueueTailPull(logQueue);
+ return dataLen;
+ }
+ }
+ return dataLen;
+}
+
+void *loggingThreadFn(void *pv)
+{
+ (void) pv;
+
+ while (loggingThreadRunning) {
+ SLEEP_MSEC(LOG_QUEUE_SLEEP_MSEC);
+ shaperLogDisplayAll();
+ }
+
+ return NULL;
+}
+
+void shaperLogDisplayAll(void)
+{
+ int more = TRUE;
+
+ while (more) {
+ more = FALSE;
+ shaper_log_queue_elem_t elem = shaperLogQueueTailLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)shaperLogQueueData(elem);
+
+ if (pLogItem->bRT)
+ shaperLogRTRender(pLogItem);
+
+ fputs((const char *)pLogItem->msg, SHAPER_LOG_OUTPUT_FD);
+ shaperLogQueueTailPull(logQueue);
+ more = TRUE;
+ }
+ }
+}
+
+void shaperLogInit(void)
+{
+ MUTEX_CREATE_ALT(gLogMutex);
+
+ logQueue = shaperLogQueueNewQueue(sizeof(log_queue_item_t), LOG_QUEUE_MSG_CNT);
+ if (!logQueue) {
+ printf("Failed to initialize logging facility\n");
+ }
+
+ logRTQueue = shaperLogQueueNewQueue(sizeof(log_rt_queue_item_t), LOG_RT_QUEUE_CNT);
+ if (!logRTQueue) {
+ printf("Failed to initialize logging RT facility\n");
+ }
+
+ // Start the logging task
+ if (SHAPER_LOG_FROM_THREAD) {
+ int errResult;
+ loggingThreadRunning = TRUE;
+ THREAD_CREATE(loggingThread, loggingThread, NULL, loggingThreadFn, NULL);
+ THREAD_CHECK_ERROR(loggingThread, "Thread / task creation failed", errResult);
+ if (errResult) {} // Already reported
+ }
+}
+
+void shaperLogExit()
+{
+ if (SHAPER_LOG_FROM_THREAD) {
+ loggingThreadRunning = FALSE;
+ THREAD_JOIN(loggingThread, NULL);
+ }
+}
+
+void shaperLogFn(
+ int level,
+ const char *tag,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line,
+ const char *fmt,
+ ...)
+{
+ if (level <= SHAPER_LOG_LEVEL) {
+ va_list args;
+ va_start(args, fmt);
+
+ LOG_LOCK();
+
+ vsprintf(msg, fmt, args);
+
+ if (SHAPER_LOG_FILE_INFO && path) {
+ char* file = strrchr(path, '/');
+ if (!file)
+ file = strrchr(path, '\\');
+ if (file)
+ file += 1;
+ else
+ file = (char*)path;
+ sprintf(file_msg, " %s:%d", file, line);
+ }
+ if (SHAPER_LOG_PROC_INFO) {
+ sprintf(proc_msg, " P:%5.5d", GET_PID());
+ }
+ if (SHAPER_LOG_THREAD_INFO) {
+ sprintf(thread_msg, " T:%lu", THREAD_SELF());
+ }
+ if (SHAPER_LOG_TIME_INFO) {
+ time_t tNow = time(NULL);
+ struct tm tmNow;
+ localtime_r(&tNow, &tmNow);
+
+ sprintf(time_msg, "%2.2d:%2.2d:%2.2d", tmNow.tm_hour, tmNow.tm_min, tmNow.tm_sec);
+ }
+ if (SHAPER_LOG_TIMESTAMP_INFO) {
+ struct timespec nowTS;
+ clock_gettime(CLOCK_REALTIME, &nowTS);
+
+ sprintf(timestamp_msg, "%lu:%09lu", nowTS.tv_sec, nowTS.tv_nsec);
+ }
+
+ // using sprintf and puts allows using static buffers rather than heap.
+ if (SHAPER_LOG_EXTRA_NEWLINE)
+ /* int32_t full_msg_len = */ sprintf(full_msg, "[%s%s%s%s %s %s%s] %s: %s\n", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg);
+ else
+ /* int32_t full_msg_len = */ sprintf(full_msg, "[%s%s%s%s %s %s%s] %s: %s", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg);
+
+ if (!SHAPER_LOG_FROM_THREAD && !SHAPER_LOG_PULL_MODE) {
+ fputs(full_msg, SHAPER_LOG_OUTPUT_FD);
+ }
+ else {
+ if (logQueue) {
+ shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)shaperLogQueueData(elem);
+ pLogItem->bRT = FALSE;
+ strncpy((char *)pLogItem->msg, full_msg, LOG_QUEUE_MSG_LEN);
+ shaperLogQueueHeadPush(logQueue);
+ }
+ }
+ }
+
+ va_end(args);
+
+ LOG_UNLOCK();
+ }
+}
+
+void shaperLogRT(int level, int bBegin, int bItem, int bEnd, char *pFormat, log_rt_datatype_t dataType, void *pVar)
+{
+ if (level <= SHAPER_LOG_LEVEL) {
+ if (logRTQueue) {
+ if (bBegin) {
+ LOG_LOCK();
+
+ shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)shaperLogQueueData(elem);
+ pLogRTItem->bEnd = FALSE;
+ pLogRTItem->pFormat = NULL;
+ pLogRTItem->dataType = LOG_RT_DATATYPE_NOW_TS;
+ clock_gettime(CLOCK_REALTIME, &pLogRTItem->data.nowTS);
+ shaperLogQueueHeadPush(logRTQueue);
+ }
+ }
+
+ if (bItem) {
+ shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)shaperLogQueueData(elem);
+ if (bEnd)
+ pLogRTItem->bEnd = TRUE;
+ else
+ pLogRTItem->bEnd = FALSE;
+ pLogRTItem->pFormat = pFormat;
+ pLogRTItem->dataType = dataType;
+
+ switch (pLogRTItem->dataType) {
+ case LOG_RT_DATATYPE_CONST_STR:
+ break;
+ case LOG_RT_DATATYPE_U16:
+ pLogRTItem->data.unsignedLongVar = *(uint16_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S16:
+ pLogRTItem->data.signedLongVar = *(int16_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_U32:
+ pLogRTItem->data.unsignedLongVar = *(uint32_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S32:
+ pLogRTItem->data.signedLongVar = *(int32_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_U64:
+ pLogRTItem->data.unsignedLongLongVar = *(uint64_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S64:
+ pLogRTItem->data.signedLongLongVar = *(int64_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_FLOAT:
+ pLogRTItem->data.floatVar = *(float *)pVar;
+ break;
+ default:
+ break;
+ }
+ shaperLogQueueHeadPush(logRTQueue);
+ }
+ }
+
+ if (!bItem && bEnd) {
+ shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)shaperLogQueueData(elem);
+ pLogRTItem->bEnd = TRUE;
+ pLogRTItem->pFormat = NULL;
+ pLogRTItem->dataType = LOG_RT_DATATYPE_NONE;
+ shaperLogQueueHeadPush(logRTQueue);
+ }
+ }
+
+ if (bEnd) {
+ if (logQueue) {
+ shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)shaperLogQueueData(elem);
+ pLogItem->bRT = TRUE;
+ if (SHAPER_LOG_FROM_THREAD) {
+ shaperLogQueueHeadPush(logQueue);
+ } else {
+ shaperLogRTRender(pLogItem);
+ fputs((const char *)pLogItem->msg, SHAPER_LOG_OUTPUT_FD);
+ shaperLogQueueHeadUnlock(logQueue);
+ }
+ }
+ }
+
+ LOG_UNLOCK();
+ }
+ }
+ }
+}
+
+void shaperLogBuffer(
+ int level,
+ const uint8_t *pData,
+ int dataLen,
+ int lineLen,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line)
+{
+ char szDataLine[ 400 ];
+ char *pszOut;
+ int i, j;
+
+ if (level > SHAPER_LOG_LEVEL) { return; }
+
+ for (i = 0; i < dataLen; i += lineLen) {
+ /* Create the hexadecimal output for the buffer. */
+ pszOut = szDataLine;
+ *pszOut++ = '\t';
+ for (j = i; j < i + lineLen; ++j) {
+ if (j < dataLen) {
+ sprintf(pszOut, "%02x ", pData[j]);
+ } else {
+ strcpy(pszOut, " ");
+ }
+ pszOut += 3;
+ }
+
+ *pszOut++ = ' ';
+ *pszOut++ = ' ';
+
+ /* Append the ASCII equivalent of each character. */
+ for (j = i; j < dataLen && j < i + lineLen; ++j) {
+ if (pData[j] >= 0x20 && pData[j] < 0x7f) {
+ *pszOut++ = (char) pData[j];
+ } else {
+ *pszOut++ = '.';
+ }
+ }
+
+ /* Display this line of text. */
+ *pszOut = '\0';
+ shaperLogFn(level, "BUFFER", company, component, path, line, "%s", szDataLine);
+ }
+}
diff --git a/daemons/shaper/src/shaper_log_queue.c b/daemons/shaper/src/shaper_log_queue.c
new file mode 100644
index 00000000..52c6eb5e
--- /dev/null
+++ b/daemons/shaper/src/shaper_log_queue.c
@@ -0,0 +1,200 @@
+/*************************************************************************************************************
+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.
+*************************************************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "shaper_log_queue.h"
+
+#define SHAPER_LOG_COMPONENT "Queue"
+#include "shaper_log.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+struct shaper_log_queue_elem {
+ int setFlg;
+ void *data;
+};
+
+struct shaper_log_queue {
+ // Size of each element
+ uint32_t elemSize;
+
+ // Number of queue element slots
+ uint32_t queueSize;
+
+ // Next element to be filled
+ uint32_t head;
+
+ // Next element to be pulled
+ uint32_t tail;
+
+ shaper_log_queue_elem_t elemArray;
+};
+
+shaper_log_queue_t shaperLogQueueNewQueue(uint32_t elemSize, uint32_t queueSize)
+{
+ if (elemSize < 1 || queueSize < 1)
+ return NULL;
+
+ shaper_log_queue_t retQueue = calloc(1, sizeof(struct shaper_log_queue));
+ if (retQueue) {
+ retQueue->elemArray = calloc(queueSize, sizeof(struct shaper_log_queue_elem));
+ if (retQueue->elemArray) {
+ uint32_t i1;
+ for (i1 = 0; i1 < queueSize; i1++) {
+ retQueue->elemArray[i1].data = calloc(1, elemSize);
+ if (!retQueue->elemArray[i1].data) {
+ shaperLogQueueDeleteQueue(retQueue);
+ return NULL;
+ }
+ }
+ }
+ else {
+ shaperLogQueueDeleteQueue(retQueue);
+ return NULL;
+ }
+
+ retQueue->elemSize = elemSize;
+ retQueue->queueSize = queueSize;
+ retQueue->head = 0;
+ retQueue->tail = 0;
+ }
+
+ return retQueue;
+}
+
+void shaperLogQueueDeleteQueue(shaper_log_queue_t queue)
+{
+ if (queue) {
+ uint32_t i1;
+ for (i1 = 0; i1 < queue->queueSize; i1++) {
+ free(queue->elemArray[i1].data);
+ queue->elemArray[i1].data = NULL;
+ }
+ free(queue->elemArray);
+ queue->elemArray = NULL;
+ free(queue);
+ }
+}
+
+uint32_t shaperLogQueueGetQueueSize(shaper_log_queue_t queue)
+{
+ if (queue) {
+ return queue->queueSize;
+ }
+ return 0;
+}
+
+uint32_t shaperLogQueueGetElemCount(shaper_log_queue_t queue)
+{
+ uint32_t cnt = 0;
+ if (queue) {
+ if (queue->head > queue->tail) {
+ cnt += queue->head - queue->tail - 1;
+ }
+ else if (queue->head < queue->tail) {
+ cnt += queue->head + ((queue->queueSize - 1) - queue->tail);
+ }
+
+ if (queue->elemArray[queue->tail].setFlg) {
+ cnt++;
+ }
+ }
+ return cnt;
+}
+
+uint32_t shaperLogQueueGetElemSize(shaper_log_queue_t queue)
+{
+ if (queue) {
+ return queue->elemSize;
+ }
+ return 0;
+}
+
+void *shaperLogQueueData(shaper_log_queue_elem_t elem)
+{
+ if (elem) {
+ return elem->data;
+ }
+ return NULL;
+}
+
+shaper_log_queue_elem_t shaperLogQueueHeadLock(shaper_log_queue_t queue)
+{
+ if (queue) {
+ if (!queue->elemArray[queue->head].setFlg) {
+ return &queue->elemArray[queue->head];
+ }
+ }
+ return NULL;
+}
+
+void shaperLogQueueHeadUnlock(shaper_log_queue_t queue)
+{
+ (void) queue;
+}
+
+void shaperLogQueueHeadPush(shaper_log_queue_t queue)
+{
+ if (queue) {
+ queue->elemArray[queue->head++].setFlg = TRUE;
+ if (queue->head >= queue->queueSize) {
+ queue->head = 0;
+ }
+ }
+}
+
+shaper_log_queue_elem_t shaperLogQueueTailLock(shaper_log_queue_t queue)
+{
+ if (queue) {
+ if (queue->elemArray[queue->tail].setFlg) {
+ return &queue->elemArray[queue->tail];
+ }
+ }
+ return NULL;
+}
+
+void shaperLogQueueTailUnlock(shaper_log_queue_t queue)
+{
+ (void) queue;
+}
+
+void shaperLogQueueTailPull(shaper_log_queue_t queue)
+{
+ if (queue) {
+ queue->elemArray[queue->tail++].setFlg = FALSE;
+ if (queue->tail >= queue->queueSize) {
+ queue->tail = 0;
+ }
+ }
+}
diff --git a/daemons/shaper/src/shaper_log_queue.h b/daemons/shaper/src/shaper_log_queue.h
new file mode 100644
index 00000000..5453fa8c
--- /dev/null
+++ b/daemons/shaper/src/shaper_log_queue.h
@@ -0,0 +1,78 @@
+/*************************************************************************************************************
+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.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : Interface for a basic dynamic array abstraction.
+*
+* - Fixed size queue.
+* - Only head and tail access possible.
+* - Head and Tail locking.
+* - If there is a single task accessing head and a single task accessing tail no synchronization is needed.
+* - If synchronization is needed the Pull and Push functions should be protected before calling.
+*/
+
+#ifndef SHAPER_LOG_QUEUE_H
+#define SHAPER_LOG_QUEUE_H 1
+
+typedef struct shaper_log_queue_elem * shaper_log_queue_elem_t;
+typedef struct shaper_log_queue * shaper_log_queue_t;
+
+// Create an queue. Returns NULL on failure.
+shaper_log_queue_t shaperLogQueueNewQueue(uint32_t elemSize, uint32_t queueSize);
+
+// Delete an array.
+void shaperLogQueueDeleteQueue(shaper_log_queue_t queue);
+
+// Get number of queue slots
+uint32_t shaperLogQueueGetQueueSize(shaper_log_queue_t queue);
+
+// Get number of element
+uint32_t shaperLogQueueGetElemCount(shaper_log_queue_t queue);
+
+// Get element size
+uint32_t shaperLogQueueGetElemSize(shaper_log_queue_t queue);
+
+// Get data of the element. Returns NULL on failure.
+void *shaperLogQueueData(shaper_log_queue_elem_t elem);
+
+// Lock the head element.
+shaper_log_queue_elem_t shaperLogQueueHeadLock(shaper_log_queue_t queue);
+
+// Unlock the head element.
+void shaperLogQueueHeadUnlock(shaper_log_queue_t queue);
+
+// Push the head element making it available for tail access.
+void shaperLogQueueHeadPush(shaper_log_queue_t queue);
+
+// Lock the tail element.
+shaper_log_queue_elem_t shaperLogQueueTailLock(shaper_log_queue_t queue);
+
+// Unlock the tail element.
+void shaperLogQueueTailUnlock(shaper_log_queue_t queue);
+
+// Pull (remove) the tail element
+void shaperLogQueueTailPull(shaper_log_queue_t queue);
+
+#endif // SHAPER_LOG_QUEUE_H
diff --git a/kmod/igb/igb_main.c b/kmod/igb/igb_main.c
index 3310680d..c8a4a7e3 100644
--- a/kmod/igb/igb_main.c
+++ b/kmod/igb/igb_main.c
@@ -181,8 +181,14 @@ static void igb_restore_vf_multicasts(struct igb_adapter *adapter);
static void igb_process_mdd_event(struct igb_adapter *);
#ifdef IFLA_VF_MAX
static int igb_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac);
+#ifdef IFLA_VF_VLAN_INFO_MAX
+static int igb_ndo_set_vf_vlan(struct net_device *netdev,
+ int vf, u16 vlan, u8 qos, __be16 vlan_proto);
+#else
static int igb_ndo_set_vf_vlan(struct net_device *netdev,
int vf, u16 vlan, u8 qos);
+#endif /*IFLA_VF_VLAN_INFO_MAX*/
+
#ifdef HAVE_VF_SPOOFCHK_CONFIGURE
static int igb_ndo_set_vf_spoofchk(struct net_device *netdev, int vf,
bool setting);
@@ -6648,9 +6654,15 @@ static void igb_set_vmvir(struct igb_adapter *adapter, u32 vid, u32 vf)
else
E1000_WRITE_REG(hw, E1000_VMVIR(vf), 0);
}
+#ifdef IFLA_VF_VLAN_INFO_MAX
+static int igb_ndo_set_vf_vlan(struct net_device *netdev,
+ int vf, u16 vlan, u8 qos, __be16 vlan_proto)
+#else
static int igb_ndo_set_vf_vlan(struct net_device *netdev,
- int vf, u16 vlan, u8 qos)
+ int vf, u16 vlan, u8 qos)
+#endif /*IFLA_VF_VLAN_INFO_MAX*/
+
{
int err = 0;
struct igb_adapter *adapter = netdev_priv(netdev);
@@ -6659,6 +6671,7 @@ static int igb_ndo_set_vf_vlan(struct net_device *netdev,
if ((vf >= adapter->vfs_allocated_count) || (vlan > VLAN_VID_MASK-1)
|| (qos > 7))
return -EINVAL;
+
if (vlan || qos) {
err = igb_vlvf_set(adapter, vlan, !!vlan, vf);
if (err)
@@ -6816,9 +6829,16 @@ static inline void igb_vf_reset(struct igb_adapter *adapter, u32 vf)
igb_clear_vf_vfta(adapter, vf);
#ifdef IFLA_VF_MAX
if (adapter->vf_data[vf].pf_vlan)
+#ifdef IFLA_VF_VLAN_INFO_MAX
+ igb_ndo_set_vf_vlan(adapter->netdev, vf,
+ adapter->vf_data[vf].pf_vlan,
+ adapter->vf_data[vf].pf_qos, 0);
+#else
+
igb_ndo_set_vf_vlan(adapter->netdev, vf,
adapter->vf_data[vf].pf_vlan,
adapter->vf_data[vf].pf_qos);
+#endif
else
igb_clear_vf_vfta(adapter, vf);
#endif
diff --git a/lib/avtp_pipeline/LICENSE b/lib/avtp_pipeline/LICENSE
index 71e4e44e..bce20a35 100644
--- a/lib/avtp_pipeline/LICENSE
+++ b/lib/avtp_pipeline/LICENSE
@@ -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.
*************************************************************************************************************/
diff --git a/lib/avtp_pipeline/README.md b/lib/avtp_pipeline/README.md
index 315f8825..23e6e525 100644
--- a/lib/avtp_pipeline/README.md
+++ b/lib/avtp_pipeline/README.md
@@ -1,23 +1,22 @@
-# STC AVTP Pipeline Contribution Notes
+# STC/Harman AVTP Pipeline Contribution Notes
## General Status
- Consider the AVTP Pipeline a work in progress.
-- Integrated with OpenAVB:
+- Integrated with OpenAvnu:
- gPTP
+ - MAAP
- MSRP
- igb direct for packet TX.
- igb credit based shaper
- build system
-- Not yet integreated with OpenAVB:
- - MAAP
- Credit-based shaper algorithm is not used for individual streams.
- Testing of various mappings and benchmarking has been performed. Look at the end of this file for benchmark results.
- Documentation and doc generation has not been fully updated.
-## Building Current OpenAVB
+## Building Current OpenAvnu
### Tool chain and libraries
- Ubuntu 14.04
-- Install dependencies for OpenAVB ($ sudo apt-get install ...)
+- Install dependencies for OpenAvnu ($ sudo apt-get install ...)
- $ sudo apt-get install build-essential
- $ sudo apt-get install libpcap-dev
- $ sudo apt-get install libpci-dev
@@ -36,21 +35,30 @@
- Building from the repo root
- $ ARCH=I210 make all
-### Building just AVTP pipeline.
+### Building just AVTP pipeline
- $ make avtp_pipeline
Binaries will be installed in lib/avtp_pipeline/build/bin.
-### Building AVTP pipeline without SRP.
+### Building AVTP pipeline without SRP or MAAP support
- $ AVB_FEATURE_ENDPOINT=0 make avtp_pipeline
Make sure to call `make avtp_pipeline_clean` before.
-
### Building AVTP pipeline documentation
- $ make avtp_pipeline_doc
-## Running OpenAVB daemons
+### Building just AVTP AVDECC support
+- $ make avtp_avdecc
+
+Binaries will be installed in lib/avtp_pipeline/build_avdecc/bin.
+
+The openavb_avdecc binary needs to be run in addition to the AVTP pipeline binary (openavb_harness or openavb_host) for AVDECC to be supported.
+
+### Building AVTP AVDECC documentation
+- $ make avtp_avdecc_doc
+
+## Running OpenAvnu daemons
- Helper scripts in the repo root.
- `$ sudo ./run_igb.sh eth1`
- Load the igb driver. Supply the interface name (ethx) as parameter.
@@ -58,16 +66,18 @@ Make sure to call `make avtp_pipeline_clean` before.
- Start gptp daemon. Supply the interface name (ethx) as parameter.
- `$ sudo ./run_srp.sh eth1`
- Start msrp daemon. Supply the interface name (ethx) as parameter.
+- `$ sudo ./run_maap.sh eth1`
+ - Start maap daemon. Supply the interface name (ethx) as parameter.
-## Running OpenAVB simple talker example
+## Running OpenAvnu simple talker example
- `$ sudo ./run_simple_talker.sh eth1`
- - Run the current OpenAVB simple talker example. Supply the interface name (ethx) as parameter.
+ - Run the current OpenAvnu simple talker example. Supply the interface name (ethx) as parameter.
-## Running STC Echo Talker
+## Running OpenAvnu Echo Talker
- `$ sudo ./run_echo_talker.sh eth1`
- Run the AVTP Echo talker test stream. Supply the interface name (ethx) as parameter.
-## Running STC Echo Listener
+## Running OpenAvnu Echo Listener
- `$ sudo ./run_echo_listener.sh eth1`
- Run the AVTP Echo talker test stream. Supply the interface name (ethx) as parameter.
diff --git a/lib/avtp_pipeline/acmp/CMakeLists.txt b/lib/avtp_pipeline/acmp/CMakeLists.txt
new file mode 100644
index 00000000..41d67923
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/CMakeLists.txt
@@ -0,0 +1,9 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/acmp/openavb_acmp.c
+ ${AVB_SRC_DIR}/acmp/openavb_acmp_message.c
+ ${AVB_SRC_DIR}/acmp/openavb_acmp_sm_listener.c
+ ${AVB_SRC_DIR}/acmp/openavb_acmp_sm_talker.c
+ ${AVB_SRC_DIR}/acmp/openavb_acmp_sm_controller.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp.c b/lib/avtp_pipeline/acmp/openavb_acmp.c
new file mode 100644
index 00000000..9324c60d
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp.c
@@ -0,0 +1,147 @@
+/*************************************************************************************************************
+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 : ACMP - AVDECC Connection Management Protocol
+ * MODULE SUMMARY : Implements the 1722.1 (AVDECC) connection management protocol
+ ******************************************************************
+ */
+#include "openavb_platform.h"
+
+#include <signal.h>
+
+#define AVB_LOG_COMPONENT "ACMP"
+#include "openavb_log.h"
+
+#include "openavb_aem.h"
+#include "openavb_acmp.h"
+#include "openavb_acmp_sm_listener.h"
+#include "openavb_acmp_sm_talker.h"
+#include "openavb_acmp_sm_controller.h"
+#include "openavb_acmp_message.h"
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+
+openavb_acmp_sm_global_vars_t openavbAcmpSMGlobalVars;
+
+MUTEX_HANDLE(openavbAcmpMutex);
+#define ACMP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAcmpMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ACMP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAcmpMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+static bool bListenerStarted = FALSE;
+static bool bTalkerStarted = FALSE;
+
+openavbRC openavbAcmpStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavb_avdecc_entity_model_t *pAem = openavbAemGetModel();
+ if (!pAem) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING), AVB_TRACE_ACMP);
+ }
+
+ {
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "openavbAcmpMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(openavbAcmpMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'openavbAcmpMutex' mutex");
+ }
+
+ ACMP_LOCK();
+ {
+ // Populate global ACMP vars
+ openavb_acmp_control_header_t *pHeader = &openavbAcmpSMGlobalVars.controlHeader;
+
+ pHeader->cd = 1;
+ pHeader->subtype = OPENAVB_ACMP_AVTP_SUBTYPE;
+ pHeader->sv = 0;
+ pHeader->version = 0;
+ //pHeader->message_type = 0; // Set later depending on message type
+ //pHeader->status = 0; // Set later depending on message
+ pHeader->control_data_length = 44;
+ //pHeader->stream_id; // Set later depending on stream
+ }
+
+ {
+ memcpy(openavbAcmpSMGlobalVars.my_id, pAem->pDescriptorEntity->entity_id, sizeof(openavbAcmpSMGlobalVars.my_id));
+ }
+ ACMP_UNLOCK();
+
+ openavbRC rc = openavbAcmpMessageHandlerStart();
+ if (IS_OPENAVB_FAILURE(rc)) {
+ openavbAcmpStop();
+ AVB_RC_TRACE_RET(rc, AVB_TRACE_ACMP);
+ }
+
+ if (gAvdeccCfg.bListener) {
+ if (!openavbAcmpSMListenerStart()) {
+ AVB_RC_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_GENERIC), AVB_TRACE_ACMP);
+ }
+ bListenerStarted = TRUE;
+ }
+
+ if (gAvdeccCfg.bTalker) {
+ if (!openavbAcmpSMTalkerStart()) {
+ AVB_RC_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_GENERIC), AVB_TRACE_ACMP);
+ }
+ bTalkerStarted = TRUE;
+ }
+
+ if (!openavbAcmpSMControllerStart()) {
+ AVB_RC_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_GENERIC), AVB_TRACE_ACMP);
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_ACMP);
+}
+
+void openavbAcmpStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavbAcmpSMControllerStop();
+
+ if (bTalkerStarted) {
+ openavbAcmpSMTalkerStop();
+ }
+
+ if (bListenerStarted) {
+ openavbAcmpSMListenerStop();
+ }
+
+ openavbAcmpMessageHandlerStop();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp.h b/lib/avtp_pipeline/acmp/openavb_acmp.h
new file mode 100644
index 00000000..0d124fe7
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp.h
@@ -0,0 +1,195 @@
+/*************************************************************************************************************
+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 : ACMP - AVDECC Connection Management Protocol
+ * MODULE SUMMARY : Interface for the 1722.1 (AVDECC) connection management protocol
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ACMP_H
+#define OPENAVB_ACMP_H 1
+
+#include "openavb_tl.h"
+#include "openavb_array.h"
+#include "openavb_list.h"
+#include "openavb_avdecc.h"
+#include "openavb_acmp_pub.h"
+
+#define OPENAVB_ACMP_AVTP_SUBTYPE (0x7C)
+
+#define OPENAVB_ADP_MESSAGE_TYPE_ENTITY_AVAILABLE (0x00)
+
+// message_type field IEEE Std 1722.1-2013 clause 8.2.1.5
+#define OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND (0)
+#define OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE (1)
+#define OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND (2)
+#define OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE (3)
+#define OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_COMMAND (4)
+#define OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE (5)
+#define OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND (6)
+#define OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE (7)
+#define OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_COMMAND (8)
+#define OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE (9)
+#define OPENAVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_COMMAND (10)
+#define OPENAVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE (11)
+#define OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_COMMAND (12)
+#define OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_RESPONSE (13)
+
+// status field field IEEE Std 1722.1-2013 clause 8.2.1.6
+#define OPENAVB_ACMP_STATUS_SUCCESS (0)
+#define OPENAVB_ACMP_STATUS_LISTENER_UNKNOWN_ID (1)
+#define OPENAVB_ACMP_STATUS_TALKER_UNKNOWN_ID (2)
+#define OPENAVB_ACMP_STATUS_TALKER_DEST_MAC_FAIL (3)
+#define OPENAVB_ACMP_STATUS_TALKER_NO_STREAM_INDEX (4)
+#define OPENAVB_ACMP_STATUS_TALKER_NO_BANDWIDTH (5)
+#define OPENAVB_ACMP_STATUS_TALKER_EXCLUSIVE (6)
+#define OPENAVB_ACMP_STATUS_LISTENER_TALKER_TIMEOUT (7)
+#define OPENAVB_ACMP_STATUS_LISTENER_EXCLUSIVE (8)
+#define OPENAVB_ACMP_STATUS_STATE_UNAVAILABLE (9)
+#define OPENAVB_ACMP_STATUS_NOT_CONNECTED (10)
+#define OPENAVB_ACMP_STATUS_NO_SUCH_CONNECTION (11)
+#define OPENAVB_ACMP_STATUS_COULD_NOT_SEND_MESSAGE (12)
+#define OPENAVB_ACMP_STATUS_TALKER_MISBEHAVING (13)
+#define OPENAVB_ACMP_STATUS_LISTENER_MISBEHAVING (14)
+#define OPENAVB_ACMP_STATUS_CONTROLLER_NOT_AUTHORIZED (16)
+#define OPENAVB_ACMP_STATUS_INCOMPATIBLE_REQUEST (17)
+#define OPENAVB_ACMP_STATUS_NOT_SUPPORTED (31)
+
+// flags field IEEE Std 1722.1-2013 clause 8.2.1.17
+#define OPENAVB_ACMP_FLAG_CLASS_B (0x0001)
+#define OPENAVB_ACMP_FLAG_FAST_CONNECT (0x0002)
+#define OPENAVB_ACMP_FLAG_SAVED_STATE (0x0004)
+#define OPENAVB_ACMP_FLAG_STREAMING_WAIT (0x0008)
+#define OPENAVB_ACMP_FLAG_SUPPORTS_ENCRYPTED (0x0010)
+#define OPENAVB_ACMP_FLAG_ENCRYPTED_PDU (0x0020)
+#define OPENAVB_ACMP_FLAG_TALKER_FAILED (0x0040)
+
+// ACMP command timeouts IEEE Std 1722.1-2013 Table 8.4
+#define OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_TX_COMMAND (2000)
+#define OPENAVB_ACMP_COMMAND_TIMEOUT_DISCONNECT_TX_COMMAND (200)
+#define OPENAVB_ACMP_COMMAND_TIMEOUT_GET_TX_STATE_COMMAND (200)
+#define OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_RX_COMMAND (4500)
+#define OPENAVB_ACMP_COMMAND_TIMEOUT_DISCONNECT_RX_COMMAND (500)
+#define OPENAVB_ACMP_COMMAND_TIMEOUT_GET_RX_STATE_COMMAND (200)
+#define OPENAVB_ACMP_COMMAND_TIMEOUT_GET_TX_CONNECTION_COMMAND (200)
+
+
+typedef struct {
+ U8 cd;
+ U8 subtype;
+ U8 sv;
+ U8 version;
+ U8 message_type; // Redefined from control data
+ U8 status;
+ U16 control_data_length;
+ U8 stream_id[8];
+} openavb_acmp_control_header_t;
+
+// ACMPCommandResponse type IEEE Std 1722.1-2013 clause 8.2.2.2.1
+typedef struct {
+ U8 message_type;
+ U8 status;
+ U8 stream_id[8];
+ U8 controller_entity_id[8];
+ U8 talker_entity_id[8];
+ U8 listener_entity_id[8];
+ U16 talker_unique_id;
+ U16 listener_unique_id;
+ U8 stream_dest_mac[6];
+ U16 connection_count;
+ U16 sequence_id;
+ U16 flags;
+ U16 stream_vlan_id;
+} openavb_acmp_ACMPCommandResponse_t;
+
+// ListenerStreamInfo type IEEE Std 1722.1-2013 clause 8.2.2.2.2
+typedef struct {
+ U8 talker_entity_id[8];
+ U16 talker_unique_id;
+ U8 connected; // Boolean
+ U8 stream_id[8];
+ U8 stream_dest_mac[6];
+ U8 controller_entity_id[8];
+ U16 flags;
+ U16 stream_vlan_id;
+} openavb_acmp_ListenerStreamInfo_t;
+
+// ListenerPair type IEEE Std 1722.1-2013 clause 8.2.2.2.3
+typedef struct {
+ U8 listener_entity_id[8];
+ U16 listener_unique_id;
+} openavb_acmp_ListenerPair_t;
+
+// TalkerStreamInfo type IEEE Std 1722.1-2013 clause 8.2.2.2.4
+typedef struct {
+ U8 stream_id[8];
+ U8 stream_dest_mac[6];
+ U16 connection_count;
+ openavb_list_t connected_listeners;
+ U16 stream_vlan_id;
+
+ // Extra information indicating a GET_TX_CONNECTION_RESPONSE command is needed.
+ openavb_acmp_ACMPCommandResponse_t *waiting_on_talker;
+} openavb_acmp_TalkerStreamInfo_t;
+
+// InflightCommand type IEEE Std 1722.1-2013 clause 8.2.2.2.5
+typedef struct {
+ struct timespec timer;
+ U8 retried;
+ openavb_acmp_ACMPCommandResponse_t command;
+ U16 original_sequence_id;
+} openavb_acmp_InflightCommand_t;
+
+// ACMPCommandParams type IEEE Std 1722.1-2013 clause 8.2.2.2.6
+typedef struct {
+ U8 message_type;
+ U8 talker_entity_id[8];
+ U8 listener_entity_id[8];
+ U16 talker_unique_id;
+ U16 listener_unique_id;
+ U16 connection_count;
+ U16 flags;
+ U16 stream_vlan_id;
+} openavb_acmp_ACMPCommandParams_t;
+
+// State machine global variables IEEE Std 1722.1-2013 clause 8.2.2.3
+typedef struct {
+ U8 my_id[8];
+ //openavb_acmp_ACMPCommandResponse_t rcvdCmdResp; // defined in spec but implemented such that the listener and talker state machines maintain their own.
+ openavb_acmp_control_header_t controlHeader;
+} openavb_acmp_sm_global_vars_t;
+
+openavbRC openavbAcmpStart(void);
+void openavbAcmpStop(void);
+
+#endif // OPENAVB_ACMP_H
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp_message.c b/lib/avtp_pipeline/acmp/openavb_acmp_message.c
new file mode 100644
index 00000000..8969f9cd
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp_message.c
@@ -0,0 +1,424 @@
+/*************************************************************************************************************
+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 : ACMP - AVDECC Connection Management Protocol Message Handler
+ * MODULE SUMMARY : Implements the 1722.1 ACMP - AVDECC Connection Management Protocol message handlers
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#define AVB_LOG_COMPONENT "ACMP"
+#include "openavb_log.h"
+
+#include "openavb_debug.h"
+#include "openavb_rawsock.h"
+#include "openavb_avtp.h"
+#include "openavb_srp.h"
+#include "openavb_acmp.h"
+#include "openavb_acmp_sm_controller.h"
+#include "openavb_acmp_sm_listener.h"
+#include "openavb_acmp_sm_talker.h"
+
+#define INVALID_SOCKET (-1)
+
+// ACMP Multicast address
+#define ACMP_PROTOCOL_ADDR "91:E0:F0:01:00:00"
+
+// message length
+#define AVTP_HDR_LEN 12
+#define ACMP_DATA_LEN 44
+#define ACMP_FRAME_LEN (ETH_HDR_LEN_VLAN + AVTP_HDR_LEN + ACMP_DATA_LEN)
+
+// number of buffers
+#define ACMP_NUM_TX_BUFFERS 2
+#define ACMP_NUM_RX_BUFFERS 20
+
+// do cast from ether_addr to U8*
+#define ADDR_PTR(A) (U8*)(&((A)->ether_addr_octet))
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+
+extern MUTEX_HANDLE(openavbAcmpMutex);
+#define ACMP_LOCK() MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAcmpMutex); MUTEX_LOG_ERR("Mutex lock failure");
+#define ACMP_UNLOCK() MUTEX_UNLOCK(openavbAcmpMutex);
+
+static void *rxSock = NULL;
+static void *txSock = NULL;
+static struct ether_addr intfAddr;
+static struct ether_addr acmpAddr;
+
+extern openavb_acmp_sm_global_vars_t openavbAcmpSMGlobalVars;
+
+THREAD_TYPE(openavbAcmpMessageRxThread);
+THREAD_DEFINITON(openavbAcmpMessageRxThread);
+
+static bool bRunning = FALSE;
+
+void openavbAcmpCloseSocket()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ if (rxSock) {
+ openavbRawsockClose(rxSock);
+ rxSock = NULL;
+ }
+ if (txSock) {
+ openavbRawsockClose(txSock);
+ txSock = NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+bool openavbAcmpOpenSocket(const char* ifname, U16 vlanID, U8 vlanPCP)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ hdr_info_t hdr;
+
+ rxSock = openavbRawsockOpen(ifname, TRUE, FALSE, ETHERTYPE_AVTP, ACMP_FRAME_LEN, ACMP_NUM_RX_BUFFERS);
+ txSock = openavbRawsockOpen(ifname, FALSE, TRUE, ETHERTYPE_AVTP, ACMP_FRAME_LEN, ACMP_NUM_TX_BUFFERS);
+
+ if (txSock && rxSock
+ && openavbRawsockGetAddr(txSock, ADDR_PTR(&intfAddr))
+ && ether_aton_r(ACMP_PROTOCOL_ADDR, &acmpAddr)
+ && openavbRawsockRxMulticast(rxSock, TRUE, ADDR_PTR(&acmpAddr)))
+ {
+ if (!openavbRawsockRxAVTPSubtype(rxSock, OPENAVB_ACMP_AVTP_SUBTYPE | 0x80)) {
+ AVB_LOG_DEBUG("RX AVTP Subtype not supported");
+ }
+
+ memset(&hdr, 0, sizeof(hdr_info_t));
+ hdr.shost = ADDR_PTR(&intfAddr);
+ hdr.dhost = ADDR_PTR(&acmpAddr);
+ hdr.ethertype = ETHERTYPE_AVTP;
+ if (vlanID != 0 || vlanPCP != 0) {
+ hdr.vlan = TRUE;
+ hdr.vlan_pcp = vlanPCP;
+ hdr.vlan_vid = vlanID;
+ AVB_LOGF_DEBUG("VLAN pcp=%d vid=%d", hdr.vlan_pcp, hdr.vlan_vid);
+ }
+ if (!openavbRawsockTxSetHdr(txSock, &hdr)) {
+ AVB_LOG_ERROR("TX socket Header Failure");
+ openavbAcmpCloseSocket();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return false;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return true;
+ }
+
+ AVB_LOG_ERROR("Invalid socket");
+ openavbAcmpCloseSocket();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return false;
+}
+
+static void openavbAcmpMessageRxFrameParse(U8* payload, int payload_len, hdr_info_t *hdr)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavb_acmp_control_header_t acmpHeader;
+ openavb_acmp_ACMPCommandResponse_t acmpCommandResponse;
+
+#if 0
+ AVB_LOGF_DEBUG("openavbAcmpMessageRxFrameParse packet data (length %d):", payload_len);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_DEBUG, payload, payload_len, 16);
+#endif
+
+ U8 *pSrc = payload;
+ {
+ openavb_acmp_control_header_t *pDst1 = &acmpHeader;
+ openavb_acmp_ACMPCommandResponse_t *pDst2 = &acmpCommandResponse;
+
+ memset(&acmpHeader, 0, sizeof(acmpHeader));
+ memset(&acmpCommandResponse, 0, sizeof(acmpCommandResponse));
+
+ // AVTP Control Header
+ BIT_B2DNTOHB(pDst1->cd, pSrc, 0x80, 7, 0);
+ BIT_B2DNTOHB(pDst1->subtype, pSrc, 0x7f, 0, 1);
+ BIT_B2DNTOHB(pDst1->sv, pSrc, 0x80, 7, 0);
+ BIT_B2DNTOHB(pDst1->version, pSrc, 0x70, 4, 0);
+ BIT_B2DNTOHB(pDst2->message_type, pSrc, 0x0f, 0, 1);
+ BIT_B2DNTOHB(pDst2->status, pSrc, 0xf800, 11, 0);
+ BIT_B2DNTOHS(pDst1->control_data_length, pSrc, 0x07ff, 0, 2);
+ OCT_B2DMEMCP(pDst2->stream_id, pSrc);
+
+ // ACMP PDU
+ OCT_B2DMEMCP(pDst2->controller_entity_id, pSrc);
+ OCT_B2DMEMCP(pDst2->talker_entity_id, pSrc);
+ OCT_B2DMEMCP(pDst2->listener_entity_id, pSrc);
+ OCT_B2DNTOHS(pDst2->talker_unique_id, pSrc);
+ OCT_B2DNTOHS(pDst2->listener_unique_id, pSrc);
+ OCT_B2DMEMCP(pDst2->stream_dest_mac, pSrc);
+ OCT_B2DNTOHS(pDst2->connection_count, pSrc);
+ OCT_B2DNTOHS(pDst2->sequence_id, pSrc);
+ OCT_B2DNTOHS(pDst2->flags, pSrc);
+ OCT_B2DNTOHS(pDst2->stream_vlan_id, pSrc);
+ }
+
+ // Update the state machine
+ switch (acmpCommandResponse.message_type) {
+ case OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND:
+ openavbAcmpSMTalkerSet_rcvdConnectTXCmd(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE:
+ openavbAcmpSMListenerSet_rcvdConnectTXResp(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND:
+ openavbAcmpSMTalkerSet_rcvdDisconnectTXCmd(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE:
+ openavbAcmpSMListenerSet_rcvdDisconnectTXResp(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_COMMAND:
+ openavbAcmpSMTalkerSet_rcvdGetTXState(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE:
+ openavbAcmpSMControllerSet_rcvdResponse(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND:
+ openavbAcmpSMListenerSet_rcvdConnectRXCmd(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE:
+ openavbAcmpSMControllerSet_rcvdResponse(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_COMMAND:
+ openavbAcmpSMListenerSet_rcvdDisconnectRXCmd(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE:
+ openavbAcmpSMControllerSet_rcvdResponse(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_COMMAND:
+ openavbAcmpSMListenerSet_rcvdGetRXState(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE:
+ openavbAcmpSMControllerSet_rcvdResponse(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_COMMAND:
+ openavbAcmpSMTalkerSet_rcvdGetTXConnectionCmd(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_RESPONSE:
+ openavbAcmpSMControllerSet_rcvdResponse(&acmpCommandResponse);
+ break;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+static void openavbAcmpMessageRxFrameReceive(U32 timeoutUsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ hdr_info_t hdrInfo;
+ unsigned int offset, len;
+ U8 *pBuf, *pFrame;
+
+ memset(&hdrInfo, 0, sizeof(hdr_info_t));
+
+ pBuf = (U8 *)openavbRawsockGetRxFrame(rxSock, timeoutUsec, &offset, &len);
+ if (pBuf) {
+ pFrame = pBuf + offset;
+
+ offset = openavbRawsockRxParseHdr(rxSock, pBuf, &hdrInfo);
+ {
+#ifndef UBUNTU
+ if (hdrInfo.ethertype == ETHERTYPE_8021Q) {
+ // Oh! Need to look past the VLAN tag
+ U16 vlan_bits = ntohs(*(U16 *)(pFrame + offset));
+ hdrInfo.vlan = TRUE;
+ hdrInfo.vlan_vid = vlan_bits & 0x0FFF;
+ hdrInfo.vlan_pcp = (vlan_bits >> 13) & 0x0007;
+ offset += 2;
+ hdrInfo.ethertype = ntohs(*(U16 *)(pFrame + offset));
+ offset += 2;
+ }
+#endif
+
+ // Make sure that this is an AVTP packet
+ // (Should always be AVTP if it's to our AVTP-specific multicast address)
+ if (hdrInfo.ethertype == ETHERTYPE_AVTP) {
+ // parse the PDU only for ACMP messages
+ if (*(pFrame + offset) == (0x80 | OPENAVB_ACMP_AVTP_SUBTYPE)) {
+ openavbAcmpMessageRxFrameParse(pFrame + offset, len - offset, &hdrInfo);
+ }
+ }
+ else {
+ AVB_LOG_WARNING("Received non-AVTP frame!");
+ AVB_LOGF_DEBUG("Unexpected packet data (length %d):", len);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_DEBUG, pFrame, len, 16);
+ }
+ }
+
+ // Release the frame
+ openavbRawsockRelRxFrame(rxSock, pBuf);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpMessageTxFrame(U8 messageType, openavb_acmp_ACMPCommandResponse_t *pACMPCommandResponse, U8 status)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ U8 *pBuf;
+ U32 size;
+ unsigned int hdrlen = 0;
+
+ pBuf = openavbRawsockGetTxFrame(txSock, TRUE, &size);
+
+ if (!pBuf) {
+ AVB_LOG_ERROR("No TX buffer");
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return; // AVDECC_TODO - return error result
+ }
+
+ if (size < ACMP_FRAME_LEN) {
+ AVB_LOG_ERROR("TX buffer too small");
+ openavbRawsockRelTxFrame(txSock, pBuf);
+ pBuf = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return; // AVDECC_TODO - return error result
+ }
+
+ memset(pBuf, 0, ACMP_FRAME_LEN);
+ openavbRawsockTxFillHdr(txSock, pBuf, &hdrlen);
+
+ ACMP_LOCK();
+ U8 *pDst = pBuf + hdrlen;
+ {
+ openavb_acmp_control_header_t *pSrc1 = &openavbAcmpSMGlobalVars.controlHeader;
+ openavb_acmp_ACMPCommandResponse_t *pSrc2 = pACMPCommandResponse;
+
+ // AVTP Control Header
+ BIT_D2BHTONB(pDst, pSrc1->cd, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc1->subtype, 0, 1);
+ BIT_D2BHTONB(pDst, pSrc1->sv, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc1->version, 4, 0);
+ BIT_D2BHTONB(pDst, messageType, 0, 1);
+ BIT_D2BHTONS(pDst, status, 11, 0);
+ BIT_D2BHTONS(pDst, pSrc1->control_data_length, 0, 2);
+ OCT_D2BMEMCP(pDst, pSrc2->stream_id);
+
+ // ACMP PDU
+ OCT_D2BMEMCP(pDst, pSrc2->controller_entity_id);
+ OCT_D2BMEMCP(pDst, pSrc2->talker_entity_id);
+ OCT_D2BMEMCP(pDst, pSrc2->listener_entity_id);
+ OCT_D2BHTONS(pDst, pSrc2->talker_unique_id);
+ OCT_D2BHTONS(pDst, pSrc2->listener_unique_id);
+ OCT_D2BMEMCP(pDst, pSrc2->stream_dest_mac);
+ OCT_D2BHTONS(pDst, pSrc2->connection_count);
+ OCT_D2BHTONS(pDst, pSrc2->sequence_id);
+ OCT_D2BHTONS(pDst, pSrc2->flags);
+ OCT_D2BHTONS(pDst, pSrc2->stream_vlan_id);
+ }
+ ACMP_UNLOCK();
+
+#if 0
+ AVB_LOGF_DEBUG("openavbAcmpMessageTxFrame packet data (length %d):", hdrlen + AVTP_HDR_LEN + ACMP_DATA_LEN);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_DEBUG, pBuf, hdrlen + AVTP_HDR_LEN + ACMP_DATA_LEN, 16);
+#endif
+
+ openavbRawsockTxFrameReady(txSock, pBuf, hdrlen + AVTP_HDR_LEN + ACMP_DATA_LEN, 0);
+ openavbRawsockSend(txSock);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void* openavbAcmpMessageRxThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ AVB_LOG_DEBUG("ACMP Thread Started");
+ while (bRunning) {
+ // Try to get and process an ACMP.
+ openavbAcmpMessageRxFrameReceive(MICROSECONDS_PER_SECOND);
+ }
+ AVB_LOG_DEBUG("ACMP Thread Done");
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return NULL;
+}
+
+openavbRC openavbAcmpMessageHandlerStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ bRunning = TRUE;
+
+ if (openavbAcmpOpenSocket((const char *)gAvdeccCfg.ifname, gAvdeccCfg.vlanID, gAvdeccCfg.vlanPCP)) {
+
+ // Start the RX thread
+ bool errResult;
+ THREAD_CREATE(openavbAcmpMessageRxThread, openavbAcmpMessageRxThread, NULL, openavbAcmpMessageRxThreadFn, NULL);
+ THREAD_CHECK_ERROR(openavbAcmpMessageRxThread, "Thread / task creation failed", errResult);
+ if (errResult) {
+ bRunning = FALSE;
+ openavbAcmpCloseSocket();
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_FAILURE, AVB_TRACE_ACMP);
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_ACMP);
+ }
+
+ bRunning = FALSE;
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_FAILURE, AVB_TRACE_ACMP);
+}
+
+void openavbAcmpMessageHandlerStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ if (bRunning) {
+ bRunning = FALSE;
+ THREAD_JOIN(openavbAcmpMessageRxThread, NULL);
+ openavbAcmpCloseSocket();
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+openavbRC openavbAcmpMessageSend(U8 messageType, openavb_acmp_ACMPCommandResponse_t *pACMPCommandResponse, U8 status)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavbAcmpMessageTxFrame(messageType, pACMPCommandResponse, status);
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_ACMP);
+}
+
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp_message.h b/lib/avtp_pipeline/acmp/openavb_acmp_message.h
new file mode 100644
index 00000000..f54f7bfe
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp_message.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.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ACMP - AVDECC Connection Management Protocol Message Handler Interface
+ * MODULE SUMMARY : Interface for the 1722.1 ACMP - AVDECC Connection Management Protocol message handlers
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ADP_MESSAGE_H
+#define OPENAVB_ADP_MESSAGE_H 1
+
+#include "openavb_avdecc.h"
+
+openavbRC openavbAcmpMessageHandlerStart(void);
+
+void openavbAcmpMessageHandlerStop(void);
+
+openavbRC openavbAcmpMessageSend(U8 messageType, openavb_acmp_ACMPCommandResponse_t *pACMPCommandResponse, U8 status);
+
+#endif // OPENAVB_ADP_MESSAGE_H
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp_pub.h b/lib/avtp_pipeline/acmp/openavb_acmp_pub.h
new file mode 100644
index 00000000..82e6b3ed
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp_pub.h
@@ -0,0 +1,42 @@
+/*************************************************************************************************************
+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 : ACMP - AVDECC Connection Management Protocol Public Interface
+ * MODULE SUMMARY : Public interface for the 1722.1 ACMP - AVDECC Connection Management Protocol
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ACMP_PUB_H
+#define OPENAVB_ACMP_PUB_H 1
+
+#endif // OPENAVB_ACMP_PUB_H
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp_sm_controller.c b/lib/avtp_pipeline/acmp/openavb_acmp_sm_controller.c
new file mode 100644
index 00000000..e61522bb
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp_sm_controller.c
@@ -0,0 +1,435 @@
+/*************************************************************************************************************
+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 : ACMP - AVDECC Connection Management Protocol : Controller State Machine
+ * MODULE SUMMARY : Implements the ACMP - AVDECC Connection Management Protocol : Controller State Machine
+ * IEEE Std 1722.1-2013 clause 8.2.2.4
+ ******************************************************************
+ */
+
+#define AVB_LOG_COMPONENT "ACMP"
+#include "openavb_log.h"
+
+#include "openavb_debug.h"
+#include "openavb_time.h"
+#include "openavb_acmp_sm_controller.h"
+#include "openavb_acmp_message.h"
+#include "openavb_avdecc_pipeline_interaction_pub.h"
+
+typedef enum {
+ OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING,
+ OPENAVB_ACMP_SM_CONTROLLER_STATE_TIMEOUT,
+ OPENAVB_ACMP_SM_CONTROLLER_STATE_RESPONSE
+} openavb_acmp_sm_controller_state_t;
+
+extern openavb_acmp_sm_global_vars_t openavbAcmpSMGlobalVars;
+
+static openavb_acmp_ACMPCommandResponse_t rcvdCmdResp;
+static openavb_acmp_ACMPCommandResponse_t *pRcvdCmdResp = &rcvdCmdResp;
+static openavb_acmp_sm_controller_vars_t openavbAcmpSMControllerVars = {0};
+static bool bRunning = FALSE;
+
+extern MUTEX_HANDLE(openavbAcmpMutex);
+#define ACMP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAcmpMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ACMP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAcmpMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+static MUTEX_HANDLE(openavbAcmpSMControllerMutex);
+#define ACMP_SM_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAcmpSMControllerMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ACMP_SM_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAcmpSMControllerMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+SEM_T(openavbAcmpSMControllerSemaphore);
+THREAD_TYPE(openavbAcmpSmControllerThread);
+THREAD_DEFINITON(openavbAcmpSmControllerThread);
+
+
+static openavb_list_node_t openavbAcmpSMController_findInflightNodeFromCommand(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavb_list_node_t node = openavbListIterFirst(openavbAcmpSMControllerVars.inflight);
+ while (node) {
+ openavb_acmp_InflightCommand_t *pInFlightCommand = openavbListData(node);
+ if (pInFlightCommand) {
+ if (memcmp(pInFlightCommand->command.controller_entity_id, command->controller_entity_id, sizeof(pInFlightCommand->command.controller_entity_id)) == 0 &&
+ pInFlightCommand->command.sequence_id == command->sequence_id) {
+ break;
+ }
+ }
+ node = openavbListIterNext(openavbAcmpSMControllerVars.inflight);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return node;
+}
+
+
+void openavbAcmpSMController_txCommand(U8 messageType, openavb_acmp_ACMPCommandResponse_t *command, bool retry)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavb_list_node_t node = NULL;
+
+ openavbRC rc = openavbAcmpMessageSend(messageType, command, OPENAVB_ACMP_STATUS_SUCCESS);
+ if (IS_OPENAVB_SUCCESS(rc)) {
+ if (!retry) {
+ node = openavbListNew(openavbAcmpSMControllerVars.inflight, sizeof(openavb_acmp_InflightCommand_t));
+ if (node) {
+ openavb_acmp_InflightCommand_t *pInFlightCommand = openavbListData(node);
+ if (pInFlightCommand) {
+
+ memcpy(&pInFlightCommand->command, command, sizeof(pInFlightCommand->command));
+ pInFlightCommand->command.message_type = messageType;
+ pInFlightCommand->retried = FALSE;
+ pInFlightCommand->original_sequence_id = command->sequence_id; // AVDECC_TODO - is this correct?
+
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pInFlightCommand->timer);
+ switch (messageType) {
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_GET_TX_STATE_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_RX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_DISCONNECT_RX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_GET_RX_STATE_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_GET_TX_CONNECTION_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ default:
+ AVB_LOGF_ERROR("Unsupported command %u in openavbAcmpSMController_txCommand", messageType);
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_RX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ }
+ }
+ }
+ }
+ else {
+ // Retry case
+ node = openavbAcmpSMController_findInflightNodeFromCommand(command);
+ if (node) {
+ openavb_acmp_InflightCommand_t *pInFlightCommand = openavbListData(node);
+ if (pInFlightCommand) {
+ pInFlightCommand->retried = TRUE;
+
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pInFlightCommand->timer);
+ switch (messageType) {
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_GET_TX_STATE_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_RX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_DISCONNECT_RX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_GET_RX_STATE_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_GET_TX_CONNECTION_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ default:
+ AVB_LOGF_ERROR("Unsupported command %u in openavbAcmpSMController_txCommand", messageType);
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_RX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ }
+ }
+ }
+ }
+ }
+ else {
+ // Failed to send command
+ openavbAcmpMessageSend(messageType, command, OPENAVB_ACMP_STATUS_COULD_NOT_SEND_MESSAGE);
+ if (retry) {
+ node = openavbAcmpSMController_findInflightNodeFromCommand(command);
+ if (node) {
+ openavbListDelete(openavbAcmpSMControllerVars.inflight, node);
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMController_cancelTimeout(openavb_acmp_ACMPCommandResponse_t *commandResponse)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ // Nothing to do since the timer is reset during the wait state and the inFlight entry will have already been removed.
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMController_removeInflight(openavb_acmp_ACMPCommandResponse_t *commandResponse)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavb_list_node_t node = openavbAcmpSMController_findInflightNodeFromCommand(commandResponse);
+ if (node) {
+ openavbListDelete(openavbAcmpSMControllerVars.inflight, node);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMController_processResponse(openavb_acmp_ACMPCommandResponse_t *commandResponse)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ // AVDECC_TODO: Is there anything we need to do here, such as updating the saved state?
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMController_makeCommand(openavb_acmp_ACMPCommandParams_t *param)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ // AVDECC_TODO: Fill this in if implementing the doCommand support.
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMControllerStateMachine()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavb_acmp_InflightCommand_t *pInflightActive = NULL; // The inflight command for the current state
+ openavb_acmp_sm_controller_state_t state = OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING;
+
+ // Lock such that the mutex is held unless waiting for a semaphore. Synchronous processing of command responses.
+ ACMP_SM_LOCK();
+ while (bRunning) {
+ switch (state) {
+ case OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING:
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING");
+
+ openavbAcmpSMControllerVars.rcvdResponse = FALSE;
+
+ // Calculate timeout for inflight commands
+ // Start is a arbitrary large time out.
+ struct timespec timeout;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &timeout);
+ timeout.tv_sec += 60; // At most will timeout after 60 seconds
+
+ // Look for soonest inflight command timeout
+ openavb_list_node_t node = openavbListIterFirst(openavbAcmpSMControllerVars.inflight);
+ while (node) {
+ openavb_acmp_InflightCommand_t *pInflight = openavbListData(node);
+ if ((openavbTimeTimespecCmp(&pInflight->timer, &timeout) < 0)) {
+ timeout.tv_sec = pInflight->timer.tv_sec;
+ timeout.tv_nsec = pInflight->timer.tv_nsec;
+ }
+ node = openavbListIterNext(openavbAcmpSMControllerVars.inflight);
+ }
+
+ ACMP_SM_UNLOCK();
+ U32 timeoutMSec = 0;
+ struct timespec now;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &now);
+ timeoutMSec = openavbTimeUntilMSec(&now, &timeout);
+ SEM_ERR_T(err);
+ SEM_TIMEDWAIT(openavbAcmpSMControllerSemaphore, timeoutMSec, err);
+ ACMP_SM_LOCK();
+
+ if (!SEM_IS_ERR_NONE(err)) {
+ if (SEM_IS_ERR_TIMEOUT(err)) {
+ struct timespec now;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &now);
+
+ // Look for a timed out inflight command
+ openavb_list_node_t node = openavbListIterFirst(openavbAcmpSMControllerVars.inflight);
+ while (node) {
+ openavb_acmp_InflightCommand_t *pInflight = openavbListData(node);
+ if ((openavbTimeTimespecCmp(&now, &pInflight->timer) >= 0)) {
+ // Found a timed out command
+ state = OPENAVB_ACMP_SM_CONTROLLER_STATE_TIMEOUT;
+ pInflightActive = pInflight;
+ break;
+ }
+ node = openavbListIterNext(openavbAcmpSMControllerVars.inflight);
+ }
+ }
+ }
+ else {
+ if (openavbAcmpSMControllerVars.doTerminate) {
+ bRunning = FALSE;
+ }
+ else if (openavbAcmpSMControllerVars.rcvdResponse &&
+ memcmp(pRcvdCmdResp->controller_entity_id, openavbAcmpSMGlobalVars.my_id, sizeof(openavbAcmpSMGlobalVars.my_id)) == 0) {
+ // Look for a corresponding inflight command
+ openavb_list_node_t node = openavbListIterFirst(openavbAcmpSMControllerVars.inflight);
+ while (node) {
+ openavb_acmp_InflightCommand_t *pInflight = openavbListData(node);
+ if (pRcvdCmdResp->sequence_id == pInflight->command.sequence_id &&
+ pRcvdCmdResp->message_type == pInflight->command.message_type + 1) {
+ // Found a corresponding command
+ state = OPENAVB_ACMP_SM_CONTROLLER_STATE_RESPONSE;
+ pInflightActive = pInflight;
+ break;
+ }
+ node = openavbListIterNext(openavbAcmpSMControllerVars.inflight);
+ }
+ }
+ break;
+
+ case OPENAVB_ACMP_SM_CONTROLLER_STATE_TIMEOUT:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_CONTROLLER_STATE_TIMEOUT");
+
+ if (pInflightActive) {
+ if (pInflightActive->retried) {
+ openavbAcmpSMController_removeInflight(&pInflightActive->command);
+ }
+ else {
+ openavbAcmpSMController_txCommand(pInflightActive->command.message_type, &pInflightActive->command, TRUE);
+ }
+ }
+ pInflightActive = NULL;
+ state = OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING;
+ }
+ break;
+
+ case OPENAVB_ACMP_SM_CONTROLLER_STATE_RESPONSE:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_CONTROLLER_STATE_RESPONSE");
+
+ if (pInflightActive) {
+ openavbAcmpSMController_cancelTimeout(pRcvdCmdResp);
+ openavbAcmpSMController_processResponse(pRcvdCmdResp);
+ openavbAcmpSMController_removeInflight(pRcvdCmdResp);
+ }
+ pInflightActive = NULL;
+ state = OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING;
+ }
+ break;
+ }
+ }
+ }
+ ACMP_SM_UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void* openavbAcmpSMControllerThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavbAcmpSMControllerStateMachine();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return NULL;
+}
+
+bool openavbAcmpSMControllerStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavbAcmpSMControllerVars.inflight = openavbListNewList();
+ if (!openavbAcmpSMControllerVars.inflight) {
+ AVB_LOG_ERROR("Unable to create inflight list. ACMP protocol not started.");
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return FALSE;
+ }
+
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "openavbAcmpSMControllerMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(openavbAcmpSMControllerMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'openavbAcmpSMControllerMutex' mutex");
+
+ SEM_ERR_T(err);
+ SEM_INIT(openavbAcmpSMControllerSemaphore, 1, err);
+ SEM_LOG_ERR(err);
+
+ // Start the State Machine
+ bool errResult;
+ bRunning = TRUE;
+ THREAD_CREATE(openavbAcmpSmControllerThread, openavbAcmpSmControllerThread, NULL, openavbAcmpSMControllerThreadFn, NULL);
+ THREAD_CHECK_ERROR(openavbAcmpSmControllerThread, "Thread / task creation failed", errResult);
+ if (errResult) {
+ bRunning = FALSE;
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return TRUE;
+}
+
+void openavbAcmpSMControllerStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ if (bRunning) {
+ openavbAcmpSMControllerSet_doTerminate(TRUE);
+
+ THREAD_JOIN(openavbAcmpSmControllerThread, NULL);
+ }
+
+ SEM_ERR_T(err);
+ SEM_DESTROY(openavbAcmpSMControllerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ openavbListDeleteList(openavbAcmpSMControllerVars.inflight);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMControllerSet_rcvdResponse(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMControllerVars.rcvdResponse = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMControllerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMControllerSet_doTerminate(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavbAcmpSMControllerVars.doTerminate = value;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMControllerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp_sm_controller.h b/lib/avtp_pipeline/acmp/openavb_acmp_sm_controller.h
new file mode 100644
index 00000000..15e0394f
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp_sm_controller.h
@@ -0,0 +1,67 @@
+/*************************************************************************************************************
+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 : ACMP - AVDECC Connection Management Protocol : Controller State Machine Interface
+ * MODULE SUMMARY : Interface for ACMP - AVDECC Connection Management Protocol : Controller State Machine
+ * IEEE Std 1722.1-2013 clause 8.2.2.4
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ACMP_SM_CONTROLLER_H
+#define OPENAVB_ACMP_SM_CONTROLLER_H 1
+
+#include "openavb_acmp.h"
+
+// State machine vars IEEE Std 1722.1-2013 clause 8.2.2.4.1
+typedef struct {
+ openavb_list_t inflight;
+ bool rcvdResponse;
+
+ // Not part of spec
+ bool doTerminate;
+} openavb_acmp_sm_controller_vars_t;
+
+// State machine functions IEEE Std 1722.1-2013 clause 8.2.2.4.2
+void openavbAcmpSMController_txCommand(U8 messageType, openavb_acmp_ACMPCommandResponse_t *command, bool retry);
+void openavbAcmpSMController_cancelTimeout(openavb_acmp_ACMPCommandResponse_t *commandResponse);
+void openavbAcmpSMController_removeInflight(openavb_acmp_ACMPCommandResponse_t *commandResponse);
+void openavbAcmpSMController_processResponse(openavb_acmp_ACMPCommandResponse_t *commandResponse);
+void openavbAcmpSMController_makeCommand(openavb_acmp_ACMPCommandParams_t *param);
+
+bool openavbAcmpSMControllerStart(void);
+void openavbAcmpSMControllerStop(void);
+
+void openavbAcmpSMControllerSet_rcvdResponse(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMControllerSet_doTerminate(bool value);
+
+#endif // OPENAVB_ACMP_SM_CONTROLLER_H
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp_sm_listener.c b/lib/avtp_pipeline/acmp/openavb_acmp_sm_listener.c
new file mode 100644
index 00000000..515a557f
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp_sm_listener.c
@@ -0,0 +1,982 @@
+/*************************************************************************************************************
+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 : ACMP - AVDECC Connection Management Protocol : Listener State Machine
+ * MODULE SUMMARY : Implements the ACMP - AVDECC Connection Management Protocol : Listener State Machine
+ * IEEE Std 1722.1-2013 clause 8.2.2.5
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <errno.h>
+
+#define AVB_LOG_COMPONENT "ACMP"
+#include "openavb_log.h"
+
+#include "openavb_debug.h"
+#include "openavb_time.h"
+#include "openavb_aem.h"
+#include "openavb_acmp.h"
+#include "openavb_acmp_message.h"
+#include "openavb_acmp_sm_talker.h"
+#include "openavb_acmp_sm_listener.h"
+#include "openavb_avdecc_pipeline_interaction_pub.h"
+#include "openavb_time.h"
+
+typedef enum {
+ OPENAVB_ACMP_SM_LISTENER_STATE_WAITING,
+ OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_RX_COMMAND,
+ OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_TX_RESPONSE,
+ OPENAVB_ACMP_SM_LISTENER_STATE_GET_STATE,
+ OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_RX_COMMAND,
+ OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_TX_RESPONSE,
+ OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_TX_TIMEOUT,
+ OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_TX_TIMEOUT,
+} openavb_acmp_sm_listener_state_t;
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+extern openavb_acmp_sm_global_vars_t openavbAcmpSMGlobalVars;
+
+static openavb_acmp_ACMPCommandResponse_t rcvdCmdResp;
+static openavb_acmp_ACMPCommandResponse_t *pRcvdCmdResp = &rcvdCmdResp;
+static openavb_acmp_sm_listener_vars_t openavbAcmpSMListenerVars = {0};
+static bool bRunning = FALSE;
+
+extern MUTEX_HANDLE(openavbAcmpMutex);
+#define ACMP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAcmpMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ACMP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAcmpMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+static MUTEX_HANDLE(openavbAcmpSMListenerMutex);
+#define ACMP_SM_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAcmpSMListenerMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ACMP_SM_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAcmpSMListenerMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+SEM_T(openavbAcmpSMListenerSemaphore);
+THREAD_TYPE(openavbAcmpSmListenerThread);
+THREAD_DEFINITON(openavbAcmpSmListenerThread);
+
+openavb_list_node_t openavbAcmpSMListener_findInflightNodeFromCommand(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavb_list_node_t node = NULL;
+
+ node = openavbListIterFirst(openavbAcmpSMListenerVars.inflight);
+ while (node) {
+ openavb_acmp_InflightCommand_t *pInFlightCommand = openavbListData(node);
+ if (pInFlightCommand) {
+ if (memcmp(pInFlightCommand->command.talker_entity_id, command->talker_entity_id, sizeof(pInFlightCommand->command.talker_entity_id)) == 0) {
+ if (pInFlightCommand->command.talker_unique_id == command->talker_unique_id ) {
+ if (pInFlightCommand->command.sequence_id == command->sequence_id) {
+ break;
+ }
+ }
+ }
+ }
+ node = openavbListIterNext(openavbAcmpSMListenerVars.inflight);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return node;
+}
+
+bool openavbAcmpSMListener_validListenerUnique(U16 listenerUniqueId)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ if (!openavbAemGetDescriptor(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, listenerUniqueId)) {
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return TRUE;
+}
+
+bool openavbAcmpSMListener_listenerIsConnected(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ bool bResult = FALSE;
+
+ // Returns TRUE if listener is connected to a stream source other than the one specified in the command.
+ openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo = openavbArrayDataIdx(openavbAcmpSMListenerVars.listenerStreamInfos, command->listener_unique_id);
+ if (pListenerStreamInfo) {
+ if (pListenerStreamInfo->connected) {
+ bResult = TRUE;
+ if (memcmp(pListenerStreamInfo->talker_entity_id, command->talker_entity_id, sizeof(command->talker_entity_id)) == 0) {
+ if (pListenerStreamInfo->talker_unique_id == command->talker_unique_id) {
+ bResult = FALSE;
+ }
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return bResult;
+}
+
+bool openavbAcmpSMListener_listenerIsConnectedTo(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ bool bResult = FALSE;
+
+ // Returns TRUE if listener is connected to the stream source specified in the command.
+ openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo = openavbArrayDataIdx(openavbAcmpSMListenerVars.listenerStreamInfos, command->listener_unique_id);
+ if (pListenerStreamInfo) {
+ if (pListenerStreamInfo->connected) {
+ if (memcmp(pListenerStreamInfo->talker_entity_id, command->talker_entity_id, sizeof(command->talker_entity_id)) == 0) {
+ if (pListenerStreamInfo->talker_unique_id == command->talker_unique_id) {
+ bResult = TRUE;
+ }
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return bResult;
+}
+
+void openavbAcmpSMListener_txCommand(U8 messageType, openavb_acmp_ACMPCommandResponse_t *command, bool retry)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavb_list_node_t node = NULL;
+
+ openavbRC rc = openavbAcmpMessageSend(messageType, command, OPENAVB_ACMP_STATUS_SUCCESS);
+ if (IS_OPENAVB_SUCCESS(rc)) {
+ if (!retry) {
+ node = openavbListNew(openavbAcmpSMListenerVars.inflight, sizeof(openavb_acmp_InflightCommand_t));
+ if (node) {
+ openavb_acmp_InflightCommand_t *pInFlightCommand = openavbListData(node);
+ if (pInFlightCommand) {
+
+ memcpy(&pInFlightCommand->command, command, sizeof(pInFlightCommand->command));
+ pInFlightCommand->command.message_type = messageType;
+ pInFlightCommand->retried = FALSE;
+ pInFlightCommand->original_sequence_id = command->sequence_id; // AVDECC_TODO - is this correct?
+
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pInFlightCommand->timer);
+ switch (messageType) {
+ case OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_TX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_DISCONNECT_TX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ default:
+ AVB_LOGF_ERROR("Unsupported command %u in openavbAcmpSMListener_txCommand", messageType);
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_RX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ }
+ }
+ }
+ }
+ else {
+ // Retry case
+ node = openavbAcmpSMListener_findInflightNodeFromCommand(command);
+ if (node) {
+ openavb_acmp_InflightCommand_t *pInFlightCommand = openavbListData(node);
+ if (pInFlightCommand) {
+ pInFlightCommand->retried = TRUE;
+
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pInFlightCommand->timer);
+ switch (messageType) {
+ case OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_TX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_DISCONNECT_TX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ default:
+ AVB_LOGF_ERROR("Unsupported command %u in openavbAcmpSMListener_txCommand", messageType);
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_RX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ }
+ }
+ }
+ }
+ }
+ else {
+ // Failed to send command
+ openavbAcmpSMListener_txResponse(messageType + 1, command, OPENAVB_ACMP_STATUS_COULD_NOT_SEND_MESSAGE);
+ if (retry) {
+ node = openavbAcmpSMListener_findInflightNodeFromCommand(command);
+ if (node) {
+ openavbListDelete(openavbAcmpSMListenerVars.inflight, node);
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMListener_txResponse(U8 messageType, openavb_acmp_ACMPCommandResponse_t *response, U8 error)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavbAcmpMessageSend(messageType, response, error);
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+U8 openavbAcmpSMListener_connectListener(openavb_acmp_ACMPCommandResponse_t *response)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ U8 retStatus;
+
+ // AVDECC_TODO: What do we do if the Listener is already connected?
+
+ openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo = openavbArrayDataIdx(openavbAcmpSMListenerVars.listenerStreamInfos, response->listener_unique_id);
+ if (pListenerStreamInfo) {
+ memcpy(pListenerStreamInfo->stream_id, response->stream_id, sizeof(pListenerStreamInfo->stream_id));
+ memcpy(pListenerStreamInfo->controller_entity_id, response->controller_entity_id, sizeof(pListenerStreamInfo->controller_entity_id));
+ memcpy(pListenerStreamInfo->talker_entity_id, response->talker_entity_id, sizeof(pListenerStreamInfo->talker_entity_id));
+ pListenerStreamInfo->talker_unique_id = response->talker_unique_id;
+ memcpy(pListenerStreamInfo->stream_dest_mac, response->stream_dest_mac, sizeof(pListenerStreamInfo->stream_dest_mac));
+ pListenerStreamInfo->connected = TRUE;
+ pListenerStreamInfo->flags = response->flags;
+ pListenerStreamInfo->stream_vlan_id = response->stream_vlan_id;
+
+ U16 configIdx = openavbAemGetConfigIdx();
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(configIdx, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, response->listener_unique_id);
+
+ // AVDECC_TODO: Verify that the pDescriptorStreamInput->stream details match that of pListenerStreamInfo.
+
+ if (!pDescriptorStreamInput) {
+ retStatus = OPENAVB_ACMP_STATUS_LISTENER_UNKNOWN_ID;
+ }
+ else if (openavbAVDECCRunListener(pDescriptorStreamInput, configIdx, pListenerStreamInfo)) {
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+ else {
+ retStatus = OPENAVB_ACMP_STATUS_LISTENER_MISBEHAVING;
+ }
+ }
+ else {
+ retStatus = OPENAVB_ACMP_STATUS_LISTENER_UNKNOWN_ID;
+ }
+
+ // AVDECC_TODO - any flags need to be updated in the response?
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+}
+
+U8 openavbAcmpSMListener_disconnectListener(openavb_acmp_ACMPCommandResponse_t *response)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ U8 retStatus;
+
+ openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo = openavbArrayDataIdx(openavbAcmpSMListenerVars.listenerStreamInfos, response->listener_unique_id);
+ if (pListenerStreamInfo) {
+ U16 configIdx = openavbAemGetConfigIdx();
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(configIdx, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, response->listener_unique_id);
+
+ // AVDECC_TODO: Verify that the pDescriptorStreamInput->stream details match that of pListenerStreamInfo.
+
+ if (!pDescriptorStreamInput) {
+ retStatus = OPENAVB_ACMP_STATUS_LISTENER_UNKNOWN_ID;
+ }
+ else if (openavbAVDECCStopListener(pDescriptorStreamInput, configIdx, pListenerStreamInfo)) {
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+ else {
+ retStatus = OPENAVB_ACMP_STATUS_LISTENER_MISBEHAVING;
+ }
+ memset(pListenerStreamInfo, 0, sizeof(*pListenerStreamInfo));
+ }
+ else {
+ retStatus = OPENAVB_ACMP_STATUS_LISTENER_UNKNOWN_ID;
+ }
+
+ // AVDECC_TODO - any flags need to be updated in the response?
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+}
+
+void openavbAcmpSMListener_cancelTimeout(openavb_acmp_ACMPCommandResponse_t *commandResponse)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ // Nothing to do since the timer is reset during the wait state and the inFlight entry will have already been removed.
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMListener_removeInflight(openavb_acmp_ACMPCommandResponse_t *commandResponse)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavb_list_node_t node = openavbAcmpSMListener_findInflightNodeFromCommand(commandResponse);
+ if (node) {
+ openavbListDelete(openavbAcmpSMListenerVars.inflight, node);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+U8 openavbAcmpSMListener_getState(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ U8 retStatus = OPENAVB_ACMP_STATUS_LISTENER_MISBEHAVING;
+
+ openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo = openavbArrayDataIdx(openavbAcmpSMListenerVars.listenerStreamInfos, command->listener_unique_id);
+ if (pListenerStreamInfo) {
+ memcpy(command->stream_id, pListenerStreamInfo->stream_id, sizeof(command->stream_id));
+ memcpy(command->talker_entity_id, pListenerStreamInfo->talker_entity_id, sizeof(command->talker_entity_id));
+ command->talker_unique_id = pListenerStreamInfo->talker_unique_id;
+ //command->listener_unique_id = command->listener_unique_id; // Overwriting data in passed in structure
+ memcpy(command->stream_dest_mac, pListenerStreamInfo->stream_dest_mac, sizeof(command->stream_dest_mac));
+ command->connection_count = pListenerStreamInfo->connected ? 1 : 0; // AVDECC_TODO - questionable information in spec.
+ command->flags = pListenerStreamInfo->flags;
+ command->stream_vlan_id = pListenerStreamInfo->stream_vlan_id;
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+}
+
+void openavbAcmpSMListenerStateMachine()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavb_acmp_InflightCommand_t *pInflightActive = NULL; // The inflight command for the current state
+ openavb_acmp_sm_listener_state_t state = OPENAVB_ACMP_SM_LISTENER_STATE_WAITING;
+
+ // Lock such that the mutex is held unless waiting for a semaphore. Synchronous processing of command responses.
+ ACMP_SM_LOCK();
+ while (bRunning) {
+ switch (state) {
+ case OPENAVB_ACMP_SM_LISTENER_STATE_WAITING:
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_LISTENER_STATE_WAITING");
+
+ openavbAcmpSMListenerVars.rcvdConnectRXCmd = FALSE;
+ openavbAcmpSMListenerVars.rcvdDisconnectRXCmd = FALSE;
+ openavbAcmpSMListenerVars.rcvdConnectTXResp = FALSE;
+ openavbAcmpSMListenerVars.rcvdDisconnectTXResp = FALSE;
+ openavbAcmpSMListenerVars.rcvdGetRXState = FALSE;
+
+ // Wait for a change in state
+ while (state == OPENAVB_ACMP_SM_LISTENER_STATE_WAITING && bRunning) {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+
+ // Calculate timeout for inflight commands
+ // Start is a arbitrary large time out.
+ struct timespec timeout;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &timeout);
+ timeout.tv_sec += 60; // At most will timeout after 60 seconds
+
+ // Look for soonest inflight command timeout
+ openavb_list_node_t node = openavbListIterFirst(openavbAcmpSMListenerVars.inflight);
+ while (node) {
+ openavb_acmp_InflightCommand_t *pInflight = openavbListData(node);
+ if ((openavbTimeTimespecCmp(&pInflight->timer, &timeout) < 0)) {
+ timeout.tv_sec = pInflight->timer.tv_sec;
+ timeout.tv_nsec = pInflight->timer.tv_nsec;
+ }
+ node = openavbListIterNext(openavbAcmpSMListenerVars.inflight);
+ }
+
+ ACMP_SM_UNLOCK();
+ U32 timeoutMSec = 0;
+ struct timespec now;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &now);
+ timeoutMSec = openavbTimeUntilMSec(&now, &timeout);
+ SEM_ERR_T(err);
+ SEM_TIMEDWAIT(openavbAcmpSMListenerSemaphore, timeoutMSec, err);
+ ACMP_SM_LOCK();
+
+ if (!SEM_IS_ERR_NONE(err)) {
+ if (SEM_IS_ERR_TIMEOUT(err)) {
+ struct timespec now;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &now);
+
+ // Look for a timed out inflight command
+ openavb_list_node_t node = openavbListIterFirst(openavbAcmpSMListenerVars.inflight);
+ while (node) {
+ openavb_acmp_InflightCommand_t *pInflight = openavbListData(node);
+ if ((openavbTimeTimespecCmp(&now, &pInflight->timer) >= 0)) {
+ // Found a timed out command
+ if (pInflight->command.message_type == OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND) {
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_TX_TIMEOUT;
+ pInflightActive = pInflight;
+ }
+ else if (pInflight->command.message_type == OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND) {
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_TX_TIMEOUT;
+ pInflightActive = pInflight;
+ }
+ else {
+ AVB_LOGF_ERROR("Unrecognized listener timeout command %u", pInflight->command.message_type);
+ bRunning = FALSE;
+ }
+ break;
+ }
+ node = openavbListIterNext(openavbAcmpSMListenerVars.inflight);
+ }
+ }
+ }
+ else {
+ if (openavbAcmpSMListenerVars.doTerminate) {
+ bRunning = FALSE;
+ }
+ else if (memcmp(pRcvdCmdResp->listener_entity_id, openavbAcmpSMGlobalVars.my_id, sizeof(openavbAcmpSMGlobalVars.my_id)) == 0) {
+ if (openavbAcmpSMListenerVars.rcvdConnectRXCmd) {
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_RX_COMMAND;
+ }
+ else if (openavbAcmpSMListenerVars.rcvdConnectTXResp) {
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_TX_RESPONSE;
+ }
+ else if (openavbAcmpSMListenerVars.rcvdGetRXState) {
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_GET_STATE;
+ }
+ else if (openavbAcmpSMListenerVars.rcvdDisconnectRXCmd) {
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_RX_COMMAND;
+ }
+ else if (openavbAcmpSMListenerVars.rcvdDisconnectTXResp) {
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_TX_RESPONSE;
+ }
+ }
+ }
+ }
+ break;
+
+ case OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_RX_COMMAND:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_RX_COMMAND");
+
+ if (openavbAcmpSMListener_validListenerUnique(pRcvdCmdResp->listener_unique_id)) {
+ if (!openavbAcmpSMListener_listenerIsConnected(pRcvdCmdResp)) {
+ openavbAcmpSMListener_txCommand(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND, pRcvdCmdResp, FALSE);
+ }
+ else {
+ openavbAcmpSMListener_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE, pRcvdCmdResp, OPENAVB_ACMP_STATUS_LISTENER_EXCLUSIVE);
+ }
+ }
+ else {
+ openavbAcmpSMListener_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE, pRcvdCmdResp, OPENAVB_ACMP_STATUS_LISTENER_UNKNOWN_ID);
+ }
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_WAITING;
+ }
+ break;
+ case OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_TX_RESPONSE:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_TX_RESPONSE");
+
+ U8 status;
+ if (openavbAcmpSMListener_validListenerUnique(pRcvdCmdResp->listener_unique_id)) {
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, pRcvdCmdResp, sizeof(response));
+ if (pRcvdCmdResp->status == OPENAVB_ACMP_STATUS_SUCCESS) {
+ status = openavbAcmpSMListener_connectListener(&response);
+ }
+ else {
+ status = pRcvdCmdResp->status;
+ }
+
+ // Save the state for this connection, so it can potentially be fast connected later.
+ // TODO: Add fast connect support for STREAMING_WAIT connections by handling START_STREAMING and STOP_STREAMING commands.
+ if (status == OPENAVB_ACMP_STATUS_SUCCESS) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, pRcvdCmdResp->listener_unique_id);
+ if (pDescriptorStreamInput != NULL && pDescriptorStreamInput->stream != NULL) {
+ if (gAvdeccCfg.bFastConnectSupported &&
+ (pRcvdCmdResp->flags & OPENAVB_ACMP_FLAG_STREAMING_WAIT) == 0) {
+ if (openavbAvdeccSaveState(
+ pDescriptorStreamInput->stream,
+ (pRcvdCmdResp->flags & (OPENAVB_ACMP_FLAG_CLASS_B | OPENAVB_ACMP_FLAG_SUPPORTS_ENCRYPTED | OPENAVB_ACMP_FLAG_ENCRYPTED_PDU)),
+ pRcvdCmdResp->talker_unique_id,
+ pRcvdCmdResp->talker_entity_id,
+ pRcvdCmdResp->controller_entity_id)) {
+ // Let the Controller know that the state is saved.
+ response.flags |= OPENAVB_ACMP_FLAG_SAVED_STATE;
+ }
+ if (pDescriptorStreamInput->fast_connect_status >= OPENAVB_FAST_CONNECT_STATUS_IN_PROGRESS) {
+ pDescriptorStreamInput->fast_connect_status = OPENAVB_FAST_CONNECT_STATUS_SUCCEEDED;
+ }
+ }
+
+ // Save the response flags for reference later.
+ pDescriptorStreamInput->acmp_flags = response.flags;
+
+ // Save the stream information for reference later.
+ memcpy(pDescriptorStreamInput->acmp_stream_id, pRcvdCmdResp->stream_id, 8);
+ memcpy(pDescriptorStreamInput->acmp_dest_addr, pRcvdCmdResp->stream_dest_mac, 6);
+ pDescriptorStreamInput->acmp_stream_vlan_id = pRcvdCmdResp->stream_vlan_id;
+ }
+ }
+
+ openavb_list_node_t node = openavbAcmpSMListener_findInflightNodeFromCommand(pRcvdCmdResp);
+ if (node) {
+ openavb_acmp_InflightCommand_t *pInFlightCommand = openavbListData(node);
+ if (pInFlightCommand) {
+ response.sequence_id = pInFlightCommand->original_sequence_id;
+ }
+ }
+ openavbAcmpSMListener_cancelTimeout(pRcvdCmdResp);
+ openavbAcmpSMListener_removeInflight(pRcvdCmdResp);
+ openavbAcmpSMListener_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE, &response, status);
+ }
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_WAITING;
+ }
+ break;
+ case OPENAVB_ACMP_SM_LISTENER_STATE_GET_STATE:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_LISTENER_STATE_GET_STATE");
+
+ U8 error;
+
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, pRcvdCmdResp, sizeof(response));
+ if (openavbAcmpSMListener_validListenerUnique(pRcvdCmdResp->listener_unique_id)) {
+ error = openavbAcmpSMListener_getState(&response);
+ }
+ else {
+ error = OPENAVB_ACMP_STATUS_LISTENER_UNKNOWN_ID;
+ }
+ openavbAcmpSMListener_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE, &response, error);
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_WAITING;
+ }
+ break;
+ case OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_RX_COMMAND:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_RX_COMMAND");
+
+ if (openavbAcmpSMListener_validListenerUnique(pRcvdCmdResp->listener_unique_id)) {
+ U8 status;
+
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, pRcvdCmdResp, sizeof(response));
+ status = openavbAcmpSMListener_disconnectListener(pRcvdCmdResp);
+ if (status == OPENAVB_ACMP_STATUS_SUCCESS) {
+ openavbAcmpSMListener_txCommand(OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND, pRcvdCmdResp, FALSE);
+ }
+ else {
+ openavbAcmpSMListener_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE, &response, status);
+ }
+
+ // Clear the saved state for this connection, so it won't be fast connected later.
+ if (gAvdeccCfg.bFastConnectSupported) {
+ U16 configIdx = openavbAemGetConfigIdx();
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(configIdx, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, pRcvdCmdResp->listener_unique_id);
+ if (pDescriptorStreamInput != NULL && pDescriptorStreamInput->stream != NULL) {
+ pDescriptorStreamInput->fast_connect_status = OPENAVB_FAST_CONNECT_STATUS_NOT_AVAILABLE;
+ openavbAvdeccClearSavedState(pDescriptorStreamInput->stream);
+ }
+ }
+ }
+ else {
+ openavbAcmpSMListener_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE, pRcvdCmdResp, OPENAVB_ACMP_STATUS_NOT_CONNECTED);
+ }
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_WAITING;
+ }
+ break;
+ case OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_TX_RESPONSE:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_TX_RESPONSE");
+
+ if (openavbAcmpSMListener_validListenerUnique(pRcvdCmdResp->listener_unique_id)) {
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, pRcvdCmdResp, sizeof(response));
+ U8 status = pRcvdCmdResp->status;
+
+ openavb_list_node_t node = openavbAcmpSMListener_findInflightNodeFromCommand(pRcvdCmdResp);
+ if (node) {
+ openavb_acmp_InflightCommand_t *pInFlightCommand = openavbListData(node);
+ if (pInFlightCommand) {
+ response.sequence_id = pInFlightCommand->original_sequence_id;
+ }
+ }
+ openavbAcmpSMListener_cancelTimeout(pRcvdCmdResp);
+ openavbAcmpSMListener_removeInflight(pRcvdCmdResp);
+ openavbAcmpSMListener_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE, &response, status);
+
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_WAITING;
+ }
+ }
+ break;
+ case OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_TX_TIMEOUT:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_TX_TIMEOUT");
+
+ if (pInflightActive) {
+ if (pInflightActive->retried) {
+ if ((pInflightActive->command.flags & OPENAVB_ACMP_FLAG_FAST_CONNECT) != 0) {
+ // Special handling for Fast Connect CONNECT_TX_COMMAND failures.
+ AVB_LOG_DEBUG("Fast Connect timeout handling");
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, pInflightActive->command.listener_unique_id);
+ if (pDescriptorStreamInput != NULL &&
+ pDescriptorStreamInput->fast_connect_status == OPENAVB_FAST_CONNECT_STATUS_IN_PROGRESS) {
+ pDescriptorStreamInput->fast_connect_status = OPENAVB_FAST_CONNECT_STATUS_TIMED_OUT;
+ }
+#if 0
+ // Wait another CONNECT_TX_COMMAND timeout period and then try again.
+ // This option is described at the end of the second paragraph of IEEE 1722.1-2013 Clause 8.2.2.1.1.
+ //
+ // This feature is currently disabled, as it's not clear all the ramifications
+ // of having an inflight attempt at the same time we might be initiating another
+ // fast connect as a result of the ADP discovery of the Talker,
+ // or of using the state machine to allow retries indefinitely.
+ //
+ pInflightActive->retried = FALSE;
+ openavbTimeTimespecAddUsec(&pInflightActive->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_TX_COMMAND * MICROSECONDS_PER_MSEC);
+#else
+ // Abort this attempt without sending a message the Controller.
+ openavbAcmpSMListener_removeInflight(&pInflightActive->command);
+#endif
+ }
+ else {
+ // Standard handling. Notify the AVDECC controller.
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, &pInflightActive->command, sizeof(response));
+ response.sequence_id = pInflightActive->original_sequence_id;
+ openavbAcmpSMListener_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE, &response, OPENAVB_ACMP_STATUS_LISTENER_TALKER_TIMEOUT);
+ openavbAcmpSMListener_removeInflight(&pInflightActive->command);
+ }
+ }
+ else {
+ openavbAcmpSMListener_txCommand(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND, &pInflightActive->command, TRUE);
+ }
+ }
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_WAITING;
+ }
+ break;
+ case OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_TX_TIMEOUT:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_TX_TIMEOUT");
+
+ if (pInflightActive) {
+ if (pInflightActive->retried) {
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, &pInflightActive->command, sizeof(response));
+ response.sequence_id = pInflightActive->original_sequence_id;
+ openavbAcmpSMListener_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE, &response, OPENAVB_ACMP_STATUS_LISTENER_TALKER_TIMEOUT);
+ openavbAcmpSMListener_removeInflight(&pInflightActive->command);
+ }
+ else {
+ openavbAcmpSMListener_txCommand(OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND, &pInflightActive->command, TRUE);
+ }
+ }
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_WAITING;
+ }
+ break;
+ }
+ }
+ ACMP_SM_UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void* openavbAcmpSmListenerThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavbAcmpSMListenerStateMachine();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return NULL;
+}
+
+bool openavbAcmpSMListenerStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavbAcmpSMListenerVars.inflight = openavbListNewList();
+ if (!openavbAcmpSMListenerVars.inflight) {
+ AVB_LOG_ERROR("Unable to create inflight list. ACMP protocol not started.");
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return FALSE;
+ }
+ openavbAcmpSMListenerVars.listenerStreamInfos = openavbArrayNewArray(sizeof(openavb_acmp_ListenerStreamInfo_t));
+ if (!openavbAcmpSMListenerVars.listenerStreamInfos) {
+ AVB_LOG_ERROR("Unable to create listenerStreamInfos array. ACMP protocol not started.");
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return FALSE;
+ }
+ openavb_array_t streamInputDescriptorArray = openavbAemGetDescriptorArray(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT);
+ if (streamInputDescriptorArray) {
+ openavbArrayMultiNew(openavbAcmpSMListenerVars.listenerStreamInfos, openavbArrayCount(streamInputDescriptorArray));
+ }
+
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "openavbAcmpSMListenerMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(openavbAcmpSMListenerMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'openavbAcmpSMListenerMutex' mutex");
+
+ SEM_ERR_T(err);
+ SEM_INIT(openavbAcmpSMListenerSemaphore, 1, err);
+ SEM_LOG_ERR(err);
+
+ // Start the State Machine
+ bool errResult;
+ bRunning = TRUE;
+ THREAD_CREATE(openavbAcmpSmListenerThread, openavbAcmpSmListenerThread, NULL, openavbAcmpSmListenerThreadFn, NULL);
+ THREAD_CHECK_ERROR(openavbAcmpSmListenerThread, "Thread / task creation failed", errResult);
+ if (errResult) {
+ bRunning = FALSE;
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return TRUE;
+}
+
+void openavbAcmpSMListenerStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ if (bRunning) {
+ openavbAcmpSMListenerSet_doTerminate(TRUE);
+
+ THREAD_JOIN(openavbAcmpSmListenerThread, NULL);
+ }
+
+ SEM_ERR_T(err);
+ SEM_DESTROY(openavbAcmpSMListenerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ openavbListDeleteList(openavbAcmpSMListenerVars.inflight);
+ openavbArrayDeleteArray(openavbAcmpSMListenerVars.listenerStreamInfos);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMListenerSet_rcvdConnectRXCmd(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMListenerVars.rcvdConnectRXCmd = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMListenerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMListenerSet_rcvdDisconnectRXCmd(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMListenerVars.rcvdDisconnectRXCmd = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMListenerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMListenerSet_rcvdConnectTXResp(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMListenerVars.rcvdConnectTXResp = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMListenerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMListenerSet_rcvdDisconnectTXResp(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMListenerVars.rcvdDisconnectTXResp = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMListenerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMListenerSet_rcvdGetRXState(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMListenerVars.rcvdGetRXState = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMListenerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMListenerSet_doTerminate(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavbAcmpSMListenerVars.doTerminate = value;
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMListenerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+
+// Special command to initiate the fast connect support.
+void openavbAcmpSMListenerSet_doFastConnect(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])
+{
+ openavb_acmp_ACMPCommandResponse_t command;
+ static U16 s_sequence_id = 0;
+
+ // Get the descriptor and listener_unique_id for the supplied listener.
+ openavb_aem_descriptor_stream_io_t *pDescriptor;
+ U16 listenerUniqueId;
+ for (listenerUniqueId = 0; listenerUniqueId < 0xFFFF; ++listenerUniqueId) {
+ pDescriptor = openavbAemGetDescriptor(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, listenerUniqueId);
+ if (!pDescriptor) {
+ // Out of listeners to try. Assume something went wrong.
+ AVB_LOG_ERROR("Unable to find listener_unique_id for fast connect");
+ return;
+ }
+ if (pDescriptor->stream && strcmp(pDescriptor->stream->friendly_name, pListener->friendly_name) == 0) {
+ // We found a match.
+ break;
+ }
+ }
+
+ // Should we attempt to fast connect?
+ if (!gAvdeccCfg.bFastConnectSupported ||
+ (pDescriptor->fast_connect_status != OPENAVB_FAST_CONNECT_STATUS_UNKNOWN &&
+ pDescriptor->fast_connect_status != OPENAVB_FAST_CONNECT_STATUS_TIMED_OUT)) {
+ return;
+ }
+
+ // Update the descriptor.
+ pDescriptor->fast_connect_status = OPENAVB_FAST_CONNECT_STATUS_IN_PROGRESS;
+ memcpy(pDescriptor->fast_connect_talker_entity_id, talker_entity_id, sizeof(pDescriptor->fast_connect_talker_entity_id));
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pDescriptor->fast_connect_start_time);
+
+ // Create a fake CONNECT_RX_COMMAND to kick off the fast connect process.
+ // The FAST_CONNECT flag is used to indicate internally that the controller didn't initiate this.
+ //
+ // TODO: IEEE 1722.1-2013 Clause 8.2.1.18 implies that stream_vlan_id should always be 0 for CONNECT_RX_COMMAND,
+ // as it is the Talker that may set a non-zero value in CONNECT_TX_RESPONSE.
+ // Is that really the case?
+ //
+ memset(&command, 0, sizeof(command));
+ command.message_type = OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND;
+ memset(command.stream_id, 0xFF, 8);
+ memcpy(command.controller_entity_id, controller_entity_id, 8);
+ memcpy(command.talker_entity_id, talker_entity_id, 8);
+ memcpy(command.listener_entity_id, openavbAcmpSMGlobalVars.my_id, 8);
+ command.talker_unique_id = talker_unique_id;
+ command.listener_unique_id = listenerUniqueId;
+ memset(command.stream_dest_mac, 0xFF, 6);
+ command.sequence_id = ++s_sequence_id;
+ command.flags = flags | OPENAVB_ACMP_FLAG_FAST_CONNECT | OPENAVB_ACMP_FLAG_SAVED_STATE;
+
+ AVB_LOGF_INFO("Listener %s attempting fast connect to 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));
+
+ // Start processing the faked command.
+ openavbAcmpSMListenerSet_rcvdConnectRXCmd(&command);
+}
+
+// Assist function to detect if Talker available for fast connect
+void openavbAcmpSMListenerSet_talkerTestFastConnect(
+ const U8 entity_id[8])
+{
+ //AVB_LOGF_DEBUG("Talker entity discovered: " ENTITYID_FORMAT, ENTITYID_ARGS(entity_id));
+
+ // Are there any Listeners that have been unsuccessful in a fast connect?
+ openavb_aem_descriptor_stream_io_t *pDescriptor;
+ U16 listenerUniqueId;
+ for (listenerUniqueId = 0; listenerUniqueId < 0xFFFF; ++listenerUniqueId) {
+ pDescriptor = openavbAemGetDescriptor(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, listenerUniqueId);
+ if (!pDescriptor) {
+ // Out of listeners to try.
+ break;
+ }
+
+ if (pDescriptor->stream &&
+ pDescriptor->fast_connect_status == OPENAVB_FAST_CONNECT_STATUS_TIMED_OUT &&
+ memcmp(pDescriptor->fast_connect_talker_entity_id, entity_id, sizeof(pDescriptor->fast_connect_talker_entity_id)) == 0) {
+ //
+ // We found a Talker matching the one we have been looking for.
+ //
+
+ // See if it is time to connect yet.
+ struct timespec currenttime;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &currenttime);
+ if (openavbTimeTimespecCmp(&currenttime, &pDescriptor->fast_connect_start_time) < 0) {
+ AVB_LOG_DEBUG("Not yet time to do a fast connect");
+ break;
+ }
+
+ // Get the rest of the details we need to connect to it.
+ U16 flags, talker_unique_id;
+ U8 talker_entity_id[8], controller_entity_id[8];
+ bool bAvailable = openavbAvdeccGetSaveStateInfo(pDescriptor->stream, &flags, &talker_unique_id, &talker_entity_id, &controller_entity_id);
+ if (bAvailable && memcmp(entity_id, talker_entity_id, 8) == 0) {
+ AVB_LOGF_DEBUG("Detected talker_entity_id=" ENTITYID_FORMAT ". Retrying fast connect.", ENTITYID_ARGS(talker_entity_id));
+ openavbAcmpSMListenerSet_doFastConnect(pDescriptor->stream, flags, talker_unique_id, talker_entity_id, controller_entity_id);
+ }
+ else {
+ AVB_LOGF_DEBUG("Fast connect info for talker_entity_id=" ENTITYID_FORMAT " no longer valid", ENTITYID_ARGS(entity_id));
+ memset(pDescriptor->fast_connect_talker_entity_id, 0, sizeof(pDescriptor->fast_connect_talker_entity_id));
+ }
+
+ break;
+ }
+ }
+}
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp_sm_listener.h b/lib/avtp_pipeline/acmp/openavb_acmp_sm_listener.h
new file mode 100644
index 00000000..4cfd9dfa
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp_sm_listener.h
@@ -0,0 +1,94 @@
+/*************************************************************************************************************
+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 : ACMP - AVDECC Connection Management Protocol : Listener State Machine Interface
+ * MODULE SUMMARY : Interface for the ACMP - AVDECC Connection Management Protocol : Listener State Machine
+ * IEEE Std 1722.1-2013 clause 8.2.2.5
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ACMP_SM_LISTENER_H
+#define OPENAVB_ACMP_SM_LISTENER_H 1
+
+#include "openavb_list.h"
+#include "openavb_acmp.h"
+
+// State machine vars IEEE Std 1722.1-2013 clause 8.2.2.5.1
+typedef struct {
+ openavb_list_t inflight;
+ openavb_array_t listenerStreamInfos;
+ bool rcvdConnectRXCmd;
+ bool rcvdDisconnectRXCmd;
+ bool rcvdConnectTXResp;
+ bool rcvdDisconnectTXResp;
+ bool rcvdGetRXState;
+
+ // Not part of spec
+ bool doTerminate;
+} openavb_acmp_sm_listener_vars_t;
+
+// State machine functions IEEE Std 1722.1-2013 clause 8.2.2.5.2
+bool openavbAcmpSMListener_validListenerUnique(U16 listenerUniqueId);
+bool openavbAcmpSMListener_listenerIsConnected(openavb_acmp_ACMPCommandResponse_t *command);
+bool openavbAcmpSMListener_listenerIsConnectedTo(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMListener_txCommand(U8 messageType, openavb_acmp_ACMPCommandResponse_t *command, bool retry);
+void openavbAcmpSMListener_txResponse(U8 messageType, openavb_acmp_ACMPCommandResponse_t *response, U8 error);
+U8 openavbAcmpSMListener_connectListener(openavb_acmp_ACMPCommandResponse_t *response);
+U8 openavbAcmpSMListener_disconnectListener(openavb_acmp_ACMPCommandResponse_t *response);
+void openavbAcmpSMListener_cancelTimeout(openavb_acmp_ACMPCommandResponse_t *commandResponse);
+void openavbAcmpSMListener_removeInflight(openavb_acmp_ACMPCommandResponse_t *commandResponse);
+U8 openavbAcmpSMListener_getState(openavb_acmp_ACMPCommandResponse_t *command);
+
+bool openavbAcmpSMListenerStart(void);
+void openavbAcmpSMListenerStop(void);
+
+void openavbAcmpSMListenerSet_rcvdConnectRXCmd(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMListenerSet_rcvdDisconnectRXCmd(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMListenerSet_rcvdConnectTXResp(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMListenerSet_rcvdDisconnectTXResp(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMListenerSet_rcvdGetRXState(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMListenerSet_doTerminate(bool value);
+
+// Special command to initiate the fast connect support.
+void openavbAcmpSMListenerSet_doFastConnect(
+ 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]);
+
+// Assist function to detect if Talker available for fast connect
+void openavbAcmpSMListenerSet_talkerTestFastConnect(
+ const U8 entity_id[8]);
+
+#endif // OPENAVB_ACMP_SM_LISTENER_H
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp_sm_talker.c b/lib/avtp_pipeline/acmp/openavb_acmp_sm_talker.c
new file mode 100644
index 00000000..f0818a24
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp_sm_talker.c
@@ -0,0 +1,682 @@
+/*************************************************************************************************************
+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 : ACMP - AVDECC Connection Management Protocol : Talker State Machine
+ * MODULE SUMMARY : Implements the ACMP - AVDECC Connection Management Protocol : Talker State Machine
+ * IEEE Std 1722.1-2013 clause 8.2.2.6
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <signal.h>
+
+#define AVB_LOG_COMPONENT "ACMP"
+#include "openavb_log.h"
+
+#include "openavb_aem.h"
+#include "openavb_acmp_sm_talker.h"
+#include "openavb_acmp_sm_listener.h"
+#include "openavb_acmp_message.h"
+#include "openavb_avdecc_pipeline_interaction_pub.h"
+
+typedef enum {
+ OPENAVB_ACMP_SM_TALKER_STATE_WAITING,
+ OPENAVB_ACMP_SM_TALKER_STATE_CONNECT,
+ OPENAVB_ACMP_SM_TALKER_STATE_DISCONNECT,
+ OPENAVB_ACMP_SM_TALKER_STATE_GET_STATE,
+ OPENAVB_ACMP_SM_TALKER_STATE_GET_CONNECTION
+} openavb_acmp_sm_talker_state_t;
+
+extern openavb_acmp_sm_global_vars_t openavbAcmpSMGlobalVars;
+
+static openavb_acmp_ACMPCommandResponse_t rcvdCmdResp;
+static openavb_acmp_ACMPCommandResponse_t *pRcvdCmdResp = &rcvdCmdResp;
+static openavb_acmp_sm_talker_vars_t openavbAcmpSMTalkerVars = {0};
+static bool bRunning = FALSE;
+
+extern MUTEX_HANDLE(openavbAcmpMutex);
+#define ACMP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAcmpMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ACMP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAcmpMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+static MUTEX_HANDLE(openavbAcmpSMTalkerMutex);
+#define ACMP_SM_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAcmpSMTalkerMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ACMP_SM_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAcmpSMTalkerMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+SEM_T(openavbAcmpSMTalkerSemaphore);
+THREAD_TYPE(openavbAcmpSmTalkerThread);
+THREAD_DEFINITON(openavbAcmpSmTalkerThread);
+
+
+openavb_list_node_t openavbAcmpSMTalker_findListenerPairNodeFromCommand(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavb_list_node_t node = NULL;
+
+ openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo = openavbArrayDataIdx(openavbAcmpSMTalkerVars.talkerStreamInfos, command->talker_unique_id);
+ if (pTalkerStreamInfo) {
+ node = openavbListIterFirst(pTalkerStreamInfo->connected_listeners);
+ while (node) {
+ openavb_acmp_ListenerPair_t *pListenerPair = openavbListData(node);
+ if (pListenerPair) {
+ if (memcmp(pListenerPair->listener_entity_id, command->listener_entity_id, sizeof(pListenerPair->listener_entity_id)) == 0) {
+ if (pListenerPair->listener_unique_id == command->listener_unique_id) {
+ break;
+ }
+ }
+ }
+ node = openavbListIterNext(pTalkerStreamInfo->connected_listeners);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return node;
+}
+
+
+bool openavbAcmpSMTalker_validTalkerUnique(U16 talkerUniqueId)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ if (!openavbAemGetDescriptor(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT, talkerUniqueId)) {
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return TRUE;
+}
+
+U8 openavbAcmpSMTalker_connectTalker(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ U8 retStatus = OPENAVB_ACMP_STATUS_TALKER_MISBEHAVING;
+
+ openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo = openavbArrayDataIdx(openavbAcmpSMTalkerVars.talkerStreamInfos, command->talker_unique_id);
+ if (pTalkerStreamInfo) {
+ openavb_list_node_t node = openavbAcmpSMTalker_findListenerPairNodeFromCommand(command);
+ if (node) {
+ if (memcmp(pTalkerStreamInfo->stream_id, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0 ||
+ memcmp(pTalkerStreamInfo->stream_dest_mac, "\x00\x00\x00\x00\x00\x00", 6) == 0) {
+ // In the process of connecting. Ignore this, as we don't yet have a response.
+ AVB_LOG_INFO("Ignoring duplicate CONNECT_TX_COMMAND");
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+ else {
+ // Already connected, so return the current status.
+ AVB_LOG_DEBUG("Sending immediate response to CONNECT_TX_COMMAND");
+ U16 configIdx = openavbAemGetConfigIdx();
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(configIdx, OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT, command->talker_unique_id);
+ if (pDescriptorStreamOutput) {
+ command->flags = (pDescriptorStreamOutput->acmp_flags &
+ (OPENAVB_ACMP_FLAG_CLASS_B |
+ OPENAVB_ACMP_FLAG_FAST_CONNECT |
+ OPENAVB_ACMP_FLAG_SAVED_STATE |
+ OPENAVB_ACMP_FLAG_SUPPORTS_ENCRYPTED |
+ OPENAVB_ACMP_FLAG_ENCRYPTED_PDU));
+ }
+ memcpy(command->stream_id, pTalkerStreamInfo->stream_id, sizeof(command->stream_id));
+ memcpy(command->stream_dest_mac, pTalkerStreamInfo->stream_dest_mac, sizeof(command->stream_dest_mac));
+ command->stream_vlan_id = pTalkerStreamInfo->stream_vlan_id;
+ command->connection_count = pTalkerStreamInfo->connection_count;
+ openavbAcmpSMTalker_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE, command, OPENAVB_ACMP_STATUS_SUCCESS);
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+ }
+ else {
+ if (!pTalkerStreamInfo->connected_listeners) {
+ pTalkerStreamInfo->connected_listeners = openavbListNewList();
+ }
+ node = openavbListNew(pTalkerStreamInfo->connected_listeners, sizeof(openavb_acmp_ListenerPair_t));
+ if (node) {
+ openavb_acmp_ListenerPair_t *pListenerPair = openavbListData(node);
+ memcpy(pListenerPair->listener_entity_id, command->listener_entity_id, sizeof(pListenerPair->listener_entity_id));
+ pListenerPair->listener_unique_id = command->listener_unique_id;
+ pTalkerStreamInfo->connection_count++;
+
+ U16 configIdx = openavbAemGetConfigIdx();
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(configIdx, OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT, command->talker_unique_id);
+ if (!pDescriptorStreamOutput) {
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+ }
+
+ if (openavbAVDECCRunTalker(pDescriptorStreamOutput, configIdx, pTalkerStreamInfo)) {
+
+ command->connection_count = pTalkerStreamInfo->connection_count;
+
+ // Wait for the Talker to supply us with updated stream information.
+ if (!pTalkerStreamInfo->waiting_on_talker) {
+ pTalkerStreamInfo->waiting_on_talker = (openavb_acmp_ACMPCommandResponse_t *) malloc(sizeof(openavb_acmp_ACMPCommandResponse_t));
+ if (!pTalkerStreamInfo->waiting_on_talker) {
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return OPENAVB_ACMP_STATUS_TALKER_MISBEHAVING;
+ }
+ }
+ memcpy(pTalkerStreamInfo->waiting_on_talker, command, sizeof(openavb_acmp_ACMPCommandResponse_t));
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+ }
+ }
+ }
+ else {
+ retStatus = OPENAVB_ACMP_STATUS_TALKER_UNKNOWN_ID;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+}
+
+void openavbAcmpSMTalker_txResponse(U8 messageType, openavb_acmp_ACMPCommandResponse_t *response, U8 error)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavbAcmpMessageSend(messageType, response, error);
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+U8 openavbAcmpSMTalker_disconnectTalker(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ U8 retStatus = OPENAVB_ACMP_STATUS_TALKER_MISBEHAVING;
+
+ openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo = openavbArrayDataIdx(openavbAcmpSMTalkerVars.talkerStreamInfos, command->talker_unique_id);
+ if (pTalkerStreamInfo) {
+ openavb_list_node_t node = openavbAcmpSMTalker_findListenerPairNodeFromCommand(command);
+ if (!node) {
+ // Already disconnected, so return the current status.
+ memcpy(command->stream_id, pTalkerStreamInfo->stream_id, sizeof(command->stream_id));
+ memcpy(command->stream_dest_mac, pTalkerStreamInfo->stream_dest_mac, sizeof(command->stream_dest_mac));
+ command->connection_count = pTalkerStreamInfo->connection_count;
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+ else {
+ openavbListDelete(pTalkerStreamInfo->connected_listeners, node);
+ pTalkerStreamInfo->connection_count--;
+
+ U16 configIdx = openavbAemGetConfigIdx();
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(configIdx, OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT, command->talker_unique_id);
+ if (!pDescriptorStreamOutput) {
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+ }
+ openavbAVDECCGetTalkerStreamInfo(pDescriptorStreamOutput, configIdx, pTalkerStreamInfo);
+
+ // Stop the Talker if connection_count is 0.
+ if (pTalkerStreamInfo->connection_count > 0 ||
+ openavbAVDECCStopTalker(pDescriptorStreamOutput, configIdx, pTalkerStreamInfo)) {
+ memcpy(command->stream_id, pTalkerStreamInfo->stream_id, sizeof(command->stream_id));
+ memcpy(command->stream_dest_mac, pTalkerStreamInfo->stream_dest_mac, sizeof(command->stream_dest_mac));
+ command->connection_count = pTalkerStreamInfo->connection_count;
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+ }
+ }
+ else {
+ retStatus = OPENAVB_ACMP_STATUS_TALKER_UNKNOWN_ID;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+}
+
+U8 openavbAcmpSMTalker_getState(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ U8 retStatus = OPENAVB_ACMP_STATUS_TALKER_MISBEHAVING;
+
+ openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo = openavbArrayDataIdx(openavbAcmpSMTalkerVars.talkerStreamInfos, command->talker_unique_id);
+ if (pTalkerStreamInfo) {
+ U16 configIdx = openavbAemGetConfigIdx();
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(configIdx, OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT, command->talker_unique_id);
+ if (!pDescriptorStreamOutput) {
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+ }
+ openavbAVDECCGetTalkerStreamInfo(pDescriptorStreamOutput, configIdx, pTalkerStreamInfo);
+
+ memcpy(command->stream_id, pTalkerStreamInfo->stream_id, sizeof(command->stream_id));
+ memcpy(command->stream_dest_mac, pTalkerStreamInfo->stream_dest_mac, sizeof(command->stream_dest_mac));
+ command->stream_vlan_id = pTalkerStreamInfo->stream_vlan_id;
+ command->connection_count = pTalkerStreamInfo->connection_count;
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+}
+
+U8 openavbAcmpSMTalker_getConnection(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ U8 retStatus = OPENAVB_ACMP_STATUS_TALKER_MISBEHAVING;
+
+ openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo = openavbArrayDataIdx(openavbAcmpSMTalkerVars.talkerStreamInfos, command->talker_unique_id);
+ if (pTalkerStreamInfo) {
+ int count = command->connection_count;
+
+ openavb_list_node_t node = openavbListIterFirst(pTalkerStreamInfo->connected_listeners);
+ while (node && count-- > 0) {
+ node = openavbListIterNext(pTalkerStreamInfo->connected_listeners);
+ }
+
+ openavb_acmp_ListenerPair_t *pListenerPair = openavbListData(node);
+ if (pListenerPair) {
+ memcpy(command->stream_id, pTalkerStreamInfo->stream_id, sizeof(command->stream_id));
+ memcpy(command->stream_dest_mac, pTalkerStreamInfo->stream_dest_mac, sizeof(command->stream_dest_mac));
+ command->stream_vlan_id = pTalkerStreamInfo->stream_vlan_id;
+ command->connection_count = pTalkerStreamInfo->connection_count;
+
+ memcpy(command->listener_entity_id, pListenerPair->listener_entity_id, sizeof(command->listener_entity_id));
+ command->listener_unique_id = pListenerPair->listener_unique_id;
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+ else {
+ retStatus = OPENAVB_ACMP_STATUS_NO_SUCH_CONNECTION;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+}
+
+void openavbAcmpSMTalkerStateMachine()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavb_acmp_sm_talker_state_t state = OPENAVB_ACMP_SM_TALKER_STATE_WAITING;
+
+ // Lock such that the mutex is held unless waiting for a semaphore. Synchronous processing of command responses.
+ ACMP_SM_LOCK();
+ while (bRunning) {
+ switch (state) {
+ case OPENAVB_ACMP_SM_TALKER_STATE_WAITING:
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_TALKER_STATE_WAITING");
+
+ openavbAcmpSMTalkerVars.rcvdConnectTX = FALSE;
+ openavbAcmpSMTalkerVars.rcvdDisconnectTX = FALSE;
+ openavbAcmpSMTalkerVars.rcvdGetTXState = FALSE;
+ openavbAcmpSMTalkerVars.rcvdGetTXConnection = FALSE;
+
+ // Wait for a change in state
+ while (state == OPENAVB_ACMP_SM_TALKER_STATE_WAITING && bRunning) {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+
+ ACMP_SM_UNLOCK();
+ SEM_ERR_T(err);
+ SEM_WAIT(openavbAcmpSMTalkerSemaphore, err);
+ ACMP_SM_LOCK();
+
+ if (SEM_IS_ERR_NONE(err)) {
+ if (openavbAcmpSMTalkerVars.doTerminate) {
+ bRunning = FALSE;
+ }
+ else if (memcmp(pRcvdCmdResp->talker_entity_id, openavbAcmpSMGlobalVars.my_id, sizeof(openavbAcmpSMGlobalVars.my_id)) == 0) {
+
+ if (openavbAcmpSMTalkerVars.rcvdConnectTX) {
+ state = OPENAVB_ACMP_SM_TALKER_STATE_CONNECT;
+ }
+ else if (openavbAcmpSMTalkerVars.rcvdDisconnectTX) {
+ state = OPENAVB_ACMP_SM_TALKER_STATE_DISCONNECT;
+ }
+ else if (openavbAcmpSMTalkerVars.rcvdGetTXState) {
+ state = OPENAVB_ACMP_SM_TALKER_STATE_GET_STATE;
+ }
+ else if (openavbAcmpSMTalkerVars.rcvdGetTXConnection) {
+ state = OPENAVB_ACMP_SM_TALKER_STATE_GET_CONNECTION;
+ }
+ }
+ }
+ }
+ break;
+
+ case OPENAVB_ACMP_SM_TALKER_STATE_CONNECT:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_TALKER_STATE_CONNECT");
+
+ U8 error;
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, pRcvdCmdResp, sizeof(response));
+ if (!openavbAcmpSMTalker_validTalkerUnique(pRcvdCmdResp->talker_unique_id)) {
+ // Talker ID is not recognized.
+ error = OPENAVB_ACMP_STATUS_TALKER_UNKNOWN_ID;
+ openavbAcmpSMTalker_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE, &response, error);
+ state = OPENAVB_ACMP_SM_TALKER_STATE_WAITING;
+ break;
+ }
+
+ // Try and start the Talker.
+ error = openavbAcmpSMTalker_connectTalker(&response);
+ if (error != OPENAVB_ACMP_STATUS_SUCCESS) {
+ openavbAcmpSMTalker_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE, &response, error);
+ state = OPENAVB_ACMP_SM_TALKER_STATE_WAITING;
+ break;
+ }
+
+ // openavbAcmpSMTalker_connectTalker() either sent a response, or updated the state
+ // to indicate we are waiting for information from the Talker.
+ // Either way, there is nothing else to do for now.
+ state = OPENAVB_ACMP_SM_TALKER_STATE_WAITING;
+ }
+ break;
+
+ case OPENAVB_ACMP_SM_TALKER_STATE_DISCONNECT:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_TALKER_STATE_DISCONNECT");
+
+ U8 error;
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, pRcvdCmdResp, sizeof(response));
+ if (openavbAcmpSMTalker_validTalkerUnique(pRcvdCmdResp->talker_unique_id)) {
+ error = openavbAcmpSMTalker_disconnectTalker(&response);
+ }
+ else {
+ error = OPENAVB_ACMP_STATUS_TALKER_UNKNOWN_ID;
+ }
+ openavbAcmpSMTalker_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE, &response, error);
+
+ state = OPENAVB_ACMP_SM_TALKER_STATE_WAITING;
+ }
+ break;
+
+ case OPENAVB_ACMP_SM_TALKER_STATE_GET_STATE:
+ {
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_TALKER_STATE_GET_STATE");
+
+ U8 error;
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, pRcvdCmdResp, sizeof(response));
+ if (openavbAcmpSMTalker_validTalkerUnique(pRcvdCmdResp->talker_unique_id)) {
+ error = openavbAcmpSMTalker_getState(&response);
+ }
+ else {
+ error = OPENAVB_ACMP_STATUS_TALKER_UNKNOWN_ID;
+ }
+ openavbAcmpSMTalker_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE, &response, error);
+
+ state = OPENAVB_ACMP_SM_TALKER_STATE_WAITING;
+ }
+ break;
+
+ case OPENAVB_ACMP_SM_TALKER_STATE_GET_CONNECTION:
+ {
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_TALKER_STATE_GET_CONNECTION");
+
+ U8 error;
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, pRcvdCmdResp, sizeof(response));
+ if (openavbAcmpSMTalker_validTalkerUnique(pRcvdCmdResp->talker_unique_id)) {
+ error = openavbAcmpSMTalker_getConnection(&response);
+ }
+ else {
+ error = OPENAVB_ACMP_STATUS_TALKER_UNKNOWN_ID;
+ }
+ openavbAcmpSMTalker_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_RESPONSE, &response, error);
+
+ state = OPENAVB_ACMP_SM_TALKER_STATE_WAITING;
+ }
+ break;
+ }
+ }
+ ACMP_SM_UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void* openavbAcmpSMTalkerThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavbAcmpSMTalkerStateMachine();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return NULL;
+}
+
+bool openavbAcmpSMTalkerStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavbAcmpSMTalkerVars.talkerStreamInfos = openavbArrayNewArray(sizeof(openavb_acmp_TalkerStreamInfo_t));
+ if (!openavbAcmpSMTalkerVars.talkerStreamInfos) {
+ AVB_LOG_ERROR("Unable to create talkerStreamInfos array. ACMP protocol not started.");
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return FALSE;
+ }
+ openavb_array_t streamOutputDescriptorArray = openavbAemGetDescriptorArray(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT);
+ if (streamOutputDescriptorArray) {
+ openavbArrayMultiNew(openavbAcmpSMTalkerVars.talkerStreamInfos, openavbArrayCount(streamOutputDescriptorArray));
+ }
+
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "openavbAcmpSMTalkerMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(openavbAcmpSMTalkerMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'openavbAcmpSMTalkerMutex' mutex");
+
+ SEM_ERR_T(err);
+ SEM_INIT(openavbAcmpSMTalkerSemaphore, 1, err);
+ SEM_LOG_ERR(err);
+
+ // Start the State Machine
+ bool errResult;
+ bRunning = TRUE;
+ THREAD_CREATE(openavbAcmpSmTalkerThread, openavbAcmpSmTalkerThread, NULL, openavbAcmpSMTalkerThreadFn, NULL);
+ THREAD_CHECK_ERROR(openavbAcmpSmTalkerThread, "Thread / task creation failed", errResult);
+ if (errResult) {
+ bRunning = FALSE;
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return TRUE;
+}
+
+void openavbAcmpSMTalkerStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ if (bRunning) {
+ openavbAcmpSMTalkerSet_doTerminate(TRUE);
+
+ THREAD_JOIN(openavbAcmpSmTalkerThread, NULL);
+ }
+
+ SEM_ERR_T(err);
+ SEM_DESTROY(openavbAcmpSMTalkerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ openavb_array_elem_t node = openavbArrayIterFirst(openavbAcmpSMTalkerVars.talkerStreamInfos);
+ while (node) {
+ openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo = openavbArrayData(node);
+ if (pTalkerStreamInfo != NULL) {
+ openavbListDeleteList(pTalkerStreamInfo->connected_listeners);
+ if (pTalkerStreamInfo->waiting_on_talker) {
+ free(pTalkerStreamInfo->waiting_on_talker);
+ pTalkerStreamInfo->waiting_on_talker = NULL;
+ }
+ }
+ node = openavbArrayIterNext(openavbAcmpSMTalkerVars.talkerStreamInfos);
+ }
+ openavbArrayDeleteArray(openavbAcmpSMTalkerVars.talkerStreamInfos);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMTalkerSet_rcvdConnectTXCmd(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMTalkerVars.rcvdConnectTX = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMTalkerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMTalkerSet_rcvdDisconnectTXCmd(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMTalkerVars.rcvdDisconnectTX = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMTalkerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMTalkerSet_rcvdGetTXState(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMTalkerVars.rcvdGetTXState = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMTalkerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMTalkerSet_rcvdGetTXConnectionCmd(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMTalkerVars.rcvdGetTXConnection = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMTalkerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMTalkerSet_doTerminate(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavbAcmpSMTalkerVars.doTerminate = value;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMTalkerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+
+void openavbAcmpSMTalker_updateStreamInfo(openavb_tl_data_cfg_t *pCfg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ ACMP_SM_LOCK();
+
+ // Find the talker stream waiting for the update.
+ openavb_array_elem_t node = openavbArrayIterFirst(openavbAcmpSMTalkerVars.talkerStreamInfos);
+ while (node) {
+ openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo = openavbArrayData(node);
+ if (pTalkerStreamInfo != NULL && pTalkerStreamInfo->waiting_on_talker != NULL) {
+ U16 configIdx = openavbAemGetConfigIdx();
+ S32 talker_unique_id = openavbArrayGetIdx(node);
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(configIdx, OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT, talker_unique_id);
+ if (pDescriptorStreamOutput && pDescriptorStreamOutput->stream == pCfg) {
+
+ // Verify that the destination address is valid.
+ if (pCfg->dest_addr.mac == NULL ||
+ memcmp(pCfg->dest_addr.buffer.ether_addr_octet, "\x00\x00\x00\x00\x00\x00", 6) == 0) {
+ AVB_LOG_DEBUG("stream_dest_mac not yet valid. Continue to wait.");
+ continue;
+ }
+
+ // We will handle the GET_TX_CONNECTION_RESPONSE command response here.
+ AVB_LOGF_DEBUG("Received an update for talker_unique_id %d", talker_unique_id);
+ openavb_acmp_ACMPCommandResponse_t *response = pTalkerStreamInfo->waiting_on_talker;
+ pTalkerStreamInfo->waiting_on_talker = NULL;
+
+ // Update the talker stream information with the information from the configuration.
+ memcpy(pTalkerStreamInfo->stream_id, pCfg->stream_addr.mac, ETH_ALEN);
+ U8 *pStreamUID = pTalkerStreamInfo->stream_id + 6;
+ *(U16 *)(pStreamUID) = htons(pCfg->stream_uid);
+ memcpy(pTalkerStreamInfo->stream_dest_mac, pCfg->dest_addr.buffer.ether_addr_octet, ETH_ALEN);
+ pTalkerStreamInfo->stream_vlan_id = pCfg->vlan_id;
+
+ // Update the GET_TX_CONNECTION_RESPONSE command information.
+ memcpy(response->stream_id, pTalkerStreamInfo->stream_id, sizeof(response->stream_id));
+ memcpy(response->stream_dest_mac, pTalkerStreamInfo->stream_dest_mac, sizeof(response->stream_dest_mac));
+ response->stream_vlan_id = pTalkerStreamInfo->stream_vlan_id;
+ response->connection_count = pTalkerStreamInfo->connection_count;
+
+ // Save the response flags for reference later.
+ pDescriptorStreamOutput->acmp_flags = response->flags;
+
+ // Save the stream information for reference later.
+ // (This is currently only used by Listeners, but it doesn't hurt to have it just in case.)
+ memcpy(pDescriptorStreamOutput->acmp_stream_id, response->stream_id, 8);
+ memcpy(pDescriptorStreamOutput->acmp_dest_addr, response->stream_dest_mac, 6);
+ pDescriptorStreamOutput->acmp_stream_vlan_id = response->stream_vlan_id;
+
+ // Send the response.
+ openavbAcmpSMTalker_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE, response, OPENAVB_ACMP_STATUS_SUCCESS);
+ AVB_LOG_DEBUG("Sent a CONNECT_TX_RESPONSE command");
+
+ // Done with the response command.
+ free(response);
+ break;
+ }
+ }
+ node = openavbArrayIterNext(openavbAcmpSMTalkerVars.talkerStreamInfos);
+ }
+
+ ACMP_SM_UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp_sm_talker.h b/lib/avtp_pipeline/acmp/openavb_acmp_sm_talker.h
new file mode 100644
index 00000000..f78ce72d
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp_sm_talker.h
@@ -0,0 +1,76 @@
+/*************************************************************************************************************
+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 : ACMP - AVDECC Connection Management Protocol : Talker State Machine Interface
+ * MODULE SUMMARY : Interface for the ACMP - AVDECC Connection Management Protocol : Talker State Machine
+ * IEEE Std 1722.1-2013 clause 8.2.2.6
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ACMP_SM_TALKER_H
+#define OPENAVB_ACMP_SM_TALKER_H 1
+
+#include "openavb_acmp.h"
+
+// State machine vars IEEE Std 1722.1-2013 clause 8.2.2.6.1
+typedef struct {
+ openavb_array_t talkerStreamInfos;
+ bool rcvdConnectTX;
+ bool rcvdDisconnectTX;
+ bool rcvdGetTXState;
+ bool rcvdGetTXConnection;
+
+ // Not part of spec
+ bool doTerminate;
+} openavb_acmp_sm_talker_vars_t;
+
+// State machine functions IEEE Std 1722.1-2013 clause 8.2.2.6.2
+bool openavbAcmpSMTalker_validTalkerUnique(U16 talkerUniqueId);
+U8 openavbAcmpSMTalker_connectTalker(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMTalker_txResponse(U8 messageType, openavb_acmp_ACMPCommandResponse_t *response, U8 error);
+U8 openavbAcmpSMTalker_disconnectTalker(openavb_acmp_ACMPCommandResponse_t *command);
+U8 openavbAcmpSMTalker_getState(openavb_acmp_ACMPCommandResponse_t *command);
+U8 openavbAcmpSMTalker_getConnection(openavb_acmp_ACMPCommandResponse_t *command);
+
+bool openavbAcmpSMTalkerStart(void);
+void openavbAcmpSMTalkerStop(void);
+
+void openavbAcmpSMTalkerSet_rcvdConnectTXCmd(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMTalkerSet_rcvdDisconnectTXCmd(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMTalkerSet_rcvdGetTXState(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMTalkerSet_rcvdGetTXConnectionCmd(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMTalkerSet_doTerminate(bool value);
+
+void openavbAcmpSMTalker_updateStreamInfo(openavb_tl_data_cfg_t *pCfg);
+
+#endif // OPENAVB_ACMP_SM_TALKER_H
diff --git a/lib/avtp_pipeline/adp/CMakeLists.txt b/lib/avtp_pipeline/adp/CMakeLists.txt
new file mode 100644
index 00000000..c8da8d8d
--- /dev/null
+++ b/lib/avtp_pipeline/adp/CMakeLists.txt
@@ -0,0 +1,9 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/adp/openavb_adp.c
+ ${AVB_SRC_DIR}/adp/openavb_adp_message.c
+ ${AVB_SRC_DIR}/adp/openavb_adp_sm_advertise_entity.c
+ ${AVB_SRC_DIR}/adp/openavb_adp_sm_advertise_interface.c
+ ${AVB_SRC_DIR}/adp/openavb_adp_sm_discovery.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/adp/openavb_adp.c b/lib/avtp_pipeline/adp/openavb_adp.c
new file mode 100644
index 00000000..474c8d3e
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp.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.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ADP - AVDECC Discovery Protocol
+ * MODULE SUMMARY : Implements the 1722.1 (AVDECC) discovery protocol
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <signal.h>
+
+#define AVB_LOG_COMPONENT "ADP"
+#include "openavb_log.h"
+
+#include "openavb_aem.h"
+#include "openavb_adp.h"
+#include "openavb_adp_sm_advertise_entity.h"
+#include "openavb_adp_sm_advertise_interface.h"
+#include "openavb_adp_message.h"
+
+#ifdef AVB_PTP_AVAILABLE
+#include "openavb_ptp_api.h"
+
+// PTP declarations
+openavbRC openavbPtpInitializeSharedMemory ();
+void openavbPtpReleaseSharedMemory ();
+openavbRC openavbPtpUpdateSharedMemoryEntry ();
+openavbRC openavbPtpFindLatestSharedMemoryEntry(U32 *index);
+extern gmChangeTable_t openavbPtpGMChageTable;
+#endif // AVB_PTP_AVAILABLE
+
+openavb_adp_sm_global_vars_t openavbAdpSMGlobalVars;
+
+MUTEX_HANDLE(openavbAdpMutex);
+#define ADP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAdpMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ADP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAdpMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+
+static bool s_bPreviousHaveTL = false;
+
+openavbRC openavbAdpStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ openavb_avdecc_entity_model_t *pAem = openavbAemGetModel();
+ if (!pAem) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING), AVB_TRACE_ADP);
+ }
+
+ {
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "openavbAdpMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(openavbAdpMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'openavbAdpMutex' mutex");
+ }
+
+ ADP_LOCK();
+ {
+ // Populate global ADP vars
+ openavb_adp_control_header_t *pHeader = &openavbAdpSMGlobalVars.entityInfo.header;
+
+ pHeader->cd = 1;
+ pHeader->subtype = OPENAVB_ADP_AVTP_SUBTYPE;
+ pHeader->sv = 0;
+ pHeader->version = 0;
+ pHeader->message_type = 0; // Set later depending on message type
+ pHeader->valid_time = gAvdeccCfg.valid_time;
+ pHeader->control_data_length = 56;
+ memcpy(pHeader->entity_id, pAem->pDescriptorEntity->entity_id, sizeof(pAem->pDescriptorEntity->entity_id));
+ }
+
+ {
+ // Populate global ADP PDU vars
+ openavb_adp_data_unit_t *pPdu = &openavbAdpSMGlobalVars.entityInfo.pdu;
+
+#ifdef AVB_PTP_AVAILABLE
+ openavbRC retCode = OPENAVB_PTP_FAILURE;
+ retCode = openavbPtpInitializeSharedMemory();
+ if (IS_OPENAVB_FAILURE(retCode)) {
+ AVB_LOG_WARNING("Failed to init PTP shared memory");
+ }
+#endif // AVB_PTP_AVAILABLE
+
+ memcpy(pPdu->entity_model_id, pAem->pDescriptorEntity->entity_model_id, sizeof(pPdu->entity_model_id));
+ pPdu->entity_capabilities = pAem->pDescriptorEntity->entity_capabilities;
+ pPdu->talker_stream_sources = pAem->pDescriptorEntity->talker_stream_sources;
+ pPdu->talker_capabilities = pAem->pDescriptorEntity->talker_capabilities;
+ pPdu->listener_stream_sinks = pAem->pDescriptorEntity->listener_stream_sinks;
+ pPdu->listener_capabilities = pAem->pDescriptorEntity->listener_capabilities;
+ pPdu->controller_capabilities = pAem->pDescriptorEntity->controller_capabilities;
+ pPdu->available_index = pAem->pDescriptorEntity->available_index;
+ // The pPdu->gptp_grandmaster_id and pPdu->gptp_domain_number will be filled in when the ADPDU is transmitted.
+ // pPdu->reserved0;
+ // pPdu->identify_control_index = ???; // AVDECC_TODO
+ // pPdu->interface_index = ???; // AVDECC_TODO
+ memcpy(pPdu->association_id, pAem->pDescriptorEntity->association_id, sizeof(pPdu->association_id));
+ // pPdu->reserved1;
+ }
+ ADP_UNLOCK();
+
+ // Wait until we are notified that we have a Talker or Listener before supporting discover.
+ s_bPreviousHaveTL = false;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_ADP);
+}
+
+void openavbAdpStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+#ifdef AVB_PTP_AVAILABLE
+ openavbPtpReleaseSharedMemory();
+#endif // AVB_PTP_AVAILABLE
+
+ // Stop Advertising and supporting Discovery.
+ openavbAdpHaveTL(false);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+
+openavbRC openavbAdpHaveTL(bool bHaveTL)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ if (bHaveTL && !s_bPreviousHaveTL) {
+ // Start Advertising and supporting Discovery.
+ openavbRC rc = openavbAdpMessageHandlerStart();
+ if (IS_OPENAVB_FAILURE(rc)) {
+ AVB_RC_TRACE_RET(rc, AVB_TRACE_ADP);
+ }
+
+ openavbAdpSMAdvertiseInterfaceStart();
+ openavbAdpSMAdvertiseEntityStart();
+ s_bPreviousHaveTL = true;
+ }
+ else if (!bHaveTL && s_bPreviousHaveTL) {
+ // Stop Advertising and supporting Discovery.
+ openavbAdpSMAdvertiseInterfaceStop();
+ openavbAdpSMAdvertiseEntityStop();
+ openavbAdpMessageHandlerStop();
+ s_bPreviousHaveTL = false;
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_ADP);
+}
diff --git a/lib/avtp_pipeline/adp/openavb_adp.h b/lib/avtp_pipeline/adp/openavb_adp.h
new file mode 100644
index 00000000..54594527
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp.h
@@ -0,0 +1,93 @@
+/*************************************************************************************************************
+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 : ADP - AVDECC Discovery Protocol Internal Interface
+ * MODULE SUMMARY : Internal Interface for the 1722.1 (AVDECC) discovery protocol
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ADP_H
+#define OPENAVB_ADP_H 1
+
+#include "openavb_avdecc.h"
+#include "openavb_adp_pub.h"
+
+#define OPENAVB_ADP_AVTP_SUBTYPE (0x7a)
+
+typedef struct {
+ U8 cd;
+ U8 subtype;
+ U8 sv;
+ U8 version;
+ U8 message_type; // Redefined from control data
+ U8 valid_time; // Redefined from status
+ U16 control_data_length;
+ U8 entity_id[8]; // Redefined from stream_id
+} openavb_adp_control_header_t;
+
+typedef struct {
+ U8 entity_model_id[8];
+ U32 entity_capabilities;
+ U16 talker_stream_sources;
+ U16 talker_capabilities;
+ U16 listener_stream_sinks;
+ U16 listener_capabilities;
+ U32 controller_capabilities;
+ U32 available_index;
+ U8 gptp_grandmaster_id[8];
+ U8 gptp_domain_number;
+ U8 reserved0[3];
+ U16 identify_control_index;
+ U16 interface_index;
+ U8 association_id[8];
+ U8 reserved1[4];
+} openavb_adp_data_unit_t;
+
+typedef struct {
+ openavb_adp_control_header_t header;
+ openavb_adp_data_unit_t pdu;
+} openavb_adp_entity_info_t;
+
+// IEEE Std 1722.1-2013 clause 6.2.3.
+typedef struct {
+ U64 currentTime;
+ openavb_adp_entity_info_t entityInfo;
+} openavb_adp_sm_global_vars_t;
+
+
+openavbRC openavbAdpStart(void);
+void openavbAdpStop(void);
+
+openavbRC openavbAdpHaveTL(bool bHaveTL);
+
+#endif // OPENAVB_ADP_H
diff --git a/lib/avtp_pipeline/adp/openavb_adp_message.c b/lib/avtp_pipeline/adp/openavb_adp_message.c
new file mode 100644
index 00000000..3f695101
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp_message.c
@@ -0,0 +1,464 @@
+/*************************************************************************************************************
+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 : ADP - AVDECC Discovery Protocol Message Handler
+ * MODULE SUMMARY : Implements the 1722.1 (AVDECC) discovery protocol message handlers
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#define AVB_LOG_COMPONENT "ADP"
+#include "openavb_log.h"
+
+#include "openavb_debug.h"
+#include "openavb_rawsock.h"
+#include "openavb_avtp.h"
+#include "openavb_srp.h"
+#include "openavb_adp.h"
+#include "openavb_adp_sm_advertise_interface.h"
+#include "openavb_acmp_sm_listener.h"
+
+#ifdef AVB_PTP_AVAILABLE
+#include "openavb_ptp_api.h"
+
+// PTP declarations
+openavbRC openavbPtpInitializeSharedMemory ();
+void openavbPtpReleaseSharedMemory ();
+openavbRC openavbPtpUpdateSharedMemoryEntry ();
+openavbRC openavbPtpFindLatestSharedMemoryEntry(U32 *index);
+extern gmChangeTable_t openavbPtpGMChageTable;
+#else
+#include "openavb_grandmaster_osal_pub.h"
+#endif // AVB_PTP_AVAILABLE
+
+
+#define INVALID_SOCKET (-1)
+
+// ADP Multicast address
+#define ADP_PROTOCOL_ADDR "91:E0:F0:01:00:00"
+
+// message length
+#define AVTP_HDR_LEN 12
+#define ADP_DATA_LEN 56
+#define ADP_FRAME_LEN (ETH_HDR_LEN_VLAN + AVTP_HDR_LEN + ADP_DATA_LEN)
+
+// number of buffers (arbitrary, and rounded up by rawsock)
+#define ADP_NUM_BUFFERS 2
+
+// do cast from ether_addr to U8*
+#define ADDR_PTR(A) (U8*)(&((A)->ether_addr_octet))
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+
+extern MUTEX_HANDLE(openavbAdpMutex);
+#define ADP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAdpMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ADP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAdpMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+static void *rxSock = NULL;
+static void *txSock = NULL;
+static struct ether_addr intfAddr;
+static struct ether_addr adpAddr;
+
+extern openavb_adp_sm_global_vars_t openavbAdpSMGlobalVars;
+
+THREAD_TYPE(openavbAdpMessageRxThread);
+THREAD_DEFINITON(openavbAdpMessageRxThread);
+
+static bool bRunning = FALSE;
+
+void openavbAdpCloseSocket()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ if (rxSock) {
+ openavbRawsockClose(rxSock);
+ rxSock = NULL;
+ }
+ if (txSock) {
+ openavbRawsockClose(txSock);
+ txSock = NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+bool openavbAdpOpenSocket(const char* ifname, U16 vlanID, U8 vlanPCP)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ hdr_info_t hdr;
+
+#ifndef UBUNTU
+ // This is the normal case for most of our supported platforms
+ rxSock = openavbRawsockOpen(ifname, TRUE, FALSE, ETHERTYPE_8021Q, ADP_FRAME_LEN, ADP_NUM_BUFFERS);
+#else
+ rxSock = openavbRawsockOpen(ifname, TRUE, FALSE, ETHERTYPE_AVTP, ADP_FRAME_LEN, ADP_NUM_BUFFERS);
+#endif
+ txSock = openavbRawsockOpen(ifname, FALSE, TRUE, ETHERTYPE_AVTP, ADP_FRAME_LEN, ADP_NUM_BUFFERS);
+
+ if (txSock && rxSock
+ && openavbRawsockGetAddr(txSock, ADDR_PTR(&intfAddr))
+ && ether_aton_r(ADP_PROTOCOL_ADDR, &adpAddr)
+ && openavbRawsockRxMulticast(rxSock, TRUE, ADDR_PTR(&adpAddr)))
+ {
+ if (!openavbRawsockRxAVTPSubtype(rxSock, OPENAVB_ADP_AVTP_SUBTYPE | 0x80)) {
+ AVB_LOG_DEBUG("RX AVTP Subtype not supported");
+ }
+
+ memset(&hdr, 0, sizeof(hdr_info_t));
+ hdr.shost = ADDR_PTR(&intfAddr);
+ hdr.dhost = ADDR_PTR(&adpAddr);
+ hdr.ethertype = ETHERTYPE_AVTP;
+ if (vlanID != 0 || vlanPCP != 0) {
+ hdr.vlan = TRUE;
+ hdr.vlan_pcp = vlanPCP;
+ hdr.vlan_vid = vlanID;
+ AVB_LOGF_DEBUG("VLAN pcp=%d vid=%d", hdr.vlan_pcp, hdr.vlan_vid);
+ }
+ if (!openavbRawsockTxSetHdr(txSock, &hdr)) {
+ AVB_LOG_ERROR("TX socket Header Failure");
+ openavbAdpCloseSocket();
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+ return false;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+ return true;
+ }
+
+ AVB_LOG_ERROR("Invalid socket");
+ openavbAdpCloseSocket();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+ return false;
+}
+
+static void openavbAdpMessageRxFrameParse(U8* payload, int payload_len, hdr_info_t *hdr)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ openavb_adp_control_header_t adpHeader;
+ openavb_adp_data_unit_t adpPdu;
+
+#if 0
+ AVB_LOGF_DEBUG("openavbAdpMessageRxFrameParse packet data (length %d):", payload_len);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_DEBUG, payload, payload_len, 16);
+#endif
+
+ U8 *pSrc = payload;
+ {
+ // AVTP Control Header
+ openavb_adp_control_header_t *pDst = &adpHeader;
+
+ BIT_B2DNTOHB(pDst->cd, pSrc, 0x80, 7, 0);
+ BIT_B2DNTOHB(pDst->subtype, pSrc, 0x7f, 0, 1);
+ BIT_B2DNTOHB(pDst->sv, pSrc, 0x80, 7, 0);
+ BIT_B2DNTOHB(pDst->version, pSrc, 0x70, 4, 0);
+ BIT_B2DNTOHB(pDst->message_type, pSrc, 0x0f, 0, 1);
+ BIT_B2DNTOHB(pDst->valid_time, pSrc, 0xf800, 11, 0);
+ BIT_B2DNTOHS(pDst->control_data_length, pSrc, 0x07ff, 0, 2);
+ OCT_B2DMEMCP(pDst->entity_id, pSrc);
+ }
+
+ if (adpHeader.subtype == OPENAVB_ADP_AVTP_SUBTYPE &&
+ (adpHeader.message_type == OPENAVB_ADP_MESSAGE_TYPE_ENTITY_DISCOVER ||
+ (gAvdeccCfg.bFastConnectSupported && adpHeader.message_type == OPENAVB_ADP_MESSAGE_TYPE_ENTITY_AVAILABLE))) {
+ // ADP PDU
+ openavb_adp_data_unit_t *pDst = &adpPdu;
+
+ OCT_B2DMEMCP(pDst->entity_model_id, pSrc);
+ OCT_B2DNTOHL(pDst->entity_capabilities, pSrc);
+ OCT_B2DNTOHS(pDst->talker_stream_sources, pSrc);
+ OCT_B2DNTOHS(pDst->talker_capabilities, pSrc);
+ OCT_B2DNTOHS(pDst->listener_stream_sinks, pSrc);
+ OCT_B2DNTOHS(pDst->listener_capabilities, pSrc);
+ OCT_B2DNTOHL(pDst->controller_capabilities, pSrc);
+ OCT_B2DNTOHL(pDst->available_index, pSrc);
+ OCT_B2DMEMCP(pDst->gptp_grandmaster_id, pSrc);
+ OCT_B2DNTOHB(pDst->gptp_domain_number, pSrc);
+ OCT_B2DMEMCP(pDst->reserved0, pSrc);
+ OCT_B2DNTOHS(pDst->identify_control_index, pSrc);
+ OCT_B2DNTOHS(pDst->interface_index, pSrc);
+ OCT_B2DMEMCP(pDst->association_id, pSrc);
+ OCT_B2DMEMCP(pDst->reserved1, pSrc);
+
+ if (adpHeader.message_type == OPENAVB_ADP_MESSAGE_TYPE_ENTITY_DISCOVER) {
+ // Update the interface state machine
+ openavbAdpSMAdvertiseInterfaceSet_entityID(adpHeader.entity_id);
+ openavbAdpSMAdvertiseInterfaceSet_rcvdDiscover(TRUE);
+ }
+ else {
+ // See if Fast Connect is waiting for this device to be available.
+ if (adpPdu.talker_stream_sources > 0) {
+ openavbAcmpSMListenerSet_talkerTestFastConnect(adpHeader.entity_id);
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+static void openavbAdpMessageRxFrameReceive(U32 timeoutUsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ hdr_info_t hdrInfo;
+ unsigned int offset, len;
+ U8 *pBuf, *pFrame;
+
+ memset(&hdrInfo, 0, sizeof(hdr_info_t));
+
+ pBuf = (U8 *)openavbRawsockGetRxFrame(rxSock, timeoutUsec, &offset, &len);
+ if (pBuf) {
+ pFrame = pBuf + offset;
+
+ offset = openavbRawsockRxParseHdr(rxSock, pBuf, &hdrInfo);
+ {
+#ifndef UBUNTU
+ if (hdrInfo.ethertype == ETHERTYPE_8021Q) {
+ // Oh! Need to look past the VLAN tag
+ U16 vlan_bits = ntohs(*(U16 *)(pFrame + offset));
+ hdrInfo.vlan = TRUE;
+ hdrInfo.vlan_vid = vlan_bits & 0x0FFF;
+ hdrInfo.vlan_pcp = (vlan_bits >> 13) & 0x0007;
+ offset += 2;
+ hdrInfo.ethertype = ntohs(*(U16 *)(pFrame + offset));
+ offset += 2;
+ }
+#endif
+
+ // Make sure that this is an AVTP packet
+ // (Should always be AVTP if it's to our AVTP-specific multicast address)
+ if (hdrInfo.ethertype == ETHERTYPE_AVTP) {
+ // parse the PDU only for ADP messages
+ if (*(pFrame + offset) == (0x80 | OPENAVB_ADP_AVTP_SUBTYPE)) {
+ if (memcmp(hdrInfo.shost, ADDR_PTR(&intfAddr), 6) != 0) { // Not from us!
+ openavbAdpMessageRxFrameParse(pFrame + offset, len - offset, &hdrInfo);
+ }
+ }
+ }
+ else {
+ AVB_LOG_WARNING("Received non-AVTP frame!");
+ AVB_LOGF_DEBUG("Unexpected packet data (length %d):", len);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_DEBUG, pFrame, len, 16);
+ }
+ }
+
+ // Release the frame
+ openavbRawsockRelRxFrame(rxSock, pBuf);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+
+void openavbAdpMessageTxFrame(U8 msgType, U8 *destAddr)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ U8 *pBuf;
+ U32 size;
+ unsigned int hdrlen = 0;
+
+ pBuf = openavbRawsockGetTxFrame(txSock, TRUE, &size);
+
+ if (!pBuf) {
+ AVB_LOG_ERROR("No TX buffer");
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+ return;
+ }
+
+ if (size < ADP_FRAME_LEN) {
+ AVB_LOG_ERROR("TX buffer too small");
+ openavbRawsockRelTxFrame(txSock, pBuf);
+ pBuf = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+ return;
+ }
+
+ memset(pBuf, 0, ADP_FRAME_LEN);
+ openavbRawsockTxFillHdr(txSock, pBuf, &hdrlen);
+
+ if (destAddr)
+ memcpy(pBuf, destAddr, ETH_ALEN);
+
+ ADP_LOCK();
+ U8 *pDst = pBuf + hdrlen;
+ {
+ // AVTP Control Header
+ openavb_adp_control_header_t *pSrc = &openavbAdpSMGlobalVars.entityInfo.header;
+ BIT_D2BHTONB(pDst, pSrc->cd, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtype, 0, 1);
+ BIT_D2BHTONB(pDst, pSrc->sv, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->version, 4, 0);
+ BIT_D2BHTONB(pDst, msgType, 0, 1);
+ BIT_D2BHTONS(pDst, pSrc->valid_time, 11, 0);
+ BIT_D2BHTONS(pDst, pSrc->control_data_length, 0, 2);
+ OCT_D2BMEMCP(pDst, pSrc->entity_id);
+ }
+
+ {
+ // ADP PDU
+ openavb_adp_data_unit_t *pSrc = &openavbAdpSMGlobalVars.entityInfo.pdu;
+ OCT_D2BMEMCP(pDst, pSrc->entity_model_id);
+ OCT_D2BHTONL(pDst, pSrc->entity_capabilities);
+ OCT_D2BHTONS(pDst, pSrc->talker_stream_sources);
+ OCT_D2BHTONS(pDst, pSrc->talker_capabilities);
+ OCT_D2BHTONS(pDst, pSrc->listener_stream_sinks);
+ OCT_D2BHTONS(pDst, pSrc->listener_capabilities);
+ OCT_D2BHTONL(pDst, pSrc->controller_capabilities);
+ OCT_D2BHTONL(pDst, pSrc->available_index);
+ OCT_D2BMEMCP(pDst, pSrc->gptp_grandmaster_id);
+ OCT_D2BHTONB(pDst, pSrc->gptp_domain_number);
+ OCT_D2BMEMCP(pDst, pSrc->reserved0);
+ OCT_D2BHTONS(pDst, pSrc->identify_control_index);
+ OCT_D2BHTONS(pDst, pSrc->interface_index);
+ OCT_D2BMEMCP(pDst, pSrc->association_id);
+ OCT_D2BMEMCP(pDst, pSrc->reserved1);
+ }
+ ADP_UNLOCK();
+
+#if 0
+ AVB_LOGF_DEBUG("openavbAdpMessageTxFrame packet data (length %d):", hdrlen + AVTP_HDR_LEN + ADP_DATA_LEN);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_DEBUG, pBuf, hdrlen + AVTP_HDR_LEN + ADP_DATA_LEN, 16);
+#endif
+
+ openavbRawsockTxFrameReady(txSock, pBuf, hdrlen + AVTP_HDR_LEN + ADP_DATA_LEN, 0);
+ openavbRawsockSend(txSock);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void* openavbAdpMessageRxThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ AVB_LOG_DEBUG("ADP Thread Started");
+ while (bRunning) {
+ // Try to get and process an ADP discovery message.
+ openavbAdpMessageRxFrameReceive(MICROSECONDS_PER_SECOND);
+ }
+ AVB_LOG_DEBUG("ADP Thread Done");
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+ return NULL;
+}
+
+openavbRC openavbAdpMessageHandlerStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ bRunning = TRUE;
+
+ if (openavbAdpOpenSocket((const char *)gAvdeccCfg.ifname, gAvdeccCfg.vlanID, gAvdeccCfg.vlanPCP)) {
+
+ // Start the RX thread
+ bool errResult;
+ THREAD_CREATE(openavbAdpMessageRxThread, openavbAdpMessageRxThread, NULL, openavbAdpMessageRxThreadFn, NULL);
+ THREAD_CHECK_ERROR(openavbAdpMessageRxThread, "Thread / task creation failed", errResult);
+ if (errResult) {
+ bRunning = FALSE;
+ openavbAdpCloseSocket();
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_FAILURE, AVB_TRACE_ADP);
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_ADP);
+ }
+
+ bRunning = FALSE;
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_FAILURE, AVB_TRACE_ADP);
+}
+
+void openavbAdpMessageHandlerStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ if (bRunning) {
+ bRunning = FALSE;
+ THREAD_JOIN(openavbAdpMessageRxThread, NULL);
+ openavbAdpCloseSocket();
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+openavbRC openavbAdpMessageSend(U8 messageType)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ // Note: this entire process of the GM ID is not as the 1722.1 spec expects.
+ // The openavbAdpSMAdvertiseInterfaceSet_advertisedGrandmasterID() should be called when the
+ // stack detects a GM change that will trigger an advertise. Instead we are detecting
+ // the GM change when we have are sending an advertise message. This means we will not have a timely
+ // new advertise in the event of a GM change. Additionally the handling the advertiseInterface var
+ // of GM ID is not normal since the GM ID is being placed directly into the PDU rather than getting
+ // pulled from the state machine var.
+ // AVDECC_TODO: This logic should change to detect GM change else where in the system and call the
+ // expected openavbAdpSMAdvertiseInterfaceSet_advertisedGrandmasterID() to start the advertise process.
+#ifdef AVB_PTP_AVAILABLE
+ openavb_adp_data_unit_t *pPdu = &openavbAdpSMGlobalVars.entityInfo.pdu;
+ openavbRC retCode = OPENAVB_PTP_FAILURE;
+ U32 ptpSharedMemoryEntryIndex;
+ retCode = openavbPtpFindLatestSharedMemoryEntry(&ptpSharedMemoryEntryIndex);
+ if (IS_OPENAVB_FAILURE(retCode)) {
+ AVB_LOG_INFO("Failed to find PTP shared memory entry.");
+ }
+ else {
+ if (memcmp(pPdu->gptp_grandmaster_id, openavbPtpGMChageTable.entry[ptpSharedMemoryEntryIndex].gmId, sizeof(pPdu->gptp_grandmaster_id))) {
+ memcpy(pPdu->gptp_grandmaster_id, openavbPtpGMChageTable.entry[ptpSharedMemoryEntryIndex].gmId, sizeof(pPdu->gptp_grandmaster_id));
+ openavbAdpSMAdvertiseInterfaceSet_advertisedGrandmasterID(pPdu->gptp_grandmaster_id);
+ }
+ }
+#else
+ openavb_adp_data_unit_t *pPdu = &openavbAdpSMGlobalVars.entityInfo.pdu;
+ uint8_t current_grandmaster_id[8];
+ if (!osalAVBGrandmasterGetCurrent(current_grandmaster_id, &(pPdu->gptp_domain_number)))
+ {
+ AVB_LOG_ERROR("osalAVBGrandmasterGetCurrent failure");
+ }
+ else if (memcmp(pPdu->gptp_grandmaster_id, current_grandmaster_id, sizeof(pPdu->gptp_grandmaster_id)))
+ {
+ memcpy(pPdu->gptp_grandmaster_id, current_grandmaster_id, sizeof(pPdu->gptp_grandmaster_id));
+ openavbAdpSMAdvertiseInterfaceSet_advertisedGrandmasterID(pPdu->gptp_grandmaster_id);
+ }
+#endif
+
+ openavbAdpMessageTxFrame(messageType, NULL);
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_ADP);
+}
+
diff --git a/lib/avtp_pipeline/adp/openavb_adp_message.h b/lib/avtp_pipeline/adp/openavb_adp_message.h
new file mode 100644
index 00000000..3769ebc6
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp_message.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.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ADP - AVDECC Discovery Protocol Message Handler Interface
+ * MODULE SUMMARY : Interface for the the 1722.1 (AVDECC) discovery protocol message handlers
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ADP_MESSAGE_H
+#define OPENAVB_ADP_MESSAGE_H 1
+
+#include "openavb_avdecc.h"
+
+openavbRC openavbAdpMessageHandlerStart(void);
+
+void openavbAdpMessageHandlerStop(void);
+
+openavbRC openavbAdpMessageSend(U8 messageType);
+
+#endif // OPENAVB_ADP_MESSAGE_H
diff --git a/lib/avtp_pipeline/adp/openavb_adp_pub.h b/lib/avtp_pipeline/adp/openavb_adp_pub.h
new file mode 100644
index 00000000..6e332486
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp_pub.h
@@ -0,0 +1,90 @@
+/*************************************************************************************************************
+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 : ADP - AVDECC Discovery Protocol Public Interface
+ * MODULE SUMMARY : Public interface for the 1722.1 (AVDECC) discovery protocol
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ADP_PUB_H
+#define OPENAVB_ADP_PUB_H 1
+
+// message_type field IEEE Std 1722.1-2013 clause 6.2.1.5
+#define OPENAVB_ADP_MESSAGE_TYPE_ENTITY_AVAILABLE (0x00)
+#define OPENAVB_ADP_MESSAGE_TYPE_ENTITY_DEPARTING (0x01)
+#define OPENAVB_ADP_MESSAGE_TYPE_ENTITY_DISCOVER (0x02)
+
+// entity_capabilities field IEEE Std 1722.1-2013 clause 6.2.1.10
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_EFU_MODE (0x00000001)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_ADDRESS_ACCESS_SUPPORTED (0x00000002)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_GATEWAY_ENTITY (0x00000004)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_AEM_SUPPORTED (0x00000008)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_LEGACY_AVC (0x00000010)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_ASSOCIATION_ID_SUPPORTED (0x00000020)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_ASSOCIATION_ID_VALID (0x00000040)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_VENDOR_UNIQUE_SUPPORTED (0x00000080)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_CLASS_A_SUPPORTED (0x00000100)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_CLASS_B_SUPPORTED (0x00000200)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_GPTP_SUPPORTED (0x00000400)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_AEM_AUTHENTICATION_SUPPORTED (0x00000800)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_AEM_AUTHENTICATION_REQUIRED (0x00001000)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_AEM_PERSISTENT_ACQUIRE_SUPPORTED (0x00002000)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_AEM_IDENTIFY_CONTROL_INDEX_VALID (0x00004000)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_AEM_INTERFACE_INDEX_VALID (0x00008000)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_GENERAL_CONTROLLER_IGNORE (0x00010000)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_ENTITY_NOT_READY (0x00020000)
+
+// talker_capabilities field IEEE Std 1722.1-2013 clause 6.2.1.12
+#define OPENAVB_ADP_TALKER_CAPABILITIES_IMPLEMENTED (0x0001)
+#define OPENAVB_ADP_TALKER_CAPABILITIES_OTHER_SOURCE (0x0200)
+#define OPENAVB_ADP_TALKER_CAPABILITIES_CONTROL_SOURCE (0x0400)
+#define OPENAVB_ADP_TALKER_CAPABILITIES_MEDIA_CLOCK_SOURCE (0x0800)
+#define OPENAVB_ADP_TALKER_CAPABILITIES_SMPTE_SOURCE (0x1000)
+#define OPENAVB_ADP_TALKER_CAPABILITIES_MIDI_SOURCE (0x2000)
+#define OPENAVB_ADP_TALKER_CAPABILITIES_AUDIO_SOURCE (0x4000)
+#define OPENAVB_ADP_TALKER_CAPABILITIES_VIDEO_SOURCE (0x8000)
+
+// listener_capabilities field IEEE Std 1722.1-2013 clause 6.2.1.14
+#define OPENAVB_ADP_LISTENER_CAPABILITIES_IMPLEMENTED (0x0001)
+#define OPENAVB_ADP_LISTENER_CAPABILITIES_OTHER_SINK (0x0200)
+#define OPENAVB_ADP_LISTENER_CAPABILITIES_CONTROL_SINK (0x0400)
+#define OPENAVB_ADP_LISTENER_CAPABILITIES_MEDIA_CLOCK_SINK (0x0800)
+#define OPENAVB_ADP_LISTENER_CAPABILITIES_SMPTE_SINK (0x1000)
+#define OPENAVB_ADP_LISTENER_CAPABILITIES_MIDI_SINK (0x2000)
+#define OPENAVB_ADP_LISTENER_CAPABILITIES_AUDIO_SINK (0x4000)
+#define OPENAVB_ADP_LISTENER_CAPABILITIES_VIDEO_SINK (0x8000)
+
+// controller_capabilities field IEEE Std 1722.1-2013 clause 6.2.1.15
+#define OPENAVB_ADP_CONTROLLER_CAPABILITES_IMPLEMENTED (0x00000001)
+
+#endif // OPENAVB_ADP_PUB_H
diff --git a/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_entity.c b/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_entity.c
new file mode 100644
index 00000000..6a1e5d44
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_entity.c
@@ -0,0 +1,252 @@
+/*************************************************************************************************************
+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 : ADP - AVDECC Discovery Protocol : Advertise Entity State Machine
+ * MODULE SUMMARY : Implements the AVDECC Discovery Protocol : Advertise Entity State Machine
+ * IEEE Std 1722.1-2013 clause 6.2.4.
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <errno.h>
+
+#define AVB_LOG_COMPONENT "ADP"
+#include "openavb_log.h"
+
+#include "openavb_time.h"
+#include "openavb_adp.h"
+#include "openavb_adp_sm_advertise_interface.h"
+#include "openavb_adp_sm_advertise_entity.h"
+
+typedef enum {
+ OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_INITIALIZE,
+ OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_ADVERTISE,
+ OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_RESET_WAIT,
+ OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_WAITING,
+ OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_TERMINATE,
+} openavb_adp_sm_advertise_entity_state_t;
+
+extern openavb_adp_sm_global_vars_t openavbAdpSMGlobalVars;
+extern openavb_adp_sm_advertise_interface_vars_t openavbAdpSMAdvertiseInterfaceVars;
+openavb_adp_sm_advertise_entity_vars_t openavbAdpSMAdvertiseEntityVars;
+
+extern MUTEX_HANDLE(openavbAdpMutex);
+#define ADP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAdpMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ADP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAdpMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+SEM_T(openavbAdpSMAdvertiseEntitySemaphore);
+THREAD_TYPE(openavbAdpSmAdvertiseEntityThread);
+THREAD_DEFINITON(openavbAdpSmAdvertiseEntityThread);
+
+void openavbAdpSMAdvertiseEntity_sendAvailable()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ openavbAdpSMAdvertiseInterfaceSet_doAdvertise(TRUE);
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseEntityStateMachine()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ bool bRunning = TRUE;
+
+ openavb_adp_sm_advertise_entity_state_t state = OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_INITIALIZE;
+
+ while (bRunning) {
+ switch (state) {
+ case OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_INITIALIZE:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_INITIALIZE");
+
+ ADP_LOCK();
+ openavbAdpSMGlobalVars.entityInfo.pdu.available_index = 0;
+ ADP_UNLOCK();
+
+ // The advertise interface will send the first advertisement on startup.
+ // This entity will be responsible for sending subsequent advertisements.
+ // This allows the advertise entity and advertise interface to startup without any inter-dependencies.
+ state = OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_RESET_WAIT;
+ }
+ break;
+ case OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_ADVERTISE:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_ADVERTISE");
+
+ openavbAdpSMAdvertiseEntity_sendAvailable();
+ ADP_LOCK();
+ openavbAdpSMAdvertiseEntityVars.needsAdvertise = FALSE;
+ ADP_UNLOCK();
+ state = OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_RESET_WAIT;
+ }
+ break;
+ case OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_RESET_WAIT:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_RESET_WAIT");
+
+ ADP_LOCK();
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &openavbAdpSMAdvertiseEntityVars.reannounceTimerTimeout);
+ /* The advertisements should be sent at intervals of 1/4 valid_time, where valid_time is in 2-second units.
+ * See IEEE Std 1722.1-2013 clauses 6.2.1.6 and 6.2.4. */
+ U32 advDelayUsec = openavbAdpSMGlobalVars.entityInfo.header.valid_time / 2 * MICROSECONDS_PER_SECOND;
+ if (advDelayUsec < MICROSECONDS_PER_SECOND) {
+ advDelayUsec = MICROSECONDS_PER_SECOND;
+ }
+ openavbTimeTimespecAddUsec(&openavbAdpSMAdvertiseEntityVars.reannounceTimerTimeout, advDelayUsec);
+ ADP_UNLOCK();
+ state = OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_WAITING;
+ }
+ break;
+ case OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_WAITING:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_WAITING");
+
+ ADP_LOCK();
+ openavbAdpSMAdvertiseInterfaceSet_rcvdDiscover(FALSE);
+ openavbAdpSMGlobalVars.entityInfo.pdu.available_index++;
+ ADP_UNLOCK();
+
+ // Wait for change in state
+ while (state == OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_WAITING && bRunning) {
+ U32 timeoutMSec;
+ struct timespec now;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &now);
+ timeoutMSec = openavbTimeUntilMSec(&now, &openavbAdpSMAdvertiseEntityVars.reannounceTimerTimeout);
+
+ if (timeoutMSec == 0) {
+ /* No need to wait. */
+ state = OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_ADVERTISE;
+ }
+ else {
+ SEM_ERR_T(err);
+ SEM_TIMEDWAIT(openavbAdpSMAdvertiseEntitySemaphore, timeoutMSec, err);
+ if (!SEM_IS_ERR_NONE(err) && !SEM_IS_ERR_TIMEOUT(err)) { AVB_LOGF_WARNING("Semaphore error %d", err); }
+
+ if (openavbAdpSMAdvertiseEntityVars.doTerminate) {
+ bRunning = FALSE;
+ } else if (SEM_IS_ERR_TIMEOUT(err) ||
+ openavbAdpSMAdvertiseEntityVars.needsAdvertise) {
+ state = OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_ADVERTISE;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ AVB_LOG_ERROR("State: Unexpected!");
+ bRunning = FALSE; // Unexpected
+ break;
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void* openavbAdpSMAdvertiseEntityThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ openavbAdpSMAdvertiseEntityStateMachine();
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+ return NULL;
+}
+
+void openavbAdpSMAdvertiseEntityStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ SEM_ERR_T(err);
+ SEM_INIT(openavbAdpSMAdvertiseEntitySemaphore, 1, err);
+ SEM_LOG_ERR(err);
+
+ ADP_LOCK();
+ openavbAdpSMAdvertiseEntityVars.needsAdvertise = FALSE;
+ openavbAdpSMAdvertiseEntityVars.doTerminate = FALSE;
+ ADP_UNLOCK();
+
+ // Start the Advertise Entity State Machine
+ bool errResult;
+ THREAD_CREATE(openavbAdpSmAdvertiseEntityThread, openavbAdpSmAdvertiseEntityThread, NULL, openavbAdpSMAdvertiseEntityThreadFn, NULL);
+ THREAD_CHECK_ERROR(openavbAdpSmAdvertiseEntityThread, "Thread / task creation failed", errResult);
+ if (errResult); // Already reported
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseEntityStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ openavbAdpSMAdvertiseEntitySet_doTerminate(TRUE);
+ THREAD_JOIN(openavbAdpSmAdvertiseEntityThread, NULL);
+
+ SEM_ERR_T(err);
+ SEM_DESTROY(openavbAdpSMAdvertiseEntitySemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseEntitySet_needsAdvertise(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ openavbAdpSMAdvertiseEntityVars.needsAdvertise = value;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAdpSMAdvertiseEntitySemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseEntitySet_doTerminate(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ openavbAdpSMAdvertiseEntityVars.doTerminate = value;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAdpSMAdvertiseEntitySemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+
+
+
+
diff --git a/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_entity.h b/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_entity.h
new file mode 100644
index 00000000..97f20e39
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_entity.h
@@ -0,0 +1,63 @@
+/*************************************************************************************************************
+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 : ADP - AVDECC Discovery Protocol : Advertise Entity State Machine Interface
+ * MODULE SUMMARY : Interface for the AVDECC Discovery Protocol : Advertise Entity State Machine
+ * IEEE Std 1722.1-2013 clause 6.2.4.
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ADP_SM_ADVERTISE_ENTITY_H
+#define OPENAVB_ADP_SM_ADVERTISE_ENTITY_H 1
+
+#include "openavb_adp.h"
+
+// State machine vars IEEE Std 1722.1-2013 clause 6.2.4.1
+typedef struct {
+ struct timespec reannounceTimerTimeout;
+ bool needsAdvertise;
+ bool doTerminate;
+} openavb_adp_sm_advertise_entity_vars_t;
+
+// State machine functions IEEE Std 1722.1-2013 clause 6.2.4.2
+void openavbAdpSMAdvertiseEntity_sendAvailable(void);
+
+void openavbAdpSMAdvertiseEntityStart(void);
+void openavbAdpSMAdvertiseEntityStop(void);
+
+// Accessors
+void openavbAdpSMAdvertiseEntitySet_needsAdvertise(bool value);
+void openavbAdpSMAdvertiseEntitySet_doTerminate(bool value);
+
+
+#endif // OPENAVB_ADP_SM_ADVERTISE_ENTITY_H
diff --git a/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_interface.c b/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_interface.c
new file mode 100644
index 00000000..1bc1f101
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_interface.c
@@ -0,0 +1,341 @@
+/*************************************************************************************************************
+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 : ADP - AVDECC Discovery Protocol : Advertise interface State Machine
+ * MODULE SUMMARY : Implements the AVDECC Discovery Protocol : Advertise Interface State Machine
+ * IEEE Std 1722.1-2013 clause 6.2.5.
+ *
+ * Note: 1722.1 allows for multiple Interface state machines,
+ * one per AVB Interface descriptor. This implementation
+ * assumes one AVB Interface descriptor exists in the Entity Model.
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <signal.h>
+
+#define AVB_LOG_COMPONENT "ADP"
+#include "openavb_log.h"
+
+#include "openavb_adp_sm_advertise_interface.h"
+#include "openavb_adp_sm_advertise_entity.h"
+#include "openavb_adp_message.h"
+
+#define OPENAVB_ADP_SM_ADVERTISE_INTERFACE_WAIT_TIME_USEC 10000
+
+typedef enum {
+ OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_INITIALIZE,
+ OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_WAITING,
+ OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_DEPARTING,
+ OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_ADVERTISE,
+ OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_RECEIVED_DISCOVER,
+ OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_UPDATE_GM,
+ OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_LINK_STATE_CHANGE,
+} openavb_adp_sm_advertise_interface_state_t;
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+extern openavb_adp_sm_global_vars_t openavbAdpSMGlobalVars;
+extern openavb_adp_sm_advertise_entity_vars_t openavbAdpSMAdvertiseEntityVars;
+openavb_adp_sm_advertise_interface_vars_t openavbAdpSMAdvertiseInterfaceVars;
+
+extern MUTEX_HANDLE(openavbAdpMutex);
+#define ADP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAdpMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ADP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAdpMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+SEM_T(openavbAdpSMAdvertiseInterfaceSemaphore);
+THREAD_TYPE(openavbAdpSmAdvertiseInterfaceThread);
+THREAD_DEFINITON(openavbAdpSmAdvertiseInterfaceThread);
+
+void openavbAdpSMAdvertiseInterface_txEntityAvailable()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ ADP_LOCK();
+ openavbAdpSMGlobalVars.entityInfo.header.valid_time = gAvdeccCfg.valid_time;
+ ADP_UNLOCK();
+ openavbAdpMessageSend(OPENAVB_ADP_MESSAGE_TYPE_ENTITY_AVAILABLE);
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseInterface_txEntityDeparting()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ ADP_LOCK();
+ openavbAdpSMGlobalVars.entityInfo.header.valid_time = 0;
+ ADP_UNLOCK();
+ openavbAdpMessageSend(OPENAVB_ADP_MESSAGE_TYPE_ENTITY_DEPARTING);
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseInterfaceStateMachine()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ bool bRunning = TRUE;
+
+ openavb_adp_sm_advertise_interface_state_t state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_INITIALIZE;
+
+ while (bRunning) {
+ switch (state) {
+ case OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_INITIALIZE:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_INITIALIZE");
+
+ ADP_LOCK();
+ openavbAdpSMAdvertiseInterfaceVars.lastLinkIsUp = FALSE;
+ openavbAdpSMAdvertiseInterfaceVars.doAdvertise = FALSE; // Per 1722.1 What's next notes
+ memcpy(openavbAdpSMAdvertiseInterfaceVars.advertisedGrandmasterID,
+ openavbAdpSMGlobalVars.entityInfo.pdu.gptp_grandmaster_id,
+ sizeof(openavbAdpSMGlobalVars.entityInfo.pdu.gptp_grandmaster_id));
+ ADP_UNLOCK();
+
+ // This interface will send the first advertisement on startup.
+ // The advertise entity will be responsible for sending subsequent advertisements.
+ // This allows the advertise entity and advertise interface to startup without any inter-dependencies.
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_ADVERTISE;
+ }
+ break;
+ case OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_WAITING:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_WAITING");
+
+ // openavbAdpSMAdvertiseInterfaceVars.rcvdDiscover = FALSE; // Per 1722.1 What's next notes. Note: setting this elsewhere otherwise incorrect behavior.
+ // openavbAdpSMGlobalVars.entityInfo.pdu.available_index++; // Per 1722.1 What's next notes
+
+ // Wait for a change in state
+ while (state == OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_WAITING && bRunning) {
+ SEM_ERR_T(err);
+ SEM_WAIT(openavbAdpSMAdvertiseInterfaceSemaphore, err);
+ if (!SEM_IS_ERR_NONE(err)) { AVB_LOGF_WARNING("Semaphore error %d", err); }
+
+ ADP_LOCK();
+ if (openavbAdpSMAdvertiseInterfaceVars.doTerminate)
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_DEPARTING;
+ else if (openavbAdpSMAdvertiseInterfaceVars.doAdvertise)
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_ADVERTISE;
+ else if (openavbAdpSMAdvertiseInterfaceVars.rcvdDiscover)
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_RECEIVED_DISCOVER;
+ else if (memcmp(openavbAdpSMAdvertiseInterfaceVars.advertisedGrandmasterID,
+ openavbAdpSMGlobalVars.entityInfo.pdu.gptp_grandmaster_id,
+ sizeof(openavbAdpSMGlobalVars.entityInfo.pdu.gptp_grandmaster_id)))
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_UPDATE_GM;
+ else if (openavbAdpSMAdvertiseInterfaceVars.lastLinkIsUp != openavbAdpSMAdvertiseInterfaceVars.linkIsUp)
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_LINK_STATE_CHANGE;
+ ADP_UNLOCK();
+ }
+ }
+ break;
+ case OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_DEPARTING:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_DEPARTING");
+
+ openavbAdpSMAdvertiseInterface_txEntityDeparting();
+ bRunning = FALSE;
+ }
+ break;
+ case OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_ADVERTISE:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_ADVERTISE");
+
+ ADP_LOCK();
+ openavbAdpSMAdvertiseInterfaceVars.doAdvertise = FALSE; // Per 1722.1 What's next notes
+ ADP_UNLOCK();
+ openavbAdpSMAdvertiseInterface_txEntityAvailable();
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_WAITING;
+ }
+ break;
+ case OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_RECEIVED_DISCOVER:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_RECEIVED_DISCOVER");
+
+ ADP_LOCK();
+ openavbAdpSMAdvertiseInterfaceVars.rcvdDiscover = FALSE; // Not per spec but is needed.
+ if (((U64)*openavbAdpSMAdvertiseInterfaceVars.entityID == 0x0000000000000000L) ||
+ ((U64)*openavbAdpSMAdvertiseInterfaceVars.entityID == (U64)*openavbAdpSMGlobalVars.entityInfo.header.entity_id)) {
+ openavbAdpSMAdvertiseEntitySet_needsAdvertise(TRUE);
+ }
+ ADP_UNLOCK();
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_WAITING;
+ }
+ break;
+ case OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_UPDATE_GM:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_UPDATE_GM");
+
+ openavbAdpSMAdvertiseEntitySet_needsAdvertise(TRUE);
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_WAITING;
+ }
+ break;
+ case OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_LINK_STATE_CHANGE:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_LINK_STATE_CHANGE");
+
+ openavbAdpSMAdvertiseInterfaceVars.lastLinkIsUp = openavbAdpSMAdvertiseInterfaceVars.linkIsUp;
+ if (openavbAdpSMAdvertiseInterfaceVars.linkIsUp) {
+ openavbAdpSMAdvertiseEntitySet_needsAdvertise(TRUE);
+ }
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_WAITING;
+ }
+ break;
+ default:
+ AVB_LOG_ERROR("State: Unexpected!");
+ bRunning = FALSE; // Unexpected
+ break;
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void* openavbAdpSMAdvertiseInterfaceThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ openavbAdpSMAdvertiseInterfaceStateMachine();
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+ return NULL;
+}
+
+
+void openavbAdpSMAdvertiseInterfaceStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ SEM_ERR_T(err);
+ SEM_INIT(openavbAdpSMAdvertiseInterfaceSemaphore, 1, err);
+ SEM_LOG_ERR(err);
+
+ ADP_LOCK();
+ memset(&openavbAdpSMAdvertiseInterfaceVars, 0, sizeof(openavbAdpSMAdvertiseInterfaceVars));
+ ADP_UNLOCK();
+
+ // Start the Advertise Entity State Machine
+ bool errResult;
+ THREAD_CREATE(openavbAdpSmAdvertiseInterfaceThread, openavbAdpSmAdvertiseInterfaceThread, NULL, openavbAdpSMAdvertiseInterfaceThreadFn, NULL);
+ THREAD_CHECK_ERROR(openavbAdpSmAdvertiseInterfaceThread, "Thread / task creation failed", errResult);
+ if (errResult); // Already reported
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseInterfaceStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ openavbAdpSMAdvertiseInterfaceSet_doTerminate(TRUE);
+ THREAD_JOIN(openavbAdpSmAdvertiseInterfaceThread, NULL);
+
+ SEM_ERR_T(err);
+ SEM_DESTROY(openavbAdpSMAdvertiseInterfaceSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseInterfaceSet_advertisedGrandmasterID(U8 *pValue)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ if (pValue) {
+ memcpy(openavbAdpSMAdvertiseInterfaceVars.advertisedGrandmasterID, pValue, sizeof(openavbAdpSMAdvertiseInterfaceVars.advertisedGrandmasterID));
+ }
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAdpSMAdvertiseInterfaceSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseInterfaceSet_rcvdDiscover(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ openavbAdpSMAdvertiseInterfaceVars.rcvdDiscover = value;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAdpSMAdvertiseInterfaceSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseInterfaceSet_entityID(U8 *pValue)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ if (pValue) {
+ memcpy(openavbAdpSMAdvertiseInterfaceVars.entityID, pValue, sizeof(openavbAdpSMAdvertiseInterfaceVars.entityID));
+ }
+ // sem post is done when the rcvdDiscover is set.
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseInterfaceSet_doTerminate(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ openavbAdpSMAdvertiseInterfaceVars.doTerminate = value;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAdpSMAdvertiseInterfaceSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseInterfaceSet_doAdvertise(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ openavbAdpSMAdvertiseInterfaceVars.doAdvertise = value;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAdpSMAdvertiseInterfaceSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseInterfaceSet_linkIsUp(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ openavbAdpSMAdvertiseInterfaceVars.linkIsUp = value;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAdpSMAdvertiseInterfaceSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+
diff --git a/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_interface.h b/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_interface.h
new file mode 100644
index 00000000..4c32b5f7
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_interface.h
@@ -0,0 +1,73 @@
+/*************************************************************************************************************
+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 : ADP - AVDECC Discovery Protocol : Advertise interface State Machine Interface
+ * MODULE SUMMARY : Interface for the AVDECC Discovery Protocol : Advertise Interface State Machine
+ * IEEE Std 1722.1-2013 clause 6.2.5.
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ADP_SM_ADVERTISE_INTERFACE_H
+#define OPENAVB_ADP_SM_ADVERTISE_INTERFACE_H 1
+
+#include "openavb_adp.h"
+
+// State machine vars IEEE Std 1722.1-2013 clause 6.2.5.1
+typedef struct {
+ U8 advertisedGrandmasterID[8];
+ bool rcvdDiscover;
+ U8 entityID[8];
+ bool doTerminate;
+ bool doAdvertise;
+ bool linkIsUp;
+ bool lastLinkIsUp;
+} openavb_adp_sm_advertise_interface_vars_t;
+
+// State machine functions IEEE Std 1722.1-2013 clause 6.2.5.2
+void openavbAdpSMAdvertiseInterface_txEntityAvailable(void);
+void openavbAdpSMAdvertiseInterface_txEntityDeparting(void);
+
+void openavbAdpSMAdvertiseInterfaceStart(void);
+void openavbAdpSMAdvertiseInterfaceStop(void);
+
+// Accessors
+void openavbAdpSMAdvertiseInterfaceSet_advertisedGrandmasterID(U8 *pValue);
+void openavbAdpSMAdvertiseInterfaceSet_rcvdDiscover(bool value);
+void openavbAdpSMAdvertiseInterfaceSet_entityID(U8 *pValue);
+void openavbAdpSMAdvertiseInterfaceSet_doTerminate(bool value);
+void openavbAdpSMAdvertiseInterfaceSet_doAdvertise(bool value);
+void openavbAdpSMAdvertiseInterfaceSet_linkIsUp(bool value);
+
+
+
+#endif // OPENAVB_ADP_SM_ADVERTISE_INTERFACE_H
diff --git a/lib/avtp_pipeline/adp/openavb_adp_sm_discovery.c b/lib/avtp_pipeline/adp/openavb_adp_sm_discovery.c
new file mode 100644
index 00000000..b4c1390a
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp_sm_discovery.c
@@ -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.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ADP - AVDECC Discovery Protocol : Discovery State Machine
+ * MODULE SUMMARY : Implements the AVDECC Discovery Protocol : Discovery State Machine
+ * IEEE Std 1722.1-2013 clause 6.2.6.
+ ******************************************************************
+ */
+
+// Not implemented in OPENAVB phase 1 support of 1722.1
+
+#define AVB_LOG_COMPONENT "ADP"
+#include "openavb_log.h"
+
+#include "openavb_adp_sm_discovery.h"
diff --git a/lib/avtp_pipeline/adp/openavb_adp_sm_discovery.h b/lib/avtp_pipeline/adp/openavb_adp_sm_discovery.h
new file mode 100644
index 00000000..7c6cb8be
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp_sm_discovery.h
@@ -0,0 +1,48 @@
+/*************************************************************************************************************
+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 : ADP - AVDECC Discovery Protocol : Discovery State Machine Interface
+ * MODULE SUMMARY : Interface for the Implements the AVDECC Discovery Protocol : Discovery State Machine
+ * IEEE Std 1722.1-2013 clause 6.2.6.
+ ******************************************************************
+ */
+
+// Not implemented in OPENAVB phase 1 support of 1722.1
+
+#ifndef OPENAVB_ADP_SM_DISCOVERY_H
+#define OPENAVB_ADP_SM_DISCOVERY_H 1
+
+#include "openavb_adp.h"
+
+
+#endif // OPENAVB_ADP_SM_DISCOVERY_H
diff --git a/lib/avtp_pipeline/aecp/CMakeLists.txt b/lib/avtp_pipeline/aecp/CMakeLists.txt
new file mode 100644
index 00000000..ae4bb6e9
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/CMakeLists.txt
@@ -0,0 +1,8 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/aecp/openavb_aecp.c
+ ${AVB_SRC_DIR}/aecp/openavb_aecp_message.c
+ ${AVB_SRC_DIR}/aecp/openavb_aecp_sm_entity_model_entity.c
+ ${AVB_SRC_DIR}/aecp/openavb_aecp_cmd_get_counters.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/aecp/openavb_aecp.c b/lib/avtp_pipeline/aecp/openavb_aecp.c
new file mode 100644
index 00000000..c87be0de
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/openavb_aecp.c
@@ -0,0 +1,98 @@
+/*************************************************************************************************************
+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 : AVDECC Enumeration and control protocol (AECP)
+ * MODULE SUMMARY : Implements the AVDECC Enumeration and control protocol (AECP)
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <signal.h>
+
+#define AVB_LOG_COMPONENT "AECP"
+#include "openavb_log.h"
+
+#include "openavb_aem.h"
+#include "openavb_aecp.h"
+#include "openavb_aecp_sm_entity_model_entity.h"
+#include "openavb_aecp_message.h"
+
+openavb_aecp_sm_global_vars_t openavbAecpSMGlobalVars;
+
+MUTEX_HANDLE(openavbAecpMutex);
+#define ADP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAecpMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ADP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAecpMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+openavbRC openavbAecpStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ openavb_avdecc_entity_model_t *pAem = openavbAemGetModel();
+ if (!pAem) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING), AVB_TRACE_AECP);
+ }
+
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "openavbAecpMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(openavbAecpMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'openavbAecpMutex' mutex");
+
+ // Set AECP global vars
+ memcpy(openavbAecpSMGlobalVars.myEntityID, pAem->pDescriptorEntity->entity_id, sizeof(openavbAecpSMGlobalVars.myEntityID));
+
+ openavbRC rc = openavbAecpMessageHandlerStart();
+ if (IS_OPENAVB_FAILURE(rc)) {
+ openavbAecpStop();
+ AVB_RC_TRACE_RET(rc, AVB_TRACE_AECP);
+ }
+
+ openavbAecpSMEntityModelEntityStart();
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AECP);
+}
+
+void openavbAecpStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ openavbAecpSMEntityModelEntityStop();
+ openavbAecpMessageHandlerStop();
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+
diff --git a/lib/avtp_pipeline/aecp/openavb_aecp.h b/lib/avtp_pipeline/aecp/openavb_aecp.h
new file mode 100644
index 00000000..cdd57b70
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/openavb_aecp.h
@@ -0,0 +1,408 @@
+/*************************************************************************************************************
+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 : AVDECC Enumeration and control protocol (AECP)
+ * MODULE SUMMARY : Interface for the AVDECC Enumeration and control protocol (AECP)
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_AECP_H
+#define OPENAVB_AECP_H 1
+
+#include "openavb_avdecc.h"
+#include "openavb_aecp_pub.h"
+
+#define OPENAVB_AECP_AVTP_SUBTYPE (0x7b)
+
+// message_type field IEEE Std 1722.1-2013 clause 9.2.1.1.5
+#define OPENAVB_AECP_MESSAGE_TYPE_AEM_COMMAND (0)
+#define OPENAVB_AECP_MESSAGE_TYPE_AEM_RESPONSE (1)
+#define OPENAVB_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_COMMAND (2)
+#define OPENAVB_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_RESPONSE (3)
+#define OPENAVB_AECP_MESSAGE_TYPE_AVC_COMMAND (4)
+#define OPENAVB_AECP_MESSAGE_TYPE_AVC_RESPONSE (5)
+#define OPENAVB_AECP_MESSAGE_TYPE_VENDOR_UNIQUE_COMMAND (6)
+#define OPENAVB_AECP_MESSAGE_TYPE_VENDOR_UNIQUE_RESPONSE (7)
+#define OPENAVB_AECP_MESSAGE_TYPE_HDCP_APM_COMMAND (8)
+#define OPENAVB_AECP_MESSAGE_TYPE_HDCP_APM_RESPONSE (9)
+#define OPENAVB_AECP_MESSAGE_TYPE_EXTENDED_COMMAND (14)
+#define OPENAVB_AECP_MESSAGE_TYPE_EXTENDED_RESPONSE (15)
+
+// status field IEEE Std 1722.1-2013 clause 9.2.1.1.6
+#define OPENAVB_AECP_STATUS_SUCCESS (0)
+#define OPENAVB_AECP_STATUS_NOT_IMPLEMENTED (1)
+
+typedef struct {
+ U8 cd;
+ U8 subtype;
+ U8 sv;
+ U8 version;
+ U8 message_type; // Redefined from control data
+ U8 status;
+ U16 control_data_length;
+ U8 target_entity_id[8]; // Redefined from stream_id
+} openavb_aecp_control_header_t;
+
+typedef struct {
+ U8 controller_entity_id[8];
+ U16 sequence_id;
+} openavb_aecp_common_data_unit_t;
+
+typedef struct {
+ U32 flags;
+ U8 owner_id[8];
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_command_data_acquire_entity_t;
+
+typedef struct {
+ // No command specific data
+} openavb_aecp_commandresponse_data_lock_entity_t;
+
+typedef struct {
+ // No command specific data
+} openavb_aecp_commandresponse_data_entity_available_t;
+
+typedef struct {
+ // No command specific data
+} openavb_aecp_commandresponse_data_controller_available_t;
+
+typedef struct {
+ U16 configuration_index;
+ U16 reserved;
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_command_data_read_descriptor_t;
+
+typedef struct {
+ U16 configuration_index;
+ U16 reserved;
+ U16 descriptor_length;
+ U8 descriptor_data[508];
+} openavb_aecp_response_data_read_descriptor_t;
+
+// SET_STREAM_FORMAT command and response IEEE Std 1722.1-2013 clause 7.4.9
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U8 stream_format[8]; // Stream format sub details aren't needed for this command
+} openavb_aecp_commandresponse_data_set_stream_format_t;
+
+// GET_STREAM_FORMAT command IEEE Std 1722.1-2013 clause 7.4.10
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_command_data_get_stream_format_t;
+
+// GET_STREAM_FORMAT response IEEE Std 1722.1-2013 clause 7.4.10
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U8 stream_format[8]; // Stream format sub details aren't needed for this command
+} openavb_aecp_response_data_get_stream_format_t;
+
+// SET_STREAM_INFO command and response IEEE Std 1722.1-2013 clause 7.4.15
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U32 flags;
+ U8 stream_format[8];
+ U8 stream_id[8];
+ U32 msrp_accumulated_latency;
+ U8 stream_dest_mac[6];
+ U8 msrp_failure_code;
+ U8 reserved_1;
+ U8 msrp_failure_bridge_id[8];
+ U16 stream_vlan_id;
+ U16 reserved_2;
+} openavb_aecp_commandresponse_data_set_stream_info_t;
+
+// GET_STREAM_INFO command IEEE Std 1722.1-2013 clause 7.4.16
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_command_data_get_stream_info_t;
+
+// GET_STREAM_INFO response IEEE Std 1722.1-2013 clause 7.4.16
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U32 flags;
+ U8 stream_format[8];
+ U8 stream_id[8];
+ U32 msrp_accumulated_latency;
+ U8 stream_dest_mac[6];
+ U8 msrp_failure_code;
+ U8 reserved_1;
+ U8 msrp_failure_bridge_id[8];
+ U16 stream_vlan_id;
+ U16 reserved_2;
+} openavb_aecp_response_data_get_stream_info_t;
+
+// SET_SAMPLING_RATE command and response IEEE Std 1722.1-2013 clause 7.4.21
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U8 sampling_rate[4]; // Sampling rate format sub details aren't needed for this command
+} openavb_aecp_commandresponse_data_set_sampling_rate_t;
+
+// GET_SAMPLING_RATE command IEEE Std 1722.1-2013 clause 7.4.22
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_command_data_get_sampling_rate_t;
+
+// GET_SAMPLING_RATE response IEEE Std 1722.1-2013 clause 7.4.22
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U8 sampling_rate[4]; // Sampling rate format sub details aren't needed for this command
+} openavb_aecp_response_data_get_sampling_rate_t;
+
+// SET_CLOCK_SOURCE command and response IEEE Std 1722.1-2013 clause 7.4.23
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U16 clock_source_index;
+ U16 reserved;
+} openavb_aecp_commandresponse_data_set_clock_source_t;
+
+// GET_CLOCK_SOURCE command IEEE Std 1722.1-2013 clause 7.4.24
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_command_data_get_clock_source_t;
+
+// GET_CLOCK_SOURCE response IEEE Std 1722.1-2013 clause 7.4.24
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U16 clock_source_index;
+ U16 reserved;
+} openavb_aecp_response_data_get_clock_source_t;
+
+// SET_CONTROL command and response IEEE Std 1722.1-2013 clause 7.4.25
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ union {
+ S8 linear_int8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT8];
+ U8 linear_uint8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT8];
+ S16 linear_int16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT16];
+ U16 linear_uint16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT16];
+ S32 linear_int32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT32];
+ U32 linear_uint32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT32];
+ S64 linear_int64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT64];
+ U64 linear_uint64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT64];
+ float linear_float[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_FLOAT];
+ double linear_double[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_DOUBLE];
+ // AVDECC_TODO : These aren't implemented in the CONTROl descriptor yet.
+ //selector_int8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT8];
+ //selector_uint8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT8];
+ //selector_int16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT16];
+ //selector_uint16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT16];
+ //selector_int32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT32];
+ //selector_uint32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT32];
+ //selector_int64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT64];
+ //selector_uint64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT64];
+ //selector_float[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_FLOAT];
+ //selector_double[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_DOUBLE];
+ //selector_string[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_STRING];
+ //array_int8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT8];
+ //array_uint8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT8];
+ //array_int16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT16];
+ //array_uint16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT16];
+ //array_int32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT32];
+ //array_uint32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT32];
+ //array_int64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT64];
+ //array_uint64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT64];
+ //array_float[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_FLOAT];
+ //array_double[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_DOUBLE];
+ //utf8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_UTF8];
+ //bode_plot[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_BODE_PLOT];
+ //smpte_time[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SMPTE_TIME];
+ //sample_rate[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SAMPLE_RATE];
+ //gptp_time[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_GPTP_TIME];
+ //vendor[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_VENDOR];
+ } values;
+
+ U16 valuesCount; // Not part of spec. Used to track elements in arrays.
+} openavb_aecp_commandresponse_data_set_control_t;
+
+// GET_CONTROL command IEEE Std 1722.1-2013 clause 7.4.26
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_command_data_get_control_t;
+
+// GET_CONTROL response IEEE Std 1722.1-2013 clause 7.4.26
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ union {
+ S8 linear_int8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT8];
+ U8 linear_uint8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT8];
+ S16 linear_int16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT16];
+ U16 linear_uint16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT16];
+ S32 linear_int32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT32];
+ U32 linear_uint32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT32];
+ S64 linear_int64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT64];
+ U64 linear_uint64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT64];
+ float linear_float[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_FLOAT];
+ double linear_double[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_DOUBLE];
+ // AVDECC_TODO : These aren't implemented in the CONTROl descriptor yet.
+ //selector_int8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT8];
+ //selector_uint8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT8];
+ //selector_int16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT16];
+ //selector_uint16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT16];
+ //selector_int32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT32];
+ //selector_uint32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT32];
+ //selector_int64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT64];
+ //selector_uint64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT64];
+ //selector_float[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_FLOAT];
+ //selector_double[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_DOUBLE];
+ //selector_string[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_STRING];
+ //array_int8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT8];
+ //array_uint8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT8];
+ //array_int16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT16];
+ //array_uint16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT16];
+ //array_int32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT32];
+ //array_uint32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT32];
+ //array_int64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT64];
+ //array_uint64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT64];
+ //array_float[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_FLOAT];
+ //array_double[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_DOUBLE];
+ //utf8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_UTF8];
+ //bode_plot[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_BODE_PLOT];
+ //smpte_time[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SMPTE_TIME];
+ //sample_rate[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SAMPLE_RATE];
+ //gptp_time[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_GPTP_TIME];
+ //vendor[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_VENDOR];
+ } values;
+
+ U16 valuesCount; // Not part of spec. Used to track elements in arrays.
+} openavb_aecp_response_data_get_control_t;
+
+// START_STREAMING command and response IEEE Std 1722.1-2013 clause 7.4.35
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_commandresponse_data_start_streaming_t;
+
+// STOP_STREAMING command and response IEEE Std 1722.1-2013 clause 7.4.36
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_commandresponse_data_stop_streaming_t;
+
+// GET_COUNTERS command IEEE Std 1722.1-2013 clause 7.4.42
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_command_data_get_counters_t;
+
+// GET_COUNTERS response IEEE Std 1722.1-2013 clause 7.4.42
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U32 counters_valid;
+ U16 counters_block_length;
+ U8 counters_block[128];
+} openavb_aecp_response_data_get_counters_t;
+
+
+typedef struct {
+ U8 u;
+ U16 command_type;
+ union {
+ openavb_aecp_command_data_acquire_entity_t acquireEntityCmd;
+ openavb_aecp_command_data_acquire_entity_t acquireEntityRsp;
+ openavb_aecp_commandresponse_data_lock_entity_t lockEntityCmd;
+ openavb_aecp_commandresponse_data_lock_entity_t lockEntityRsp;
+ openavb_aecp_commandresponse_data_entity_available_t entityAvailableCmd;
+ openavb_aecp_commandresponse_data_entity_available_t entityAvailableRsp;
+ openavb_aecp_commandresponse_data_controller_available_t controllerAvailableCmd;
+ openavb_aecp_commandresponse_data_controller_available_t controllerAvailableRsp;
+ openavb_aecp_command_data_read_descriptor_t readDescriptorCmd;
+ openavb_aecp_response_data_read_descriptor_t readDescriptorRsp;
+ openavb_aecp_commandresponse_data_set_stream_format_t setStreamFormatCmd;
+ openavb_aecp_commandresponse_data_set_stream_format_t setStreamFormatRsp;
+ openavb_aecp_command_data_get_stream_format_t getStreamFormatCmd;
+ openavb_aecp_response_data_get_stream_format_t getStreamFormatRsp;
+ openavb_aecp_commandresponse_data_set_stream_info_t setStreamInfoCmd;
+ openavb_aecp_commandresponse_data_set_stream_info_t setStreamInfoRsp;
+ openavb_aecp_command_data_get_stream_info_t getStreamInfoCmd;
+ openavb_aecp_response_data_get_stream_info_t getStreamInfoRsp;
+ openavb_aecp_commandresponse_data_set_sampling_rate_t setSamplingRateCmd;
+ openavb_aecp_commandresponse_data_set_sampling_rate_t setSamplingRateRsp;
+ openavb_aecp_command_data_get_sampling_rate_t getSamplingRateCmd;
+ openavb_aecp_response_data_get_sampling_rate_t getSamplingRateRsp;
+ openavb_aecp_commandresponse_data_set_clock_source_t setClockSourceCmd;
+ openavb_aecp_commandresponse_data_set_clock_source_t setClockSourceRsp;
+ openavb_aecp_command_data_get_clock_source_t getClockSourceCmd;
+ openavb_aecp_response_data_get_clock_source_t getClockSourceRsp;
+ openavb_aecp_commandresponse_data_set_control_t setControlCmd;
+ openavb_aecp_commandresponse_data_set_control_t setControlRsp;
+ openavb_aecp_command_data_get_control_t getControlCmd;
+ openavb_aecp_response_data_get_control_t getControlRsp;
+ openavb_aecp_commandresponse_data_start_streaming_t startStreamingCmd;
+ openavb_aecp_commandresponse_data_start_streaming_t startStreamingRsp;
+ openavb_aecp_commandresponse_data_stop_streaming_t stopStreamingCmd;
+ openavb_aecp_commandresponse_data_stop_streaming_t stopStreamingRsp;
+ openavb_aecp_command_data_get_counters_t getCountersCmd;
+ openavb_aecp_response_data_get_counters_t getCountersRsp;
+ } command_data;
+} openavb_aecp_entity_model_data_unit_t;
+
+typedef struct {
+ openavb_aecp_common_data_unit_t commonPdu;
+ openavb_aecp_entity_model_data_unit_t entityModelPdu;
+} openavb_aecp_data_unit_t;
+
+// IEEE Std 1722.1-2013 clause 9.2.2.3.1.1.1
+typedef struct {
+ U8 host[ETH_ALEN];
+ openavb_aecp_control_header_t headers;
+ openavb_aecp_common_data_unit_t commonPdu;
+ openavb_aecp_entity_model_data_unit_t entityModelPdu;
+} openavb_aecp_AEMCommandResponse_t;
+
+// IEEE Std 1722.1-2013 clause 9.2.2.3.1.2.3
+typedef struct {
+ U8 myEntityID[8];
+} openavb_aecp_sm_global_vars_t;
+
+openavbRC openavbAecpStart(void);
+void openavbAecpStop(void);
+
+#endif // OPENAVB_AECP_H
diff --git a/lib/avtp_pipeline/aecp/openavb_aecp_cmd_get_counters.c b/lib/avtp_pipeline/aecp/openavb_aecp_cmd_get_counters.c
new file mode 100644
index 00000000..756f7bbc
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/openavb_aecp_cmd_get_counters.c
@@ -0,0 +1,223 @@
+/*************************************************************************************************************
+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 <errno.h>
+
+#define AVB_LOG_COMPONENT "AECP"
+#include "openavb_log.h"
+
+#include "openavb_aem.h"
+#include "openavb_aecp.h"
+#include "openavb_aecp_message.h"
+#include "openavb_aecp_cmd_get_counters.h"
+#include "openavb_avdecc_pipeline_interaction_pub.h"
+
+
+static void GetEntitySpecificCounters(void * pDescriptor, U16 descriptorType, openavb_aecp_response_data_get_counters_t *pRsp)
+{
+ U32 retValue;
+
+ // Code assumes that ENTITY_SPECIFIC flags and offsets are the same regardless of the Descriptor Type.
+ if (openavbAVDECCGetCounterValue(pDescriptor, descriptorType, OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_1, &retValue)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_1;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_1]) = htonl(retValue);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptor, descriptorType, OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_2, &retValue)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_2;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_2]) = htonl(retValue);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptor, descriptorType, OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_3, &retValue)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_3;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_3]) = htonl(retValue);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptor, descriptorType, OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_4, &retValue)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_4;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_4]) = htonl(retValue);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptor, descriptorType, OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_5, &retValue)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_5;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_5]) = htonl(retValue);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptor, descriptorType, OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_6, &retValue)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_6;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_6]) = htonl(retValue);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptor, descriptorType, OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_7, &retValue)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_7;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_7]) = htonl(retValue);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptor, descriptorType, OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_8, &retValue)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_8;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_8]) = htonl(retValue);
+ }
+}
+
+U8 openavbAecpCommandGetCountersHandler(
+ openavb_aecp_command_data_get_counters_t *pCmd,
+ openavb_aecp_response_data_get_counters_t *pRsp )
+{
+ U8 result = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ U32 value = 0;
+
+ if (!pCmd || !pRsp) {
+ return OPENAVB_AEM_COMMAND_STATUS_NO_RESOURCES;
+ }
+
+ // Default to no counters.
+ pRsp->counters_valid = 0;
+ pRsp->counters_block_length = 128;
+ memset(pRsp->counters_block, 0, sizeof(pRsp->counters_block));
+
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_ENTITY) {
+ openavb_aem_descriptor_entity_t *pDescriptorEntity = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorEntity) {
+ // Get the supported counter values.
+ GetEntitySpecificCounters(pDescriptorEntity, OPENAVB_AEM_DESCRIPTOR_ENTITY, pRsp);
+
+ result = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ else if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE) {
+ openavb_aem_descriptor_avb_interface_t *pDescriptorAvbInterface = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorAvbInterface) {
+ // Get the supported counter values.
+ if (openavbAVDECCGetCounterValue(pDescriptorAvbInterface, OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE, OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_LINK_UP, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_LINK_UP;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_LINK_UP]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorAvbInterface, OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE, OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_LINK_DOWN, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_LINK_DOWN;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_LINK_DOWN]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorAvbInterface, OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE, OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_FRAMES_TX, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_FRAMES_TX;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_FRAMES_TX]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorAvbInterface, OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE, OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_FRAMES_RX, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_FRAMES_RX;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_FRAMES_RX]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorAvbInterface, OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE, OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_RX_CRC_ERROR, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_RX_CRC_ERROR;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_RX_CRC_ERROR]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorAvbInterface, OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE, OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_GPTP_GM_CHANGED, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_GPTP_GM_CHANGED;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_GPTP_GM_CHANGED]) = htonl(value);
+ }
+ GetEntitySpecificCounters(pDescriptorAvbInterface, OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE, pRsp);
+
+ result = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ else if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN) {
+ openavb_aem_descriptor_clock_domain_t *pDescriptorClockDomain = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorClockDomain) {
+ // Get the supported counter values.
+ if (openavbAVDECCGetCounterValue(pDescriptorClockDomain, OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN, OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_LOCKED, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_LOCKED;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_LOCKED]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorClockDomain, OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN, OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_UNLOCKED, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_UNLOCKED;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_UNLOCKED]) = htonl(value);
+ }
+ GetEntitySpecificCounters(pDescriptorClockDomain, OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN, pRsp);
+
+ result = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ else if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamInput) {
+ // Get the supported counter values.
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_MEDIA_LOCKED, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_MEDIA_LOCKED;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_MEDIA_LOCKED]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_MEDIA_UNLOCKED, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_MEDIA_UNLOCKED;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_MEDIA_UNLOCKED]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_STREAM_RESET, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_STREAM_RESET;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_STREAM_RESET]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_SEQ_NUM_MISMATCH, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_SEQ_NUM_MISMATCH;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_SEQ_NUM_MISMATCH]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_MEDIA_RESET, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_MEDIA_RESET;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_MEDIA_RESET]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_TIMESTAMP_UNCERTAIN, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_TIMESTAMP_UNCERTAIN;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_TIMESTAMP_UNCERTAIN]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_TIMESTAMP_VALID, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_TIMESTAMP_VALID;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_TIMESTAMP_VALID]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_TIMESTAMP_NOT_VALID, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_TIMESTAMP_NOT_VALID;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_TIMESTAMP_NOT_VALID]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_UNSUPPORTED_FORMAT, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_UNSUPPORTED_FORMAT;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_UNSUPPORTED_FORMAT]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_LATE_TIMESTAMP, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_LATE_TIMESTAMP;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_LATE_TIMESTAMP]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_EARLY_TIMESTAMP, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_EARLY_TIMESTAMP;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_EARLY_TIMESTAMP]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_FRAMES_RX, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_FRAMES_RX;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_FRAMES_RX]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_FRAMES_TX, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_FRAMES_TX;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_FRAMES_TX]) = htonl(value);
+ }
+ GetEntitySpecificCounters(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, pRsp);
+
+ result = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+
+ return result;
+}
diff --git a/lib/avtp_pipeline/aecp/openavb_aecp_cmd_get_counters.h b/lib/avtp_pipeline/aecp/openavb_aecp_cmd_get_counters.h
new file mode 100644
index 00000000..777940a6
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/openavb_aecp_cmd_get_counters.h
@@ -0,0 +1,103 @@
+/*************************************************************************************************************
+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_AECP_CMD_GET_COUNTERS_H
+#define OPENAVB_AECP_CMD_GET_COUNTERS_H 1
+
+#include "openavb_aecp.h"
+
+// GET_COUNTERS Command ENTITY Counter offsets IEEE Std 1722.1-2013 clause 7.4.42
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_8 (96)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_7 (100)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_6 (104)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_5 (108)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_4 (112)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_3 (116)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_2 (120)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_1 (124)
+
+// GET_COUNTERS Command AVB_INTERFACE Counter offsets IEEE Std 1722.1-2013 clause 7.4.42
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_LINK_UP (0)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_LINK_DOWN (4)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_FRAMES_TX (8)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_FRAMES_RX (12)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_RX_CRC_ERROR (16)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_GPTP_GM_CHANGED (20)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_ENTITY_SPECIFIC_8 (96)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_ENTITY_SPECIFIC_7 (100)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_ENTITY_SPECIFIC_6 (104)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_ENTITY_SPECIFIC_5 (108)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_ENTITY_SPECIFIC_4 (112)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_ENTITY_SPECIFIC_3 (116)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_ENTITY_SPECIFIC_2 (120)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_ENTITY_SPECIFIC_1 (124)
+
+// GET_COUNTERS Command CLOCK_DOMAIN Counter offsets IEEE Std 1722.1-2013 clause 7.4.42
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_LOCKED (0)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_UNLOCKED (4)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_ENTITY_SPECIFIC_8 (96)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_ENTITY_SPECIFIC_7 (100)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_ENTITY_SPECIFIC_6 (104)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_ENTITY_SPECIFIC_5 (108)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_ENTITY_SPECIFIC_4 (112)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_ENTITY_SPECIFIC_3 (116)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_ENTITY_SPECIFIC_2 (120)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_ENTITY_SPECIFIC_1 (124)
+
+// GET_COUNTERS Command STREAM_INPUT Counter offsets IEEE Std 1722.1-2013 clause 7.4.42
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_MEDIA_LOCKED (0)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_MEDIA_UNLOCKED (4)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_STREAM_RESET (8)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_SEQ_NUM_MISMATCH (12)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_MEDIA_RESET (16)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_TIMESTAMP_UNCERTAIN (20)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_TIMESTAMP_VALID (24)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_TIMESTAMP_NOT_VALID (28)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_UNSUPPORTED_FORMAT (32)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_LATE_TIMESTAMP (36)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_EARLY_TIMESTAMP (40)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_FRAMES_RX (44)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_FRAMES_TX (48)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_ENTITY_SPECIFIC_8 (96)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_ENTITY_SPECIFIC_7 (100)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_ENTITY_SPECIFIC_6 (104)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_ENTITY_SPECIFIC_5 (108)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_ENTITY_SPECIFIC_4 (112)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_ENTITY_SPECIFIC_3 (116)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_ENTITY_SPECIFIC_2 (120)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_ENTITY_SPECIFIC_1 (124)
+
+
+U8 openavbAecpCommandGetCountersHandler(
+ openavb_aecp_command_data_get_counters_t *pCmd,
+ openavb_aecp_response_data_get_counters_t *pRsp );
+
+#endif // OPENAVB_AECP_CMD_GET_COUNTERS_H
diff --git a/lib/avtp_pipeline/aecp/openavb_aecp_message.c b/lib/avtp_pipeline/aecp/openavb_aecp_message.c
new file mode 100644
index 00000000..b2e55bee
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/openavb_aecp_message.c
@@ -0,0 +1,1049 @@
+/*************************************************************************************************************
+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 : AVDECC Enumeration and control protocol (AECP) Message Handler
+ * MODULE SUMMARY : Implements the AVDECC Enumeration and control protocol (AECP) message handler
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#define AVB_LOG_COMPONENT "AECP"
+#include "openavb_log.h"
+
+#include "openavb_debug.h"
+#include "openavb_rawsock.h"
+#include "openavb_avtp.h"
+#include "openavb_srp.h"
+#include "openavb_aecp.h"
+#include "openavb_aecp_sm_entity_model_entity.h"
+
+#define INVALID_SOCKET (-1)
+
+// message length
+#define AVTP_HDR_LEN 12
+#define AECP_DATA_LEN 1480 // AVDECC_TODO - Need to figure out a valid length
+#define AECP_FRAME_LEN (ETH_HDR_LEN_VLAN + AVTP_HDR_LEN + AECP_DATA_LEN)
+
+// number of buffers (arbitrary, and rounded up by rawsock)
+#define AECP_NUM_BUFFERS 3
+
+// do cast from ether_addr to U8*
+#define ADDR_PTR(A) (U8*)(&((A)->ether_addr_octet))
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+
+static void *rxSock = NULL;
+static void *txSock = NULL;
+static struct ether_addr intfAddr;
+
+extern openavb_aecp_sm_global_vars_t openavbAecpSMGlobalVars;
+
+THREAD_TYPE(openavbAecpMessageRxThread);
+THREAD_DEFINITON(openavbAecpMessageRxThread);
+
+static bool bRunning = FALSE;
+
+void openavbAecpCloseSocket()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ if (rxSock) {
+ openavbRawsockClose(rxSock);
+ rxSock = NULL;
+ }
+ if (txSock) {
+ openavbRawsockClose(txSock);
+ txSock = NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+bool openavbAecpOpenSocket(const char* ifname, U16 vlanID, U8 vlanPCP)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ hdr_info_t hdr;
+
+#ifndef UBUNTU
+ // This is the normal case for most of our supported platforms
+ rxSock = openavbRawsockOpen(ifname, TRUE, FALSE, ETHERTYPE_8021Q, AECP_FRAME_LEN, AECP_NUM_BUFFERS);
+#else
+ rxSock = openavbRawsockOpen(ifname, TRUE, FALSE, ETHERTYPE_AVTP, AECP_FRAME_LEN, AECP_NUM_BUFFERS);
+#endif
+ txSock = openavbRawsockOpen(ifname, FALSE, TRUE, ETHERTYPE_AVTP, AECP_FRAME_LEN, AECP_NUM_BUFFERS);
+
+ if (txSock && rxSock
+ && openavbRawsockGetAddr(txSock, ADDR_PTR(&intfAddr))
+ && openavbRawsockRxMulticast(rxSock, TRUE, ADDR_PTR(&intfAddr))) // Only accept packets sent directly to this interface
+ {
+ if (!openavbRawsockRxAVTPSubtype(rxSock, OPENAVB_AECP_AVTP_SUBTYPE | 0x80)) {
+ AVB_LOG_DEBUG("RX AVTP Subtype not supported");
+ }
+
+ memset(&hdr, 0, sizeof(hdr_info_t));
+ hdr.shost = ADDR_PTR(&intfAddr);
+ // hdr.dhost; // Set at tx time.
+ hdr.ethertype = ETHERTYPE_AVTP;
+ if (vlanID != 0 || vlanPCP != 0) {
+ hdr.vlan = TRUE;
+ hdr.vlan_pcp = vlanPCP;
+ hdr.vlan_vid = vlanID;
+ AVB_LOGF_DEBUG("VLAN pcp=%d vid=%d", hdr.vlan_pcp, hdr.vlan_vid);
+ }
+ if (!openavbRawsockTxSetHdr(txSock, &hdr)) {
+ AVB_LOG_ERROR("TX socket Header Failure");
+ openavbAecpCloseSocket();
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return false;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return true;
+ }
+
+ AVB_LOG_ERROR("Invalid socket");
+ openavbAecpCloseSocket();
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return false;
+}
+
+static void openavbAecpMessageRxFrameParse(U8* payload, int payload_len, hdr_info_t *hdr)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+#if 0
+ AVB_LOGF_DEBUG("openavbAecpMessageRxFrameParse packet data (length %d):", payload_len);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_DEBUG, payload, payload_len, 16);
+#endif
+
+ // Save the source address
+ openavb_aecp_AEMCommandResponse_t * openavbAecpCommandResponse = calloc(1, sizeof(openavb_aecp_AEMCommandResponse_t));
+ if (!openavbAecpCommandResponse) { return; }
+ memcpy(openavbAecpCommandResponse->host, hdr->shost, ETH_ALEN);
+
+ U8 *pSrc = payload;
+ {
+ // AVTP Control Header
+ openavb_aecp_control_header_t *pDst = &openavbAecpCommandResponse->headers;
+ BIT_B2DNTOHB(pDst->cd, pSrc, 0x80, 7, 0);
+ BIT_B2DNTOHB(pDst->subtype, pSrc, 0x7f, 0, 1);
+ BIT_B2DNTOHB(pDst->sv, pSrc, 0x80, 7, 0);
+ BIT_B2DNTOHB(pDst->version, pSrc, 0x70, 4, 0);
+ BIT_B2DNTOHB(pDst->message_type, pSrc, 0x0f, 0, 1);
+ BIT_B2DNTOHB(pDst->status, pSrc, 0xf800, 11, 0);
+ BIT_B2DNTOHS(pDst->control_data_length, pSrc, 0x07ff, 0, 2);
+ OCT_B2DMEMCP(pDst->target_entity_id, pSrc);
+ }
+
+ if (openavbAecpCommandResponse->headers.subtype == OPENAVB_AECP_AVTP_SUBTYPE) {
+ // AECP Common PDU Fields
+ openavb_aecp_common_data_unit_t *pDst = &openavbAecpCommandResponse->commonPdu;
+ OCT_B2DMEMCP(pDst->controller_entity_id, pSrc);
+ OCT_B2DNTOHS(pDst->sequence_id, pSrc);
+ }
+ else {
+ free(openavbAecpCommandResponse);
+ return;
+ }
+
+ if (openavbAecpCommandResponse->headers.message_type == OPENAVB_AECP_MESSAGE_TYPE_AEM_COMMAND) {
+ // Entity Model PDU Fields
+ openavb_aecp_entity_model_data_unit_t *pDst = &openavbAecpCommandResponse->entityModelPdu;
+ BIT_B2DNTOHS(pDst->u, pSrc, 0x8000, 15, 0);
+ BIT_B2DNTOHS(pDst->command_type, pSrc, 0x7fff, 0, 2);
+
+ switch (openavbAecpCommandResponse->entityModelPdu.command_type) {
+ case OPENAVB_AEM_COMMAND_CODE_ACQUIRE_ENTITY:
+ {
+ openavb_aecp_command_data_acquire_entity_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.acquireEntityCmd;
+ OCT_B2DNTOHL(pDst->flags, pSrc);
+ OCT_B2DMEMCP(pDst->owner_id, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_LOCK_ENTITY:
+ // No command specific data
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ENTITY_AVAILABLE:
+ // No command specific data
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_CONTROLLER_AVAILABLE:
+ // No command specific data
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_READ_DESCRIPTOR:
+ {
+ openavb_aecp_command_data_read_descriptor_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.readDescriptorCmd;
+ OCT_B2DNTOHS(pDst->configuration_index, pSrc);
+ OCT_B2DNTOHS(pDst->reserved, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_WRITE_DESCRIPTOR:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_CONFIGURATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_CONFIGURATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_STREAM_FORMAT:
+ {
+ openavb_aecp_commandresponse_data_set_stream_format_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.setStreamFormatCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->stream_format, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_STREAM_FORMAT:
+ {
+ openavb_aecp_command_data_get_stream_format_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.getStreamFormatCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_VIDEO_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_VIDEO_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_SENSOR_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SENSOR_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_STREAM_INFO:
+ {
+ openavb_aecp_commandresponse_data_set_stream_info_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.setStreamInfoCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DNTOHL(pDst->flags, pSrc);
+ OCT_B2DMEMCP(pDst->stream_format, pSrc);
+ OCT_B2DMEMCP(pDst->stream_id, pSrc);
+ OCT_B2DNTOHL(pDst->msrp_accumulated_latency, pSrc);
+ OCT_B2DMEMCP(pDst->stream_dest_mac, pSrc);
+ OCT_B2DNTOHB(pDst->msrp_failure_code, pSrc);
+ OCT_B2DNTOHB(pDst->reserved_1, pSrc);
+ OCT_B2DMEMCP(pDst->msrp_failure_bridge_id, pSrc);
+ OCT_B2DNTOHS(pDst->stream_vlan_id, pSrc);
+ OCT_B2DNTOHS(pDst->reserved_2, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_STREAM_INFO:
+ {
+ openavb_aecp_command_data_get_stream_info_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.getStreamInfoCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_NAME:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_NAME:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_ASSOCIATION_ID:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_ASSOCIATION_ID:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_SAMPLING_RATE:
+ {
+ openavb_aecp_commandresponse_data_set_sampling_rate_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.setSamplingRateCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->sampling_rate, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SAMPLING_RATE:
+ {
+ openavb_aecp_command_data_get_sampling_rate_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.getSamplingRateCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_CLOCK_SOURCE:
+ {
+ openavb_aecp_commandresponse_data_set_clock_source_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.setClockSourceCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DNTOHS(pDst->clock_source_index, pSrc);
+ OCT_B2DNTOHS(pDst->reserved, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_CLOCK_SOURCE:
+ {
+ openavb_aecp_command_data_get_clock_source_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.getClockSourceCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_CONTROL:
+ {
+ U8 *pSrcEnd = pSrc + openavbAecpCommandResponse->headers.control_data_length;
+ openavb_aecp_commandresponse_data_set_control_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.setControlCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+
+ // Need to get the descriptor to proper parse the values.
+ if (pDst->descriptor_type == OPENAVB_AEM_DESCRIPTOR_CONTROL) {
+ openavb_aem_descriptor_control_t *pDescriptorControl = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pDst->descriptor_type, pDst->descriptor_index);
+ if (pDescriptorControl) {
+ bool bDone = FALSE;
+ pDst->valuesCount = 0;
+ while ((pSrc < pSrcEnd) || bDone) {
+ switch (pDescriptorControl->control_value_type) {
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT8:
+ OCT_B2DNTOHB(pDst->values.linear_int8[pDst->valuesCount++], pSrc);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT16:
+ OCT_B2DNTOHS(pDst->values.linear_int16[pDst->valuesCount++], pSrc);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT32:
+ OCT_B2DNTOHL(pDst->values.linear_int32[pDst->valuesCount++], pSrc);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT64:
+ OCT_B2DMEMCP(&pDst->values.linear_int64[pDst->valuesCount++], pSrc);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_FLOAT:
+ OCT_B2DMEMCP(&pDst->values.linear_float[pDst->valuesCount++], pSrc);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_DOUBLE:
+ OCT_B2DMEMCP(&pDst->values.linear_double[pDst->valuesCount++], pSrc);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_STRING:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_UTF8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_BODE_PLOT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SMPTE_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SAMPLE_RATE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_GPTP_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_VENDOR:
+ bDone = TRUE; // Not yet supported
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_CONTROL:
+ {
+ openavb_aecp_command_data_get_control_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.getControlCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_INCREMENT_CONTROL:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DECREMENT_CONTROL:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_SIGNAL_SELECTOR:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SIGNAL_SELECTOR:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_MIXER:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_MIXER:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_MATRIX:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_MATRIX:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_START_STREAMING:
+ {
+ openavb_aecp_commandresponse_data_start_streaming_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.startStreamingCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_STOP_STREAMING:
+ {
+ openavb_aecp_commandresponse_data_stop_streaming_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.stopStreamingCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REGISTER_UNSOLICITED_NOTIFICATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DEREGISTER_UNSOLICITED_NOTIFICATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_IDENTIFY_NOTIFICATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_AVB_INFO:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_AS_PATH:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_COUNTERS:
+ {
+ openavb_aecp_command_data_get_counters_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.getCountersCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REBOOT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_AUDIO_MAP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ADD_AUDIO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REMOVE_AUDIO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_VIDEO_MAP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ADD_VIDEO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REMOVE_VIDEO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SENSOR_MAP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ADD_SENSOR_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REMOVE_SENSOR_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_START_OPERATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ABORT_OPERATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_OPERATION_STATUS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_KEY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_KEY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEY_LIST:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_KEY_TO_CHAIN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_KEY_FROM_CHAIN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEYCHAIN_LIST:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_IDENTITY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_TOKEN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_TOKEN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTHENTICATE:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DEAUTHENTICATE:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ENABLE_TRANSPORT_SECURITY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DISABLE_TRANSPORT_SECURITY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ENABLE_STREAM_ENCRYPTION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DISABLE_STREAM_ENCRYPTION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_MEMORY_OBJECT_LENGTH:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_MEMORY_OBJECT_LENGTH:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_STREAM_BACKUP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_STREAM_BACKUP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_EXPANSION:
+ break;
+ default:
+ break;
+ }
+
+ if (pSrc - payload <= payload_len) {
+ // Notify the state machine of the command request
+ // The buffer will be deleted once the request is handled.
+ openavbAecpSMEntityModelEntitySet_rcvdCommand(openavbAecpCommandResponse);
+ }
+ else {
+ AVB_LOGF_ERROR("Expected packet of size %d, but received one of size %d. Discarding.", pSrc - payload, payload_len);
+ free(openavbAecpCommandResponse);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+static void openavbAecpMessageRxFrameReceive(U32 timeoutUsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ hdr_info_t hdrInfo;
+ unsigned int offset, len;
+ U8 *pBuf, *pFrame;
+
+ memset(&hdrInfo, 0, sizeof(hdr_info_t));
+
+ pBuf = (U8 *)openavbRawsockGetRxFrame(rxSock, timeoutUsec, &offset, &len);
+ if (pBuf) {
+ pFrame = pBuf + offset;
+
+ offset = openavbRawsockRxParseHdr(rxSock, pBuf, &hdrInfo);
+ {
+#ifndef UBUNTU
+ if (hdrInfo.ethertype == ETHERTYPE_8021Q) {
+ // Oh! Need to look past the VLAN tag
+ U16 vlan_bits = ntohs(*(U16 *)(pFrame + offset));
+ hdrInfo.vlan = TRUE;
+ hdrInfo.vlan_vid = vlan_bits & 0x0FFF;
+ hdrInfo.vlan_pcp = (vlan_bits >> 13) & 0x0007;
+ offset += 2;
+ hdrInfo.ethertype = ntohs(*(U16 *)(pFrame + offset));
+ offset += 2;
+ }
+#endif
+
+ // Make sure that this is an AVTP packet
+ // (Should always be AVTP if it's to our AVTP-specific multicast address)
+ if (hdrInfo.ethertype == ETHERTYPE_AVTP) {
+ // parse the PDU only for AECP messages
+ if (*(pFrame + offset) == (0x80 | OPENAVB_AECP_AVTP_SUBTYPE)) {
+ openavbAecpMessageRxFrameParse(pFrame + offset, len - offset, &hdrInfo);
+ }
+ }
+ else {
+ AVB_LOG_WARNING("Received non-AVTP frame!");
+ AVB_LOGF_DEBUG("Unexpected packet data (length %d):", len);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_DEBUG, pFrame, len, 16);
+ }
+ }
+
+ // Release the frame
+ openavbRawsockRelRxFrame(rxSock, pBuf);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+
+void openavbAecpMessageTxFrame(openavb_aecp_AEMCommandResponse_t *AEMCommandResponse)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ U8 *pBuf;
+ U8 *pcontrol_data_length;
+ U8 *pcontrol_data_length_start_marker;
+ U32 size;
+ unsigned int hdrlen = 0;
+
+ pBuf = openavbRawsockGetTxFrame(txSock, TRUE, &size);
+
+ if (!pBuf) {
+ AVB_LOG_ERROR("No TX buffer");
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return;
+ }
+
+ if (size < AECP_FRAME_LEN) {
+ AVB_LOG_ERROR("TX buffer too small");
+ openavbRawsockRelTxFrame(txSock, pBuf);
+ pBuf = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return;
+ }
+
+ memset(pBuf, 0, AECP_FRAME_LEN);
+ openavbRawsockTxFillHdr(txSock, pBuf, &hdrlen);
+
+ // Set the destination address
+ memcpy(pBuf, AEMCommandResponse->host, ETH_ALEN);
+
+ U8 *pDst = pBuf + hdrlen;
+ {
+ // AVTP Control Header
+ openavb_aecp_control_header_t *pSrc = &AEMCommandResponse->headers;
+ BIT_D2BHTONB(pDst, pSrc->cd, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtype, 0, 1);
+ BIT_D2BHTONB(pDst, pSrc->sv, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->version, 4, 0);
+ BIT_D2BHTONB(pDst, pSrc->message_type, 0, 1);
+ BIT_D2BHTONS(pDst, pSrc->status, 11, 0);
+ pcontrol_data_length = pDst; // Set later
+ BIT_D2BHTONS(pDst, pSrc->control_data_length, 0, 2);
+ OCT_D2BMEMCP(pDst, pSrc->target_entity_id);
+ pcontrol_data_length_start_marker = pDst;
+ }
+
+ {
+ // AECP Common PDU
+ openavb_aecp_common_data_unit_t *pSrc = &AEMCommandResponse->commonPdu;
+ OCT_D2BMEMCP(pDst, pSrc->controller_entity_id);
+ OCT_D2BHTONS(pDst, pSrc->sequence_id);
+ }
+
+ if (AEMCommandResponse->headers.message_type == OPENAVB_AECP_MESSAGE_TYPE_AEM_RESPONSE) {
+ // Entity Model PDU Fields
+ openavb_aecp_entity_model_data_unit_t *pSrc = &AEMCommandResponse->entityModelPdu;
+ BIT_D2BHTONS(pDst, pSrc->u, 15, 0);
+ BIT_D2BHTONS(pDst, pSrc->command_type, 0, 2);
+
+ // Command specific data
+ switch (AEMCommandResponse->entityModelPdu.command_type) {
+ case OPENAVB_AEM_COMMAND_CODE_ACQUIRE_ENTITY:
+ {
+ openavb_aecp_command_data_acquire_entity_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.acquireEntityRsp;
+ OCT_D2BHTONL(pDst, pSrc->flags);
+ OCT_D2BMEMCP(pDst, pSrc->owner_id);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_LOCK_ENTITY:
+ // No command specific data
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ENTITY_AVAILABLE:
+ // No command specific data
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_CONTROLLER_AVAILABLE:
+ // No command specific data
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_READ_DESCRIPTOR:
+ {
+ openavb_aecp_response_data_read_descriptor_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.readDescriptorRsp;
+ OCT_D2BHTONS(pDst, pSrc->configuration_index);
+ OCT_D2BHTONS(pDst, pSrc->reserved);
+ OCT_D2BBUFCP(pDst, pSrc->descriptor_data, pSrc->descriptor_length);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_WRITE_DESCRIPTOR:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_CONFIGURATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_CONFIGURATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_STREAM_FORMAT:
+ {
+ openavb_aecp_commandresponse_data_set_stream_format_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.setStreamFormatRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->stream_format);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_STREAM_FORMAT:
+ {
+ openavb_aecp_response_data_get_stream_format_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.getStreamFormatRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->stream_format);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_VIDEO_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_VIDEO_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_SENSOR_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SENSOR_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_STREAM_INFO:
+ {
+ openavb_aecp_commandresponse_data_set_stream_info_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.setStreamInfoRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BHTONL(pDst, pSrc->flags);
+ OCT_D2BMEMCP(pDst, pSrc->stream_format);
+ OCT_D2BMEMCP(pDst, pSrc->stream_id);
+ OCT_D2BHTONL(pDst, pSrc->msrp_accumulated_latency);
+ OCT_D2BMEMCP(pDst, pSrc->stream_dest_mac);
+ OCT_D2BHTONB(pDst, pSrc->msrp_failure_code);
+ OCT_D2BHTONB(pDst, pSrc->reserved_1);
+ OCT_D2BMEMCP(pDst, pSrc->msrp_failure_bridge_id);
+ OCT_D2BHTONS(pDst, pSrc->stream_vlan_id);
+ OCT_D2BHTONS(pDst, pSrc->reserved_2);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_STREAM_INFO:
+ {
+ openavb_aecp_response_data_get_stream_info_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.getStreamInfoRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BHTONL(pDst, pSrc->flags);
+ OCT_D2BMEMCP(pDst, pSrc->stream_format);
+ OCT_D2BMEMCP(pDst, pSrc->stream_id);
+ OCT_D2BHTONL(pDst, pSrc->msrp_accumulated_latency);
+ OCT_D2BMEMCP(pDst, pSrc->stream_dest_mac);
+ OCT_D2BHTONB(pDst, pSrc->msrp_failure_code);
+ OCT_D2BHTONB(pDst, pSrc->reserved_1);
+ OCT_D2BMEMCP(pDst, pSrc->msrp_failure_bridge_id);
+ OCT_D2BHTONS(pDst, pSrc->stream_vlan_id);
+ OCT_D2BHTONS(pDst, pSrc->reserved_2);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_NAME:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_NAME:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_ASSOCIATION_ID:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_ASSOCIATION_ID:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_SAMPLING_RATE:
+ {
+ openavb_aecp_commandresponse_data_set_sampling_rate_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.setSamplingRateRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->sampling_rate);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SAMPLING_RATE:
+ {
+ openavb_aecp_response_data_get_sampling_rate_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.getSamplingRateRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->sampling_rate);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_CLOCK_SOURCE:
+ {
+ openavb_aecp_commandresponse_data_set_clock_source_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.setClockSourceRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BHTONS(pDst, pSrc->clock_source_index);
+ OCT_D2BHTONS(pDst, pSrc->reserved);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_CLOCK_SOURCE:
+ {
+ openavb_aecp_response_data_get_clock_source_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.getClockSourceRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BHTONS(pDst, pSrc->clock_source_index);
+ OCT_D2BHTONS(pDst, pSrc->reserved);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_CONTROL:
+ {
+ openavb_aecp_commandresponse_data_set_control_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.setControlRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+
+ openavb_aem_descriptor_control_t *pDescriptorControl = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pSrc->descriptor_type, pSrc->descriptor_index);
+ if (pDescriptorControl) {
+ pSrc->valuesCount = 0;
+ int i1;
+ for (i1 = 0; i1 < pSrc->valuesCount; i1++) {
+ switch (pDescriptorControl->control_value_type) {
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT8:
+ OCT_D2BHTONB(pDst, pSrc->values.linear_int8[i1]);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT16:
+ OCT_D2BHTONS(pDst, pSrc->values.linear_int16[i1]);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT32:
+ OCT_D2BHTONL(pDst, pSrc->values.linear_int32[i1]);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT64:
+ OCT_D2BMEMCP(pDst, &pSrc->values.linear_int64[i1]);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_FLOAT:
+ OCT_D2BMEMCP(pDst, &pSrc->values.linear_float[i1]);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_DOUBLE:
+ OCT_D2BMEMCP(pDst, &pSrc->values.linear_double[i1]);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_STRING:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_UTF8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_BODE_PLOT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SMPTE_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SAMPLE_RATE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_GPTP_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_VENDOR:
+ break;
+ }
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_CONTROL:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_INCREMENT_CONTROL:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DECREMENT_CONTROL:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_SIGNAL_SELECTOR:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SIGNAL_SELECTOR:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_MIXER:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_MIXER:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_MATRIX:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_MATRIX:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_START_STREAMING:
+ {
+ openavb_aecp_commandresponse_data_start_streaming_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.startStreamingRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_STOP_STREAMING:
+ {
+ openavb_aecp_commandresponse_data_stop_streaming_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.stopStreamingRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REGISTER_UNSOLICITED_NOTIFICATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DEREGISTER_UNSOLICITED_NOTIFICATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_IDENTIFY_NOTIFICATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_AVB_INFO:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_AS_PATH:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_COUNTERS:
+ {
+ openavb_aecp_response_data_get_counters_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.getCountersRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BHTONL(pDst, pSrc->counters_valid);
+ OCT_D2BBUFCP(pDst, pSrc->counters_block, pSrc->counters_block_length);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REBOOT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_AUDIO_MAP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ADD_AUDIO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REMOVE_AUDIO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_VIDEO_MAP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ADD_VIDEO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REMOVE_VIDEO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SENSOR_MAP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ADD_SENSOR_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REMOVE_SENSOR_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_START_OPERATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ABORT_OPERATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_OPERATION_STATUS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_KEY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_KEY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEY_LIST:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_KEY_TO_CHAIN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_KEY_FROM_CHAIN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEYCHAIN_LIST:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_IDENTITY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_TOKEN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_TOKEN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTHENTICATE:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DEAUTHENTICATE:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ENABLE_TRANSPORT_SECURITY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DISABLE_TRANSPORT_SECURITY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ENABLE_STREAM_ENCRYPTION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DISABLE_STREAM_ENCRYPTION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_MEMORY_OBJECT_LENGTH:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_MEMORY_OBJECT_LENGTH:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_STREAM_BACKUP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_STREAM_BACKUP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_EXPANSION:
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Set length into buffer
+ BIT_D2BHTONS(pcontrol_data_length, (pDst - pcontrol_data_length_start_marker), 0, 2);
+
+ // Make sure the packet will be at least 64 bytes long.
+ if (pDst - pBuf < 64) { pDst = pBuf + 64; }
+
+#if 0
+ AVB_LOGF_DEBUG("openavbAecpMessageTxFrame packet data (length %d):", pDst - pBuf);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_DEBUG, pBuf, pDst - pBuf, 16);
+#endif
+
+ openavbRawsockTxFrameReady(txSock, pBuf, pDst - pBuf, 0);
+ openavbRawsockSend(txSock);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+void* openavbAecpMessageRxThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ AVB_LOG_DEBUG("AECP Thread Started");
+ while (bRunning) {
+ // Try to get and process an AECP message.
+ openavbAecpMessageRxFrameReceive(MICROSECONDS_PER_SECOND);
+ }
+ AVB_LOG_DEBUG("AECP Thread Done");
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return NULL;
+}
+
+openavbRC openavbAecpMessageHandlerStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ bRunning = TRUE;
+
+ if (openavbAecpOpenSocket((const char *)gAvdeccCfg.ifname, gAvdeccCfg.vlanID, gAvdeccCfg.vlanPCP)) {
+
+ // Start the RX thread
+ bool errResult;
+ THREAD_CREATE(openavbAecpMessageRxThread, openavbAecpMessageRxThread, NULL, openavbAecpMessageRxThreadFn, NULL);
+ THREAD_CHECK_ERROR(openavbAecpMessageRxThread, "Thread / task creation failed", errResult);
+ if (errResult) {
+ bRunning = FALSE;
+ openavbAecpCloseSocket();
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_FAILURE, AVB_TRACE_AECP);
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AECP);
+ }
+
+ bRunning = FALSE;
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_FAILURE, AVB_TRACE_AECP);
+}
+
+void openavbAecpMessageHandlerStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ if (bRunning) {
+ bRunning = FALSE;
+ THREAD_JOIN(openavbAecpMessageRxThread, NULL);
+ openavbAecpCloseSocket();
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+openavbRC openavbAecpMessageSendUnsolicitedNotificationIfNeeded(openavb_aecp_AEMCommandResponse_t *AEMCommandResponse)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+ // AVDECC_TODO : Currently not implemented. IEEE Std 1722.1-2013 clause 7.5
+ // The basic idea is to inform interested controllers about a change in state of the Entity Model. This change in state
+ // could be from a AEM Command or other interfaces into the Entity Model. For AEM Commands this function will check the CommandResponse
+ // for the Success and correct Message Type and set the Unsolicited flag and sent to interested controllers.
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AECP);
+}
+
+openavbRC openavbAecpMessageSend(openavb_aecp_AEMCommandResponse_t *AEMCommandResponse)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+ openavbAecpMessageTxFrame(AEMCommandResponse);
+ openavbAecpMessageSendUnsolicitedNotificationIfNeeded(AEMCommandResponse);
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AECP);
+}
+
diff --git a/lib/avtp_pipeline/aecp/openavb_aecp_message.h b/lib/avtp_pipeline/aecp/openavb_aecp_message.h
new file mode 100644
index 00000000..225d2312
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/openavb_aecp_message.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.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AVDECC Enumeration and control protocol (AECP) Message Handler Interface
+ * MODULE SUMMARY : Interface for the AVDECC Enumeration and control protocol (AECP) message handlers
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_AECP_MESSAGE_H
+#define OPENAVB_AECP_MESSAGE_H 1
+
+#include "openavb_avdecc.h"
+
+openavbRC openavbAecpMessageHandlerStart(void);
+
+void openavbAecpMessageHandlerStop(void);
+
+openavbRC openavbAecpMessageSend(openavb_aecp_AEMCommandResponse_t *AEMCommandResponse);
+
+#endif // OPENAVB_AECP_MESSAGE_H
diff --git a/lib/avtp_pipeline/aecp/openavb_aecp_pub.h b/lib/avtp_pipeline/aecp/openavb_aecp_pub.h
new file mode 100644
index 00000000..00a5f2d2
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/openavb_aecp_pub.h
@@ -0,0 +1,42 @@
+/*************************************************************************************************************
+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 : AVDECC Enumeration and control protocol (AECP) Public Interface
+ * MODULE SUMMARY : Public interface for the AVDECC Enumeration and control protocol (AECP)
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_AECP_PUB_H
+#define OPENAVB_AECP_PUB_H 1
+
+#endif // OPENAVB_AECP_PUB_H
diff --git a/lib/avtp_pipeline/aecp/openavb_aecp_sm_entity_model_entity.c b/lib/avtp_pipeline/aecp/openavb_aecp_sm_entity_model_entity.c
new file mode 100644
index 00000000..e570f654
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/openavb_aecp_sm_entity_model_entity.c
@@ -0,0 +1,1378 @@
+/*************************************************************************************************************
+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 : AVDECC Enumeration and control protocol (AECP) : Entity Model Entity State Machine
+ * MODULE SUMMARY : Implements the AVDECC Enumeration and control protocol (AECP) : Entity Model Entity State Machine
+ * IEEE Std 1722.1-2013 clause 9.2.2.3
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <errno.h>
+
+#define AVB_LOG_COMPONENT "AECP"
+#include "openavb_log.h"
+
+#include "openavb_aem.h"
+#include "openavb_aecp.h"
+#include "openavb_aecp_message.h"
+#include "openavb_aecp_sm_entity_model_entity.h"
+#include "openavb_list.h"
+
+#include "openavb_avdecc_pipeline_interaction_pub.h"
+#include "openavb_aecp_cmd_get_counters.h"
+
+typedef enum {
+ OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_WAITING,
+ OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_UNSOLICITED_RESPONSE,
+ OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_RECEIVED_COMMAND,
+} openavb_aecp_sm_entity_model_entity_state_t;
+
+extern openavb_aecp_sm_global_vars_t openavbAecpSMGlobalVars;
+openavb_aecp_sm_entity_model_entity_vars_t openavbAecpSMEntityModelEntityVars;
+
+extern MUTEX_HANDLE(openavbAemMutex);
+#define AEM_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAemMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define AEM_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAemMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+MUTEX_HANDLE(openavbAecpQueueMutex);
+#define AECP_QUEUE_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAecpQueueMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define AECP_QUEUE_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAecpQueueMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+MUTEX_HANDLE(openavbAecpSMMutex);
+#define AECP_SM_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAecpSMMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define AECP_SM_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAecpSMMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+SEM_T(openavbAecpSMEntityModelEntityWaitingSemaphore);
+THREAD_TYPE(openavbAecpSMEntityModelEntityThread);
+THREAD_DEFINITON(openavbAecpSMEntityModelEntityThread);
+
+
+static openavb_list_t s_commandQueue = NULL;
+
+// Returns 1 if the queue was not empty before adding the new command,
+// 0 if the queue was empty before adding the new command,
+// or -1 if an error occurred.
+static int addCommandToQueue(openavb_aecp_AEMCommandResponse_t *command)
+{
+ int returnVal;
+
+ if (!s_commandQueue) { return -1; }
+ if (!command) { return -1; }
+
+ AECP_QUEUE_LOCK();
+ // Determine if the queue has something in it.
+ returnVal = (openavbListFirst(s_commandQueue) != NULL ? 1 : 0);
+
+ // Add the command to the end of the linked list.
+ if (openavbListAdd(s_commandQueue, command) == NULL) {
+ returnVal = -1;
+ }
+ AECP_QUEUE_UNLOCK();
+ return (returnVal);
+}
+
+static openavb_aecp_AEMCommandResponse_t * getNextCommandFromQueue(void)
+{
+ openavb_aecp_AEMCommandResponse_t *item = NULL;
+ openavb_list_node_t node;
+
+ if (!s_commandQueue) { return NULL; }
+
+ AECP_QUEUE_LOCK();
+ node = openavbListFirst(s_commandQueue);
+ if (node) {
+ item = openavbListData(node);
+ openavbListDelete(s_commandQueue, node);
+ }
+ AECP_QUEUE_UNLOCK();
+ return item;
+}
+
+
+void acquireEntity()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ openavb_aecp_AEMCommandResponse_t *pCommand = openavbAecpSMEntityModelEntityVars.rcvdCommand;
+ if (!pCommand) {
+ AVB_LOG_ERROR("acquireEntity called without command");
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return;
+ }
+
+ pCommand->headers.message_type = OPENAVB_AECP_MESSAGE_TYPE_AEM_RESPONSE;
+
+ if (pCommand->entityModelPdu.command_data.acquireEntityCmd.descriptor_type != OPENAVB_AEM_DESCRIPTOR_ENTITY) {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_SUPPORTED;
+ }
+ else {
+ openavb_avdecc_entity_model_t *pAem = openavbAemGetModel();
+ if (!pAem) {
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return;
+ }
+
+ AEM_LOCK();
+ if (pCommand->entityModelPdu.command_data.acquireEntityCmd.flags & OPENAVB_AEM_ACQUIRE_ENTITY_COMMAND_FLAG_RELEASE) {
+ // AVDECC_TODO - need to add mutex for the entity model
+ AVB_LOG_DEBUG("Entity Released");
+ pAem->entityAcquired = FALSE;
+ }
+ else {
+ if (pAem->entityAcquired) {
+ if (memcmp(pAem->acquiredControllerId, pCommand->commonPdu.controller_entity_id, sizeof(pAem->acquiredControllerId))) {
+ // AVDECC_TODO - Per 7.4.1 ACQUIRE_ENTITY Command. Need to add the CONTROLLER_AVAILABLE command and response to ensure the controller is still alive.
+ // For now just respond acquired by a different controller.
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_ENTITY_ACQUIRED;
+ memcpy(pCommand->entityModelPdu.command_data.acquireEntityRsp.owner_id, pAem->acquiredControllerId, sizeof(pCommand->commonPdu.controller_entity_id));
+ }
+ else {
+ // Entity was already acquired by this controller, so indicate a successful acquisition.
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ else {
+ pAem->entityAcquired = TRUE;
+ memcpy(pAem->acquiredControllerId, pCommand->commonPdu.controller_entity_id, sizeof(pAem->acquiredControllerId));
+ memcpy(pCommand->entityModelPdu.command_data.acquireEntityRsp.owner_id, pCommand->commonPdu.controller_entity_id, sizeof(pCommand->commonPdu.controller_entity_id));
+ AVB_LOGF_DEBUG("Entity Acquired by " ENTITYID_FORMAT, pCommand->entityModelPdu.command_data.acquireEntityRsp.owner_id);
+ }
+ }
+ AEM_UNLOCK();
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+void lockEntity()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ openavb_aecp_AEMCommandResponse_t *pCommand = openavbAecpSMEntityModelEntityVars.rcvdCommand;
+ if (!pCommand) {
+ AVB_LOG_ERROR("lockEntity called without command");
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return;
+ }
+
+ pCommand->headers.message_type = OPENAVB_AECP_MESSAGE_TYPE_AEM_RESPONSE;
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_IMPLEMENTED;
+
+ // AVDECC_TODO - needs implementation
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+// Returns TRUE is current rcvdCommand controlID matches the AEM acquire or lock controller id
+bool processCommandCheckRestriction_CorrectController()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+ bool bResult = TRUE;
+
+ openavb_aecp_AEMCommandResponse_t *pCommand = openavbAecpSMEntityModelEntityVars.rcvdCommand;
+ if (!pCommand) {
+ AVB_LOG_ERROR("processCommandCheckRestriction_CorrectController called without command");
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return bResult;
+ }
+
+ openavb_avdecc_entity_model_t *pAem = openavbAemGetModel();
+ if (pAem) {
+ AEM_LOCK();
+ if (pAem->entityAcquired) {
+ if (memcmp(pAem->acquiredControllerId, pCommand->commonPdu.controller_entity_id, sizeof(pAem->acquiredControllerId)) == 0) {
+ bResult = TRUE;
+ }
+ else {
+ AVB_LOGF_DEBUG("Access denied to " ENTITYID_FORMAT " as " ENTITYID_FORMAT " already acquired it", pCommand->commonPdu.controller_entity_id, pAem->acquiredControllerId);
+ bResult = FALSE;
+ }
+ }
+ else if (pAem->entityLocked) {
+ if (memcmp(pAem->lockedControllerId, pCommand->commonPdu.controller_entity_id, sizeof(pAem->lockedControllerId)) == 0) {
+ bResult = TRUE;
+ }
+ else {
+ AVB_LOGF_DEBUG("Access denied to " ENTITYID_FORMAT " as " ENTITYID_FORMAT " already locked it", pCommand->commonPdu.controller_entity_id, pAem->lockedControllerId);
+ bResult = FALSE;
+ }
+ }
+ AEM_UNLOCK();
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return bResult;
+}
+
+// Returns TRUE the stream_input or stream_output descriptor is currently not running.
+// NOTE: This function is using the last reported state from the client, not the state AVDECC last told the client to be in.
+bool processCommandCheckRestriction_StreamNotRunning(U16 descriptor_type, U16 descriptor_index)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+ bool bResult = TRUE;
+
+ if (descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT ||
+ descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+ U16 configIdx = openavbAemGetConfigIdx();
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamIO = openavbAemGetDescriptor(configIdx, descriptor_type, descriptor_index);
+ if (pDescriptorStreamIO) {
+ openavbAvdeccMsgStateType_t state = openavbAVDECCGetStreamingState(pDescriptorStreamIO, configIdx);
+ if (state >= OPENAVB_AVDECC_MSG_RUNNING) {
+ bResult = FALSE;
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return bResult;
+}
+
+// Process an incoming command and make it the response data on return.
+void processCommand()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ openavb_aecp_AEMCommandResponse_t *pCommand = openavbAecpSMEntityModelEntityVars.rcvdCommand;
+ if (!pCommand) {
+ AVB_LOG_ERROR("processCommand called without command");
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return;
+ }
+
+ // Set message type as response
+ pCommand->headers.message_type = OPENAVB_AECP_MESSAGE_TYPE_AEM_RESPONSE;
+
+ // Set to Not Implemented. Will be overridden by commands that are implemented.
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_IMPLEMENTED;
+
+ switch (pCommand->entityModelPdu.command_type) {
+ case OPENAVB_AEM_COMMAND_CODE_ACQUIRE_ENTITY:
+ // Implemented in the acquireEntity() function. Should never get here.
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_LOCK_ENTITY:
+ // Implemented in the lockEntity() function. Should never get here.
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ENTITY_AVAILABLE:
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_CONTROLLER_AVAILABLE:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_READ_DESCRIPTOR:
+ {
+ openavb_aecp_command_data_read_descriptor_t *pCmd = &pCommand->entityModelPdu.command_data.readDescriptorCmd;
+ openavb_aecp_response_data_read_descriptor_t *pRsp = &pCommand->entityModelPdu.command_data.readDescriptorRsp;
+ U16 configuration_index = pCmd->configuration_index;
+ U16 descriptor_type = pCmd->descriptor_type;
+ U16 descriptor_index = pCmd->descriptor_index;
+
+ openavbRC rc = openavbAemSerializeDescriptor(configuration_index, descriptor_type, descriptor_index,
+ sizeof(pRsp->descriptor_data), pRsp->descriptor_data, &pRsp->descriptor_length);
+ if (IS_OPENAVB_FAILURE(rc)) {
+ U8 *pDst = pRsp->descriptor_data;
+
+ // Send a basic response back to the controller.
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ pRsp->configuration_index = configuration_index;
+ pRsp->reserved = 0;
+ OCT_D2BHTONS(pDst, descriptor_type);
+ OCT_D2BHTONS(pDst, descriptor_index);
+ pRsp->descriptor_length = pDst - pRsp->descriptor_data;
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_WRITE_DESCRIPTOR:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_CONFIGURATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_CONFIGURATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_STREAM_FORMAT:
+ {
+ openavb_aecp_commandresponse_data_set_stream_format_t *pCmd = &pCommand->entityModelPdu.command_data.setStreamFormatCmd;
+ openavb_aecp_commandresponse_data_set_stream_format_t *pRsp = &pCommand->entityModelPdu.command_data.setStreamFormatRsp;
+
+ if (processCommandCheckRestriction_CorrectController()) {
+ if (processCommandCheckRestriction_StreamNotRunning(pCmd->descriptor_type, pCmd->descriptor_index)) {
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamInput) {
+ if (memcmp(&pDescriptorStreamInput->current_format, pCmd->stream_format, sizeof(pDescriptorStreamInput->current_format)) == 0) {
+ // No change needed.
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ else {
+ // AVDECC_TODO: Verify that the stream format is supported, and notify the Listener of the change.
+ //memcpy(&pDescriptorStreamInput->current_format, pCmd->stream_format, sizeof(pDescriptorStreamInput->current_format));
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_SUPPORTED;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ else if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamOutput) {
+ if (memcmp(&pDescriptorStreamOutput->current_format, pCmd->stream_format, sizeof(pDescriptorStreamOutput->current_format)) == 0) {
+ // No change needed.
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ else {
+ // AVDECC_TODO: Verify that the stream format is supported, and notify the Talker of the change.
+ //memcpy(&pDescriptorStreamOutput->current_format, pCmd->stream_format, sizeof(pDescriptorStreamOutput->current_format));
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_SUPPORTED;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_STREAM_IS_RUNNING;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_ENTITY_ACQUIRED;
+ }
+
+ if (pRsp->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamInput) {
+ memcpy(pRsp->stream_format, &pDescriptorStreamInput->current_format, sizeof(pRsp->stream_format));
+ }
+ }
+ else if (pRsp->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamOutput) {
+ memcpy(pRsp->stream_format, &pDescriptorStreamOutput->current_format, sizeof(pRsp->stream_format));
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_STREAM_FORMAT:
+ {
+ openavb_aecp_command_data_get_stream_format_t *pCmd = &pCommand->entityModelPdu.command_data.getStreamFormatCmd;
+ openavb_aecp_response_data_get_stream_format_t *pRsp = &pCommand->entityModelPdu.command_data.getStreamFormatRsp;
+
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+
+ if (pRsp->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamInput) {
+ openavbAemStreamFormatToBuf(&pDescriptorStreamInput->current_format, pRsp->stream_format);
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ else if (pRsp->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamOutput) {
+ memcpy(pRsp->stream_format, &pDescriptorStreamOutput->current_format, sizeof(pRsp->stream_format));
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_VIDEO_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_VIDEO_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_SENSOR_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SENSOR_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_STREAM_INFO:
+ {
+ openavb_aecp_commandresponse_data_set_stream_info_t *pCmd = &pCommand->entityModelPdu.command_data.setStreamInfoCmd;
+ openavb_aecp_commandresponse_data_set_stream_info_t *pRsp = &pCommand->entityModelPdu.command_data.setStreamInfoRsp;
+
+ if (processCommandCheckRestriction_CorrectController()) {
+ if (processCommandCheckRestriction_StreamNotRunning(pCmd->descriptor_type, pCmd->descriptor_index)) {
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT ||
+ pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamIO = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamIO) {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+
+ if ((pCmd->flags & OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_FORMAT_VALID) != 0) {
+ if (memcmp(&pDescriptorStreamIO->current_format, pCmd->stream_format, sizeof(pDescriptorStreamIO->current_format)) != 0) {
+ // AVDECC_TODO: Verify that the stream format is supported, and notify the Listener of the change.
+ //memcpy(&pDescriptorStreamInput->current_format, pCmd->stream_format, sizeof(pDescriptorStreamInput->current_format));
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_SUPPORTED;
+ }
+ }
+
+ // AVDECC_TODO: Add support for ENCRYPTED_PDU.
+ if ((pCmd->flags & OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_ENCRYPTED_PDU) != 0) {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_SUPPORTED;
+ }
+
+ // AVDECC_TODO: Add support for accumulated latency.
+ // For now, just clear the flags and values.
+ pRsp->flags &= ~OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_MSRP_ACC_LAT_VALID;
+ pRsp->msrp_accumulated_latency = 0;
+ pRsp->flags &= ~OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_MSRP_FAILURE_VALID;
+ pRsp->msrp_failure_code = 0;
+ memset(pRsp->msrp_failure_bridge_id, 0, sizeof(pRsp->msrp_failure_bridge_id));
+
+ if (pCommand->headers.status != OPENAVB_AEM_COMMAND_STATUS_SUCCESS) {
+ // As there are already issues, don't bother trying anything following this.
+ }
+ else if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) {
+ // If the controller is trying to set the streaming information for the Listener, this is a problem.
+ // The Listener gets this information from the Talker when the connection starts, so setting it here makes no sense.
+ // We also ignore the CLASS_A flag (or absence of it), as the Talker will indicate that value as well.
+ if ((pCmd->flags &
+ (OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_ID_VALID |
+ OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_DEST_MAC_VALID |
+ OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_VLAN_ID_VALID)) != 0) {
+ AVB_LOG_ERROR("SET_STREAM_INFO cannot set stream parameters for Listener");
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_BAD_ARGUMENTS;
+ }
+ }
+ else {
+ // Get the streaming values to send to the Talker.
+ // Invalid values used to indicate those that should not be changed.
+ U8 sr_class = ((pCmd->flags & OPENAVB_ACMP_FLAG_CLASS_B) != 0 ? SR_CLASS_B : SR_CLASS_A);
+ U8 stream_id_valid = FALSE;
+ U8 stream_src_mac[6] = {0, 0, 0, 0, 0, 0};
+ U16 stream_uid = 0;
+ U8 stream_dest_valid = FALSE;
+ U8 stream_dest_mac[6] = {0, 0, 0, 0, 0, 0};
+ U8 stream_vlan_id_valid = FALSE;
+ U16 stream_vlan_id = 0;
+ if ((pCmd->flags & OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_ID_VALID) != 0) {
+ stream_id_valid = TRUE;
+ memcpy(stream_src_mac, pCmd->stream_format, 6);
+ stream_uid = ntohs(*(U16*) (pCmd->stream_format + 6));
+ AVB_LOGF_INFO("AVDECC-specified Stream ID " ETH_FORMAT "/%u for Talker", ETH_OCTETS(stream_src_mac), stream_uid);
+ }
+ if ((pCmd->flags & OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_DEST_MAC_VALID) != 0) {
+ stream_dest_valid = TRUE;
+ memcpy(stream_dest_mac, pCmd->stream_dest_mac, 6);
+ AVB_LOGF_INFO("AVDECC-specified Stream Dest Addr " ETH_FORMAT " for Talker", ETH_OCTETS(stream_dest_mac));
+ }
+ if ((pCmd->flags & OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_VLAN_ID_VALID) != 0) {
+ stream_vlan_id_valid = TRUE;
+ stream_vlan_id = pCmd->stream_vlan_id;
+ AVB_LOGF_INFO("AVDECC-specified Stream VLAN ID %u for Talker", stream_vlan_id);
+ }
+
+ // Pass the values to the Talker.
+ if (!openavbAVDECCSetTalkerStreamInfo(
+ pDescriptorStreamIO, 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("SET_STREAM_INFO error setting stream parameters for Talker");
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_SUPPORTED;
+ }
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_STREAM_IS_RUNNING;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_ENTITY_ACQUIRED;
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_STREAM_INFO:
+ {
+ openavb_aecp_command_data_get_stream_info_t *pCmd = &pCommand->entityModelPdu.command_data.getStreamInfoCmd;
+ openavb_aecp_response_data_get_stream_info_t *pRsp = &pCommand->entityModelPdu.command_data.getStreamInfoRsp;
+
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+
+ if (pRsp->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT ||
+ pRsp->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+ U16 configIdx = openavbAemGetConfigIdx();
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamIO = openavbAemGetDescriptor(configIdx, pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamIO && pDescriptorStreamIO->stream) {
+ openavbAvdeccMsgStateType_t clientState = openavbAVDECCGetStreamingState(pDescriptorStreamIO, configIdx);
+
+ // Get the flags for the current status.
+ pRsp->flags = 0;
+ if (pDescriptorStreamIO->fast_connect_status >= OPENAVB_FAST_CONNECT_STATUS_IN_PROGRESS) {
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_FAST_CONNECT;
+ }
+ if (openavbAvdeccGetSaveStateInfo(pDescriptorStreamIO->stream, NULL, NULL, NULL, NULL)) {
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_SAVED_STATE;
+ }
+ if (clientState >= OPENAVB_AVDECC_MSG_RUNNING) {
+ pRsp->flags |= (pDescriptorStreamIO->acmp_flags &
+ (OPENAVB_ACMP_FLAG_CLASS_B |
+ OPENAVB_ACMP_FLAG_FAST_CONNECT |
+ OPENAVB_ACMP_FLAG_SUPPORTS_ENCRYPTED |
+ OPENAVB_ACMP_FLAG_ENCRYPTED_PDU));
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_CONNECTED;
+ if (clientState == OPENAVB_AVDECC_MSG_PAUSED) {
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAMING_WAIT;
+ }
+
+ // For the Listener, use the streaming values we received from the current Talker.
+ if (pRsp->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) {
+ // Get the Stream ID.
+ memcpy(pRsp->stream_id, pDescriptorStreamIO->acmp_stream_id, 8);
+ if (memcmp(pRsp->stream_id, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) != 0) {
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_ID_VALID;
+ }
+
+ // Get the Destination MAC Address.
+ memcpy(pRsp->stream_dest_mac, pDescriptorStreamIO->acmp_dest_addr, 6);
+ if (memcmp(pRsp->stream_id, "\x00\x00\x00\x00\x00\x00", 6) != 0) {
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_DEST_MAC_VALID;
+ }
+
+ // Get the Stream VLAN ID if the other stream identifiers are valid.
+ if ((pRsp->flags & (OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_ID_VALID | OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_DEST_MAC_VALID)) ==
+ (OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_ID_VALID | OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_DEST_MAC_VALID)) {
+ pRsp->stream_vlan_id = pDescriptorStreamIO->acmp_stream_vlan_id;
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_VLAN_ID_VALID;
+ }
+ }
+ }
+
+ // For the Talker, use the values we are or will use for a connection.
+ if (pRsp->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+ // Get the Stream ID.
+ if (pDescriptorStreamIO->stream->stream_addr.mac != NULL) {
+ memcpy(pRsp->stream_id, pDescriptorStreamIO->stream->stream_addr.buffer.ether_addr_octet, 6);
+ *(U16*)(pRsp->stream_id) = htons(pDescriptorStreamIO->stream->stream_uid);
+ if (memcmp(pRsp->stream_id, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) != 0) {
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_ID_VALID;
+ }
+ }
+
+ // Get the Destination MAC Address.
+ if (pDescriptorStreamIO->stream->dest_addr.mac != NULL) {
+ memcpy(pRsp->stream_dest_mac, pDescriptorStreamIO->stream->dest_addr.buffer.ether_addr_octet, 6);
+ if (memcmp(pRsp->stream_id, "\x00\x00\x00\x00\x00\x00", 6) != 0) {
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_DEST_MAC_VALID;
+ }
+ }
+
+ // Get the Stream VLAN ID.
+ if (pDescriptorStreamIO->stream->vlan_id != 0) {
+ pRsp->stream_vlan_id = pDescriptorStreamIO->stream->vlan_id;
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_VLAN_ID_VALID;
+ }
+ }
+
+ // AVDECC_TODO: Add TALKER_FAILED flag support.
+
+ // Get the stream format.
+ openavbAemStreamFormatToBuf(&pDescriptorStreamIO->current_format, pRsp->stream_format);
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_FORMAT_VALID;
+
+ // AVDECC_TODO: Add support for msrp_accumulated_latency
+ // AVDECC_TODO: Add support for msrp_failure_bridge_id, and msrp_failure_code
+
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_NAME:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_NAME:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_ASSOCIATION_ID:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_ASSOCIATION_ID:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_SAMPLING_RATE:
+ {
+ openavb_aecp_commandresponse_data_set_sampling_rate_t *pCmd = &pCommand->entityModelPdu.command_data.setSamplingRateCmd;
+ openavb_aecp_commandresponse_data_set_sampling_rate_t *pRsp = &pCommand->entityModelPdu.command_data.setSamplingRateRsp;
+
+ if (processCommandCheckRestriction_CorrectController()) {
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_AUDIO_UNIT) {
+ openavb_aem_descriptor_audio_unit_t *pDescriptorAudioUnit = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorAudioUnit) {
+ if (memcmp(&pDescriptorAudioUnit->current_sampling_rate, pCmd->sampling_rate, sizeof(pDescriptorAudioUnit->current_sampling_rate)) == 0) {
+ // No change needed.
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ else {
+ // AVDECC_TODO: Verify that the sample rate is supported, and notify the Talker/Listener of the change.
+ //memcpy(&pDescriptorAudioUnit->current_sampling_rate, pCmd->sampling_rate, sizeof(pDescriptorAudioUnit->current_sampling_rate));
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_SUPPORTED;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_IMPLEMENTED;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_ENTITY_ACQUIRED;
+ }
+
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_AUDIO_UNIT) {
+ openavb_aem_descriptor_audio_unit_t *pDescriptorAudioUnit = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorAudioUnit) {
+ memcpy(pRsp->sampling_rate, &pDescriptorAudioUnit->current_sampling_rate, sizeof(pRsp->sampling_rate));
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SAMPLING_RATE:
+ {
+ openavb_aecp_command_data_get_sampling_rate_t *pCmd = &pCommand->entityModelPdu.command_data.getSamplingRateCmd;
+ openavb_aecp_response_data_get_sampling_rate_t *pRsp = &pCommand->entityModelPdu.command_data.getSamplingRateRsp;
+
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_AUDIO_UNIT) {
+ openavb_aem_descriptor_audio_unit_t *pDescriptorAudioUnit = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorAudioUnit) {
+ U8 *pSrDst = (U8*)(pRsp->sampling_rate);
+ memset(pRsp->sampling_rate, 0, sizeof(pRsp->sampling_rate));
+ BIT_D2BHTONL(pSrDst, pDescriptorAudioUnit->current_sampling_rate.pull, 29, 0);
+ BIT_D2BHTONL(pSrDst, pDescriptorAudioUnit->current_sampling_rate.base, 0, 0);
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_CLOCK_SOURCE:
+ {
+ openavb_aecp_commandresponse_data_set_clock_source_t *pCmd = &pCommand->entityModelPdu.command_data.setClockSourceCmd;
+ openavb_aecp_commandresponse_data_set_clock_source_t *pRsp = &pCommand->entityModelPdu.command_data.setClockSourceRsp;
+
+ if (processCommandCheckRestriction_CorrectController()) {
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN) {
+ openavb_aem_descriptor_clock_domain_t *pDescriptorClockDomain = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorClockDomain) {
+ if (pDescriptorClockDomain->clock_source_index == pCmd->clock_source_index) {
+ // No change needed.
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ else {
+ // AVDECC_TODO: Verify that the clock source is supported, and notify the Talker/Listener of the change.
+ //pDescriptorClockDomain->clock_source_index = pCmd->clock_source_index;
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_SUPPORTED;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_IMPLEMENTED;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_ENTITY_ACQUIRED;
+ }
+
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN) {
+ openavb_aem_descriptor_clock_domain_t *pDescriptorClockDomain = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorClockDomain) {
+ pRsp->clock_source_index = pDescriptorClockDomain->clock_source_index;
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_CLOCK_SOURCE:
+ {
+ openavb_aecp_command_data_get_clock_source_t *pCmd = &pCommand->entityModelPdu.command_data.getClockSourceCmd;
+ openavb_aecp_response_data_get_clock_source_t *pRsp = &pCommand->entityModelPdu.command_data.getClockSourceRsp;
+
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN) {
+ openavb_aem_descriptor_clock_domain_t *pDescriptorClockDomain = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorClockDomain) {
+ pRsp->clock_source_index = pDescriptorClockDomain->clock_source_index;
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_CONTROL:
+ {
+ openavb_aecp_commandresponse_data_set_control_t *pCmd = &pCommand->entityModelPdu.command_data.setControlCmd;
+ openavb_aecp_commandresponse_data_set_control_t *pRsp = &pCommand->entityModelPdu.command_data.setControlRsp;
+
+ if (processCommandCheckRestriction_CorrectController()) {
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_CONTROL) {
+ openavb_aem_descriptor_control_t *pDescriptorControl = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorControl) {
+ pDescriptorControl->number_of_values = pCmd->valuesCount;
+ int i1;
+ for (i1 = 0; i1 < pCmd->valuesCount; i1++) {
+ switch (pDescriptorControl->control_value_type) {
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT8:
+ pDescriptorControl->value_details.linear_int8[i1].current = pCmd->values.linear_int8[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT8:
+ pDescriptorControl->value_details.linear_uint8[i1].current = pCmd->values.linear_uint8[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT16:
+ pDescriptorControl->value_details.linear_int16[i1].current = pCmd->values.linear_int16[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT16:
+ pDescriptorControl->value_details.linear_uint16[i1].current = pCmd->values.linear_uint16[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT32:
+ pDescriptorControl->value_details.linear_int32[i1].current = pCmd->values.linear_int32[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT32:
+ pDescriptorControl->value_details.linear_uint32[i1].current = pCmd->values.linear_uint32[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT64:
+ pDescriptorControl->value_details.linear_int64[i1].current = pCmd->values.linear_int64[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT64:
+ pDescriptorControl->value_details.linear_uint64[i1].current = pCmd->values.linear_uint64[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_FLOAT:
+ pDescriptorControl->value_details.linear_float[i1].current = pCmd->values.linear_float[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_DOUBLE:
+ pDescriptorControl->value_details.linear_double[i1].current = pCmd->values.linear_double[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_STRING:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_UTF8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_BODE_PLOT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SMPTE_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SAMPLE_RATE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_GPTP_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_VENDOR:
+ break;
+ }
+ }
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_IMPLEMENTED;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_ENTITY_ACQUIRED;
+ }
+
+ // Populate response
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_CONTROL) {
+ openavb_aem_descriptor_control_t *pDescriptorControl = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorControl) {
+ int i1;
+ for (i1 = 0; i1 < pDescriptorControl->number_of_values; i1++) {
+ switch (pDescriptorControl->control_value_type) {
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT8:
+ pRsp->values.linear_int8[i1] = pDescriptorControl->value_details.linear_int8[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT8:
+ pRsp->values.linear_uint8[i1] = pDescriptorControl->value_details.linear_uint8[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT16:
+ pRsp->values.linear_int16[i1] = pDescriptorControl->value_details.linear_int16[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT16:
+ pRsp->values.linear_uint16[i1] = pDescriptorControl->value_details.linear_uint16[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT32:
+ pRsp->values.linear_int32[i1] = pDescriptorControl->value_details.linear_int32[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT32:
+ pRsp->values.linear_uint32[i1] = pDescriptorControl->value_details.linear_uint32[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT64:
+ pRsp->values.linear_int64[i1] = pDescriptorControl->value_details.linear_int64[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT64:
+ pRsp->values.linear_uint64[i1] = pDescriptorControl->value_details.linear_uint64[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_FLOAT:
+ pRsp->values.linear_float[i1] = pDescriptorControl->value_details.linear_float[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_DOUBLE:
+ pRsp->values.linear_double[i1] = pDescriptorControl->value_details.linear_double[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_STRING:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_UTF8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_BODE_PLOT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SMPTE_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SAMPLE_RATE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_GPTP_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_VENDOR:
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_CONTROL:
+ {
+ openavb_aecp_commandresponse_data_set_control_t *pCmd = &pCommand->entityModelPdu.command_data.setControlCmd;
+ openavb_aecp_commandresponse_data_set_control_t *pRsp = &pCommand->entityModelPdu.command_data.setControlRsp;
+
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_CONTROL) {
+ openavb_aem_descriptor_control_t *pDescriptorControl = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorControl) {
+ int i1;
+ for (i1 = 0; i1 < pDescriptorControl->number_of_values; i1++) {
+ switch (pDescriptorControl->control_value_type) {
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT8:
+ pRsp->values.linear_int8[i1] = pDescriptorControl->value_details.linear_int8[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT8:
+ pRsp->values.linear_uint8[i1] = pDescriptorControl->value_details.linear_uint8[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT16:
+ pRsp->values.linear_int16[i1] = pDescriptorControl->value_details.linear_int16[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT16:
+ pRsp->values.linear_uint16[i1] = pDescriptorControl->value_details.linear_uint16[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT32:
+ pRsp->values.linear_int32[i1] = pDescriptorControl->value_details.linear_int32[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT32:
+ pRsp->values.linear_uint32[i1] = pDescriptorControl->value_details.linear_uint32[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT64:
+ pRsp->values.linear_int64[i1] = pDescriptorControl->value_details.linear_int64[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT64:
+ pRsp->values.linear_uint64[i1] = pDescriptorControl->value_details.linear_uint64[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_FLOAT:
+ pRsp->values.linear_float[i1] = pDescriptorControl->value_details.linear_float[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_DOUBLE:
+ pRsp->values.linear_double[i1] = pDescriptorControl->value_details.linear_double[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_STRING:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_UTF8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_BODE_PLOT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SMPTE_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SAMPLE_RATE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_GPTP_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_VENDOR:
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_INCREMENT_CONTROL:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DECREMENT_CONTROL:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_SIGNAL_SELECTOR:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SIGNAL_SELECTOR:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_MIXER:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_MIXER:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_MATRIX:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_MATRIX:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_START_STREAMING:
+ {
+ openavb_aecp_commandresponse_data_start_streaming_t *pCmd = &pCommand->entityModelPdu.command_data.startStreamingCmd;
+ //openavb_aecp_commandresponse_data_start_streaming_t *pRsp = &pCommand->entityModelPdu.command_data.startStreamingRsp;
+
+ if (processCommandCheckRestriction_CorrectController()) {
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamInput) {
+ openavbAVDECCPauseStream(pDescriptorStreamInput, FALSE);
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ else if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamOutput) {
+ openavbAVDECCPauseStream(pDescriptorStreamOutput, FALSE);
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_IMPLEMENTED;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_ENTITY_ACQUIRED;
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_STOP_STREAMING:
+ {
+ openavb_aecp_commandresponse_data_start_streaming_t *pCmd = &pCommand->entityModelPdu.command_data.startStreamingCmd;
+ //openavb_aecp_commandresponse_data_start_streaming_t *pRsp = &pCommand->entityModelPdu.command_data.startStreamingRsp;
+
+ if (processCommandCheckRestriction_CorrectController()) {
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamInput) {
+ openavbAVDECCPauseStream(pDescriptorStreamInput, TRUE);
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ else if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamOutput) {
+ openavbAVDECCPauseStream(pDescriptorStreamOutput, TRUE);
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_IMPLEMENTED;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_ENTITY_ACQUIRED;
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REGISTER_UNSOLICITED_NOTIFICATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DEREGISTER_UNSOLICITED_NOTIFICATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_IDENTIFY_NOTIFICATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_AVB_INFO:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_AS_PATH:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_COUNTERS:
+ {
+ openavb_aecp_command_data_get_counters_t *pCmd = &pCommand->entityModelPdu.command_data.getCountersCmd;
+ openavb_aecp_response_data_get_counters_t *pRsp = &pCommand->entityModelPdu.command_data.getCountersRsp;
+ pCommand->headers.status = openavbAecpCommandGetCountersHandler(pCmd, pRsp);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REBOOT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_AUDIO_MAP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ADD_AUDIO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REMOVE_AUDIO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_VIDEO_MAP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ADD_VIDEO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REMOVE_VIDEO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SENSOR_MAP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ADD_SENSOR_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REMOVE_SENSOR_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_START_OPERATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ABORT_OPERATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_OPERATION_STATUS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_KEY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_KEY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEY_LIST:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_KEY_TO_CHAIN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_KEY_FROM_CHAIN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEYCHAIN_LIST:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_IDENTITY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_TOKEN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_TOKEN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTHENTICATE:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DEAUTHENTICATE:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ENABLE_TRANSPORT_SECURITY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DISABLE_TRANSPORT_SECURITY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ENABLE_STREAM_ENCRYPTION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DISABLE_STREAM_ENCRYPTION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_MEMORY_OBJECT_LENGTH:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_MEMORY_OBJECT_LENGTH:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_STREAM_BACKUP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_STREAM_BACKUP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_EXPANSION:
+ break;
+ default:
+ break;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+void openavbAecpSMEntityModelEntityStateMachine()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+ bool bRunning = TRUE;
+
+ openavb_aecp_sm_entity_model_entity_state_t state = OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_WAITING;
+
+ // Lock such that the mutex is held unless waiting for a semaphore. Synchronous processing of command responses.
+ AECP_SM_LOCK();
+ while (bRunning) {
+ switch (state) {
+ case OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_WAITING:
+ AVB_LOG_DEBUG("State: OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_WAITING");
+ openavbAecpSMEntityModelEntityVars.rcvdAEMCommand = FALSE;
+ openavbAecpSMEntityModelEntityVars.doUnsolicited = FALSE;
+
+ // Wait for a change in state
+ while (state == OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_WAITING && bRunning) {
+ AECP_SM_UNLOCK();
+ SEM_ERR_T(err);
+ SEM_WAIT(openavbAecpSMEntityModelEntityWaitingSemaphore, err);
+ AECP_SM_LOCK();
+
+ if (SEM_IS_ERR_NONE(err)) {
+ if (openavbAecpSMEntityModelEntityVars.doTerminate) {
+ bRunning = FALSE;
+ }
+ else if (openavbAecpSMEntityModelEntityVars.doUnsolicited) {
+ state = OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_UNSOLICITED_RESPONSE;
+ }
+ else if (openavbAecpSMEntityModelEntityVars.rcvdAEMCommand) {
+ state = OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_RECEIVED_COMMAND;
+ }
+ }
+ }
+ break;
+
+ case OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_UNSOLICITED_RESPONSE:
+ AVB_LOG_DEBUG("State: OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_UNSOLICITED_RESPONSE");
+
+ state = OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_WAITING;
+ break;
+
+ case OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_RECEIVED_COMMAND:
+ AVB_LOG_DEBUG("State: OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_RECEIVED_COMMAND");
+
+ while (TRUE) {
+ openavbAecpSMEntityModelEntityVars.rcvdCommand = getNextCommandFromQueue();
+ if (openavbAecpSMEntityModelEntityVars.rcvdCommand == NULL) {
+ break;
+ }
+
+ if (memcmp(openavbAecpSMEntityModelEntityVars.rcvdCommand->headers.target_entity_id,
+ openavbAecpSMGlobalVars.myEntityID,
+ sizeof(openavbAecpSMGlobalVars.myEntityID)) != 0) {
+ // Not intended for us.
+ free(openavbAecpSMEntityModelEntityVars.rcvdCommand);
+ continue;
+ }
+
+ if (openavbAecpSMEntityModelEntityVars.rcvdCommand->entityModelPdu.command_type == OPENAVB_AEM_COMMAND_CODE_ACQUIRE_ENTITY) {
+ acquireEntity();
+ }
+ else if (openavbAecpSMEntityModelEntityVars.rcvdCommand->entityModelPdu.command_type == OPENAVB_AEM_COMMAND_CODE_LOCK_ENTITY) {
+ lockEntity();
+ }
+ else if (openavbAecpSMEntityModelEntityVars.rcvdCommand->entityModelPdu.command_type == OPENAVB_AEM_COMMAND_CODE_ENTITY_AVAILABLE) {
+ // State machine defines just returning the request command. Doing that in the processCommand function for consistency.
+ processCommand();
+ }
+ else {
+ processCommand();
+ }
+
+ openavbAecpMessageSend(openavbAecpSMEntityModelEntityVars.rcvdCommand);
+ free(openavbAecpSMEntityModelEntityVars.rcvdCommand);
+ }
+
+ state = OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_WAITING;
+ break;
+
+ default:
+ AVB_LOG_ERROR("State: Unknown");
+ bRunning = FALSE; // Unexpected
+ break;
+
+ }
+ }
+ AECP_SM_UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+void* openavbAecpSMEntityModelEntityThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+ openavbAecpSMEntityModelEntityStateMachine();
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return NULL;
+}
+
+void openavbAecpSMEntityModelEntityStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ MUTEX_ATTR_HANDLE(mtq);
+ MUTEX_ATTR_INIT(mtq);
+ MUTEX_ATTR_SET_TYPE(mtq, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mtq, "openavbAecpQueueMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(openavbAecpQueueMutex, mtq);
+ MUTEX_LOG_ERR("Could not create/initialize 'openavbAecpQueueMutex' mutex");
+
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "openavbAecpSMMutex");
+ MUTEX_CREATE(openavbAecpSMMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'openavbAecpSMMutex' mutex");
+
+ SEM_ERR_T(err);
+ SEM_INIT(openavbAecpSMEntityModelEntityWaitingSemaphore, 1, err);
+ SEM_LOG_ERR(err);
+
+ // Initialize the linked list (queue).
+ s_commandQueue = openavbListNewList();
+
+ // Start the Advertise Entity State Machine
+ bool errResult;
+ THREAD_CREATE(openavbAecpSMEntityModelEntityThread, openavbAecpSMEntityModelEntityThread, NULL, openavbAecpSMEntityModelEntityThreadFn, NULL);
+ THREAD_CHECK_ERROR(openavbAecpSMEntityModelEntityThread, "Thread / task creation failed", errResult);
+ if (errResult); // Already reported
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+void openavbAecpSMEntityModelEntityStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ openavbAecpSMEntityModelEntitySet_doTerminate(TRUE);
+
+ THREAD_JOIN(openavbAecpSMEntityModelEntityThread, NULL);
+
+ // Delete the linked list (queue).
+ openavb_aecp_AEMCommandResponse_t *item;
+ while ((item = getNextCommandFromQueue()) != NULL) {
+ free(item);
+ }
+ openavbListDeleteList(s_commandQueue);
+
+ SEM_ERR_T(err);
+ SEM_DESTROY(openavbAecpSMEntityModelEntityWaitingSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ MUTEX_CREATE_ERR();
+ MUTEX_DESTROY(openavbAecpQueueMutex);
+ MUTEX_LOG_ERR("Could not destroy 'openavbAecpQueueMutex' mutex");
+ MUTEX_DESTROY(openavbAecpSMMutex);
+ MUTEX_LOG_ERR("Could not destroy 'openavbAecpSMMutex' mutex");
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+void openavbAecpSMEntityModelEntitySet_rcvdCommand(openavb_aecp_AEMCommandResponse_t *rcvdCommand)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ if (memcmp(rcvdCommand->headers.target_entity_id,
+ openavbAecpSMGlobalVars.myEntityID,
+ sizeof(openavbAecpSMGlobalVars.myEntityID)) != 0) {
+ // Not intended for us.
+ free(rcvdCommand);
+ return;
+ }
+
+ int result = addCommandToQueue(rcvdCommand);
+ if (result < 0) {
+ AVB_LOG_DEBUG("addCommandToQueue failed");
+ free(rcvdCommand);
+ }
+ else if (result == 0) {
+ // We just added an item to an empty queue.
+ // Notify the machine state thread that something is waiting.
+ AECP_SM_LOCK();
+ openavbAecpSMEntityModelEntityVars.rcvdAEMCommand = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAecpSMEntityModelEntityWaitingSemaphore, err);
+ SEM_LOG_ERR(err);
+ AECP_SM_UNLOCK();
+ }
+ else {
+ // We added an item to a non-empty queue.
+ // Assume it will be handled when the other items in the queue are handled.
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+void openavbAecpSMEntityModelEntitySet_unsolicited(openavb_aecp_AEMCommandResponse_t *unsolicited)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+ AECP_SM_LOCK();
+ memcpy(&openavbAecpSMEntityModelEntityVars.unsolicited, unsolicited, sizeof(*unsolicited));
+ openavbAecpSMEntityModelEntityVars.doUnsolicited = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAecpSMEntityModelEntityWaitingSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AECP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+void openavbAecpSMEntityModelEntitySet_doTerminate(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+ AECP_SM_LOCK();
+ openavbAecpSMEntityModelEntityVars.doTerminate = value;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAecpSMEntityModelEntityWaitingSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AECP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
diff --git a/lib/avtp_pipeline/aecp/openavb_aecp_sm_entity_model_entity.h b/lib/avtp_pipeline/aecp/openavb_aecp_sm_entity_model_entity.h
new file mode 100644
index 00000000..5d234b15
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/openavb_aecp_sm_entity_model_entity.h
@@ -0,0 +1,71 @@
+/*************************************************************************************************************
+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 : AVDECC Enumeration and control protocol (AECP) : Entity Model Entity State Machine Interface
+ * MODULE SUMMARY : Interface for the AVDECC Enumeration and control protocol (AECP) : Entity Model Entity State Machine
+ * IEEE Std 1722.1-2013 clause 9.2.2.3
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_H
+#define OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_H 1
+
+#include "openavb_aecp.h"
+
+// State machine vars IEEE Std 1722.1-2013 clause 9.2.2.3.1.2
+typedef struct {
+ openavb_aecp_AEMCommandResponse_t *rcvdCommand;
+ bool rcvdAEMCommand;
+ openavb_aecp_AEMCommandResponse_t unsolicited;
+ bool doUnsolicited;
+
+ // Not part of spec
+ bool doTerminate;
+} openavb_aecp_sm_entity_model_entity_vars_t;
+
+// State machine functions IEEE Std 1722.1-2013 clause 9.2.2.3.1.3
+void acquireEntity(void);
+void lockEntity(void);
+void processCommand(void);
+
+void openavbAecpSMEntityModelEntityStart(void);
+void openavbAecpSMEntityModelEntityStop(void);
+
+// Accessors
+void openavbAecpSMEntityModelEntitySet_rcvdCommand(openavb_aecp_AEMCommandResponse_t *rcvdCommand);
+ // Note: rcvdAEMCommand is set during the call to openavbAecpSMEntityModelEntitySet_rcvdCommand()
+void openavbAecpSMEntityModelEntitySet_unsolicited(openavb_aecp_AEMCommandResponse_t *unsolicited);
+ // Note: doUnsolicited is set during the call to openavbAecpSMEntityModelEntitySet_unsolicited()
+void openavbAecpSMEntityModelEntitySet_doTerminate(bool value);
+
+#endif // OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_H
diff --git a/lib/avtp_pipeline/aem/CMakeLists.txt b/lib/avtp_pipeline/aem/CMakeLists.txt
new file mode 100644
index 00000000..276e403a
--- /dev/null
+++ b/lib/avtp_pipeline/aem/CMakeLists.txt
@@ -0,0 +1,21 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/aem/openavb_aem.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_entity.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_configuration.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_audio_unit.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_locale.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_strings.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_stream_io.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_jack_io.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_avb_interface.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_clock_source.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_stream_port_io.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_external_port_io.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_audio_cluster.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_audio_map.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_control.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_clock_domain.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_locale_strings_handler.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/aem/openavb_aem.c b/lib/avtp_pipeline/aem/openavb_aem.c
new file mode 100644
index 00000000..e9f0f4de
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_aem.c
@@ -0,0 +1,534 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Entity Model
+ * MODULE SUMMARY : Implements the 1722.1 (AVDECC) Entity Model
+ ******************************************************************
+ */
+
+#include "stdlib.h"
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_avdecc.h"
+#include "openavb_aem.h"
+
+MUTEX_HANDLE(openavbAemMutex);
+#define AEM_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAemMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define AEM_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAemMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+static openavb_avdecc_entity_model_t *pAemEntityModel = NULL;
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemCreate(openavb_aem_descriptor_entity_t *pDescriptorEntity)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "openavbAemMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(openavbAemMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'openavbAemMutex' mutex");
+
+ if (!pDescriptorEntity) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING), AVB_TRACE_AEM);
+ }
+
+ if (!pAemEntityModel) {
+ pAemEntityModel = calloc(1, sizeof(*pAemEntityModel));
+ }
+
+ if (!pAemEntityModel) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY), AVB_TRACE_AEM);
+ }
+
+ pAemEntityModel->pDescriptorEntity = pDescriptorEntity;
+ pAemEntityModel->aemConfigurations = openavbArrayNewArray(sizeof(openavb_aem_configuration_t));
+ memset(pAemEntityModel->aemNonTopLevelDescriptorsArray, 0, sizeof(pAemEntityModel->aemNonTopLevelDescriptorsArray));
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDestroy()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+ // AVDECC_TODO all deallocations will occur here
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+bool openavbAemCheckModel(bool bLog)
+{
+ if (!pAemEntityModel || !pAemEntityModel->pDescriptorEntity) {
+ if (bLog) {
+ AVB_RC_LOG(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING);
+ }
+ return FALSE;
+ }
+ return TRUE;
+}
+
+openavbRC openavbAemAddDescriptorToConfiguration(U16 descriptorType, U16 configIdx)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+ int i1;
+
+ // Make sure Entity Model is created
+ if (!openavbAemCheckModel(FALSE)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING), AVB_TRACE_AEM);
+ }
+
+ if (configIdx == OPENAVB_AEM_DESCRIPTOR_INVALID) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_INVALID_CONFIG_IDX), AVB_TRACE_AEM);
+ }
+ openavb_aem_configuration_t *pConfiguration = openavbArrayDataIdx(pAemEntityModel->aemConfigurations, configIdx);
+ if (!pConfiguration) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_INVALID_CONFIG_IDX), AVB_TRACE_AEM);
+ }
+
+ openavb_aem_descriptor_configuration_t *pConfig = pConfiguration->pDescriptorConfiguration;
+ if (!pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_INVALID_CONFIG_IDX), AVB_TRACE_AEM);
+ }
+
+ // Check if the new descriptor type is in the configuration array
+ for (i1 = 0; i1 < pConfig->descriptor_counts_count; i1++) {
+ if (pConfig->descriptor_counts[i1].descriptor_type == descriptorType) {
+ // Found this descriptor type so just increase the count.
+ pConfig->descriptor_counts[i1].count++;
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+ }
+ }
+
+ // Update counts
+ pConfig->descriptor_counts[pConfig->descriptor_counts_count].descriptor_type = descriptorType;
+ pConfig->descriptor_counts[pConfig->descriptor_counts_count].count++;
+ pConfig->descriptor_counts_count++;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavb_avdecc_entity_model_t *openavbAemGetModel()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pAemEntityModel;
+}
+
+openavb_array_t openavbAemGetDescriptorArray(U16 configIdx, U16 descriptorType)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_array_t retDescriptors = NULL;
+
+ // Make sure Entity Model is created
+ if (!openavbAemCheckModel(TRUE)) {
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ if (descriptorType == OPENAVB_AEM_DESCRIPTOR_ENTITY) {
+ // There is always only a single Entity Descriptor and therefore there isn't an array. NULL will be returned.
+ }
+ else if (descriptorType == OPENAVB_AEM_DESCRIPTOR_CONFIGURATION) {
+ // The configuration descriptor is a special descriptor and not return by this function. NULL will be returned.
+ }
+ else {
+ if (configIdx != OPENAVB_AEM_DESCRIPTOR_INVALID) {
+ openavb_aem_configuration_t *pConfig = openavbArrayDataIdx(pAemEntityModel->aemConfigurations, configIdx);
+ if (pConfig) {
+ retDescriptors = pConfig->descriptorsArray[descriptorType];
+ }
+ }
+
+ // Search the alternate location for non-top-level descriptors.
+ if (!retDescriptors) {
+ retDescriptors = pAemEntityModel->aemNonTopLevelDescriptorsArray[descriptorType];
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return retDescriptors;
+}
+
+void *openavbAemFindDescriptor(U16 configIdx, U16 descriptorType, U16 descriptorIdx)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ void *retDescriptor = NULL;
+
+ // Make sure Entity Model is created
+ if (!openavbAemCheckModel(TRUE)) {
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ if (descriptorType == OPENAVB_AEM_DESCRIPTOR_ENTITY) {
+ if (pAemEntityModel->pDescriptorEntity &&
+ pAemEntityModel->pDescriptorEntity->descriptor_index == descriptorIdx) {
+ retDescriptor = pAemEntityModel->pDescriptorEntity;
+ }
+ }
+ else if (descriptorType == OPENAVB_AEM_DESCRIPTOR_CONFIGURATION) {
+ if (configIdx != OPENAVB_AEM_DESCRIPTOR_INVALID) {
+ openavb_aem_configuration_t *pConfig = openavbArrayDataIdx(pAemEntityModel->aemConfigurations, configIdx);
+ if (pConfig &&
+ pConfig->pDescriptorConfiguration &&
+ pConfig->pDescriptorConfiguration->descriptor_index == descriptorIdx) {
+ retDescriptor = pConfig->pDescriptorConfiguration;
+ }
+ }
+ }
+ else {
+ openavb_array_t descriptors = NULL;
+ if (configIdx != OPENAVB_AEM_DESCRIPTOR_INVALID) {
+ openavb_aem_configuration_t *pConfig = openavbArrayDataIdx(pAemEntityModel->aemConfigurations, configIdx);
+ if (pConfig) {
+ descriptors = pConfig->descriptorsArray[descriptorType];
+ if (descriptors) {
+ retDescriptor = openavbArrayDataIdx(descriptors, descriptorIdx);
+ }
+ }
+ }
+
+ // Search the alternate location for non-top-level descriptors.
+ if (!retDescriptor) {
+ descriptors = pAemEntityModel->aemNonTopLevelDescriptorsArray[descriptorType];
+ if (descriptors) {
+ retDescriptor = openavbArrayDataIdx(descriptors, descriptorIdx);
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return retDescriptor;
+}
+
+openavbRC openavbAemSerializeDescriptor(U16 configIdx, U16 descriptorType, U16 descriptorIdx, U16 bufSize, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ // Make sure Entity Model is created
+ if (!openavbAemCheckModel(FALSE)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING), AVB_TRACE_AEM);
+ }
+
+ if (!pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ void *pDescriptor = openavbAemFindDescriptor(configIdx, descriptorType, descriptorIdx);
+ if (pDescriptor) {
+ openavb_aem_descriptor_common_t *pDescriptorCommon = pDescriptor;
+ if (IS_OPENAVB_FAILURE(pDescriptorCommon->descriptorPvtPtr->update(pDescriptor))) {
+ AVB_RC_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_STALE_DATA), AVB_TRACE_AEM);
+ }
+ if (IS_OPENAVB_FAILURE(pDescriptorCommon->descriptorPvtPtr->toBuf(pDescriptor, bufSize, pBuf, descriptorSize))) {
+ AVB_RC_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_GENERIC), AVB_TRACE_AEM);
+ }
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+ }
+
+ AVB_RC_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_UNKNOWN_DESCRIPTOR), AVB_TRACE_AEM);
+}
+
+bool openavbAemAddDescriptorConfiguration(openavb_aem_descriptor_configuration_t *pDescriptor, U16 *pResultIdx)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ // Make sure Entity Model is created
+ if (!openavbAemCheckModel(TRUE)) {
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ if (!pDescriptor || !pResultIdx) {
+ AVB_RC_LOG(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ // Allocate the new configuration structure
+ openavb_aem_configuration_t *pAemConfiguration = openavbArrayDataNew(pAemEntityModel->aemConfigurations);
+ if (!pAemConfiguration) {
+ AVB_RC_LOG(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ // Assign the descriptor to the new configuration
+ pAemConfiguration->pDescriptorConfiguration = pDescriptor;
+
+ // Set to return descriptor index and increment the count
+ S32 retIdx = openavbArrayFindData(pAemEntityModel->aemConfigurations, pAemConfiguration);
+ if (retIdx < 0) {
+ return FALSE;
+ }
+ *pResultIdx = retIdx;
+
+ pAemEntityModel->pDescriptorEntity->configurations_count++;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT U16 openavbAemGetConfigIdx()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ // This function does NOT check for errors but at a minimum avoid a crash.
+ if (!pAemEntityModel || !pAemEntityModel->pDescriptorEntity) {
+ AVB_RC_LOG(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return 0;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pAemEntityModel->pDescriptorEntity->current_configuration;
+}
+
+
+extern DLL_EXPORT bool openavbAemAddDescriptor(void *pDescriptor, U16 configIdx, U16 *pResultIdx)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ // Make sure Entity Model is created
+ if (!openavbAemCheckModel(TRUE)) {
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ if (!pDescriptor || !pResultIdx) {
+ AVB_RC_LOG(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ openavb_aem_descriptor_common_t *pDescriptorCommon = pDescriptor;
+
+ if (pDescriptorCommon->descriptor_type == OPENAVB_AEM_DESCRIPTOR_ENTITY) {
+ // Entity Descriptors aren't handled in this function.
+ AVB_RC_LOG(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+ if (pDescriptorCommon->descriptor_type == OPENAVB_AEM_DESCRIPTOR_CONFIGURATION) {
+ // Configuration descriptors have special processing
+ bool result = openavbAemAddDescriptorConfiguration(pDescriptor, pResultIdx);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return result;
+ }
+
+ openavb_array_t descriptors = NULL;
+ if (pDescriptorCommon->descriptorPvtPtr->bTopLevel) {
+ openavb_aem_configuration_t *pConfig = openavbArrayDataIdx(pAemEntityModel->aemConfigurations, configIdx);
+ if (!pConfig) {
+ AVB_RC_LOG(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT);
+ AVB_LOGF_ERROR("Invalid configuration index %u", configIdx);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+ descriptors = pConfig->descriptorsArray[pDescriptorCommon->descriptor_type];
+
+ if (!descriptors) {
+ // Create array for this type of descriptor in this configuration
+ AVB_LOGF_DEBUG("Created description array for configuration %u, type 0x%04x", configIdx, pDescriptorCommon->descriptor_type);
+ descriptors = openavbArrayNewArray(pDescriptorCommon->descriptorPvtPtr->size);
+ pConfig->descriptorsArray[pDescriptorCommon->descriptor_type] = descriptors;
+ }
+ } else {
+ descriptors = pAemEntityModel->aemNonTopLevelDescriptorsArray[pDescriptorCommon->descriptor_type];
+
+ if (!descriptors) {
+ // Create array for this type of descriptor in this configuration
+ AVB_LOGF_DEBUG("Created non-top-level description array for type 0x%04x", pDescriptorCommon->descriptor_type);
+ descriptors = openavbArrayNewArray(pDescriptorCommon->descriptorPvtPtr->size);
+ pAemEntityModel->aemNonTopLevelDescriptorsArray[pDescriptorCommon->descriptor_type] = descriptors;
+ }
+ }
+
+ if (descriptors) {
+ if (openavbArrayFindData(descriptors, pDescriptor) >= 0) {
+ AVB_LOGF_ERROR("Attempted to add same descriptor (type 0x%04x) twice", pDescriptorCommon->descriptor_type);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ openavb_array_elem_t elem = openavbArrayAdd(descriptors, pDescriptor);
+ if (elem) {
+ *pResultIdx = openavbArrayGetIdx(elem);
+ pDescriptorCommon->descriptor_index = *pResultIdx;
+ if (pDescriptorCommon->descriptorPvtPtr->bTopLevel) {
+ if (!IS_OPENAVB_SUCCESS(openavbAemAddDescriptorToConfiguration(pDescriptorCommon->descriptor_type, configIdx))) {
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+}
+
+extern DLL_EXPORT void *openavbAemGetDescriptor(U16 configIdx, U16 descriptorType, U16 descriptorIdx)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+ void *retDescriptor = NULL;
+
+ retDescriptor = openavbAemFindDescriptor(configIdx, descriptorType, descriptorIdx);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return retDescriptor;
+}
+
+extern DLL_EXPORT U16 openavbAemGetDescriptorIndex(U16 configIdx, const void *pDescriptor)
+{
+ const openavb_aem_descriptor_common_t *pDescriptorCommon = pDescriptor;
+ U16 descriptorIdx = 0;
+ void * pTest;
+
+ if (!pDescriptorCommon) { return OPENAVB_AEM_DESCRIPTOR_INVALID; }
+
+ do {
+ pTest = openavbAemFindDescriptor(configIdx, pDescriptorCommon->descriptor_type, descriptorIdx);
+ if (pTest == pDescriptor) { return descriptorIdx; }
+ descriptorIdx++;
+ } while (pTest != NULL);
+
+ return OPENAVB_AEM_DESCRIPTOR_INVALID;
+}
+
+extern DLL_EXPORT bool openavbAemSetString(U8 *pMem, const char *pString)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (pMem && pString) {
+ U32 len = strlen(pString);
+ if (len > OPENAVB_AEM_STRLEN_MAX) {
+ len = OPENAVB_AEM_STRLEN_MAX;
+ } else if (len < OPENAVB_AEM_STRLEN_MAX) {
+ memset(pMem + len, 0, OPENAVB_AEM_STRLEN_MAX - len);
+ }
+ memcpy(pMem, pString, len); // Per 1722.1 it is allowable that the AEM string may not be null terminated.
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+}
+
+extern DLL_EXPORT bool openavbAemIsAcquired()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+ AEM_LOCK();
+ bool bResult = pAemEntityModel->entityAcquired;
+ AEM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return bResult;
+}
+
+extern DLL_EXPORT bool openavbAemIsLocked()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+ AEM_LOCK();
+ bool bResult = pAemEntityModel->entityLocked;
+ AEM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return bResult;
+}
+
+extern DLL_EXPORT bool openavbAemAcquire(bool flag)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+ AEM_LOCK();
+ bool bResult = FALSE;
+ if (flag) {
+ if (!pAemEntityModel->entityAcquired) {
+ *(pAemEntityModel->acquiredControllerId) = (U64)0x0000000000000000L;
+ pAemEntityModel->entityAcquired = TRUE;
+ bResult = TRUE;
+ }
+ }
+ else {
+ if (pAemEntityModel->entityAcquired) {
+ if ((U64)*pAemEntityModel->acquiredControllerId == 0x0000000000000000L) {
+ // Only unacquire if controller ID is zero.
+ pAemEntityModel->entityAcquired = FALSE;
+ bResult = TRUE;
+ }
+ }
+ }
+ AEM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return bResult;
+}
+
+extern DLL_EXPORT bool openavbAemLock(bool flag)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+ AEM_LOCK();
+ bool bResult = FALSE;
+ if (flag) {
+ if (!pAemEntityModel->entityLocked) {
+ *(pAemEntityModel->lockedControllerId) = (U64)0x0000000000000000L;
+ pAemEntityModel->entityLocked = TRUE;
+ bResult = TRUE;
+ }
+ }
+ else {
+ if (pAemEntityModel->entityLocked) {
+ if ((U64)*pAemEntityModel->lockedControllerId == 0x0000000000000000L) {
+ // Only unlock if controller ID is zero.
+ pAemEntityModel->entityLocked = FALSE;
+ bResult = TRUE;
+ }
+ }
+ }
+ AEM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return bResult;
+}
+
diff --git a/lib/avtp_pipeline/aem/openavb_aem.h b/lib/avtp_pipeline/aem/openavb_aem.h
new file mode 100644
index 00000000..acd8ec33
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_aem.h
@@ -0,0 +1,103 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Entity Model
+ * MODULE SUMMARY : Implements the 1722.1 (AVDECC) Entity Model
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_AEM_H
+#define OPENAVB_AEM_H 1
+
+#include "openavb_array.h"
+#include "openavb_avdecc.h"
+#include "openavb_aem_pub.h"
+#include "openavb_types_pub.h"
+#include "openavb_result_codes.h"
+#include "openavb_endpoint.h"
+
+typedef openavbRC (*openavb_aem_descriptor_to_buf_t)(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize);
+typedef openavbRC (*openavb_aem_descriptor_from_buf_t)(void *pVoidDescriptor, U16 bufLength, U8 *pBuf);
+typedef openavbRC (*openavb_aem_descriptor_update_t)(void *pVoidDescriptor);
+
+struct openavb_descriptor_pvt {
+ U32 size;
+ bool bTopLevel; // See IEEE Std 1722.1-2013 clause 7.2.2 for a list of top level descriptors.
+ openavb_aem_descriptor_to_buf_t toBuf;
+ openavb_aem_descriptor_from_buf_t fromBuf;
+ openavb_aem_descriptor_update_t update;
+};
+
+// Every descriptor must begin with these same members. The structure isn't embedded to make hosting applications cleaner.
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aem_descriptor_common_t;
+
+typedef struct {
+ openavb_aem_descriptor_configuration_t *pDescriptorConfiguration;
+ openavb_array_t descriptorsArray[OPENAVB_AEM_DESCRIPTOR_COUNT];
+} openavb_aem_configuration_t;
+
+typedef struct {
+ openavb_aem_descriptor_entity_t *pDescriptorEntity;
+ bool entityAcquired;
+ U8 acquiredControllerId[8];
+ bool entityLocked;
+ U8 lockedControllerId[8];
+
+ openavb_array_t aemConfigurations;
+ openavb_array_t aemNonTopLevelDescriptorsArray[OPENAVB_AEM_DESCRIPTOR_COUNT];
+} openavb_avdecc_entity_model_t;
+
+
+// Create the Entity Model
+openavbRC openavbAemCreate(openavb_aem_descriptor_entity_t *pDescriptorEntity);
+
+// Destory the Entity Model
+openavbRC openavbAemDestroy(void);
+
+// Return the Entity Model
+openavb_avdecc_entity_model_t *openavbAemGetModel(void);
+
+// Checks if the Entity Model is valid
+bool openavbAemCheckModel(bool bLog);
+
+// Return the array of descriptors for a specific descroptor type for the specified configuration.
+openavb_array_t openavbAemGetDescriptorArray(U16 configIdx, U16 descriptorType);
+
+// Serialize a descriptor into a buffer. pBuf is filled with the descriptor data. descriptorSize is set to the size of the data placed into the buffer.
+openavbRC openavbAemSerializeDescriptor(U16 configIdx, U16 descriptorType, U16 descriptorIdx, U16 bufSize, U8 *pBuf, U16 *descriptorSize);
+
+#endif // OPENAVB_AEM_H
diff --git a/lib/avtp_pipeline/aem/openavb_aem_pub.h b/lib/avtp_pipeline/aem/openavb_aem_pub.h
new file mode 100644
index 00000000..b5c206c3
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_aem_pub.h
@@ -0,0 +1,80 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Entity Model Public Interface
+ * MODULE SUMMARY : Public Interface for the AVDECC Entity Model Functionality
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_AEM_PUB_H
+#define OPENAVB_AEM_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+
+typedef struct openavb_descriptor_pvt *openavb_descriptor_pvt_ptr_t;
+
+typedef struct openavb_avdecc_configuration_cfg openavb_avdecc_configuration_cfg_t;
+
+// Before calling any Entity Model functions the AVDECC function openavbAvdeccInitialize() must be called with the Entity Descriptor.
+// The Entity Descriptor is the root of all descriptors and must exist to do most things in AVDECC.
+
+// Gets the current configuration descriptor index for the Entity Model. Error checking is not performed on this function.
+U16 openavbAemGetConfigIdx(void);
+
+// Adds descriptors to the Entity Model. The Configuration Descriptor must be added first.
+bool openavbAemAddDescriptor(void *pDescriptor, U16 configIdx, U16 *pResultIdx);
+
+// Get a pointer to a descriptor in the Entity Model.
+void *openavbAemGetDescriptor(U16 configIdx, U16 descriptorType, U16 descriptorIdx);
+
+// Get the index of the descriptor in the Entity Model, or OPENAVB_AEM_DESCRIPTOR_INVALID if not found.
+U16 openavbAemGetDescriptorIndex(U16 configIdx, const void *pDescriptor);
+
+// Add a string to a standard descriptor U8 [64] string field.
+bool openavbAemSetString(U8 *pMem, const char *pString);
+
+// Checks if the Entity Model is acquired.
+bool openavbAemIsAcquired(void);
+
+// Checks if the Entity Model is locked.
+bool openavbAemIsLocked(void);
+
+// Sets the internal Entity Model acquired flag. Care should be used with this function it can impact controller access.
+bool openavbAemAcquire(bool flag);
+
+// Sets the internal Entity Model acquired flag. Care should be used with this function it can impact controller access.
+bool openavbAemLock(bool flag);
+
+
+#endif // OPENAVB_AEM_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_aem_types_pub.h b/lib/avtp_pipeline/aem/openavb_aem_types_pub.h
new file mode 100644
index 00000000..71c29c28
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_aem_types_pub.h
@@ -0,0 +1,1339 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Entity Model Types
+ * MODULE SUMMARY : AVDECC Entity Model Types
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_AEM_TYPES_PUB_H
+#define OPENAVB_AEM_TYPES_PUB_H 1
+
+#include "openavb_types_pub.h"
+
+#define OPENAVB_AEM_STRLEN_MAX (64)
+
+// Descriptors IEEE Std 1722.1-2013 clause 7.2
+#define OPENAVB_AEM_DESCRIPTOR_ENTITY (0x0000)
+#define OPENAVB_AEM_DESCRIPTOR_CONFIGURATION (0x0001)
+#define OPENAVB_AEM_DESCRIPTOR_AUDIO_UNIT (0x0002)
+#define OPENAVB_AEM_DESCRIPTOR_VIDEO_UNIT (0x0003)
+#define OPENAVB_AEM_DESCRIPTOR_SENSOR_UNIT (0x0004)
+#define OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT (0x0005)
+#define OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT (0x0006)
+#define OPENAVB_AEM_DESCRIPTOR_JACK_INPUT (0x0007)
+#define OPENAVB_AEM_DESCRIPTOR_JACK_OUTPUT (0x0008)
+#define OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE (0x0009)
+#define OPENAVB_AEM_DESCRIPTOR_CLOCK_SOURCE (0x000a)
+#define OPENAVB_AEM_DESCRIPTOR_MEMORY_OBJECT (0x000b)
+#define OPENAVB_AEM_DESCRIPTOR_LOCALE (0x000c)
+#define OPENAVB_AEM_DESCRIPTOR_STRINGS (0x000d)
+#define OPENAVB_AEM_DESCRIPTOR_STREAM_PORT_INPUT (0x000e)
+#define OPENAVB_AEM_DESCRIPTOR_STREAM_PORT_OUTPUT (0x000f)
+#define OPENAVB_AEM_DESCRIPTOR_EXTERNAL_PORT_INPUT (0x0010)
+#define OPENAVB_AEM_DESCRIPTOR_EXTERNAL_PORT_OUTPUT (0x0011)
+#define OPENAVB_AEM_DESCRIPTOR_INTERNAL_PORT_INPUT (0x0012)
+#define OPENAVB_AEM_DESCRIPTOR_INTERNAL_PORT_OUTPUT (0x0013)
+#define OPENAVB_AEM_DESCRIPTOR_AUDIO_CLUSTER (0x0014)
+#define OPENAVB_AEM_DESCRIPTOR_VIDEO_CLUSTER (0x0015)
+#define OPENAVB_AEM_DESCRIPTOR_SENSOR_CLUSTER (0x0016)
+#define OPENAVB_AEM_DESCRIPTOR_AUDIO_MAP (0x0017)
+#define OPENAVB_AEM_DESCRIPTOR_VIDEO_MAP (0x0018)
+#define OPENAVB_AEM_DESCRIPTOR_SENSOR_MAP (0x0019)
+#define OPENAVB_AEM_DESCRIPTOR_CONTROL (0x001a)
+#define OPENAVB_AEM_DESCRIPTOR_SIGNAL_SELECTOR (0x001b)
+#define OPENAVB_AEM_DESCRIPTOR_MIXER (0x001c)
+#define OPENAVB_AEM_DESCRIPTOR_MATRIX (0x001d)
+#define OPENAVB_AEM_DESCRIPTOR_MATRIX_SIGNAL (0x001e)
+#define OPENAVB_AEM_DESCRIPTOR_SIGNAL_SPLITTER (0x001f)
+#define OPENAVB_AEM_DESCRIPTOR_SIGNAL_COMBINER (0x0020)
+#define OPENAVB_AEM_DESCRIPTOR_SIGNAL_DEMULTIPLEXER (0x0021)
+#define OPENAVB_AEM_DESCRIPTOR_SIGNAL_MULTIPLEXER (0x0022)
+#define OPENAVB_AEM_DESCRIPTOR_SIGNAL_TRANSCODER (0x0023)
+#define OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN (0x0024)
+#define OPENAVB_AEM_DESCRIPTOR_CONTROL_BLOCK (0x0025)
+#define OPENAVB_AEM_DESCRIPTOR_INVALID (0xffff)
+
+// This is the total number of decriptor types
+#define OPENAVB_AEM_DESCRIPTOR_COUNT (OPENAVB_AEM_DESCRIPTOR_CONTROL_BLOCK + 1)
+
+
+// Stream flags IEEE Std 1722.1-2013 clause 7.2.6.1
+#define OPENAVB_AEM_STREAM_FLAG_CLOCK_SYNC_SOURCE (0x0001)
+#define OPENAVB_AEM_STREAM_FLAG_CLASS_A (0x0002)
+#define OPENAVB_AEM_STREAM_FLAG_CLASS_B (0x0004)
+#define OPENAVB_AEM_STREAM_FLAG_SUPPORTS_ENCRYPTED (0x0008)
+#define OPENAVB_AEM_STREAM_FLAG_PRIMARY_BACKUP_SUPPORTED (0x0010)
+#define OPENAVB_AEM_STREAM_FLAG_PRIMARY_BACKUP_VALID (0x0020)
+#define OPENAVB_AEM_STREAM_FLAG_SECONDARY_BACKUP_SUPPORTED (0x0040)
+#define OPENAVB_AEM_STREAM_FLAG_SECONDARY_BACKUP_VALID (0x0080)
+#define OPENAVB_AEM_STREAM_FLAG_TERTIARY_BACKUP_SUPPORTED (0x0100)
+#define OPENAVB_AEM_STREAM_FLAG_TERTIARY_BACKUP_VALID (0x0200)
+
+// Jack Flags IEEE Std 1722.1-2013 clause 7.2.7.1
+#define OPENAVB_AEM_JACK_FLAG_CLOCK_SYNC_SOURCE (0x0001)
+#define OPENAVB_AEM_JACK_FLAG_CAPTIVE (0x0002)
+
+// Jack Types IEEE Std 1722.1-2013 clause 7.2.7.2
+#define OPENAVB_AEM_JACK_TYPE_SPEAKER (0x0000)
+#define OPENAVB_AEM_JACK_TYPE_HEADPHONE (0x0001)
+#define OPENAVB_AEM_JACK_TYPE_ANALOG_MICROPHONE (0x0002)
+#define OPENAVB_AEM_JACK_TYPE_SPDIF (0x0003)
+#define OPENAVB_AEM_JACK_TYPE_ADAT (0x0004)
+#define OPENAVB_AEM_JACK_TYPE_TDIF (0x0005)
+#define OPENAVB_AEM_JACK_TYPE_MADI (0x0006)
+#define OPENAVB_AEM_JACK_TYPE_UNBALANCED_ANALOG (0x0007)
+#define OPENAVB_AEM_JACK_TYPE_BALANCED_ANALOG (0x0008)
+#define OPENAVB_AEM_JACK_TYPE_DIGITAL (0x0009)
+#define OPENAVB_AEM_JACK_TYPE_MIDI (0x000a)
+#define OPENAVB_AEM_JACK_TYPE_AES_EBU (0x000b)
+#define OPENAVB_AEM_JACK_TYPE_COMPOSITE_VIDEO (0x000c)
+#define OPENAVB_AEM_JACK_TYPE_S_VHS_VIDEO (0x000d)
+#define OPENAVB_AEM_JACK_TYPE_COMPONENT_VIDEO (0x000e)
+#define OPENAVB_AEM_JACK_TYPE_DVI (0x000f)
+#define OPENAVB_AEM_JACK_TYPE_HDMI (0x0010)
+#define OPENAVB_AEM_JACK_TYPE_UDI (0x0011)
+#define OPENAVB_AEM_JACK_TYPE_DISPLAYPORT (0x0012)
+#define OPENAVB_AEM_JACK_TYPE_ANTENNA (0x0013)
+#define OPENAVB_AEM_JACK_TYPE_ANALOG_TUNER (0x0014)
+#define OPENAVB_AEM_JACK_TYPE_ETHERNET (0x0015)
+#define OPENAVB_AEM_JACK_TYPE_WIFI (0x0016)
+#define OPENAVB_AEM_JACK_TYPE_USB (0x0017)
+#define OPENAVB_AEM_JACK_TYPE_PCI (0x0018)
+#define OPENAVB_AEM_JACK_TYPE_PCI_E (0x0019)
+#define OPENAVB_AEM_JACK_TYPE_SCSI (0x001a)
+#define OPENAVB_AEM_JACK_TYPE_ATA (0x001b)
+#define OPENAVB_AEM_JACK_TYPE_IMAGER (0x001c)
+#define OPENAVB_AEM_JACK_TYPE_IR (0x001d)
+#define OPENAVB_AEM_JACK_TYPE_THUNDERBOLT (0x001e)
+#define OPENAVB_AEM_JACK_TYPE_SATA (0x001f)
+#define OPENAVB_AEM_JACK_TYPE_SMPTE_LTC (0x0020)
+#define OPENAVB_AEM_JACK_TYPE_DIGITAL_MICROPHONE (0x0021)
+#define OPENAVB_AEM_JACK_TYPE_AUDIO_MEDIA_CLOCK (0x0022)
+#define OPENAVB_AEM_JACK_TYPE_VIDEO_MEDIA_CLOCK (0x0023)
+#define OPENAVB_AEM_JACK_TYPE_GNSS_CLOCK (0x0024)
+#define OPENAVB_AEM_JACK_TYPE_PPS (0x0025)
+#define OPENAVB_AEM_JACK_TYPE_EXPANSION (0xffff)
+
+// Interface Types IEEE Std 1722.1-2013 clause 7.2.8.1
+#define OPENAVB_AEM_INTERFACE_TYPE_GPTP_GRANDMASTER_SUPPORTED (0x0001)
+#define OPENAVB_AEM_INTERFACE_TYPE_GPTP_SUPPORTED (0x0002)
+#define OPENAVB_AEM_INTERFACE_TYPE_SRP_SUPPORTED (0x0004)
+
+// Clock Source Flags IEEE Std 1722.1-2013 clause 7.2.9.1
+#define OPENAVB_AEM_CLOCK_SOURCE_FLAG_STREAM_ID (0x0001)
+#define OPENAVB_AEM_CLOCK_SOURCE_FLAG_LOCAL_ID (0x0002)
+
+// Clock Source Types IEEE Std 1722.1-2013 clause 7.2.9.2
+#define OPENAVB_AEM_CLOCK_SOURCE_TYPE_INTERNAL (0x0000)
+#define OPENAVB_AEM_CLOCK_SOURCE_TYPE_EXTERNAL (0x0001)
+#define OPENAVB_AEM_CLOCK_SOURCE_TYPE_INPUT_STREAM (0x0002)
+#define OPENAVB_AEM_CLOCK_SOURCE_TYPE_EXPANSION (0xffff)
+
+// Memory Object Types IEEE Std 1722.1-2013 clause 7.2.10.1
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_FIRMWARE_IMAGE (0x0000)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_VENDOR_SPECIFIC (0x0001)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_CRASH_DUMP (0x0002)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_LOG_OBJECT (0x0003)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_AUTOSTART_SETTINGS (0x0004)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_SNAPSHOT_SETTINGS (0x0005)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_SVG_MANUFACTURER (0x0006)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_SVG_ENTITY (0x0007)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_SVG_GENERIC (0x0008)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_PNG_MANUFACTURER (0x0009)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_PNG_ENTITY (0x000a)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_PNG_GENERIC (0x000b)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_DAE_MANUFACTURER (0x000c)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_DAE_ENTITY (0x000d)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_DAE_GENERIC (0x000e)
+
+// Memory Object Operation Types IEEE Std 1722.1-2013 clause 7.2.10.2
+#define OPENAVB_AEM_MEMORY_OBJECT_OPERATION_TYPE_STORE (0x0000)
+#define OPENAVB_AEM_MEMORY_OBJECT_OPERATION_TYPE_STORE_AND_REBOOT (0x0001)
+#define OPENAVB_AEM_MEMORY_OBJECT_OPERATION_TYPE_READ (0x0002)
+#define OPENAVB_AEM_MEMORY_OBJECT_OPERATION_TYPE_ERASE (0x0003)
+#define OPENAVB_AEM_MEMORY_OBJECT_OPERATION_TYPE_UPLOAD (0x0004)
+
+// Port Flags IEEE Std 1722.1-2013 clause 7.2.13.1
+#define OPENAVB_AEM_PORT_FLAG_CLOCK_SYNC_SOURCE (0x0001)
+#define OPENAVB_AEM_PORT_FLAG_ASYNC_SAMPLE_RATE_CONV (0x0002)
+#define OPENAVB_AEM_PORT_FLAG_SYNC_SAMPLE_RATE_CONV (0x0004)
+
+// Audio Cluster Formats IEEE Std 1722.1-2013 clause 7.2.16.1
+#define OPENAVB_AEM_AUDIO_CLUSTER_FORMAT_IEC_60958 (0x00)
+#define OPENAVB_AEM_AUDIO_CLUSTER_FORMAT_MBLA (0x40)
+#define OPENAVB_AEM_AUDIO_CLUSTER_FORMAT_MIDI (0x80)
+#define OPENAVB_AEM_AUDIO_CLUSTER_FORMAT_SMPTE (0x88)
+
+// Video Cluster Formats IEEE Std 1722.1-2013 clause 7.2.17.1
+#define OPENAVB_AEM_VIDEO_CLUSTER_FORMAT_MPEG_PES_FORMAT (0x00)
+#define OPENAVB_AEM_VIDEO_CLUSTER_FORMAT_AVTP_FORMAT (0x01)
+#define OPENAVB_AEM_VIDEO_CLUSTER_FORMAT_RTP_PAYLOAD_FORMAT (0x02)
+#define OPENAVB_AEM_VIDEO_CLUSTER_FORMAT_VENDOR_SPECIFIC_FORMAT (0xfe)
+#define OPENAVB_AEM_VIDEO_CLUSTER_FORMAT_EXPERIMENTAL_FORMAT (0xff)
+
+// Control Value Type Max Counts IEEE Std 1722.1-2013 clause 7.2.22
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT8 (40)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT8 (40)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT16 (25)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT16 (25)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT32 (14)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT32 (14)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT64 (7)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT64 (7)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_FLOAT (14)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_DOUBLE (7)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT8 (400)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT8 (400)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT16 (199)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT16 (199)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT32 (98)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT32 (98)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT64 (48)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT64 (48)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_FLOAT (98)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_DOUBLE (48)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_STRING (199)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT8 (396)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT8 (396)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT16 (196)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT16 (196)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT32 (96)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT32 (96)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT64 (46)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT64 (46)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_FLOAT (96)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_DOUBLE (46)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_UTF8 (1)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_BODE_PLOT (29)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SMPTE_TIME (1)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SAMPLE_RATE (1)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_GPTP_TIME (1)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_VENDOR (1)
+
+// Control Value Type Max Sources IEEE Std 1722.1-2013 clause 7.2.24
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_INT8 (68)
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_UINT8 (68)
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_INT16 (67)
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_UINT16 (67)
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_INT32 (65)
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_UINT32 (65)
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_INT64 (61)
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_UINT64 (61)
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_FLOAT (65)
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_DOUBLE (61)
+
+// Matrix Control Value Type Max Counts IEEE Std 1722.1-2013 clause 7.2.25
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT32 (14)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_LINEAR_INT64 (7)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT64 (7)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_LINEAR_FLOAT (14)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_LINEAR_DOUBLE (7)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT8 (400)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT8 (400)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT16 (199)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT16 (199)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT32 (98)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT32 (98)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT64 (48)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT64 (48)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_FLOAT (98)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_DOUBLE (48)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_UTF8 (1)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_BODE_PLOT (29)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_INT8 (396)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT8 (396)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_INT16 (196)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT16 (196)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_INT32 (96)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT32 (96)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_INT64 (46)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT64 (46)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_FLOAT (96)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_DOUBLE (46)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_STRING (199)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SMPTE_TIME (1)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SAMPLE_RATE (1)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_GPTP_TIME (1)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_VENDOR (1)
+
+// Transcoder Control Value Type Max Counts IEEE Std 1722.1-2013 clause 7.2.31
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_INT8 (41)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT8 (41)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_INT16 (26)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT16 (26)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_INT32 (14)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT32 (14)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_INT64 (8)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT64 (8)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_FLOAT (14)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_DOUBLE (8)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT8 (412)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT8 (412)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT16 (205)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT16 (205)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT32 (101)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT32 (101)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT64 (49)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT64 (49)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_FLOAT (101)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_DOUBLE (49)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_INT8 (408)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT8 (408)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_INT16 (202)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT16 (202)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_INT32 (99)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT32 (99)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_INT64 (47)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT64 (47)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_FLOAT (99)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_DOUBLE (47)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_STRING (205)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SAMPLE_RATE (1)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_VENDOR (1)
+
+// Sample rates IEEE Std 1722.1-2013 clause 7.3.1
+typedef struct {
+ U8 pull;
+ U32 base;
+} openavb_aem_sampling_rate_t;
+
+// Sample rate pull field IEEE Std 1722.1-2013 clause 7.3.1.1
+#define OPENAVB_AEM_SAMPLE_RATE_PULL_MULTI_BASE_FREQ_BY_1_0 (0)
+#define OPENAVB_AEM_SAMPLE_RATE_PULL_MULTI_BASE_FREQ_BY_1_DIV_1_001 (1)
+#define OPENAVB_AEM_SAMPLE_RATE_PULL_MULTI_BASE_FREQ_BY_1_001 (2)
+#define OPENAVB_AEM_SAMPLE_RATE_PULL_MULTI_BASE_FREQ_BY_24_DIV_25 (3)
+#define OPENAVB_AEM_SAMPLE_RATE_PULL_MULTI_BASE_FREQ_BY_25_DIV_24 (4)
+
+// Stream formats : IIDC IEEE Std 1722.1-2013 clause 7.3.2.1.1.1
+typedef struct {
+ U8 sf;
+} openavb_aem_stream_format_iec_61883_iidc_t;
+
+// Stream formats : IIDC IEEE Std 1722.1-2013 clause 7.3.2.1.1.1
+typedef struct {
+ U8 sf;
+ U8 iidc_format;
+ U8 iidc_mode;
+ U8 iidc_rate;
+} openavb_aem_stream_format_iidc_t;
+
+// Stream formats : IEC 61883 IEEE Std 1722.1-2013 clause 7.3.2.1.1.1
+typedef struct {
+ U8 sf;
+ U8 fmt;
+} openavb_aem_stream_format_iec_61883_t;
+
+// Stream formats : IEC 61883-4 IEEE Std 1722.1-2013 clause 7.3.2.1.1.2
+typedef struct {
+ U8 sf;
+ U8 fmt;
+} openavb_aem_stream_format_iec_61883_4_t;
+
+// Stream formats : IEC 61883-6 IEEE Std 1722.1-2013 clause 7.3.2.1.1.4
+typedef struct {
+ U8 sf;
+ U8 fmt;
+ U8 fdf_evt;
+ U8 fdf_sfc;
+ U8 dbs;
+ U8 b;
+ U8 nb;
+} openavb_aem_stream_format_iec_61883_6_t;
+
+// Stream formats : IEC 61883-6 32 bit IEEE Std 1722.1-2013 clause 7.3.2.1.1.4
+typedef struct {
+ U8 sf;
+ U8 fmt;
+ U8 fdf_evt;
+ U8 fdf_sfc;
+ U8 dbs;
+ U8 b;
+ U8 nb;
+} openavb_aem_stream_format_iec_61883_6_32bit_t;
+
+// Stream formats : IEC 61883-6 float IEEE Std 1722.1-2013 clause 7.3.2.1.1.5
+typedef struct {
+ U8 sf;
+ U8 fmt;
+ U8 fdf_evt;
+ U8 fdf_sfc;
+ U8 dbs;
+ U8 b;
+ U8 nb;
+} openavb_aem_stream_format_iec_61883_6_float_t;
+
+// Stream formats : IEC 61883-6 float IEEE Std 1722.1-2013 clause 7.3.2.1.1.6
+typedef struct {
+ U8 sf;
+ U8 fmt;
+ U8 fdf_evt;
+ U8 fdf_sfc;
+ U8 dbs;
+ U8 b;
+ U8 nb;
+ U8 label_iec_60958_cnt;
+ U8 label_mbla_cnt;
+ U8 label_midi_cnt;
+ U8 label_smptecnt;
+} openavb_aem_stream_format_iec_61883_6_am824_t;
+
+// Stream formats : IEC 61883-8 IEEE Std 1722.1-2013 clause 7.3.2.1.1.7
+typedef struct {
+ U8 sf;
+ U8 fmt;
+ U8 video_mode;
+ U8 compress_mode;
+ U8 color_space;
+} openavb_aem_stream_format_iec_61883_8_t;
+
+// Stream formats : AVTP Audio IEEE Std 1722.1-2013 clause 7.3.2.1.3
+typedef struct {
+ U8 nominal_sample_rate;
+ U8 format;
+ U8 bit_depth;
+ U16 channels_per_frame;
+ U16 samples_per_frame;
+} openavb_aem_stream_format_avtp_audio_t;
+
+// Stream formats : AVTP Video IEEE Std 1722.1-2013 clause 7.3.2.1.4
+typedef struct {
+ U8 format;
+} openavb_aem_stream_format_avtp_video_t;
+
+// Stream formats : AVTP Control IEEE Std 1722.1-2013 clause 7.3.2.1.5
+typedef struct {
+ U8 protocol_type;
+ U8 format_id[6];
+} openavb_aem_stream_format_avtp_control_t;
+
+// Stream formats : Vendor IEEE Std 1722.1-2013 clause 7.3.2.1.6
+typedef struct {
+ U8 format_id[6];
+} openavb_aem_stream_format_vendor_t;
+
+// Stream formats : Experimental IEEE Std 1722.1-2013 clause 7.3.2.1.7
+typedef struct {
+} openavb_aem_stream_format_experimental_t;
+
+// Stream formats : Vendor Specific IEEE Std 1722.1-2013 clause 7.3.2.2.1
+typedef struct {
+ U8 format_id[6];
+} openavb_aem_stream_format_vendor_specific_t;
+
+// Stream formats IEEE Std 1722.1-2013 clause 7.3.2
+typedef struct {
+ U8 v;
+ U8 subtype;
+ union {
+ openavb_aem_stream_format_iec_61883_iidc_t iec_61883_iidc;
+ openavb_aem_stream_format_iidc_t iidc;
+ openavb_aem_stream_format_iec_61883_t iec_61883;
+ openavb_aem_stream_format_iec_61883_4_t iec_61883_4;
+ openavb_aem_stream_format_iec_61883_6_32bit_t iec_61883_6;
+ openavb_aem_stream_format_iec_61883_6_32bit_t iec_61883_6_32bit;
+ openavb_aem_stream_format_iec_61883_6_float_t iec_61883_6_float;
+ openavb_aem_stream_format_iec_61883_6_am824_t iec_61883_6_am824;
+ openavb_aem_stream_format_iec_61883_8_t iec_61883_8;
+ openavb_aem_stream_format_avtp_audio_t avtp_audio;
+ openavb_aem_stream_format_avtp_video_t avtp_video;
+ openavb_aem_stream_format_avtp_control_t avtp_control;
+ openavb_aem_stream_format_vendor_t vendor;
+ openavb_aem_stream_format_experimental_t experimental;
+ openavb_aem_stream_format_vendor_specific_t vendor_specific;
+ } subtypes;
+} openavb_aem_stream_format_t;
+
+
+#define OPENAVB_AEM_STREAM_FORMAT_SF_IIDC (0x00)
+#define OPENAVB_AEM_STREAM_FORMAT_SF_IEC_61883 (0x00)
+
+#define OPENAVB_AEM_STREAM_FORMAT_FMT_61883_4 (0x20)
+#define OPENAVB_AEM_STREAM_FORMAT_FMT_61883_6 (0x10)
+#define OPENAVB_AEM_STREAM_FORMAT_FMT_61883_8 (0x01)
+
+#define OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_AM824 (0x00)
+#define OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_32BITS (0x06)
+#define OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_FLOAT (0x04)
+
+
+// Stream formats IEEE Std 1722.1-2013 clause 7.3.2.1
+#define OPENAVB_AEM_STREAM_FORMAT_61883_IIDC_SUBTYPE (0x00)
+#define OPENAVB_AEM_STREAM_FORMAT_MMA_SUBTYPE (0x01)
+#define OPENAVB_AEM_STREAM_FORMAT_AVTP_AUDIO_SUBTYPE (0x02)
+#define OPENAVB_AEM_STREAM_FORMAT_AVTP_VIDEO_SUBTYPE (0x03)
+#define OPENAVB_AEM_STREAM_FORMAT_AVTP_CONTROL_SUBTYPE (0x04)
+#define OPENAVB_AEM_STREAM_FORMAT_VENDOR_SUBTYPE (0x6f)
+#define OPENAVB_AEM_STREAM_FORMAT_EXPERIMENTAL_SUBTYPE (0x7f)
+
+// AVTP Audio Stream Sample Rates IEEE Std 1722.1-2013 7.3.2.1.3
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_NOT_SPECIFIED (0x0)
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_8_KHZ (0x1)
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_16_KHZ (0x2)
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_32_KHZ (0x3)
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_44_1_KHZ (0x4)
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_48_KHZ (0x5)
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_88_2_KHZ (0x6)
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_96_KHZ (0x7)
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_176_4_KHZ (0x8)
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_192_KHZ (0x9)
+
+// AVTP Audio Stream Format IEEE Std 1722.1-2013 7.3.2.1.3
+#define OPENAVB_AEM_AUDIO_STREAM_FORMAT_NOT_SPECIFIED (0)
+#define OPENAVB_AEM_AUDIO_STREAM_FORMAT_FLOAT (1)
+#define OPENAVB_AEM_AUDIO_STREAM_FORMAT_32BIT_INTEGER (2)
+#define OPENAVB_AEM_AUDIO_STREAM_FORMAT_24BIT_PACKED_INTEGER (3)
+#define OPENAVB_AEM_AUDIO_STREAM_FORMAT_16BIT_INTEGER (4)
+
+// AVTP Video Stream Format IEEE Std 1722.1-2013 7.3.2.1.4
+#define OPENAVB_AEM_VIDEO_STREAM_FORMAT_RESERVED (0x00)
+#define OPENAVB_AEM_VIDEO_STREAM_FORMAT_AVTP_FORMAT (0x01)
+#define OPENAVB_AEM_VIDEO_STREAM_FORMAT_RTP_PAYLOAD_TYPE (0x02)
+#define OPENAVB_AEM_VIDEO_STREAM_FORMAT_VENDOR_SPECIFIC (0xfe)
+#define OPENAVB_AEM_VIDEO_STREAM_FORMAT_EXPERIMENTAL (0xff)
+
+// AVTP Control Stream Format IEEE Std 1722.1-2013 7.3.2.1.5
+#define OPENAVB_AEM_CONTROL_STREAM_FORMAT_AUTOMOTIVE (0)
+#define OPENAVB_AEM_CONTROL_STREAM_FORMAT_TSCS (3)
+#define OPENAVB_AEM_CONTROL_STREAM_FORMAT_VENDOR_DEFINED (15)
+
+// Control Value Units IEEE Std 1722.1-2013 clause 7.3.3
+#define OPENAVB_AEM_UNIT_UNITLESS (0x00)
+#define OPENAVB_AEM_UNIT_UNITLESS_COUNT (0x01)
+#define OPENAVB_AEM_UNIT_UNITLESS_PERCENT (0x02)
+#define OPENAVB_AEM_UNIT_UNITLESS_FSTOP (0x03)
+#define OPENAVB_AEM_UNIT_TIME_SECONDS (0x08)
+#define OPENAVB_AEM_UNIT_TIME_MINUTES (0x09)
+#define OPENAVB_AEM_UNIT_TIME_HOURS (0x0a)
+#define OPENAVB_AEM_UNIT_TIME_DAYS (0x0b)
+#define OPENAVB_AEM_UNIT_TIME_MONTHS (0x0c)
+#define OPENAVB_AEM_UNIT_TIME_YEARS (0x0d)
+#define OPENAVB_AEM_UNIT_TIME_SAMPLES (0x0e)
+#define OPENAVB_AEM_UNIT_TIME_FRAMES (0x0f)
+#define OPENAVB_AEM_UNIT_FREQUENCY_HERTZ (0x10)
+#define OPENAVB_AEM_UNIT_FREQUENCY_SEMITONES (0x11)
+#define OPENAVB_AEM_UNIT_FREQUENCY_CENTS (0x12)
+#define OPENAVB_AEM_UNIT_FREQUENCY_OCTAVES (0x13)
+#define OPENAVB_AEM_UNIT_FREQUENCY_FPS (0x14)
+#define OPENAVB_AEM_UNIT_DISTANCE_METRES (0x18)
+#define OPENAVB_AEM_UNIT_TEMPERATURE_KELVIN (0x20)
+#define OPENAVB_AEM_UNIT_MASS_GRAMS (0x28)
+#define OPENAVB_AEM_UNIT_VOLTAGE_VOLTS (0x30)
+#define OPENAVB_AEM_UNIT_VOLTAGE_DBV (0x31)
+#define OPENAVB_AEM_UNIT_VOLTAGE_DBU (0x32)
+#define OPENAVB_AEM_UNIT_CURRENT_AMPS (0x38)
+#define OPENAVB_AEM_UNIT_POWER_WATTS (0x40)
+#define OPENAVB_AEM_UNIT_POWER_DBM (0x41)
+#define OPENAVB_AEM_UNIT_POWER_DBW (0x42)
+#define OPENAVB_AEM_UNIT_PRESSURE_PASCALS (0x48)
+#define OPENAVB_AEM_UNIT_MEMORY_BITS (0x50)
+#define OPENAVB_AEM_UNIT_MEMORY_BYTES (0x51)
+#define OPENAVB_AEM_UNIT_MEMORY_KIBIBYTES (0x52)
+#define OPENAVB_AEM_UNIT_MEMORY_MEBIBYTES (0x53)
+#define OPENAVB_AEM_UNIT_MEMORY_GIBIBYTES (0x54)
+#define OPENAVB_AEM_UNIT_MEMORY_TEBIBYTES (0x55)
+#define OPENAVB_AEM_UNIT_BANDWIDTH_BITS_PER_SEC (0x58)
+#define OPENAVB_AEM_UNIT_BANDWIDTH_BYTES_PER_SEC (0x59)
+#define OPENAVB_AEM_UNIT_BANDWIDTH_KIBIBYTES_PER_SEC (0x5a)
+#define OPENAVB_AEM_UNIT_BANDWIDTH_MEBIBYTES_PER_SEC (0x5b)
+#define OPENAVB_AEM_UNIT_BANDWIDTH_GIGIBYTES_PER_SEC (0x5c)
+#define OPENAVB_AEM_UNIT_BANDWIDTH_TEBIBYTES_PER_SEC (0x5d)
+#define OPENAVB_AEM_UNIT_LUMINOSITY_CANDELAS (0x60)
+#define OPENAVB_AEM_UNIT_ENERGY_JOULES (0x68)
+#define OPENAVB_AEM_UNIT_ANGLE_RADIANS (0x70)
+#define OPENAVB_AEM_UNIT_FORCE_NEWTONS (0x78)
+#define OPENAVB_AEM_UNIT_RESISTANCE_OHMS (0x80)
+#define OPENAVB_AEM_UNIT_VELOCITY_METRES_PER_SEC (0x88)
+#define OPENAVB_AEM_UNIT_VELOCITY_RADIANS_PER_SEC (0x89)
+#define OPENAVB_AEM_UNIT_ACCELERATION_METRES_PER_SEC_SQUARED (0x90)
+#define OPENAVB_AEM_UNIT_ACCELERATION_RADIANS_PER_SEC_SQUARED (0x91)
+#define OPENAVB_AEM_UNIT_MAGNETIC_FLUX_TESLAS (0x98)
+#define OPENAVB_AEM_UNIT_AREA_METRES_SQUARED (0xa0)
+#define OPENAVB_AEM_UNIT_VOLUME_METRES_CUBED (0xa8)
+#define OPENAVB_AEM_UNIT_VOLUME_LITRES (0xa9)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DB (0xb0)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DB_PEAK (0xb1)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DB_RMS (0xb2)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DBFS (0xb3)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DBFS_PEAK (0xb4)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DBFS_RMS (0xb5)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DBTP (0xb6)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DB_SPL_A (0xb7)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DB_Z (0xb8)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DB_SPL_C (0xb9)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DB_SPL (0xba)
+#define OPENAVB_AEM_UNIT_LOUDNESS_LU (0xbb)
+#define OPENAVB_AEM_UNIT_LOUDNESS_LUFS (0xbc)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DB_A (0xbd)
+
+// Control Types IEEE Std 1722.1-2013 clause 7.3.4
+#define OPENAVB_AEM_CONTROL_TYPE_ENABLE (0x90e0f00000000000ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_IDENTIFY (0x90e0f00000000001ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MUTE (0x90e0f00000000002ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_INVERT (0x90e0f00000000003ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_GAIN (0x90e0f00000000004ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_ATTENUATE (0x90e0f00000000005ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_DELAY (0x90e0f00000000006ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_SRC_MODE (0x90e0f00000000007ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_SNAPSHOT (0x90e0f00000000008ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_POW_LINE_FREQ (0x90e0f00000000009ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_POWER_STATUS (0x90e0f0000000000aULL)
+#define OPENAVB_AEM_CONTROL_TYPE_FAN_STATUS (0x90e0f0000000000bULL)
+#define OPENAVB_AEM_CONTROL_TYPE_TEMPERATURE (0x90e0f0000000000cULL)
+#define OPENAVB_AEM_CONTROL_TYPE_ALTITUDE (0x90e0f0000000000dULL)
+#define OPENAVB_AEM_CONTROL_TYPE_ABSOLUTE_HUMIDITY (0x90e0f0000000000eULL)
+#define OPENAVB_AEM_CONTROL_TYPE_RELATIVE_HUMIDITY (0x90e0f0000000000fULL)
+#define OPENAVB_AEM_CONTROL_TYPE_ORIENTATION (0x90e0f00000000010ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_VELOCITY (0x90e0f00000000011ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_ACCELERATION (0x90e0f00000000012ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_FILTER_RESPONSE (0x90e0f00000000013ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_PANPOT (0x90e0f00000010000ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_PHANTOM (0x90e0f00000010001ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_AUDIO_SCALE (0x90e0f00000010002ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_AUDIO_METERS (0x90e0f00000010003ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_AUDIO_SPECTRUM (0x90e0f00000010004ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_SCANNING_MODE (0x90e0f00000020000ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_AUTO_EXP_MODE (0x90e0f00000020001ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_AUTO_EXP_PRIO (0x90e0f00000020002ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_EXP_TIME (0x90e0f00000020003ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_FOCUS (0x90e0f00000020004ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_FOCUS_AUTO (0x90e0f00000020005ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_IRIS (0x90e0f00000020006ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_ZOOM (0x90e0f00000020007ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_PRIVACY (0x90e0f00000020008ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_BACKLIGHT (0x90e0f00000020009ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_BRIGHTNESS (0x90e0f0000002000aULL)
+#define OPENAVB_AEM_CONTROL_TYPE_CONTRAST (0x90e0f0000002000bULL)
+#define OPENAVB_AEM_CONTROL_TYPE_HUE (0x90e0f0000002000cULL)
+#define OPENAVB_AEM_CONTROL_TYPE_SATURATION (0x90e0f0000002000dULL)
+#define OPENAVB_AEM_CONTROL_TYPE_SHARPNESS (0x90e0f0000002000eULL)
+#define OPENAVB_AEM_CONTROL_TYPE_GAMMA (0x90e0f0000002000fULL)
+#define OPENAVB_AEM_CONTROL_TYPE_WHITE_BAL_TEMP (0x90e0f00000020010ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_WHITE_BAL_TEMP_AUTO (0x90e0f00000020011ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_WHITE_BAL_COMP (0x90e0f00000020012ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_WHITE_BAL_COMP_AUTO (0x90e0f00000020013ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_DIGITAL_ZOOM (0x90e0f00000020014ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_PLAYLIST (0x90e0f00000030000ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_PLAYLIST_NAME (0x90e0f00000030001ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_DISK (0x90e0f00000030002ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_DISK_NAME (0x90e0f00000030003ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_TRACK (0x90e0f00000030004ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_TRACK_NAME (0x90e0f00000030005ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_SPEED (0x90e0f00000030006ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_SAMPLE_POSITION (0x90e0f00000030007ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_PLAYBACK_TRANSPORT (0x90e0f00000030008ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_RECORD_TRANSPORT (0x90e0f00000030009ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_FREQUENCY (0x90e0f00000040000ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MODULATION (0x90e0f00000040001ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_POLARIZATION (0x90e0f00000040002ULL)
+
+// Sample Rate Convertor (SRC_MODE) Mode IEEE Std 1722.1-2013 clause 7.3.4.8
+#define OPENAVB_AEM_CONTROL_TYPE_SRC_MODE_OFF (0x00)
+#define OPENAVB_AEM_CONTROL_TYPE_SRC_MODE_SYNCHRONOUS (0x01)
+#define OPENAVB_AEM_CONTROL_TYPE_SRC_MODE_ASYNCHRONOUS (0x02)
+
+// Snapshot Control (SNAPSHOT) IEEE Std 1722.1-2013 clause 7.3.4.9
+#define OPENAVB_AEM_CONTROL_TYPE_SNAPSHOT_CAPTURE (0x0000)
+#define OPENAVB_AEM_CONTROL_TYPE_SNAPSHOT_RECALL (0x0001)
+#define OPENAVB_AEM_CONTROL_TYPE_SNAPSHOT_ERASE (0x0002)
+
+// Power Line Frequency Control (POW_LINE_FREQ) IEEE Std 1722.1-2013 clause 7.3.4.10
+#define OPENAVB_AEM_CONTROL_TYPE_POW_LINE_FREQ_FIFTY_HERTZ (50)
+#define OPENAVB_AEM_CONTROL_TYPE_POW_LINE_FREQ_SIXTY_HERTZ (60)
+
+// Auto Exposure Mode Control (AUTO_EXP_MODE) IEEE Std 1722.1-2013 clause 7.3.4.27
+#define OPENAVB_AEM_CONTROL_TYPE_AUTO_EXP_MODE_MANUAL (0x01)
+#define OPENAVB_AEM_CONTROL_TYPE_AUTO_EXP_MODE_AUTO (0x11)
+#define OPENAVB_AEM_CONTROL_TYPE_AUTO_EXP_MODE_SHUTTER_PRIO (0x21)
+#define OPENAVB_AEM_CONTROL_TYPE_AUTO_EXP_MODE_APER_PRIO (0x31)
+
+// Media Disk Selection Control (MEDIA_DISK) IEEE Std 1722.1-2013 clause 7.3.4.49
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_DISK_CHOOSE (0x0000)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_DISK_PREVIOUS (0x0001)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_DISK_NEXT (0x0002)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_DISK_OPEN (0x0003)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_DISK_CLOSE (0x0004)
+
+// Media Playback Transport Control (MEDIA_PLAYBACK_TRANSPORT) IEEE Std 1722.1-2013 clause 7.3.4.55
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_PLAYBACK_TRANSPORT_STOP (0x0000)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_PLAYBACK_TRANSPORT_PLAY (0x0001)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_PLAYBACK_TRANSPORT_PAUSE (0x0002)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_PLAYBACK_TRANSPORT_UNPAUSE (0x0003)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_PLAYBACK_TRANSPORT_SCAN_FORWARD (0x0004)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_PLAYBACK_TRANSPORT_SCAN_BACKWARD (0x0005)
+
+// Media Record Transport Control (MEDIA_RECORD_TRANSPORT) IEEE Std 1722.1-2013 clause 7.3.4.56
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_RECORD_TRANSPORT_STOP (0x0000)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_RECORD_TRANSPORT_PLAY (0x0001)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_RECORD_TRANSPORT_PAUSE (0x0002)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_RECORD_TRANSPORT_UNPAUSE (0x0003)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_RECORD_TRANSPORT_SCAN_FORWARD (0x0004)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_RECORD_TRANSPORT_SCAN_BACKWARD (0x0005)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_RECORD_TRANSPORT_RECORD (0x0006)
+
+// Modulation Control (MODULATION) IEEE Std 1722.1-2013 clause 7.3.4.58
+#define OPENAVB_AEM_CONTROL_TYPE_MODULATION_AMPLITUDE_MODULATION (0x00)
+#define OPENAVB_AEM_CONTROL_TYPE_MODULATION_FREQUENCY_MODULATION (0x01)
+#define OPENAVB_AEM_CONTROL_TYPE_MODULATION_PHASE_MODULATION (0x02)
+
+// Polarization Control (POLARIZATION) IEEE Std 1722.1-2013 clause 7.3.4.59
+#define OPENAVB_AEM_CONTROL_TYPE_POLARIZATION_VERTICAL (0x00)
+#define OPENAVB_AEM_CONTROL_TYPE_POLARIZATION_HORIZONTAL (0x01)
+#define OPENAVB_AEM_CONTROL_TYPE_POLARIZATION_LEFT_HAND_CIRCULAR (0x02)
+#define OPENAVB_AEM_CONTROL_TYPE_POLARIZATION_RIGHT_HAND_CIRCULAR (0x03)
+
+// Control_value_type IEEE Std 1722.1-2013 clause 7.3.5.1
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT8 (0x0000)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT8 (0x0001)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT16 (0x0002)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT16 (0x0003)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT32 (0x0004)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT32 (0x0005)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT64 (0x0006)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT64 (0x0007)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_FLOAT (0x0008)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_DOUBLE (0x0009)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT8 (0x000a)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT8 (0x000b)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT16 (0x000c)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT16 (0x000d)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT32 (0x000e)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT32 (0x000f)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT64 (0x0010)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT64 (0x0011)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_FLOAT (0x0012)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_DOUBLE (0x0013)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_STRING (0x0014)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT8 (0x0015)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT8 (0x0016)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT16 (0x0017)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT16 (0x0018)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT32 (0x0019)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT32 (0x001a)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT64 (0x001b)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT64 (0x001c)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_FLOAT (0x001d)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_DOUBLE (0x001e)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_UTF8 (0x001f)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_BODE_PLOT (0x0020)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SMPTE_TIME (0x0021)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SAMPLE_RATE (0x0022)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_GPTP_TIME (0x0023)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_VENDOR (0x3ffe)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_EXPANSION (0x3fff)
+
+// Localized String default values IEEE Std 1722.1-2013 clause 7.3.6
+#define OPENAVB_AEM_NO_STRING_OFFSET (0x1fff)
+#define OPENAVB_AEM_NO_STRING_INDEX (7)
+
+// Localized String Reference IEEE Std 1722.1-2013 clause 7.3.6
+typedef struct {
+ U16 offset;
+ U8 index;
+} openavb_aem_string_ref_t;
+
+// Control value formats IEEE Std 1722.1-2013 clause 7.3.5.2
+// Values format for Linear Value Types (CONTROL_LINEAR_INT8 to CONTROL_LINEAR_DOUBLE) IEEE Std 1722.1-2013 clause 7.3.5.2.1
+typedef struct {
+ S8 minimum;
+ S8 maximum;
+ S8 step;
+ S8 default_value;
+ S8 current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_int8_t;
+
+typedef struct {
+ U8 minimum;
+ U8 maximum;
+ U8 step;
+ U8 default_value;
+ U8 current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_uint8_t;
+
+typedef struct {
+ S16 minimum;
+ S16 maximum;
+ S16 step;
+ S16 default_value;
+ S16 current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_int16_t;
+
+typedef struct {
+ U16 minimum;
+ U16 maximum;
+ U16 step;
+ U16 default_value;
+ U16 current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_uint16_t;
+
+typedef struct {
+ S32 minimum;
+ S32 maximum;
+ S32 step;
+ S32 default_value;
+ S32 current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_int32_t;
+
+typedef struct {
+ U32 minimum;
+ U32 maximum;
+ U32 step;
+ U32 default_value;
+ U32 current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_uint32_t;
+
+typedef struct {
+ S64 minimum;
+ S64 maximum;
+ S64 step;
+ S64 default_value;
+ S64 current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_int64_t;
+
+typedef struct {
+ U64 minimum;
+ U64 maximum;
+ U64 step;
+ U64 default_value;
+ U64 current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_uint64_t;
+
+typedef struct {
+ float minimum;
+ float maximum;
+ float step;
+ float default_value;
+ float current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_float_t;
+
+typedef struct {
+ double minimum;
+ double maximum;
+ double step;
+ double default_value;
+ double current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_double_t;
+
+
+// Values format for Selector Value Types (CONTROL_SELECTOR_INT8 to CONTROL_SELECTOR_STRING) IEEE Std 1722.1-2013 clause 7.3.5.2.2
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_int8_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_uint8_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_int16_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_uint16_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_int32_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_uint32_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_int64_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_uint64_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_float_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_double_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_string_t;
+
+
+// Values format for Array Value Types (CONTROL_ARRAY_INT8 to CONTROL_ARRAY_ARRAY_DOUBLE) IEEE Std 1722.1-2013 clause 7.3.5.2.3
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_int8_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_uint8_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_int16_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_uint16_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_int32_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_uint32_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_int64_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_uint64_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_float_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_double_t;
+
+
+// Values format for UTF-8 String Value Type (CONTROL_UTF8) IEEE Std 1722.1-2013 clause 7.3.5.2.4
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_utf8_t;
+
+// Values format for Bode Plot Value Type (CONTROL_BODE_PLOT) IEEE Std 1722.1-2013 clause 7.3.5.2.5
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_bode_plot_t;
+
+// Values format for SMPTE Time Type (CONTROL_SMPTE_TIME) IEEE Std 1722.1-2013 clause 7.3.5.2.6
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_smpte_time_t;
+
+// Values format for Sample Rate Type (CONTROL_SAMPLE_RATE) IEEE Std 1722.1-2013 clause 7.3.5.2.7
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_sample_rate_t;
+
+// Values format for gPTP Time Type (CONTROL_GPTP_TIME) IEEE Std 1722.1-2013 clause 7.3.5.2.8
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_gptp_time_t;
+
+// Values format for Vendor Defined Type (CONTROL_VENDOR) IEEE Std 1722.1-2013 clause 7.3.5.2.9
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_vendor_t;
+
+
+// Content Protection for Video Cluster Format Specific fields IEEE Std 1722.1-2013 clause 7.3.7.1.1
+#define OPENAVB_AEM_VIDEO_CLUSTER_PROTECTION_NONE (0x0)
+#define OPENAVB_AEM_VIDEO_CLUSTER_PROTECTION_HDCP (0x1)
+#define OPENAVB_AEM_VIDEO_CLUSTER_PROTECTION_DTCP (0x2)
+#define OPENAVB_AEM_VIDEO_CLUSTER_PROTECTION_AES_ENCRYPTION (0x3)
+
+// Profiles for MPEG Elementary Streams IEEE Std 1722.1-2013 clause 7.3.7.2.1
+#define OPENAVB_AEM_MPEG_PROFILE_H264_CBP (0x00)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_BP (0x01)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_MP (0x02)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_XP (0x03)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_HIP (0x04)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_PHIP (0x05)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_HI10P (0x06)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_HI422P (0x07)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_HI444PP (0x08)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_HI10I (0x09)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_HI422I (0x0a)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_HI444I (0x0b)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_CAVLC44I (0x0c)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_SBP (0x0d)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_SHP (0x0e)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_SHI (0x0f)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_STHP (0x10)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_MVHP (0x11)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG2_SP (0x12)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG2_MP (0x13)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG2_SNR (0x14)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG2_SPATIAL (0x15)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG2_HP (0x16)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG2_422 (0x17)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG2_MVP (0x18)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG1_LAYER2 (0x80)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG1_LAYER3 (0x81)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG2_LAYER2 (0x82)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG2_LAYER3 (0x83)
+#define OPENAVB_AEM_MPEG_PROFILE_DOLBY_DIGITAL (0x84)
+#define OPENAVB_AEM_MPEG_PROFILE_DOLBY_DIGITAL_PLUS (0x85)
+#define OPENAVB_AEM_MPEG_PROFILE_DOLBY_DIGITAL_TRUEHD (0x86)
+#define OPENAVB_AEM_MPEG_PROFILE_DOLBY_PRO_LOGIC_II (0x87)
+#define OPENAVB_AEM_MPEG_PROFILE_DOLBY_DIGITAL_EX (0x88)
+#define OPENAVB_AEM_MPEG_PROFILE_DOLBY_DIGITAL_SURROUND_EX (0x89)
+#define OPENAVB_AEM_MPEG_PROFILE_DOLBY_DIGITAL_LIVE (0x8a)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_5_1 (0x8b)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_ES_MATRIX (0x8c)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_ES_DISCRETE (0x8d)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_NEO_6 (0x8e)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_NEO_X (0x8f)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_96_24 (0x90)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_HD (0x91)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_HD_MASTER (0x92)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_INTERACTIVE (0x93)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_NEO_PC (0x94)
+#define OPENAVB_AEM_MPEG_PROFILE_AAC_LC (0x95)
+#define OPENAVB_AEM_MPEG_PROFILE_AAC_MAIN (0x96)
+#define OPENAVB_AEM_MPEG_PROFILE_AAC_LD (0x97)
+#define OPENAVB_AEM_MPEG_PROFILE_AAC_HE (0x98)
+#define OPENAVB_AEM_MPEG_PROFILE_AAC_HE2 (0x99)
+
+// Levels for H.264 Profiles IEEE Std 1722.1-2013 clause 7.3.7.2.2.1
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_1 (0x00)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_1B (0x01)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_1_1 (0x02)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_1_2 (0x03)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_1_3 (0x01)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_2 (0x05)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_2_1 (0x06)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_2_2 (0x07)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_3 (0x08)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_3_1 (0x09)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_3_2 (0x0a)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_4 (0x0b)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_4_1 (0x0c)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_4_2 (0x0d)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_5 (0x0e)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_5_1 (0x0f)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_5_2 (0x10)
+
+// Levels for MPEG2 Profiles IEEE Std 1722.1-2013 clause 7.3.7.2.2.2
+#define OPENAVB_AEM_PROFILE_LEVEL_MPEG2_LL (0x00)
+#define OPENAVB_AEM_PROFILE_LEVEL_MPEG2_ML (0x01)
+#define OPENAVB_AEM_PROFILE_LEVEL_MPEG2_H_14 (0x02)
+#define OPENAVB_AEM_PROFILE_LEVEL_MPEG2_HL (0x03)
+
+// Audio Profiles MPEG_PES_FORMAT Compressed Audio sample rates IEEE Std 1722.1-2013 clause 7.3.7.2.3
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_SAMPLE_RATE_8K (0x0)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_SAMPLE_RATE_16K (0x1)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_SAMPLE_RATE_22K05 (0x2)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_SAMPLE_RATE_24K (0x3)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_SAMPLE_RATE_32K (0x4)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_SAMPLE_RATE_44K1 (0x5)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_SAMPLE_RATE_48K (0x6)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_SAMPLE_RATE_96K (0x7)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_SAMPLE_RATE_192K (0x8)
+
+// Audio Profiles MPEG_PES_FORMAT Compressed Audio channel options IEEE Std 1722.1-2013 clause 7.3.7.2.3
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_MONO (0x00)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_STEREO (0x01)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_STEREO_JOINED (0x02)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_DUAL_CHANNEL (0x03)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_2_1 (0x04)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_3_0 (0x05)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_3_1 (0x06)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_4_0 (0x07)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_4_1 (0x08)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_5_0 (0x09)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_5_1 (0x0a)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_6_0 (0x0b)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_6_1 (0x0c)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_7_0 (0x0d)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_7_1 (0x0e)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_8_0 (0x0f)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_10_1 (0x10)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_OTHER (0x1f)
+
+// Audio Profiles MPEG_PES_FORMAT Compressed Audio bitrates IEEE Std 1722.1-2013 clause 7.3.7.2.3
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_VARIABLE_BIT_RATE (0x00)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_16_KB_PER_SEC (0x01)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_24_KB_PER_SEC (0x02)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_32_KB_PER_SEC (0x03)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_40_KB_PER_SEC (0x01)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_48_KB_PER_SEC (0x05)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_56_KB_PER_SEC (0x06)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_64_KB_PER_SEC (0x07)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_80_KB_PER_SEC (0x08)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_96_KB_PER_SEC (0x09)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_112_KB_PER_SEC (0x0a)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_128_KB_PER_SEC (0x0b)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_144_KB_PER_SEC (0x0c)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_160_KB_PER_SEC (0x0d)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_192_KB_PER_SEC (0x0e)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_224_KB_PER_SEC (0x0f)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_256_KB_PER_SEC (0x10)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_288_KB_PER_SEC (0x11)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_320_KB_PER_SEC (0x12)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_352_KB_PER_SEC (0x13)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_384_KB_PER_SEC (0x14)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_OTHER (0x7f)
+
+// RTP Payload Subtypes IEEE Std 1722.1-2013 clause 7.3.7.4.1
+#define OPENAVB_AEM_RTP_PAYLOAD_SUBTYPE_RTP_MJPEG (0x0000)
+#define OPENAVB_AEM_RTP_PAYLOAD_SUBTYPE_RTP_H264 (0x0001)
+#define OPENAVB_AEM_RTP_PAYLOAD_SUBTYPE_RTP_JPEG200 (0x0002)
+
+// Video Cluster Color Space IEEE Std 1722.1-2013 clause 7.3.10
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_MONO8 (0x0000)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_MONO12_PACKED (0x0001)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_MONO16 (0x0002)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_MONO16_SIGNED (0x0003)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_YUV411_PACKED (0x0004)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_YUV422_PACKED (0x0005)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_YUV444_PACKED (0x0006)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_RGB_PACKED (0x0007)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_RGB16 (0x0008)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_RGB16_SIGNED (0x0009)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERGR8 (0x000a)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERGR12_PACKED (0x000b)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERGR16 (0x000c)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERRG8 (0x000d)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERRG12_PACKED (0x000e)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERRG16 (0x000f)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERGB8 (0x0010)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERGB12_PACKED (0x0011)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERGB16 (0x0012)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERBG8 (0x0013)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERBG12_PACKED (0x0014)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERBG16 (0x0015)
+
+// Command Codes IEEE Std 1722.1-2013 clause 7.4
+#define OPENAVB_AEM_COMMAND_CODE_ACQUIRE_ENTITY (0x0000)
+#define OPENAVB_AEM_COMMAND_CODE_LOCK_ENTITY (0x0001)
+#define OPENAVB_AEM_COMMAND_CODE_ENTITY_AVAILABLE (0x0002)
+#define OPENAVB_AEM_COMMAND_CODE_CONTROLLER_AVAILABLE (0x0003)
+#define OPENAVB_AEM_COMMAND_CODE_READ_DESCRIPTOR (0x0004)
+#define OPENAVB_AEM_COMMAND_CODE_WRITE_DESCRIPTOR (0x0005)
+#define OPENAVB_AEM_COMMAND_CODE_SET_CONFIGURATION (0x0006)
+#define OPENAVB_AEM_COMMAND_CODE_GET_CONFIGURATION (0x0007)
+#define OPENAVB_AEM_COMMAND_CODE_SET_STREAM_FORMAT (0x0008)
+#define OPENAVB_AEM_COMMAND_CODE_GET_STREAM_FORMAT (0x0009)
+#define OPENAVB_AEM_COMMAND_CODE_SET_VIDEO_FORMAT (0x000a)
+#define OPENAVB_AEM_COMMAND_CODE_GET_VIDEO_FORMAT (0x000b)
+#define OPENAVB_AEM_COMMAND_CODE_SET_SENSOR_FORMAT (0x000c)
+#define OPENAVB_AEM_COMMAND_CODE_GET_SENSOR_FORMAT (0x000d)
+#define OPENAVB_AEM_COMMAND_CODE_SET_STREAM_INFO (0x000e)
+#define OPENAVB_AEM_COMMAND_CODE_GET_STREAM_INFO (0x000f)
+#define OPENAVB_AEM_COMMAND_CODE_SET_NAME (0x0010)
+#define OPENAVB_AEM_COMMAND_CODE_GET_NAME (0x0011)
+#define OPENAVB_AEM_COMMAND_CODE_SET_ASSOCIATION_ID (0x0012)
+#define OPENAVB_AEM_COMMAND_CODE_GET_ASSOCIATION_ID (0x0013)
+#define OPENAVB_AEM_COMMAND_CODE_SET_SAMPLING_RATE (0x0014)
+#define OPENAVB_AEM_COMMAND_CODE_GET_SAMPLING_RATE (0x0015)
+#define OPENAVB_AEM_COMMAND_CODE_SET_CLOCK_SOURCE (0x0016)
+#define OPENAVB_AEM_COMMAND_CODE_GET_CLOCK_SOURCE (0x0017)
+#define OPENAVB_AEM_COMMAND_CODE_SET_CONTROL (0x0018)
+#define OPENAVB_AEM_COMMAND_CODE_GET_CONTROL (0x0019)
+#define OPENAVB_AEM_COMMAND_CODE_INCREMENT_CONTROL (0x001a)
+#define OPENAVB_AEM_COMMAND_CODE_DECREMENT_CONTROL (0x001b)
+#define OPENAVB_AEM_COMMAND_CODE_SET_SIGNAL_SELECTOR (0x001c)
+#define OPENAVB_AEM_COMMAND_CODE_GET_SIGNAL_SELECTOR (0x001d)
+#define OPENAVB_AEM_COMMAND_CODE_SET_MIXER (0x001e)
+#define OPENAVB_AEM_COMMAND_CODE_GET_MIXER (0x001f)
+#define OPENAVB_AEM_COMMAND_CODE_SET_MATRIX (0x0020)
+#define OPENAVB_AEM_COMMAND_CODE_GET_MATRIX (0x0021)
+#define OPENAVB_AEM_COMMAND_CODE_START_STREAMING (0x0022)
+#define OPENAVB_AEM_COMMAND_CODE_STOP_STREAMING (0x0023)
+#define OPENAVB_AEM_COMMAND_CODE_REGISTER_UNSOLICITED_NOTIFICATION (0x0024)
+#define OPENAVB_AEM_COMMAND_CODE_DEREGISTER_UNSOLICITED_NOTIFICATION (0x0025)
+#define OPENAVB_AEM_COMMAND_CODE_IDENTIFY_NOTIFICATION (0x0026)
+#define OPENAVB_AEM_COMMAND_CODE_GET_AVB_INFO (0x0027)
+#define OPENAVB_AEM_COMMAND_CODE_GET_AS_PATH (0x0028)
+#define OPENAVB_AEM_COMMAND_CODE_GET_COUNTERS (0x0029)
+#define OPENAVB_AEM_COMMAND_CODE_REBOOT (0x002a)
+#define OPENAVB_AEM_COMMAND_CODE_GET_AUDIO_MAP (0x002b)
+#define OPENAVB_AEM_COMMAND_CODE_ADD_AUDIO_MAPPINGS (0x002c)
+#define OPENAVB_AEM_COMMAND_CODE_REMOVE_AUDIO_MAPPINGS (0x002d)
+#define OPENAVB_AEM_COMMAND_CODE_GET_VIDEO_MAP (0x002e)
+#define OPENAVB_AEM_COMMAND_CODE_ADD_VIDEO_MAPPINGS (0x002f)
+#define OPENAVB_AEM_COMMAND_CODE_REMOVE_VIDEO_MAPPINGS (0x0030)
+#define OPENAVB_AEM_COMMAND_CODE_GET_SENSOR_MAP (0x0031)
+#define OPENAVB_AEM_COMMAND_CODE_ADD_SENSOR_MAPPINGS (0x0032)
+#define OPENAVB_AEM_COMMAND_CODE_REMOVE_SENSOR_MAPPINGS (0x0033)
+#define OPENAVB_AEM_COMMAND_CODE_START_OPERATION (0x0034)
+#define OPENAVB_AEM_COMMAND_CODE_ABORT_OPERATION (0x0035)
+#define OPENAVB_AEM_COMMAND_CODE_OPERATION_STATUS (0x0036)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_KEY (0x0037)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_KEY (0x0038)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEY_LIST (0x0039)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEY (0x003a)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_KEY_TO_CHAIN (0x003b)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_KEY_FROM_CHAIN (0x003c)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEYCHAIN_LIST (0x003d)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_GET_IDENTITY (0x003e)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_TOKEN (0x003f)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_TOKEN (0x0040)
+#define OPENAVB_AEM_COMMAND_CODE_AUTHENTICATE (0x0041)
+#define OPENAVB_AEM_COMMAND_CODE_DEAUTHENTICATE (0x0042)
+#define OPENAVB_AEM_COMMAND_CODE_ENABLE_TRANSPORT_SECURITY (0x0043)
+#define OPENAVB_AEM_COMMAND_CODE_DISABLE_TRANSPORT_SECURITY (0x0044)
+#define OPENAVB_AEM_COMMAND_CODE_ENABLE_STREAM_ENCRYPTION (0x0045)
+#define OPENAVB_AEM_COMMAND_CODE_DISABLE_STREAM_ENCRYPTION (0x0046)
+#define OPENAVB_AEM_COMMAND_CODE_SET_MEMORY_OBJECT_LENGTH (0x0047)
+#define OPENAVB_AEM_COMMAND_CODE_GET_MEMORY_OBJECT_LENGTH (0x0048)
+#define OPENAVB_AEM_COMMAND_CODE_SET_STREAM_BACKUP (0x0049)
+#define OPENAVB_AEM_COMMAND_CODE_GET_STREAM_BACKUP (0x004a)
+#define OPENAVB_AEM_COMMAND_CODE_EXPANSION (0x7fff)
+
+// Command Status IEEE Std 1722.1-2013 clause 7.4
+#define OPENAVB_AEM_COMMAND_STATUS_SUCCESS (0)
+#define OPENAVB_AEM_COMMAND_STATUS_NOT_IMPLEMENTED (1)
+#define OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR (2)
+#define OPENAVB_AEM_COMMAND_STATUS_ENTITY_LOCKED (3)
+#define OPENAVB_AEM_COMMAND_STATUS_ENTITY_ACQUIRED (4)
+#define OPENAVB_AEM_COMMAND_STATUS_NOT_AUTHENTICATED (5)
+#define OPENAVB_AEM_COMMAND_STATUS_AUTHENTICATION_DISABLED (6)
+#define OPENAVB_AEM_COMMAND_STATUS_BAD_ARGUMENTS (7)
+#define OPENAVB_AEM_COMMAND_STATUS_NO_RESOURCES (8)
+#define OPENAVB_AEM_COMMAND_STATUS_IN_PROGRESS (9)
+#define OPENAVB_AEM_COMMAND_STATUS_ENTITY_MISBEHAVING (10)
+#define OPENAVB_AEM_COMMAND_STATUS_NOT_SUPPORTED (11)
+#define OPENAVB_AEM_COMMAND_STATUS_STREAM_IS_RUNNING (12)
+
+// ACQUIRE_ENTITY Command Flags IEEE Std 1722.1-2013 clause 7.4.1
+#define OPENAVB_AEM_ACQUIRE_ENTITY_COMMAND_FLAG_PERSISTENT (0x00000001)
+#define OPENAVB_AEM_ACQUIRE_ENTITY_COMMAND_FLAG_RELEASE (0x80000000)
+
+// LOCK ENTITY Command Flags IEEE Std 1722.1-2013 clause 7.4.2
+#define OPENAVB_AEM_LOCK_ENTITY_COMMAND_FLAG_UNLOCK (ox00000001)
+
+// SET_STREAM_INFO Command Flags IEEE Std 1722.1-2013 clause 7.4.15
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_CLASS_B (0x00000001)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_FAST_CONNECT (0x00000002)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_SAVED_STATE (0x00000004)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAMING_WAIT (0x00000008)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_ENCRYPTED_PDU (0x00000010)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_VLAN_ID_VALID (0x02000000)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_CONNECTED (0x04000000)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_MSRP_FAILURE_VALID (0x08000000)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_DEST_MAC_VALID (0x10000000)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_MSRP_ACC_LAT_VALID (0x20000000)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_ID_VALID (0x40000000)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_FORMAT_VALID (0x80000000)
+
+// SET_MATRIX Command Direction IEEE Std 1722.1-2013 clause 7.4.33
+#define OPENAVB_AEM_SET_MATRIX_COMMAND_DIRECTION_HORIZONTAL (0)
+#define OPENAVB_AEM_SET_MATRIX_COMMAND_DIRECTION_VERTICAL (1)
+
+// GET_AVB_INFO Command Flags IEEE Std 1722.1-2013 clause 7.4.40
+#define OPENAVB_AEM_GET_AVB_INFO_COMMAND_FLAG_AS_CAPABLE (0x01)
+#define OPENAVB_AEM_GET_AVB_INFO_COMMAND_GPTP_ENABLED (0x02)
+#define OPENAVB_AEM_GET_AVB_INFO_COMMAND_SRP_ENABLED (0x04)
+
+// GET_COUNTERS Command ENTITY Counters IEEE Std 1722.1-2013 clause 7.4.42
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_8 (0x01000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_7 (0x02000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_6 (0x04000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_5 (0x08000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_4 (0x10000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_3 (0x20000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_2 (0x40000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_1 (0x80000000)
+
+// GET_COUNTERS Command AVB_INTERFACE Counters IEEE Std 1722.1-2013 clause 7.4.42
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_LINK_UP (0x00000001)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_LINK_DOWN (0x00000002)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_FRAMES_TX (0x00000004)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_FRAMES_RX (0x00000008)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_RX_CRC_ERROR (0x00000010)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_GPTP_GM_CHANGED (0x00000020)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_ENTITY_SPECIFIC_8 (0x01000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_ENTITY_SPECIFIC_7 (0x02000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_ENTITY_SPECIFIC_6 (0x04000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_ENTITY_SPECIFIC_5 (0x08000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_ENTITY_SPECIFIC_4 (0x10000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_ENTITY_SPECIFIC_3 (0x20000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_ENTITY_SPECIFIC_2 (0x40000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_ENTITY_SPECIFIC_1 (0x80000000)
+
+// GET_COUNTERS Command CLOCK_DOMAIN Counters IEEE Std 1722.1-2013 clause 7.4.42
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_LOCKED (0x00000001)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_UNLOCKED (0x00000002)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_ENTITY_SPECIFIC_1 (0x01000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_ENTITY_SPECIFIC_2 (0x02000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_ENTITY_SPECIFIC_3 (0x04000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_ENTITY_SPECIFIC_4 (0x08000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_ENTITY_SPECIFIC_5 (0x10000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_ENTITY_SPECIFIC_6 (0x20000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_ENTITY_SPECIFIC_7 (0x40000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_ENTITY_SPECIFIC_8 (0x80000000)
+
+// GET_COUNTERS Command STREAM_INPUT Counters IEEE Std 1722.1-2013 clause 7.4.42
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_MEDIA_LOCKED (0x00000001)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_MEDIA_UNLOCKED (0x00000002)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_STREAM_RESET (0x00000004)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_SEQ_NUM_MISMATCH (0x00000008)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_MEDIA_RESET (0x00000010)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_TIMESTAMP_UNCERTAIN (0x00000020)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_TIMESTAMP_VALID (0x00000040)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_TIMESTAMP_NOT_VALID (0x00000080)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_UNSUPPORTED_FORMAT (0x00000100)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_LATE_TIMESTAMP (0x00000200)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_EARLY_TIMESTAMP (0x00000400)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_FRAMES_RX (0x00000800)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_FRAMES_TX (0x00001000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_ENTITY_SPECIFIC_8 (0x01000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_ENTITY_SPECIFIC_7 (0x02000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_ENTITY_SPECIFIC_6 (0x04000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_ENTITY_SPECIFIC_5 (0x08000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_ENTITY_SPECIFIC_4 (0x10000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_ENTITY_SPECIFIC_3 (0x20000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_ENTITY_SPECIFIC_2 (0x40000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_ENTITY_SPECIFIC_1 (0x80000000)
+
+#endif // OPENAVB_AEM_TYPES_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster.c b/lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster.c
new file mode 100644
index 00000000..b3addd1a
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster.c
@@ -0,0 +1,179 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Audio Cluster Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Audio Cluster IEEE Std 1722.1-2013 clause 7.2.16
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_audio_cluster.h"
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorAudioClusterToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_cluster_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AUDIO_CLUSTER_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_audio_cluster_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->object_name);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.index, 0, 2);
+ OCT_D2BHTONS(pDst, pSrc->signal_type);
+ OCT_D2BHTONS(pDst, pSrc->signal_index);
+ OCT_D2BHTONS(pDst, pSrc->signal_output);
+ OCT_D2BHTONL(pDst, pSrc->path_latency);
+ OCT_D2BHTONL(pDst, pSrc->block_latency);
+ OCT_D2BHTONS(pDst, pSrc->channel_count);
+ OCT_D2BHTONB(pDst, pSrc->format);
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorAudioClusterFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_cluster_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AUDIO_CLUSTER_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_audio_cluster_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->object_name, pSrc);
+ BIT_B2DNTOHS(pDst->localized_description.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->localized_description.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DNTOHS(pDst->signal_type, pSrc);
+ OCT_B2DNTOHS(pDst->signal_index, pSrc);
+ OCT_B2DNTOHS(pDst->signal_output, pSrc);
+ OCT_B2DNTOHL(pDst->path_latency, pSrc);
+ OCT_B2DNTOHL(pDst->block_latency, pSrc);
+ OCT_B2DNTOHS(pDst->channel_count, pSrc);
+ OCT_B2DNTOHB(pDst->format, pSrc);
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorAudioClusterUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_cluster_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_audio_cluster_t *openavbAemDescriptorAudioClusterNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_cluster_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_audio_cluster_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = FALSE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorAudioClusterToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorAudioClusterFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorAudioClusterUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_AUDIO_CLUSTER;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster.h b/lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster.h
new file mode 100644
index 00000000..b1a5d9b5
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Audio Cluster Descriptor
+ * MODULE SUMMARY : Interface for the Audio Cluster Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_AUDIO_CLUSTER_H
+#define OPENAVB_DESCRIPTOR_AUDIO_CLUSTER_H 1
+
+#include "openavb_descriptor_audio_cluster_pub.h"
+
+#define OPENAVB_DESCRIPTOR_AUDIO_CLUSTER_BASE_LENGTH (87)
+
+#endif // OPENAVB_DESCRIPTOR_AUDIO_CLUSTER_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster_pub.h
new file mode 100644
index 00000000..4708f030
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster_pub.h
@@ -0,0 +1,65 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Audio Cluster Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Audio Cluster Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_AUDIO_CLUSTER_PUB_H
+#define OPENAVB_DESCRIPTOR_AUDIO_CLUSTER_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+// AUDIO CLUSTER Descriptor IEEE Std 1722.1-2013 clause 7.2.16
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 object_name[OPENAVB_AEM_STRLEN_MAX];
+ openavb_aem_string_ref_t localized_description;
+ U16 signal_type;
+ U16 signal_index;
+ U16 signal_output;
+ U32 path_latency;
+ U32 block_latency;
+ U16 channel_count;
+ U8 format;
+} openavb_aem_descriptor_audio_cluster_t;
+
+openavb_aem_descriptor_audio_cluster_t *openavbAemDescriptorAudioClusterNew(void);
+
+#endif // OPENAVB_DESCRIPTOR_AUDIO_CLUSTER_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_audio_map.c b/lib/avtp_pipeline/aem/openavb_descriptor_audio_map.c
new file mode 100644
index 00000000..514e1909
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_audio_map.c
@@ -0,0 +1,180 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Audio Map Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Audio Map IEEE Std 1722.1-2013 clause 7.2.19
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_audio_map.h"
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorAudioMapToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_map_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AUDIO_MAP_BASE_LENGTH + (pDescriptor->number_of_mappings * OPENAVB_DESCRIPTOR_AUDIO_MAP_AUDIO_MAPPING_FORMAT_LENGTH)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_audio_map_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BHTONS(pDst, pSrc->mappings_offset);
+ OCT_D2BHTONS(pDst, pSrc->number_of_mappings);
+
+ int i1;
+ for (i1 = 0; i1 < pSrc->number_of_mappings; i1++) {
+ OCT_D2BHTONS(pDst, pSrc->mapping_formats[i1].mapping_stream_index);
+ OCT_D2BHTONS(pDst, pSrc->mapping_formats[i1].mapping_stream_channel);
+ OCT_D2BHTONS(pDst, pSrc->mapping_formats[i1].mapping_cluster_offset);
+ OCT_D2BHTONS(pDst, pSrc->mapping_formats[i1].mapping_cluster_channel);
+ }
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorAudioMapFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_map_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AUDIO_MAP_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_audio_map_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DNTOHS(pDst->mappings_offset, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_mappings, pSrc);
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AUDIO_MAP_BASE_LENGTH + (pDescriptor->number_of_mappings * OPENAVB_DESCRIPTOR_AUDIO_MAP_AUDIO_MAPPING_FORMAT_LENGTH)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ int i1;
+ for (i1 = 0; i1 < pDst->number_of_mappings; i1++) {
+ OCT_B2DNTOHS(pDst->mapping_formats[i1].mapping_stream_index, pSrc);
+ OCT_B2DNTOHS(pDst->mapping_formats[i1].mapping_stream_channel, pSrc);
+ OCT_B2DNTOHS(pDst->mapping_formats[i1].mapping_cluster_offset, pSrc);
+ OCT_B2DNTOHS(pDst->mapping_formats[i1].mapping_cluster_channel, pSrc);
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorAudioMapUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_map_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_audio_map_t *openavbAemDescriptorAudioMapNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_map_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_audio_map_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = FALSE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorAudioMapToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorAudioMapFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorAudioMapUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_AUDIO_MAP;
+ pDescriptor->mappings_offset = OPENAVB_DESCRIPTOR_AUDIO_MAP_BASE_LENGTH;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_audio_map.h b/lib/avtp_pipeline/aem/openavb_descriptor_audio_map.h
new file mode 100644
index 00000000..7eba7ff1
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_audio_map.h
@@ -0,0 +1,47 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Audio Map Descriptor
+ * MODULE SUMMARY : Interface for the Audio Map Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_AUDIO_MAP_H
+#define OPENAVB_DESCRIPTOR_AUDIO_MAP_H 1
+
+#include "openavb_descriptor_audio_map_pub.h"
+
+#define OPENAVB_DESCRIPTOR_AUDIO_MAP_BASE_LENGTH (8)
+#define OPENAVB_DESCRIPTOR_AUDIO_MAP_AUDIO_MAPPING_FORMAT_LENGTH (8)
+
+#endif // OPENAVB_DESCRIPTOR_AUDIO_MAP_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_audio_map_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_audio_map_pub.h
new file mode 100644
index 00000000..902ff71e
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_audio_map_pub.h
@@ -0,0 +1,69 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Audio Map Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Audio Map Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_AUDIO_MAP_PUB_H
+#define OPENAVB_DESCRIPTOR_AUDIO_MAP_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+#define OPENAVB_DESCRIPTOR_AUDIO_MAP_MAX_SAMPLING_RATES (62)
+
+// AUDIO UNIT Descriptor : Audio Mappings Format IEEE Std 1722.1-2013 clause 7.2.19.1
+typedef struct {
+ U16 mapping_stream_index;
+ U16 mapping_stream_channel;
+ U16 mapping_cluster_offset;
+ U16 mapping_cluster_channel;
+} openavb_aem_descriptor_audio_map_audio_mapping_format_t;
+
+// AUDIO MAP Descriptor IEEE Std 1722.1-2013 clause 7.2.19
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U16 mappings_offset;
+ U16 number_of_mappings;
+ openavb_aem_descriptor_audio_map_audio_mapping_format_t mapping_formats[OPENAVB_DESCRIPTOR_AUDIO_MAP_MAX_SAMPLING_RATES];
+} openavb_aem_descriptor_audio_map_t;
+
+openavb_aem_descriptor_audio_map_t *openavbAemDescriptorAudioMapNew();
+
+#endif // OPENAVB_DESCRIPTOR_AUDIO_MAP_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_audio_unit.c b/lib/avtp_pipeline/aem/openavb_descriptor_audio_unit.c
new file mode 100644
index 00000000..0f6fdb4a
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_audio_unit.c
@@ -0,0 +1,297 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Audio Unit Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Audio Unit IEEE Std 1722.1-2013 clause 7.2.3
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_audio_unit.h"
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorAudioUnitToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_unit_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AUDIO_UNIT_BASE_LENGTH + (pDescriptor->sampling_rates_count * OPENAVB_DESCRIPTOR_AUDIO_UNIT_SAMPLING_RATE_LENGTH)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_audio_unit_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->object_name);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.index, 0, 2);
+ OCT_D2BHTONS(pDst, pSrc->clock_domain_index);
+ OCT_D2BHTONS(pDst, pSrc->number_of_stream_input_ports);
+ OCT_D2BHTONS(pDst, pSrc->base_stream_input_port);
+ OCT_D2BHTONS(pDst, pSrc->number_of_stream_output_ports);
+ OCT_D2BHTONS(pDst, pSrc->base_stream_output_port);
+ OCT_D2BHTONS(pDst, pSrc->number_of_external_input_ports);
+ OCT_D2BHTONS(pDst, pSrc->base_external_input_port);
+ OCT_D2BHTONS(pDst, pSrc->number_of_external_output_ports);
+ OCT_D2BHTONS(pDst, pSrc->base_external_output_port);
+ OCT_D2BHTONS(pDst, pSrc->number_of_internal_input_ports);
+ OCT_D2BHTONS(pDst, pSrc->base_internal_input_port);
+ OCT_D2BHTONS(pDst, pSrc->number_of_internal_output_ports);
+ OCT_D2BHTONS(pDst, pSrc->base_internal_output_port);
+ OCT_D2BHTONS(pDst, pSrc->number_of_controls);
+ OCT_D2BHTONS(pDst, pSrc->base_control);
+ OCT_D2BHTONS(pDst, pSrc->number_of_signal_selectors);
+ OCT_D2BHTONS(pDst, pSrc->base_signal_selector);
+ OCT_D2BHTONS(pDst, pSrc->number_of_mixers);
+ OCT_D2BHTONS(pDst, pSrc->base_mixer);
+ OCT_D2BHTONS(pDst, pSrc->number_of_matrices);
+ OCT_D2BHTONS(pDst, pSrc->base_matrix);
+ OCT_D2BHTONS(pDst, pSrc->number_of_splitters);
+ OCT_D2BHTONS(pDst, pSrc->base_splitter);
+ OCT_D2BHTONS(pDst, pSrc->number_of_combiners);
+ OCT_D2BHTONS(pDst, pSrc->base_combiner);
+ OCT_D2BHTONS(pDst, pSrc->number_of_demultiplexers);
+ OCT_D2BHTONS(pDst, pSrc->base_demultiplexer);
+ OCT_D2BHTONS(pDst, pSrc->number_of_multiplexers);
+ OCT_D2BHTONS(pDst, pSrc->base_multiplexer);
+ OCT_D2BHTONS(pDst, pSrc->number_of_transcoders);
+ OCT_D2BHTONS(pDst, pSrc->base_transcoder);
+ OCT_D2BHTONS(pDst, pSrc->number_of_control_blocks);
+ OCT_D2BHTONS(pDst, pSrc->base_control_block);
+ BIT_D2BHTONL(pDst, pSrc->current_sampling_rate.pull, 29, 0);
+ BIT_D2BHTONL(pDst, pSrc->current_sampling_rate.base, 0, 4);
+ OCT_D2BHTONS(pDst, pSrc->sampling_rates_offset);
+ OCT_D2BHTONS(pDst, pSrc->sampling_rates_count);
+
+ int i1;
+ for (i1 = 0; i1 < pSrc->sampling_rates_count; i1++) {
+ BIT_D2BHTONL(pDst, pSrc->sampling_rates[i1].pull, 29, 0);
+ BIT_D2BHTONL(pDst, pSrc->sampling_rates[i1].base, 0, 4);
+ }
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorAudioUnitFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_unit_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AUDIO_UNIT_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_audio_unit_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->object_name, pSrc);
+ BIT_B2DNTOHS(pDst->localized_description.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->localized_description.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DNTOHS(pDst->clock_domain_index, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_stream_input_ports, pSrc);
+ OCT_B2DNTOHS(pDst->base_stream_input_port, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_stream_output_ports, pSrc);
+ OCT_B2DNTOHS(pDst->base_stream_output_port, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_external_input_ports, pSrc);
+ OCT_B2DNTOHS(pDst->base_external_input_port, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_external_output_ports, pSrc);
+ OCT_B2DNTOHS(pDst->base_external_output_port, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_internal_input_ports, pSrc);
+ OCT_B2DNTOHS(pDst->base_internal_input_port, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_internal_output_ports, pSrc);
+ OCT_B2DNTOHS(pDst->base_internal_output_port, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_controls, pSrc);
+ OCT_B2DNTOHS(pDst->base_control, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_signal_selectors, pSrc);
+ OCT_B2DNTOHS(pDst->base_signal_selector, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_mixers, pSrc);
+ OCT_B2DNTOHS(pDst->base_mixer, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_matrices, pSrc);
+ OCT_B2DNTOHS(pDst->base_matrix, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_splitters, pSrc);
+ OCT_B2DNTOHS(pDst->base_splitter, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_combiners, pSrc);
+ OCT_B2DNTOHS(pDst->base_combiner, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_demultiplexers, pSrc);
+ OCT_B2DNTOHS(pDst->base_demultiplexer, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_multiplexers, pSrc);
+ OCT_B2DNTOHS(pDst->base_multiplexer, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_transcoders, pSrc);
+ OCT_B2DNTOHS(pDst->base_transcoder, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_control_blocks, pSrc);
+ OCT_B2DNTOHS(pDst->base_control_block, pSrc);
+ BIT_B2DNTOHL(pDst->current_sampling_rate.pull, pSrc, 0xe0000000, 29, 0);
+ BIT_B2DNTOHL(pDst->current_sampling_rate.base, pSrc, 0x1fffffff, 0, 2);
+ OCT_B2DNTOHS(pDst->sampling_rates_offset, pSrc);
+ OCT_B2DNTOHS(pDst->sampling_rates_count, pSrc);
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AUDIO_UNIT_BASE_LENGTH + (pDescriptor->sampling_rates_count * OPENAVB_DESCRIPTOR_AUDIO_UNIT_SAMPLING_RATE_LENGTH)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ int i1;
+ for (i1 = 0; i1 < pDst->sampling_rates_count; i1++) {
+ BIT_B2DNTOHL(pDst->sampling_rates[i1].pull, pSrc, 0xe0000000, 29, 0);
+ BIT_B2DNTOHL(pDst->sampling_rates[i1].base, pSrc, 0x1fffffff, 0, 2);
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorAudioUnitUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_unit_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_audio_unit_t *openavbAemDescriptorAudioUnitNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_unit_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_audio_unit_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorAudioUnitToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorAudioUnitFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorAudioUnitUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_AUDIO_UNIT;
+ pDescriptor->sampling_rates_offset = OPENAVB_DESCRIPTOR_AUDIO_UNIT_BASE_LENGTH;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorAudioUnitInitialize(openavb_aem_descriptor_audio_unit_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ (void) nConfigIdx;
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // Specify a name.
+ sprintf((char *)(pDescriptor->object_name), "Audio Unit %u", pDescriptor->descriptor_index);
+
+ // Add the port information.
+ if (pConfig->stream->role == AVB_ROLE_TALKER) {
+ // There will be one stream output port.
+ pDescriptor->number_of_stream_output_ports = 1;
+ pDescriptor->base_stream_output_port = 0;
+ }
+ else if (pConfig->stream->role == AVB_ROLE_LISTENER) {
+ // There will be one stream input port.
+ pDescriptor->number_of_stream_input_ports = 1;
+ pDescriptor->base_stream_input_port = 0;
+ }
+ // AVDECC_TODO - Once implemented, add support for External and Internal ports.
+
+ // AVDECC_TODO - Once implemented, add support for mixers, matrices, splitters, combiners, demultiplexers, multiplexers, transcoders, and control blocks.
+
+ // AVDECC_TODO - Add the sample rate information. Should this be done in openavbAemDescriptorAudioUnitUpdate() instead?
+ // AVDECC_TODO - Merge the configurations instead of overwriting it
+ pDescriptor->current_sampling_rate.pull = 0;
+ pDescriptor->current_sampling_rate.base = pConfig->stream->current_sampling_rate;
+ pDescriptor->sampling_rates_offset = OPENAVB_DESCRIPTOR_AUDIO_UNIT_BASE_LENGTH;
+ pDescriptor->sampling_rates_count = pConfig->stream->sampling_rates_count;
+ int i = 0;
+ while (i < OPENAVB_DESCRIPTOR_AUDIO_UNIT_MAX_SAMPLING_RATES && pConfig->stream->sampling_rates[i] != 0)
+ {
+ pDescriptor->sampling_rates[i].pull = 0;
+ pDescriptor->sampling_rates[i].base = pConfig->stream->sampling_rates[i];
+ i++;
+ }
+
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_audio_unit.h b/lib/avtp_pipeline/aem/openavb_descriptor_audio_unit.h
new file mode 100644
index 00000000..9e999530
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_audio_unit.h
@@ -0,0 +1,47 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Audio Unit Descriptor
+ * MODULE SUMMARY : Interface for the Audio Unit Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_AUDIO_UNIT_H
+#define OPENAVB_DESCRIPTOR_AUDIO_UNIT_H 1
+
+#include "openavb_descriptor_audio_unit_pub.h"
+
+#define OPENAVB_DESCRIPTOR_AUDIO_UNIT_BASE_LENGTH (144)
+#define OPENAVB_DESCRIPTOR_AUDIO_UNIT_SAMPLING_RATE_LENGTH (4)
+
+#endif // OPENAVB_DESCRIPTOR_AUDIO_UNIT_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_audio_unit_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_audio_unit_pub.h
new file mode 100644
index 00000000..6b368728
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_audio_unit_pub.h
@@ -0,0 +1,99 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Audio Unit Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Audio Unit Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_AUDIO_UNIT_PUB_H
+#define OPENAVB_DESCRIPTOR_AUDIO_UNIT_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+#define OPENAVB_DESCRIPTOR_AUDIO_UNIT_MAX_SAMPLING_RATES (91)
+
+// AUDIO UNIT Descriptor IEEE Std 1722.1-2013 clause 7.2.3
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 object_name[OPENAVB_AEM_STRLEN_MAX];
+ openavb_aem_string_ref_t localized_description;
+ U16 clock_domain_index;
+ U16 number_of_stream_input_ports;
+ U16 base_stream_input_port;
+ U16 number_of_stream_output_ports;
+ U16 base_stream_output_port;
+ U16 number_of_external_input_ports;
+ U16 base_external_input_port;
+ U16 number_of_external_output_ports;
+ U16 base_external_output_port;
+ U16 number_of_internal_input_ports;
+ U16 base_internal_input_port;
+ U16 number_of_internal_output_ports;
+ U16 base_internal_output_port;
+ U16 number_of_controls;
+ U16 base_control;
+ U16 number_of_signal_selectors;
+ U16 base_signal_selector;
+ U16 number_of_mixers;
+ U16 base_mixer;
+ U16 number_of_matrices;
+ U16 base_matrix;
+ U16 number_of_splitters;
+ U16 base_splitter;
+ U16 number_of_combiners;
+ U16 base_combiner;
+ U16 number_of_demultiplexers;
+ U16 base_demultiplexer;
+ U16 number_of_multiplexers;
+ U16 base_multiplexer;
+ U16 number_of_transcoders;
+ U16 base_transcoder;
+ U16 number_of_control_blocks;
+ U16 base_control_block;
+ openavb_aem_sampling_rate_t current_sampling_rate;
+ U16 sampling_rates_offset;
+ U16 sampling_rates_count;
+ openavb_aem_sampling_rate_t sampling_rates[OPENAVB_DESCRIPTOR_AUDIO_UNIT_MAX_SAMPLING_RATES];
+} openavb_aem_descriptor_audio_unit_t;
+
+openavb_aem_descriptor_audio_unit_t *openavbAemDescriptorAudioUnitNew(void);
+
+bool openavbAemDescriptorAudioUnitInitialize(openavb_aem_descriptor_audio_unit_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+
+#endif // OPENAVB_DESCRIPTOR_AUDIO_UNIT_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_avb_interface.c b/lib/avtp_pipeline/aem/openavb_descriptor_avb_interface.c
new file mode 100644
index 00000000..366f11e4
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_avb_interface.c
@@ -0,0 +1,244 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC AVB Interface Descriptor
+ * MODULE SUMMARY : Implements the AVDECC AVB Interface IEEE Std 1722.1-2013 clause 7.2.8
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_avb_interface.h"
+
+#ifndef AVB_PTP_AVAILABLE
+#include "openavb_grandmaster_osal_pub.h"
+#endif // !AVB_PTP_AVAILABLE
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorAvbInterfaceToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_avb_interface_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AVB_INTERFACE_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_avb_interface_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->object_name);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.index, 0, 2);
+ OCT_D2BMEMCP(pDst, pSrc->mac_address);
+ OCT_D2BHTONS(pDst, pSrc->interface_flags);
+ OCT_D2BMEMCP(pDst, pSrc->clock_identity);
+ OCT_D2BHTONB(pDst, pSrc->priority1);
+ OCT_D2BHTONB(pDst, pSrc->clock_class);
+ OCT_D2BHTONS(pDst, pSrc->offset_scaled_log_variance);
+ OCT_D2BHTONB(pDst, pSrc->clock_accuracy);
+ OCT_D2BHTONB(pDst, pSrc->priority2);
+ OCT_D2BHTONB(pDst, pSrc->domain_number);
+ OCT_D2BHTONB(pDst, pSrc->log_sync_interval);
+ OCT_D2BHTONB(pDst, pSrc->log_announce_interval);
+ OCT_D2BHTONB(pDst, pSrc->log_pdelay_interval);
+ OCT_D2BHTONS(pDst, pSrc->port_number);
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorAvbInterfaceFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_avb_interface_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AVB_INTERFACE_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_avb_interface_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->object_name, pSrc);
+ BIT_B2DNTOHS(pDst->localized_description.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->localized_description.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DMEMCP(pDst->mac_address, pSrc);
+ OCT_B2DNTOHS(pDst->interface_flags, pSrc);
+ OCT_B2DMEMCP(pDst->clock_identity, pSrc);
+ OCT_B2DNTOHB(pDst->priority1, pSrc);
+ OCT_B2DNTOHB(pDst->clock_class, pSrc);
+ OCT_B2DNTOHS(pDst->offset_scaled_log_variance, pSrc);
+ OCT_B2DNTOHB(pDst->clock_accuracy, pSrc);
+ OCT_B2DNTOHB(pDst->priority2, pSrc);
+ OCT_B2DNTOHB(pDst->domain_number, pSrc);
+ OCT_B2DNTOHB(pDst->log_sync_interval, pSrc);
+ OCT_B2DNTOHB(pDst->log_announce_interval, pSrc);
+ OCT_B2DNTOHB(pDst->log_pdelay_interval, pSrc);
+ OCT_B2DNTOHS(pDst->port_number, pSrc);
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorAvbInterfaceUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_avb_interface_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // Make the Clock Identity the same as the Entity Id.
+ // Just use the first entity descriptor from the first configuration, as they should all be the same.
+ openavb_aem_descriptor_entity_t *pEntityDescriptor =
+ (openavb_aem_descriptor_entity_t *) openavbAemGetDescriptor(0, OPENAVB_AEM_DESCRIPTOR_ENTITY, 0);
+ if (pEntityDescriptor) {
+ memcpy(pDescriptor->clock_identity, pEntityDescriptor->entity_id, sizeof(pDescriptor->clock_identity));
+ }
+
+#ifndef AVB_PTP_AVAILABLE
+ // Get the current grandmaster information.
+ if (!osalClockGrandmasterGetInterface(
+ pDescriptor->clock_identity,
+ &pDescriptor->priority1,
+ &pDescriptor->clock_class,
+ &pDescriptor->offset_scaled_log_variance,
+ &pDescriptor->clock_accuracy,
+ &pDescriptor->priority2,
+ &pDescriptor->domain_number,
+ &pDescriptor->log_sync_interval,
+ &pDescriptor->log_announce_interval,
+ &pDescriptor->log_pdelay_interval,
+ &pDescriptor->port_number))
+ {
+ AVB_LOG_ERROR("osalClockGrandmasterGetInterface failure");
+ }
+#endif // !AVB_PTP_AVAILABLE
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_avb_interface_t *openavbAemDescriptorAvbInterfaceNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_avb_interface_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_avb_interface_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorAvbInterfaceToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorAvbInterfaceFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorAvbInterfaceUpdate;
+
+ strncpy((char *) pDescriptor->object_name, gAvdeccCfg.ifname, sizeof(pDescriptor->object_name));
+ memcpy(pDescriptor->mac_address, gAvdeccCfg.ifmac, sizeof(pDescriptor->mac_address));
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE;
+
+ // Default to supporting all the interfaces.
+ pDescriptor->interface_flags =
+ OPENAVB_AEM_INTERFACE_TYPE_GPTP_GRANDMASTER_SUPPORTED |
+ OPENAVB_AEM_INTERFACE_TYPE_GPTP_SUPPORTED |
+ OPENAVB_AEM_INTERFACE_TYPE_SRP_SUPPORTED;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorAvbInterfaceInitialize(openavb_aem_descriptor_avb_interface_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ (void) nConfigIdx;
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_avb_interface.h b/lib/avtp_pipeline/aem/openavb_descriptor_avb_interface.h
new file mode 100644
index 00000000..093656c7
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_avb_interface.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC AVB Interface Descriptor
+ * MODULE SUMMARY : Interface for the AVB Interface Desciptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_AVB_INTERFACE_H
+#define OPENAVB_DESCRIPTOR_AVB_INTERFACE_H 1
+
+#include "openavb_descriptor_avb_interface_pub.h"
+
+#define OPENAVB_DESCRIPTOR_AVB_INTERFACE_BASE_LENGTH (98)
+
+#endif // OPENAVB_DESCRIPTOR_AVB_INTERFACE_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_avb_interface_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_avb_interface_pub.h
new file mode 100644
index 00000000..c2c17fed
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_avb_interface_pub.h
@@ -0,0 +1,73 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC AVB Interface Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the AVB Interface Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_AVB_INTERFACE_PUB_H
+#define OPENAVB_DESCRIPTOR_AVB_INTERFACE_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+// AVB INTERFACE Descriptor IEEE Std 1722.1-2013 clause 7.2.8
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 object_name[OPENAVB_AEM_STRLEN_MAX]; // Set internally
+ openavb_aem_string_ref_t localized_description;
+ U8 mac_address[6]; // Set internally
+ U16 interface_flags;
+ U8 clock_identity[8];
+ U8 priority1;
+ U8 clock_class;
+ S16 offset_scaled_log_variance;
+ U8 clock_accuracy;
+ U8 priority2;
+ U8 domain_number;
+ S8 log_sync_interval;
+ S8 log_announce_interval;
+ S8 log_pdelay_interval;
+ U16 port_number;
+} openavb_aem_descriptor_avb_interface_t;
+
+openavb_aem_descriptor_avb_interface_t *openavbAemDescriptorAvbInterfaceNew(void);
+
+bool openavbAemDescriptorAvbInterfaceInitialize(openavb_aem_descriptor_avb_interface_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+
+#endif // OPENAVB_DESCRIPTOR_AVB_INTERFACE_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_clock_domain.c b/lib/avtp_pipeline/aem/openavb_descriptor_clock_domain.c
new file mode 100644
index 00000000..7f0e4018
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_clock_domain.c
@@ -0,0 +1,209 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Clock Domain Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Clock Domain IEEE Std 1722.1-2013 clause 7.2.32
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_clock_domain.h"
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorClockDomainToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_clock_domain_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_BASE_LENGTH + (pDescriptor->clock_sources_count * OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_CLOCK_SOURCE_LENGTH)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_clock_domain_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->object_name);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.index, 0, 2);
+ OCT_D2BHTONS(pDst, pSrc->clock_source_index);
+ OCT_D2BHTONS(pDst, pSrc->clock_sources_offset);
+ OCT_D2BHTONS(pDst, pSrc->clock_sources_count);
+
+ int i1;
+ for (i1 = 0; i1 < pSrc->clock_sources_count; i1++) {
+ OCT_D2BHTONS(pDst, pSrc->clock_sources[i1]);
+ }
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorClockDomainFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_clock_domain_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_clock_domain_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->object_name, pSrc);
+ BIT_B2DNTOHS(pDst->localized_description.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->localized_description.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DNTOHS(pDst->clock_source_index, pSrc);
+ OCT_B2DNTOHS(pDst->clock_sources_offset, pSrc);
+ OCT_B2DNTOHS(pDst->clock_sources_count, pSrc);
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_BASE_LENGTH + (pDescriptor->clock_sources_count * OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_CLOCK_SOURCE_LENGTH)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ int i1;
+ for (i1 = 0; i1 < pDst->clock_sources_count; i1++) {
+ OCT_B2DNTOHS(pDst->clock_sources[i1], pSrc);
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorClockDomainUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_clock_domain_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_clock_domain_t *openavbAemDescriptorClockDomainNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_clock_domain_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_clock_domain_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorClockDomainToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorClockDomainFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorClockDomainUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN;
+ pDescriptor->clock_sources_offset = OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_BASE_LENGTH;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorClockDomainInitialize(openavb_aem_descriptor_clock_domain_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ int i;
+ openavb_aem_descriptor_clock_source_t *pClockSourceDescriptor;
+
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // Specify a name.
+ strcpy((char *)(pDescriptor->object_name), "Clock Domain");
+
+ // Add all the current clocks for this configuration to this domain.
+ for (i = 0; i < OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_MAX_CLOCK_SOURCES; ++i) {
+ pClockSourceDescriptor =
+ (openavb_aem_descriptor_clock_source_t *) openavbAemGetDescriptor(nConfigIdx, OPENAVB_AEM_DESCRIPTOR_CLOCK_SOURCE, i);
+ if (pClockSourceDescriptor == NULL) { break; }
+ pDescriptor->clock_sources[i] = pClockSourceDescriptor->descriptor_index;
+ pDescriptor->clock_sources_count = i + 1;
+ }
+
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_clock_domain.h b/lib/avtp_pipeline/aem/openavb_descriptor_clock_domain.h
new file mode 100644
index 00000000..7d30bd42
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_clock_domain.h
@@ -0,0 +1,47 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Clock Domain Descriptor
+ * MODULE SUMMARY : Interface for the Clock Domain Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_H
+#define OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_H 1
+
+#include "openavb_descriptor_clock_domain_pub.h"
+
+#define OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_BASE_LENGTH (76)
+#define OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_CLOCK_SOURCE_LENGTH (2)
+
+#endif // OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_clock_domain_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_clock_domain_pub.h
new file mode 100644
index 00000000..6458a41d
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_clock_domain_pub.h
@@ -0,0 +1,66 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Clock Domain Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Clock Domain Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_PUB_H
+#define OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+#define OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_MAX_CLOCK_SOURCES (249)
+
+// CLOCK DOMAIN Descriptor IEEE Std 1722.1-2013 clause 7.2.32
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 object_name[OPENAVB_AEM_STRLEN_MAX];
+ openavb_aem_string_ref_t localized_description;
+ U16 clock_source_index;
+ U16 clock_sources_offset;
+ U16 clock_sources_count;
+ U16 clock_sources[OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_MAX_CLOCK_SOURCES];
+} openavb_aem_descriptor_clock_domain_t;
+
+openavb_aem_descriptor_clock_domain_t *openavbAemDescriptorClockDomainNew(void);
+
+bool openavbAemDescriptorClockDomainInitialize(openavb_aem_descriptor_clock_domain_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+
+#endif // OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_clock_source.c b/lib/avtp_pipeline/aem/openavb_descriptor_clock_source.c
new file mode 100644
index 00000000..3246607a
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_clock_source.c
@@ -0,0 +1,205 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Clock Source Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Clock Source IEEE Std 1722.1-2013 clause 7.2.9
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_clock_source.h"
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorClockSourceToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_clock_source_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CLOCK_SOURCE_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_clock_source_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->object_name);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.index, 0, 2);
+ OCT_D2BHTONS(pDst, pSrc->clock_source_flags);
+ OCT_D2BHTONS(pDst, pSrc->clock_source_type);
+ OCT_D2BMEMCP(pDst, pSrc->clock_source_identifier);
+ OCT_D2BHTONS(pDst, pSrc->clock_source_location_type);
+ OCT_D2BHTONS(pDst, pSrc->clock_source_location_index);
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorClockSourceFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_clock_source_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CLOCK_SOURCE_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_clock_source_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->object_name, pSrc);
+ BIT_B2DNTOHS(pDst->localized_description.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->localized_description.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DNTOHS(pDst->clock_source_flags, pSrc);
+ OCT_B2DNTOHS(pDst->clock_source_type, pSrc);
+ OCT_B2DMEMCP(pDst->clock_source_identifier, pSrc);
+ OCT_B2DNTOHS(pDst->clock_source_location_type, pSrc);
+ OCT_B2DNTOHS(pDst->clock_source_location_index, pSrc);
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorClockSourceUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_clock_source_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_clock_source_t *openavbAemDescriptorClockSourceNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_clock_source_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_clock_source_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorClockSourceToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorClockSourceFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorClockSourceUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_CLOCK_SOURCE;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorClockSourceInitialize(openavb_aem_descriptor_clock_source_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ (void) nConfigIdx;
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO: These values need to be verified.
+ if (pConfig->stream->role == AVB_ROLE_TALKER)
+ {
+ // Make this an internal clock.
+ strcpy((char *) pDescriptor->object_name, "Internal Clock");
+ pDescriptor->clock_source_flags = 0;
+ pDescriptor->clock_source_type = OPENAVB_AEM_CLOCK_SOURCE_TYPE_INTERNAL;
+ pDescriptor->clock_source_location_type = OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT;
+ pDescriptor->clock_source_location_index = 0;
+ }
+ else if (pConfig->stream->role == AVB_ROLE_LISTENER)
+ {
+ // Use the Talker's clock.
+ strcpy((char *) pDescriptor->object_name, "Input Stream");
+ pDescriptor->clock_source_flags = OPENAVB_AEM_CLOCK_SOURCE_FLAG_STREAM_ID;
+ pDescriptor->clock_source_type = OPENAVB_AEM_CLOCK_SOURCE_TYPE_INPUT_STREAM;
+ memcpy(pDescriptor->clock_source_identifier, pConfig->stream->stream_addr.buffer.ether_addr_octet, ETH_ALEN);
+ pDescriptor->clock_source_location_type = OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT;
+ pDescriptor->clock_source_location_index = 0;
+ }
+
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_clock_source.h b/lib/avtp_pipeline/aem/openavb_descriptor_clock_source.h
new file mode 100644
index 00000000..29f9dd13
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_clock_source.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Clock Source Descriptor
+ * MODULE SUMMARY : Interface for the Clock Source Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_CLOCK_SOURCE_H
+#define OPENAVB_DESCRIPTOR_CLOCK_SOURCE_H 1
+
+#include "openavb_descriptor_clock_source_pub.h"
+
+#define OPENAVB_DESCRIPTOR_CLOCK_SOURCE_BASE_LENGTH (86)
+
+#endif // OPENAVB_DESCRIPTOR_CLOCK_SOURCE_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_clock_source_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_clock_source_pub.h
new file mode 100644
index 00000000..10b2b723
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_clock_source_pub.h
@@ -0,0 +1,65 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Clock Source Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Clock Source Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_CLOCK_SOURCE_PUB_H
+#define OPENAVB_DESCRIPTOR_CLOCK_SOURCE_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+// CLOCK SOURCE Descriptor IEEE Std 1722.1-2013 clause 7.2.9
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 object_name[OPENAVB_AEM_STRLEN_MAX];
+ openavb_aem_string_ref_t localized_description;
+ U16 clock_source_flags;
+ U16 clock_source_type;
+ U8 clock_source_identifier[8];
+ U16 clock_source_location_type;
+ U16 clock_source_location_index;
+} openavb_aem_descriptor_clock_source_t;
+
+openavb_aem_descriptor_clock_source_t *openavbAemDescriptorClockSourceNew(void);
+
+bool openavbAemDescriptorClockSourceInitialize(openavb_aem_descriptor_clock_source_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+
+#endif // OPENAVB_DESCRIPTOR_CLOCK_SOURCE_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_configuration.c b/lib/avtp_pipeline/aem/openavb_descriptor_configuration.c
new file mode 100644
index 00000000..aaa442fa
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_configuration.c
@@ -0,0 +1,197 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Configuration Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Configuration Descriptor IEEE Std 1722.1-2013 clause 7.2.1
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_configuration.h"
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorConfigurationToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_configuration_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CONFIGURATION_BASE_LENGTH + (pDescriptor->descriptor_counts_count * sizeof(*pDescriptor->descriptor_counts))) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_configuration_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->object_name);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.index, 0, 2);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_counts_count);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_counts_offset);
+
+ int i1;
+ for (i1 = 0; i1 < pSrc->descriptor_counts_count; i1++) {
+ OCT_D2BHTONS(pDst, pSrc->descriptor_counts[i1].descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_counts[i1].count);
+ }
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorConfigurationFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_configuration_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CONFIGURATION_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_configuration_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->object_name, pSrc);
+ BIT_B2DNTOHS(pDst->localized_description.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->localized_description.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DNTOHS(pDst->descriptor_counts_count, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_counts_offset, pSrc);
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CONFIGURATION_BASE_LENGTH + (pDescriptor->descriptor_counts_count * sizeof(*pDescriptor->descriptor_counts))) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ int i1;
+ for (i1 = 0; i1 < pDst->descriptor_counts_count; i1++) {
+ OCT_B2DNTOHS(pDst->descriptor_counts[i1].descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_counts[i1].count, pSrc);
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorConfigurationUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_configuration_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_configuration_t *openavbAemDescriptorConfigurationNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_configuration_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_configuration_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorConfigurationToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorConfigurationFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorConfigurationUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_CONFIGURATION;
+ pDescriptor->descriptor_counts_offset = OPENAVB_DESCRIPTOR_CONFIGURATION_BASE_LENGTH;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorConfigurationInitialize(openavb_aem_descriptor_configuration_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ (void) nConfigIdx;
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ openavbAemSetString(pDescriptor->object_name, pConfig->friendly_name);
+
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_configuration.h b/lib/avtp_pipeline/aem/openavb_descriptor_configuration.h
new file mode 100644
index 00000000..1b804c4f
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_configuration.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Configuration Descriptor
+ * MODULE SUMMARY : Interface for the Configuration Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_CONFIGURATION_H
+#define OPENAVB_DESCRIPTOR_CONFIGURATION_H 1
+
+#include "openavb_descriptor_configuration_pub.h"
+
+#define OPENAVB_DESCRIPTOR_CONFIGURATION_BASE_LENGTH (74)
+
+#endif // OPENAVB_DESCRIPTOR_CONFIGURATION_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_configuration_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_configuration_pub.h
new file mode 100644
index 00000000..2b6c71ff
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_configuration_pub.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.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Entity Model : Configuration Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Configuration Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_CONFIGURATION_PUB_H
+#define OPENAVB_DESCRIPTOR_CONFIGURATION_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+#define OPENAVB_DESCRIPTOR_CONFIGURATION_MAX_DESCRIPTOR_COUNTS (108)
+
+// CONFIGURATION Descriptor IEEE Std 1722.1-2013 clause 7.2.2
+typedef struct {
+ U16 descriptor_type;
+ U16 count;
+} openavb_aem_descriptor_configuration_descriptor_counts_t;
+
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 object_name[OPENAVB_AEM_STRLEN_MAX];
+ openavb_aem_string_ref_t localized_description;
+ U16 descriptor_counts_count; // Set internally
+ U16 descriptor_counts_offset; // Set internally
+ openavb_aem_descriptor_configuration_descriptor_counts_t descriptor_counts[OPENAVB_DESCRIPTOR_CONFIGURATION_MAX_DESCRIPTOR_COUNTS]; // Set internally
+} openavb_aem_descriptor_configuration_t;
+
+openavb_aem_descriptor_configuration_t *openavbAemDescriptorConfigurationNew(void);
+
+bool openavbAemDescriptorConfigurationInitialize(openavb_aem_descriptor_configuration_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+
+#endif // OPENAVB_DESCRIPTOR_CONFIGURATION_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_control.c b/lib/avtp_pipeline/aem/openavb_descriptor_control.c
new file mode 100644
index 00000000..a432fe4c
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_control.c
@@ -0,0 +1,502 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Control Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Control IEEE Std 1722.1-2013 clause 7.2.32
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_control.h"
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorControlToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_control_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CONTROL_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_control_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->object_name);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.index, 0, 2);
+ OCT_D2BHTONL(pDst, pSrc->block_latency);
+ OCT_D2BHTONL(pDst, pSrc->control_latency);
+ OCT_D2BHTONS(pDst, pSrc->control_domain);
+ OCT_D2BHTONS(pDst, pSrc->control_value_type);
+ OCT_D2BMEMCP(pDst, &pSrc->control_type);
+ OCT_D2BHTONL(pDst, pSrc->reset_time);
+ OCT_D2BHTONS(pDst, pSrc->values_offset);
+ OCT_D2BHTONS(pDst, pSrc->number_of_values);
+ OCT_D2BHTONS(pDst, pSrc->signal_type);
+ OCT_D2BHTONS(pDst, pSrc->signal_index);
+ OCT_D2BHTONS(pDst, pSrc->signal_output);
+
+ int i1;
+ for (i1 = 0; i1 < pSrc->number_of_values; i1++) {
+ switch (pSrc->control_value_type) {
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT8:
+ OCT_D2BHTONB(pDst, pSrc->value_details.linear_int8[i1].minimum);
+ OCT_D2BHTONB(pDst, pSrc->value_details.linear_int8[i1].maximum);
+ OCT_D2BHTONB(pDst, pSrc->value_details.linear_int8[i1].step);
+ OCT_D2BHTONB(pDst, pSrc->value_details.linear_int8[i1].default_value);
+ OCT_D2BHTONB(pDst, pSrc->value_details.linear_int8[i1].current);
+ OCT_D2BHTONS(pDst, pSrc->value_details.linear_int8[i1].unit);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_int8[i1].string.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_int8[i1].string.index, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT16:
+ OCT_D2BHTONS(pDst, pSrc->value_details.linear_int16[i1].minimum);
+ OCT_D2BHTONS(pDst, pSrc->value_details.linear_int16[i1].maximum);
+ OCT_D2BHTONS(pDst, pSrc->value_details.linear_int16[i1].step);
+ OCT_D2BHTONS(pDst, pSrc->value_details.linear_int16[i1].default_value);
+ OCT_D2BHTONS(pDst, pSrc->value_details.linear_int16[i1].current);
+ OCT_D2BHTONS(pDst, pSrc->value_details.linear_int16[i1].unit);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_int16[i1].string.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_int16[i1].string.index, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT32:
+ OCT_D2BHTONL(pDst, pSrc->value_details.linear_int32[i1].minimum);
+ OCT_D2BHTONL(pDst, pSrc->value_details.linear_int32[i1].maximum);
+ OCT_D2BHTONL(pDst, pSrc->value_details.linear_int32[i1].step);
+ OCT_D2BHTONL(pDst, pSrc->value_details.linear_int32[i1].default_value);
+ OCT_D2BHTONL(pDst, pSrc->value_details.linear_int32[i1].current);
+ OCT_D2BHTONL(pDst, pSrc->value_details.linear_int32[i1].unit);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_int32[i1].string.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_int32[i1].string.index, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT64:
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_int64[i1].minimum);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_int64[i1].maximum);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_int64[i1].step);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_int64[i1].default_value);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_int64[i1].current);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_int64[i1].unit);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_int64[i1].string.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_int64[i1].string.index, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_FLOAT:
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_float[i1].minimum);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_float[i1].maximum);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_float[i1].step);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_float[i1].default_value);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_float[i1].current);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_float[i1].unit);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_float[i1].string.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_float[i1].string.index, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_DOUBLE:
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_double[i1].minimum);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_double[i1].maximum);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_double[i1].step);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_double[i1].default_value);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_double[i1].current);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_double[i1].unit);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_double[i1].string.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_double[i1].string.index, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT16:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT16:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT32:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT32:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT64:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT64:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_FLOAT:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_DOUBLE:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_STRING:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT16:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT16:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT32:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT32:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT64:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT64:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_FLOAT:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_DOUBLE:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_UTF8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_BODE_PLOT:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SMPTE_TIME:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SAMPLE_RATE:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_GPTP_TIME:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_VENDOR:
+ // AVDECC_TODO
+ break;
+ }
+ }
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorControlFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_control_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CONTROL_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_control_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->object_name, pSrc);
+ BIT_B2DNTOHS(pDst->localized_description.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->localized_description.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DNTOHL(pDst->block_latency, pSrc);
+ OCT_B2DNTOHL(pDst->control_latency, pSrc);
+ OCT_B2DNTOHS(pDst->control_domain, pSrc);
+ OCT_B2DNTOHS(pDst->control_value_type, pSrc);
+ OCT_B2DMEMCP(&pDst->control_type, pSrc);
+ OCT_B2DNTOHL(pDst->reset_time, pSrc);
+ OCT_B2DNTOHS(pDst->values_offset, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_values, pSrc);
+ OCT_B2DNTOHS(pDst->signal_type, pSrc);
+ OCT_B2DNTOHS(pDst->signal_index, pSrc);
+ OCT_B2DNTOHS(pDst->signal_output, pSrc);
+
+
+ int i1;
+ for (i1 = 0; i1 < pDst->number_of_values; i1++) {
+ switch (pDst->control_value_type) {
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT8:
+ OCT_B2DNTOHB(pDst->value_details.linear_int8[i1].minimum, pSrc);
+ OCT_B2DNTOHB(pDst->value_details.linear_int8[i1].maximum, pSrc);
+ OCT_B2DNTOHB(pDst->value_details.linear_int8[i1].step, pSrc);
+ OCT_B2DNTOHB(pDst->value_details.linear_int8[i1].default_value, pSrc);
+ OCT_B2DNTOHB(pDst->value_details.linear_int8[i1].current, pSrc);
+ OCT_B2DNTOHB(pDst->value_details.linear_int8[i1].unit, pSrc);
+ BIT_B2DNTOHS(pDst->value_details.linear_int8[i1].string.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->value_details.linear_int8[i1].string.index, pSrc, 0x0007, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT16:
+ OCT_B2DNTOHS(pDst->value_details.linear_int16[i1].minimum, pSrc);
+ OCT_B2DNTOHS(pDst->value_details.linear_int16[i1].maximum, pSrc);
+ OCT_B2DNTOHS(pDst->value_details.linear_int16[i1].step, pSrc);
+ OCT_B2DNTOHS(pDst->value_details.linear_int16[i1].default_value, pSrc);
+ OCT_B2DNTOHS(pDst->value_details.linear_int16[i1].current, pSrc);
+ OCT_B2DNTOHS(pDst->value_details.linear_int16[i1].unit, pSrc);
+ BIT_B2DNTOHS(pDst->value_details.linear_int16[i1].string.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->value_details.linear_int16[i1].string.index, pSrc, 0x0007, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT32:
+ OCT_B2DNTOHL(pDst->value_details.linear_int32[i1].minimum, pSrc);
+ OCT_B2DNTOHL(pDst->value_details.linear_int32[i1].maximum, pSrc);
+ OCT_B2DNTOHL(pDst->value_details.linear_int32[i1].step, pSrc);
+ OCT_B2DNTOHL(pDst->value_details.linear_int32[i1].default_value, pSrc);
+ OCT_B2DNTOHL(pDst->value_details.linear_int32[i1].current, pSrc);
+ OCT_B2DNTOHL(pDst->value_details.linear_int32[i1].unit, pSrc);
+ BIT_B2DNTOHS(pDst->value_details.linear_int32[i1].string.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->value_details.linear_int32[i1].string.index, pSrc, 0x0007, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT64:
+ OCT_B2DMEMCP(&pDst->value_details.linear_int64[i1].minimum, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_int64[i1].maximum, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_int64[i1].step, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_int64[i1].default_value, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_int64[i1].current, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_int64[i1].unit, pSrc);
+ BIT_B2DNTOHS(pDst->value_details.linear_int64[i1].string.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->value_details.linear_int64[i1].string.index, pSrc, 0x0007, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_FLOAT:
+ OCT_B2DMEMCP(&pDst->value_details.linear_float[i1].minimum, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_float[i1].maximum, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_float[i1].step, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_float[i1].default_value, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_float[i1].current, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_float[i1].unit, pSrc);
+ BIT_B2DNTOHS(pDst->value_details.linear_float[i1].string.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->value_details.linear_float[i1].string.index, pSrc, 0x0007, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_DOUBLE:
+ OCT_B2DMEMCP(&pDst->value_details.linear_double[i1].minimum, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_double[i1].maximum, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_double[i1].step, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_double[i1].default_value, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_double[i1].current, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_double[i1].unit, pSrc);
+ BIT_B2DNTOHS(pDst->value_details.linear_double[i1].string.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->value_details.linear_double[i1].string.index, pSrc, 0x0007, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT16:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT16:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT32:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT32:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT64:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT64:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_FLOAT:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_DOUBLE:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_STRING:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT16:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT16:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT32:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT32:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT64:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT64:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_FLOAT:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_DOUBLE:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_UTF8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_BODE_PLOT:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SMPTE_TIME:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SAMPLE_RATE:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_GPTP_TIME:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_VENDOR:
+ // AVDECC_TODO
+ break;
+ }
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorControlUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_control_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_control_t *openavbAemDescriptorControlNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_control_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_control_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorControlToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorControlFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorControlUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_CONTROL;
+ pDescriptor->values_offset = OPENAVB_DESCRIPTOR_CONTROL_BASE_LENGTH;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorDescriptorControlInitialize(openavb_aem_descriptor_control_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ (void) nConfigIdx;
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_control.h b/lib/avtp_pipeline/aem/openavb_descriptor_control.h
new file mode 100644
index 00000000..6635e248
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_control.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Control Descriptor
+ * MODULE SUMMARY : Interface for the Control Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_CONTROL_H
+#define OPENAVB_DESCRIPTOR_CONTROL_H 1
+
+#include "openavb_descriptor_control_pub.h"
+
+#define OPENAVB_DESCRIPTOR_CONTROL_BASE_LENGTH (104)
+
+#endif // OPENAVB_DESCRIPTOR_CONTROL_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_control_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_control_pub.h
new file mode 100644
index 00000000..e0a6a0f4
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_control_pub.h
@@ -0,0 +1,111 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Control Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Control Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_CONTROL_PUB_H
+#define OPENAVB_DESCRIPTOR_CONTROL_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+// CONTROL Descriptor IEEE Std 1722.1-2013 clause 7.2.22
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 object_name[OPENAVB_AEM_STRLEN_MAX];
+ openavb_aem_string_ref_t localized_description;
+ U32 block_latency;
+ U32 control_latency;
+ U16 control_domain;
+ U16 control_value_type;
+ U64 control_type;
+ U32 reset_time;
+ U16 values_offset;
+ U16 number_of_values;
+ U16 signal_type;
+ U16 signal_index;
+ U16 signal_output;
+ union {
+ openavb_aem_control_value_format_control_linear_int8_t linear_int8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT8];
+ openavb_aem_control_value_format_control_linear_uint8_t linear_uint8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT8];
+ openavb_aem_control_value_format_control_linear_int16_t linear_int16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT16];
+ openavb_aem_control_value_format_control_linear_uint16_t linear_uint16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT16];
+ openavb_aem_control_value_format_control_linear_int32_t linear_int32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT32];
+ openavb_aem_control_value_format_control_linear_uint32_t linear_uint32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT32];
+ openavb_aem_control_value_format_control_linear_int64_t linear_int64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT64];
+ openavb_aem_control_value_format_control_linear_uint64_t linear_uint64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT64];
+ openavb_aem_control_value_format_control_linear_float_t linear_float[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_FLOAT];
+ openavb_aem_control_value_format_control_linear_double_t linear_double[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_DOUBLE];
+ openavb_aem_control_value_format_control_selector_int8_t selector_int8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT8];
+ openavb_aem_control_value_format_control_selector_uint8_t selector_uint8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT8];
+ openavb_aem_control_value_format_control_selector_int16_t selector_int16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT16];
+ openavb_aem_control_value_format_control_selector_uint16_t selector_uint16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT16];
+ openavb_aem_control_value_format_control_selector_int32_t selector_int32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT32];
+ openavb_aem_control_value_format_control_selector_uint32_t selector_uint32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT32];
+ openavb_aem_control_value_format_control_selector_int64_t selector_int64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT64];
+ openavb_aem_control_value_format_control_selector_uint64_t selector_uint64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT64];
+ openavb_aem_control_value_format_control_selector_float_t selector_float[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_FLOAT];
+ openavb_aem_control_value_format_control_selector_double_t selector_double[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_DOUBLE];
+ openavb_aem_control_value_format_control_selector_string_t selector_string[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_STRING];
+ openavb_aem_control_value_format_control_array_int8_t array_int8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT8];
+ openavb_aem_control_value_format_control_array_uint8_t array_uint8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT8];
+ openavb_aem_control_value_format_control_array_int16_t array_int16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT16];
+ openavb_aem_control_value_format_control_array_uint16_t array_uint16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT16];
+ openavb_aem_control_value_format_control_array_int32_t array_int32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT32];
+ openavb_aem_control_value_format_control_array_uint32_t array_uint32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT32];
+ openavb_aem_control_value_format_control_array_int64_t array_int64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT64];
+ openavb_aem_control_value_format_control_array_uint64_t array_uint64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT64];
+ openavb_aem_control_value_format_control_array_float_t array_float[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_FLOAT];
+ openavb_aem_control_value_format_control_array_double_t array_double[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_DOUBLE];
+ openavb_aem_control_value_format_control_utf8_t utf8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_UTF8];
+ openavb_aem_control_value_format_control_bode_plot_t bode_plot[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_BODE_PLOT];
+ openavb_aem_control_value_format_control_smpte_time_t smpte_time[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SMPTE_TIME];
+ openavb_aem_control_value_format_control_sample_rate_t sample_rate[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SAMPLE_RATE];
+ openavb_aem_control_value_format_control_gptp_time_t gptp_time[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_GPTP_TIME];
+ openavb_aem_control_value_format_control_vendor_t vendor[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_VENDOR];
+ } value_details;
+} openavb_aem_descriptor_control_t;
+
+
+openavb_aem_descriptor_control_t *openavbAemDescriptorControlNew(void);
+
+bool openavbAemDescriptorDescriptorControlInitialize(openavb_aem_descriptor_control_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+
+#endif // OPENAVB_DESCRIPTOR_CONTROL_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_entity.c b/lib/avtp_pipeline/aem/openavb_descriptor_entity.c
new file mode 100644
index 00000000..6e0e4666
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_entity.c
@@ -0,0 +1,411 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Entity Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Entity Descriptor IEEE Std 1722.1-2013 clause 7.2.1
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_entity.h"
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorEntityToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_entity_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_ENTITY_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_entity_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->entity_id);
+ OCT_D2BMEMCP(pDst, pSrc->entity_model_id);
+ OCT_D2BHTONL(pDst, pSrc->entity_capabilities);
+ OCT_D2BHTONS(pDst, pSrc->talker_stream_sources);
+ OCT_D2BHTONS(pDst, pSrc->talker_capabilities);
+ OCT_D2BHTONS(pDst, pSrc->listener_stream_sinks);
+ OCT_D2BHTONS(pDst, pSrc->listener_capabilities);
+ OCT_D2BHTONL(pDst, pSrc->controller_capabilities);
+ OCT_D2BHTONL(pDst, pSrc->available_index);
+ OCT_D2BMEMCP(pDst, pSrc->association_id);
+ OCT_D2BMEMCP(pDst, pSrc->entity_name);
+ BIT_D2BHTONS(pDst, pSrc->vendor_name_string.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->vendor_name_string.index, 0, 2);
+ BIT_D2BHTONS(pDst, pSrc->model_name_string.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->model_name_string.index, 0, 2);
+ OCT_D2BMEMCP(pDst, pSrc->firmware_version);
+ OCT_D2BMEMCP(pDst, pSrc->group_name);
+ OCT_D2BMEMCP(pDst, pSrc->serial_number);
+ OCT_D2BHTONS(pDst, pSrc->configurations_count);
+ OCT_D2BHTONS(pDst, pSrc->current_configuration);
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorEntityFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_entity_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_ENTITY_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_entity_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->entity_id, pSrc);
+ OCT_B2DMEMCP(pDst->entity_model_id, pSrc);
+ OCT_B2DNTOHL(pDst->entity_capabilities, pSrc);
+ OCT_B2DNTOHS(pDst->talker_stream_sources, pSrc);
+ OCT_B2DNTOHS(pDst->talker_capabilities, pSrc);
+ OCT_B2DNTOHS(pDst->listener_stream_sinks, pSrc);
+ OCT_B2DNTOHS(pDst->listener_capabilities, pSrc);
+ OCT_B2DNTOHL(pDst->controller_capabilities, pSrc);
+ OCT_B2DNTOHL(pDst->available_index, pSrc);
+ OCT_B2DMEMCP(pDst->association_id, pSrc);
+ OCT_B2DMEMCP(pDst->entity_name, pSrc);
+ BIT_B2DNTOHS(pDst->vendor_name_string.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->vendor_name_string.index, pSrc, 0x0007, 0, 2);
+ BIT_B2DNTOHS(pDst->model_name_string.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->model_name_string.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DMEMCP(pDst->firmware_version, pSrc);
+ OCT_B2DMEMCP(pDst->group_name, pSrc);
+ OCT_B2DMEMCP(pDst->serial_number, pSrc);
+ OCT_B2DNTOHS(pDst->configurations_count, pSrc);
+ OCT_B2DNTOHS(pDst->current_configuration, pSrc);
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorEntityUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_entity_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_entity_t *openavbAemDescriptorEntityNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_entity_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(openavb_aem_descriptor_entity_t));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor->descriptorPvtPtr, 0, sizeof(*pDescriptor->descriptorPvtPtr));
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_entity_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorEntityToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorEntityFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorEntityUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_ENTITY;
+ pDescriptor->descriptor_index = 0;
+
+ // Default to no localized strings.
+ pDescriptor->vendor_name_string.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->vendor_name_string.index = OPENAVB_AEM_NO_STRING_INDEX;
+ pDescriptor->model_name_string.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->model_name_string.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_entity_id(openavb_aem_descriptor_entity_t *pDescriptor, char *aMacAddr, U8 *nMacAddr, U16 id)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ struct ether_addr macAddrBuffer;
+ if (aMacAddr) {
+ // If an ascii mac address is passed in parse and use it.
+ memset(macAddrBuffer.ether_addr_octet, 0, sizeof(macAddrBuffer));
+
+ if (!ether_aton_r(aMacAddr, &macAddrBuffer)) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_PARSING_MAC_ADDRESS));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+ memcpy(pDescriptor->entity_id, macAddrBuffer.ether_addr_octet, 3);
+ memcpy(pDescriptor->entity_id + 3 + 2, macAddrBuffer.ether_addr_octet + 3, 3);
+ }
+ else if (nMacAddr) {
+ // If a network mac address is passed in use it.
+ memcpy(pDescriptor->entity_id, nMacAddr, 3);
+ memcpy(pDescriptor->entity_id + 3 + 2, nMacAddr + 3, 3);
+ }
+ else {
+ // If no mac address is passed in obtain it from the stack.
+ memcpy(pDescriptor->entity_id, gAvdeccCfg.ifmac, 3);
+ memcpy(pDescriptor->entity_id + 3 + 2, gAvdeccCfg.ifmac + 3, 3);
+ }
+
+ U16 tmpU16 = htons(id);
+ memcpy(pDescriptor->entity_id + 3, &tmpU16, sizeof(tmpU16));
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_entity_model_id(openavb_aem_descriptor_entity_t *pDescriptor, U8 pData[8])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !pData) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ memcpy(pDescriptor->entity_model_id, pData, 8);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_entity_capabilities(openavb_aem_descriptor_entity_t *pDescriptor, U32 capabilities)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ pDescriptor->entity_capabilities = capabilities;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_talker_capabilities(openavb_aem_descriptor_entity_t *pDescriptor, U16 num_sources, U16 capabilities)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ pDescriptor->talker_stream_sources = num_sources;
+ pDescriptor->talker_capabilities = capabilities;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_listener_capabilities(openavb_aem_descriptor_entity_t *pDescriptor, U16 num_sinks, U16 capabilities)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ pDescriptor->listener_stream_sinks = num_sinks;
+ pDescriptor->listener_capabilities = capabilities;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_entity_name(openavb_aem_descriptor_entity_t *pDescriptor, char *aName)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !aName) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ openavbAemSetString(pDescriptor->entity_name, aName);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_vendor_name(openavb_aem_descriptor_entity_t *pDescriptor, U16 nOffset, U8 nIndex)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ pDescriptor->vendor_name_string.offset = nOffset;
+ pDescriptor->vendor_name_string.index = nIndex;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_model_name(openavb_aem_descriptor_entity_t *pDescriptor, U16 nOffset, U8 nIndex)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ pDescriptor->model_name_string.offset = nOffset;
+ pDescriptor->model_name_string.index = nIndex;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_firmware_version(openavb_aem_descriptor_entity_t *pDescriptor, char *aFirmwareVersion)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !aFirmwareVersion) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ openavbAemSetString(pDescriptor->firmware_version, aFirmwareVersion);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_group_name(openavb_aem_descriptor_entity_t *pDescriptor, char *aGroupName)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !aGroupName) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ openavbAemSetString(pDescriptor->group_name, aGroupName);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_serial_number(openavb_aem_descriptor_entity_t *pDescriptor, char *aSerialNumber)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !aSerialNumber) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ openavbAemSetString(pDescriptor->serial_number, aSerialNumber);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_entity.h b/lib/avtp_pipeline/aem/openavb_descriptor_entity.h
new file mode 100644
index 00000000..7e8ade4f
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_entity.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Entity Model : Entity Descriptor
+ * MODULE SUMMARY : Interface for the Entity Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_ENTITY_H
+#define OPENAVB_DESCRIPTOR_ENTITY_H 1
+
+#include "openavb_descriptor_entity_pub.h"
+
+#define OPENAVB_DESCRIPTOR_ENTITY_BASE_LENGTH 312
+
+#endif // OPENAVB_DESCRIPTOR_ENTITY_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_entity_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_entity_pub.h
new file mode 100644
index 00000000..00875ae3
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_entity_pub.h
@@ -0,0 +1,108 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Entity Model : Entity Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Entity Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_ENTITY_PUB_H
+#define OPENAVB_DESCRIPTOR_ENTITY_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+// ENTITY Descriptor IEEE Std 1722.1-2013 clause 7.2.1
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 entity_id[8];
+ U8 entity_model_id[8];
+ U32 entity_capabilities;
+ U16 talker_stream_sources;
+ U16 talker_capabilities;
+ U16 listener_stream_sinks;
+ U16 listener_capabilities;
+ U32 controller_capabilities;
+ U32 available_index;
+ U8 association_id[8];
+ U8 entity_name[OPENAVB_AEM_STRLEN_MAX];
+ openavb_aem_string_ref_t vendor_name_string;
+ openavb_aem_string_ref_t model_name_string;
+ U8 firmware_version[OPENAVB_AEM_STRLEN_MAX];
+ U8 group_name[OPENAVB_AEM_STRLEN_MAX];
+ U8 serial_number[OPENAVB_AEM_STRLEN_MAX];
+ U16 configurations_count; // Set internally
+ U16 current_configuration; // Set internally
+} openavb_aem_descriptor_entity_t;
+
+// Create a new Entity Descriptor
+openavb_aem_descriptor_entity_t *openavbAemDescriptorEntityNew(void);
+
+// Set the Entity ID using the common approach of mac address and an ID. Either pass in aMacAddr (ascii) or nMacAddr (network)
+bool openavbAemDescriptorEntitySet_entity_id(openavb_aem_descriptor_entity_t *pDescriptor, char *aMacAddr, U8 *nMacAddr, U16 id);
+
+// Set the Entity Model ID. Pass in a pointer to an array of 8 bytes of arbitrary data.
+bool openavbAemDescriptorEntitySet_entity_model_id(openavb_aem_descriptor_entity_t *pDescriptor, U8 pData[8]);
+
+// Set the Entity Capabilities. Use the OPENAVB_ADP_ENTITY_CAPABILITIES_... flags from adp/openavb_adp_pub.h.
+bool openavbAemDescriptorEntitySet_entity_capabilities(openavb_aem_descriptor_entity_t *pDescriptor, U32 capabilities);
+
+// Set the Talker Capabilities. Use the OPENAVB_ADP_TALKER_CAPABILITIES_... flags from adp/openavb_adp_pub.h.
+bool openavbAemDescriptorEntitySet_talker_capabilities(openavb_aem_descriptor_entity_t *pDescriptor, U16 num_sources, U16 capabilities);
+
+// Set the Listener Capabilities. Use the OPENAVB_ADP_LISTENER_CAPABILITIES_... flags from adp/openavb_adp_pub.h.
+bool openavbAemDescriptorEntitySet_listener_capabilities(openavb_aem_descriptor_entity_t *pDescriptor, U16 num_sinks, U16 capabilities);
+
+// Set the Entity Name.
+bool openavbAemDescriptorEntitySet_entity_name(openavb_aem_descriptor_entity_t *pDescriptor, char *aName);
+
+// Set the Vendor Name.
+bool openavbAemDescriptorEntitySet_vendor_name(openavb_aem_descriptor_entity_t *pDescriptor, U16 nOffset, U8 nIndex);
+
+// Set the Model Name.
+bool openavbAemDescriptorEntitySet_model_name(openavb_aem_descriptor_entity_t *pDescriptor, U16 nOffset, U8 nIndex);
+
+// Set the Firmware Version.
+bool openavbAemDescriptorEntitySet_firmware_version(openavb_aem_descriptor_entity_t *pDescriptor, char *aFirmwareVersion);
+
+// Set the Group Name.
+bool openavbAemDescriptorEntitySet_group_name(openavb_aem_descriptor_entity_t *pDescriptor, char *aGroupName);
+
+// Set the Serial Number.
+bool openavbAemDescriptorEntitySet_serial_number(openavb_aem_descriptor_entity_t *pDescriptor, char *aSerialNumber);
+
+#endif // OPENAVB_DESCRIPTOR_ENTITY_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_external_port_io.c b/lib/avtp_pipeline/aem/openavb_descriptor_external_port_io.c
new file mode 100644
index 00000000..615e800c
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_external_port_io.c
@@ -0,0 +1,209 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC External Port IO Descriptor
+ * MODULE SUMMARY : Implements the AVDECC External Port IO IEEE Std 1722.1-2013 clause 7.2.14
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_external_port_io.h"
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorExternalPortIOToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_external_port_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_EXTERNAL_PORT_IO_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_external_port_io_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BHTONS(pDst, pSrc->clock_domain_index);
+ OCT_D2BHTONS(pDst, pSrc->port_flags);
+ OCT_D2BHTONS(pDst, pSrc->number_of_controls);
+ OCT_D2BHTONS(pDst, pSrc->base_control);
+ OCT_D2BHTONS(pDst, pSrc->signal_type);
+ OCT_D2BHTONS(pDst, pSrc->signal_index);
+ OCT_D2BHTONS(pDst, pSrc->signal_output);
+ OCT_D2BHTONL(pDst, pSrc->block_latency);
+ OCT_D2BHTONS(pDst, pSrc->jack_index);
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorExternalPortIOFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_external_port_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_EXTERNAL_PORT_IO_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_external_port_io_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DNTOHS(pDst->clock_domain_index, pSrc);
+ OCT_B2DNTOHS(pDst->port_flags, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_controls, pSrc);
+ OCT_B2DNTOHS(pDst->base_control, pSrc);
+ OCT_B2DNTOHS(pDst->signal_type, pSrc);
+ OCT_B2DNTOHS(pDst->signal_index, pSrc);
+ OCT_B2DNTOHS(pDst->signal_output, pSrc);
+ OCT_B2DNTOHL(pDst->block_latency, pSrc);
+ OCT_B2DNTOHS(pDst->jack_index, pSrc);
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorExternalPortIOUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_external_port_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_external_port_io_t *openavbAemDescriptorExternalPortInputNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_external_port_io_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_external_port_io_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = FALSE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorExternalPortIOToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorExternalPortIOFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorExternalPortIOUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_STREAM_PORT_INPUT;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT openavb_aem_descriptor_external_port_io_t *openavbAemDescriptorExternalPortOutputNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_external_port_io_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_external_port_io_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = FALSE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorExternalPortIOToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorExternalPortIOFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorExternalPortIOUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_STREAM_PORT_OUTPUT;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_external_port_io.h b/lib/avtp_pipeline/aem/openavb_descriptor_external_port_io.h
new file mode 100644
index 00000000..3336d581
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_external_port_io.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC External Port IO Descriptor
+ * MODULE SUMMARY : Interface for the External Port IO Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_EXTERNAL_PORT_IO_H
+#define OPENAVB_DESCRIPTOR_EXTERNAL_PORT_IO_H 1
+
+#include "openavb_descriptor_external_port_io_pub.h"
+
+#define OPENAVB_DESCRIPTOR_EXTERNAL_PORT_IO_BASE_LENGTH 24
+
+#endif // OPENAVB_DESCRIPTOR_EXTERNAL_PORT_IO_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_external_port_io_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_external_port_io_pub.h
new file mode 100644
index 00000000..7f7522cb
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_external_port_io_pub.h
@@ -0,0 +1,66 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC External Port IO Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the External Port IO Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_EXTERNAL_PORT_IO_PUB_H
+#define OPENAVB_DESCRIPTOR_EXTERNAL_PORT_IO_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+// EXTERNAL PORT IO Descriptor IEEE Std 1722.1-2013 clause 7.2.14
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U16 clock_domain_index;
+ U16 port_flags;
+ U16 number_of_controls;
+ U16 base_control;
+ U16 signal_type;
+ U16 signal_index;
+ U16 signal_output;
+ U32 block_latency;
+ U16 jack_index;
+} openavb_aem_descriptor_external_port_io_t;
+
+openavb_aem_descriptor_external_port_io_t *openavbAemDescriptorExternalPortInputNew(void);
+openavb_aem_descriptor_external_port_io_t *openavbAemDescriptorExternalPortOutputNew(void);
+
+#endif // OPENAVB_DESCRIPTOR_EXTERNAL_PORT_IO_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_jack_io.c b/lib/avtp_pipeline/aem/openavb_descriptor_jack_io.c
new file mode 100644
index 00000000..5813b03b
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_jack_io.c
@@ -0,0 +1,235 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Jack IO Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Jack IO IEEE Std 1722.1-2013 clause 7.2.7
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_jack_io.h"
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorJackIOToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_jack_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_JACK_IO_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_jack_io_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->object_name);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.index, 0, 2);
+ OCT_D2BHTONS(pDst, pSrc->jack_flags);
+ OCT_D2BHTONS(pDst, pSrc->jack_type);
+ OCT_D2BHTONS(pDst, pSrc->number_of_controls);
+ OCT_D2BHTONS(pDst, pSrc->base_control);
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorJackIOFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_jack_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_JACK_IO_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_jack_io_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->object_name, pSrc);
+ BIT_B2DNTOHS(pDst->localized_description.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->localized_description.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DNTOHS(pDst->jack_flags, pSrc);
+ OCT_B2DNTOHS(pDst->jack_type, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_controls, pSrc);
+ OCT_B2DNTOHS(pDst->base_control, pSrc);
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorJackIOUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_jack_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_jack_io_t *openavbAemDescriptorJackInputNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_jack_io_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_jack_io_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorJackIOToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorJackIOFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorJackIOUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_JACK_INPUT;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT openavb_aem_descriptor_jack_io_t *openavbAemDescriptorJackOutputNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_jack_io_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_jack_io_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorJackIOToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorJackIOFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorJackIOUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_JACK_OUTPUT;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorJackInputInitialize(openavb_aem_descriptor_jack_io_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ (void) nConfigIdx;
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorJackOutputInitialize(openavb_aem_descriptor_jack_io_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ (void) nConfigIdx;
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_jack_io.h b/lib/avtp_pipeline/aem/openavb_descriptor_jack_io.h
new file mode 100644
index 00000000..0a747c2a
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_jack_io.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Jack IO Descriptor
+ * MODULE SUMMARY : Interface for the Jack IO Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_JACK_IO_H
+#define OPENAVB_DESCRIPTOR_JACK_IO_H 1
+
+#include "openavb_descriptor_jack_io_pub.h"
+
+#define OPENAVB_DESCRIPTOR_JACK_IO_BASE_LENGTH 78
+
+#endif // OPENAVB_DESCRIPTOR_JACK_IO_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_jack_io_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_jack_io_pub.h
new file mode 100644
index 00000000..a2bf65b4
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_jack_io_pub.h
@@ -0,0 +1,66 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Jack IO Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Jack IO Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_JACK_IO_PUB_H
+#define OPENAVB_DESCRIPTOR_JACK_IO_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+// JACK IO Descriptor IEEE Std 1722.1-2013 clause 7.2.7
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U8 object_name[OPENAVB_AEM_STRLEN_MAX];
+ openavb_aem_string_ref_t localized_description;
+ U16 jack_flags;
+ U16 jack_type;
+ U16 number_of_controls;
+ U16 base_control;
+} openavb_aem_descriptor_jack_io_t;
+
+openavb_aem_descriptor_jack_io_t *openavbAemDescriptorJackInputNew(void);
+openavb_aem_descriptor_jack_io_t *openavbAemDescriptorJackOutputNew(void);
+
+bool openavbAemDescriptorJackInputInitialize(openavb_aem_descriptor_jack_io_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+bool openavbAemDescriptorJackOutputInitialize(openavb_aem_descriptor_jack_io_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+
+#endif // OPENAVB_DESCRIPTOR_JACK_IO_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_locale.c b/lib/avtp_pipeline/aem/openavb_descriptor_locale.c
new file mode 100644
index 00000000..4f486d0d
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_locale.c
@@ -0,0 +1,208 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Locale Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Locale IEEE Std 1722.1-2013 clause 7.2.11
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_locale.h"
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorLocaleToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_locale_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_LOCALE_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_locale_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->locale_identifier);
+ OCT_D2BHTONS(pDst, pSrc->number_of_strings);
+ OCT_D2BHTONS(pDst, pSrc->base_strings);
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorLocaleFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_locale_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_LOCALE_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_locale_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->locale_identifier, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_strings, pSrc);
+ OCT_B2DNTOHS(pDst->base_strings, pSrc);
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorLocaleUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_locale_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_locale_t *openavbAemDescriptorLocaleNew(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_locale_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_locale_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorLocaleToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorLocaleFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorLocaleUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_LOCALE;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorLocaleSet_locale_identifier(openavb_aem_descriptor_locale_t *pDescriptor, const char *aLocaleIdentifier)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !aLocaleIdentifier) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ openavbAemSetString(pDescriptor->locale_identifier, aLocaleIdentifier);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorLocaleSet_number_of_strings(openavb_aem_descriptor_locale_t *pDescriptor, U16 uNumberOfStrings)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ pDescriptor->number_of_strings = uNumberOfStrings;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorLocaleSet_base_strings(openavb_aem_descriptor_locale_t *pDescriptor, U16 uBaseStrings)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ pDescriptor->base_strings = uBaseStrings;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_locale.h b/lib/avtp_pipeline/aem/openavb_descriptor_locale.h
new file mode 100644
index 00000000..f5e0ffe3
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_locale.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Locale Descriptor
+ * MODULE SUMMARY : Interface for the Locale Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_LOCALE_H
+#define OPENAVB_DESCRIPTOR_LOCALE_H 1
+
+#include "openavb_descriptor_locale_pub.h"
+
+#define OPENAVB_DESCRIPTOR_LOCALE_BASE_LENGTH 72
+
+#endif // OPENAVB_DESCRIPTOR_LOCALE_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_locale_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_locale_pub.h
new file mode 100644
index 00000000..aba0e01a
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_locale_pub.h
@@ -0,0 +1,69 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Locale Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Locale Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_LOCALE_PUB_H
+#define OPENAVB_DESCRIPTOR_LOCALE_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+// LOCALE Descriptor IEEE Std 1722.1-2013 clause 7.2.11
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 locale_identifier[OPENAVB_AEM_STRLEN_MAX];
+ U16 number_of_strings;
+ U16 base_strings;
+} openavb_aem_descriptor_locale_t;
+
+openavb_aem_descriptor_locale_t *openavbAemDescriptorLocaleNew(void);
+
+// Specify the locale identifier for the descriptor.
+bool openavbAemDescriptorLocaleSet_locale_identifier(openavb_aem_descriptor_locale_t *pDescriptor, const char *aLocaleIdentifier);
+
+// Specify the number of strings descriptors in this locale.
+// The same number should be specified for all locales.
+bool openavbAemDescriptorLocaleSet_number_of_strings(openavb_aem_descriptor_locale_t *pDescriptor, U16 uNumberOfStrings);
+
+// Specify the descriptor index of the first strings descriptor for this locale.
+bool openavbAemDescriptorLocaleSet_base_strings(openavb_aem_descriptor_locale_t *pDescriptor, U16 uBaseStrings);
+
+#endif // OPENAVB_DESCRIPTOR_LOCALE_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler.c b/lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler.c
new file mode 100644
index 00000000..8591bda2
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler.c
@@ -0,0 +1,230 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Locale Strings Handler Descriptor
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_aem.h"
+#include "openavb_descriptor_locale_strings_handler.h"
+
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+
+extern DLL_EXPORT openavb_aem_descriptor_locale_strings_handler_t *openavbAemDescriptorLocaleStringsHandlerNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT void openavbAemDescriptorLocaleStringsHandlerFree(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (pDescriptor) {
+ while (pDescriptor->pFirstGroup) {
+ openavb_aem_descriptor_locale_strings_handler_group_t *pDel = pDescriptor->pFirstGroup;
+ pDescriptor->pFirstGroup = pDel->pNext;
+ free(pDel->pLocale); // TODO BDT_DEBUG Will this be freed elsewhere?
+ free(pDel->pStrings); // TODO BDT_DEBUG Will this be freed elsewhere?
+ free(pDel);
+ }
+ free(pDescriptor);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+}
+
+extern DLL_EXPORT openavb_aem_descriptor_locale_strings_handler_group_t * openavbAemDescriptorLocaleStringsHandlerGet_group(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor,
+ const char *aLocaleIdentifier,
+ bool bCanCreate)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !aLocaleIdentifier) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ // Do we have a matching item?
+ openavb_aem_descriptor_locale_strings_handler_group_t *pTest = pDescriptor->pFirstGroup;
+ while (pTest) {
+ if (strncmp(aLocaleIdentifier, (const char *) pTest->pLocale->locale_identifier, OPENAVB_AEM_STRLEN_MAX) == 0) {
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pTest;
+ }
+ pTest = pTest->pNext;
+ }
+
+ // Can we allocate a new language structure?
+ if (bCanCreate) {
+ // Allocate a new group.
+ openavb_aem_descriptor_locale_strings_handler_group_t *pNew = malloc(sizeof(openavb_aem_descriptor_locale_strings_handler_group_t));
+ if (!pNew) {
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ pNew->pLocale = openavbAemDescriptorLocaleNew();
+ pNew->pStrings = openavbAemDescriptorStringsNew();
+ if (!pNew->pLocale || !pNew->pStrings) {
+ free(pNew->pLocale);
+ free(pNew->pStrings);
+ free(pNew);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ openavbAemDescriptorLocaleSet_locale_identifier(pNew->pLocale, aLocaleIdentifier);
+
+ // Add the new group to the start of the linked list.
+ pNew->pNext = pDescriptor->pFirstGroup;
+ pDescriptor->pFirstGroup = pNew;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pNew;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+}
+
+extern DLL_EXPORT const char * openavbAemDescriptorLocaleStringsHandlerGet_local_string(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor,
+ const char *aLocaleIdentifier,
+ U8 uStringIndex)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !aLocaleIdentifier || uStringIndex >= OPENAVB_AEM_NUM_DESCRIPTOR_STRINGS) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ // Get the group structure to get this string from.
+ openavb_aem_descriptor_locale_strings_handler_group_t *pGroup = openavbAemDescriptorLocaleStringsHandlerGet_group(pDescriptor, aLocaleIdentifier, FALSE);
+ if (!pGroup) {
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ const char * ret = openavbAemDescriptorStringsGet_string(pGroup->pStrings, uStringIndex);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return ret;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorLocaleStringsHandlerSet_local_string(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor,
+ const char *aLocaleIdentifier,
+ const char *aString,
+ U8 uStringIndex)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !aLocaleIdentifier || !aString || uStringIndex >= OPENAVB_AEM_NUM_DESCRIPTOR_STRINGS) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ // Get the group structure to add this string to. Create it if needed.
+ openavb_aem_descriptor_locale_strings_handler_group_t *pGroup = openavbAemDescriptorLocaleStringsHandlerGet_group(pDescriptor, aLocaleIdentifier, TRUE);
+ if (!pGroup) {
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ bool ret = openavbAemDescriptorStringsSet_string(pGroup->pStrings, aString, uStringIndex);
+ if (ret) {
+ openavbAemDescriptorLocaleSet_number_of_strings(pGroup->pLocale, 1);
+ openavbAemDescriptorLocaleSet_base_strings(pGroup->pLocale, 0);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return ret;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorLocaleStringsHandlerAddToConfiguration(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor, U16 nConfigIdx)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_locale_strings_handler_group_t *pCurrent = pDescriptor->pFirstGroup;
+ while (pCurrent) {
+ U16 nResultIdx;
+
+ // Add the locale to the configuration.
+ if (!openavbAemAddDescriptor(pCurrent->pLocale, nConfigIdx, &nResultIdx)) {
+ AVB_LOG_ERROR("Locale Add Descriptor Failure");
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return false;
+ }
+
+ // Add the strings descriptor, if it hasn't already been added.
+ if (openavbAemGetDescriptorIndex(OPENAVB_AEM_DESCRIPTOR_INVALID, pCurrent->pStrings) == OPENAVB_AEM_DESCRIPTOR_INVALID) {
+ if (!openavbAemAddDescriptor(pCurrent->pStrings, OPENAVB_AEM_DESCRIPTOR_INVALID /* Not configuration-specific */, &nResultIdx)) {
+ AVB_LOG_ERROR("Strings Add Descriptor Failure");
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return false;
+ }
+ }
+
+ pCurrent = pCurrent->pNext;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return true;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler.h b/lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler.h
new file mode 100644
index 00000000..adf36ca2
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler.h
@@ -0,0 +1,44 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Locale Descriptor
+ * MODULE SUMMARY : Interface for the Locale Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_LOCALE_STRINGS_HANDLER_H
+#define OPENAVB_DESCRIPTOR_LOCALE_STRINGS_HANDLER_H 1
+
+#include "openavb_descriptor_locale_strings_handler_pub.h"
+
+#endif // OPENAVB_DESCRIPTOR_LOCALE_STRINGS_HANDLER_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler_pub.h
new file mode 100644
index 00000000..04796d0c
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler_pub.h
@@ -0,0 +1,91 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Locale Strings Handler Public Interface
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_LOCALE_STRINGS_HANDLER_PUB_H
+#define OPENAVB_DESCRIPTOR_LOCALE_STRINGS_HANDLER_PUB_H 1
+
+#include "openavb_descriptor_locale_pub.h"
+#include "openavb_descriptor_strings_pub.h"
+
+// Grouping that holds a locale, and the strings for that locale.
+struct openavb_aem_descriptor_locale_strings_handler_group {
+ openavb_aem_descriptor_locale_t *pLocale;
+ openavb_aem_descriptor_strings_t *pStrings;
+ struct openavb_aem_descriptor_locale_strings_handler_group *pNext;
+};
+typedef struct openavb_aem_descriptor_locale_strings_handler_group openavb_aem_descriptor_locale_strings_handler_group_t;
+
+// Grouping that holds a locale, and the strings for that locale.
+typedef struct {
+ openavb_aem_descriptor_locale_strings_handler_group_t *pFirstGroup;
+} openavb_aem_descriptor_locale_strings_handler_t;
+
+
+openavb_aem_descriptor_locale_strings_handler_t *openavbAemDescriptorLocaleStringsHandlerNew(void);
+
+void openavbAemDescriptorLocaleStringsHandlerFree(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor);
+
+// Return the group structure for the specified locale.
+// If bCanCreate is TRUE, a structure one will be allocated if needed.
+openavb_aem_descriptor_locale_strings_handler_group_t * openavbAemDescriptorLocaleStringsHandlerGet_group(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor,
+ const char *aLocaleIdentifier,
+ bool bCanCreate);
+
+// Returns the string at the specified index for the given locale,
+// or NULL if the string has not been specified.
+const char * openavbAemDescriptorLocaleStringsHandlerGet_local_string(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor,
+ const char *aLocaleIdentifier,
+ U8 uStringIndex);
+
+// Set a string at the specified index for the given locale.
+// If there was a previous string value, it will be overwritten.
+// The index must be a value less than OPENAVB_AEM_NUM_DESCRIPTOR_STRINGS.
+bool openavbAemDescriptorLocaleStringsHandlerSet_local_string(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor,
+ const char *aLocaleIdentifier,
+ const char *aString,
+ U8 uStringIndex);
+
+// Add the strings to the supplied configuration.
+bool openavbAemDescriptorLocaleStringsHandlerAddToConfiguration(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor,
+ U16 nConfigIdx);
+
+#endif // OPENAVB_DESCRIPTOR_LOCALE_STRINGS_HANDLER_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_stream_io.c b/lib/avtp_pipeline/aem/openavb_descriptor_stream_io.c
new file mode 100644
index 00000000..d585a47d
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_stream_io.c
@@ -0,0 +1,572 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Stream IO Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Stream IO IEEE Std 1722.1-2013 clause 7.2.6
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_stream_io.h"
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+
+openavbRC openavbAemDescriptorStreamIOToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_STREAM_IO_BASE_LENGTH + (pDescriptor->number_of_formats * OPENAVB_DESCRIPTOR_STREAM_IO_FORMAT_LENGTH)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_stream_io_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->object_name);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.index, 0, 2);
+ OCT_D2BHTONS(pDst, pSrc->clock_domain_index);
+ OCT_D2BHTONS(pDst, pSrc->stream_flags);
+ openavbAemStreamFormatToBuf(&pSrc->current_format, pDst);
+ pDst += 8;
+ OCT_D2BHTONS(pDst, pSrc->formats_offset);
+ OCT_D2BHTONS(pDst, pSrc->number_of_formats);
+ OCT_D2BMEMCP(pDst, pSrc->backup_talker_entity_id_0);
+ OCT_D2BHTONS(pDst, pSrc->backup_talker_unique_id_0);
+ OCT_D2BMEMCP(pDst, pSrc->backup_talker_entity_id_1);
+ OCT_D2BHTONS(pDst, pSrc->backup_talker_unique_id_1);
+ OCT_D2BMEMCP(pDst, pSrc->backup_talker_entity_id_2);
+ OCT_D2BHTONS(pDst, pSrc->backup_talker_unique_id_2);
+ OCT_D2BMEMCP(pDst, pSrc->backedup_talker_entity_id);
+ OCT_D2BHTONS(pDst, pSrc->backedup_talker_unique_id);
+ OCT_D2BHTONS(pDst, pSrc->avb_interface_index);
+ OCT_D2BHTONL(pDst, pSrc->buffer_length);
+
+ int i1;
+ for (i1 = 0; i1 < pSrc->number_of_formats; i1++) {
+ openavbAemStreamFormatToBuf(&pSrc->stream_formats[i1], pDst);
+ pDst += 8;
+ }
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+
+void x_openavbAemStreamFormatFromBuf(openavb_aem_stream_format_t *pDst, U8 *pBuf)
+{
+ U8 *pSrc = pBuf;
+
+ // Tightly bound to caller not safety checks needed.
+
+ BIT_B2DNTOHB(pDst->v, pSrc, 0x80, 7, 0);
+ if (pDst->v == 0) {
+ BIT_B2DNTOHB(pDst->subtype, pSrc, 0x7f, 0, 1);
+ switch (pDst->subtype) {
+ case OPENAVB_AEM_STREAM_FORMAT_61883_IIDC_SUBTYPE:
+ {
+ BIT_B2DNTOHB(pDst->subtypes.iec_61883_iidc.sf, pSrc, 0x80, 7, 0);
+ if (pDst->subtypes.iec_61883_iidc.sf == OPENAVB_AEM_STREAM_FORMAT_SF_IIDC) {
+ pSrc += 4;
+ OCT_B2DNTOHB(pDst->subtypes.iidc.iidc_format, pSrc);
+ OCT_B2DNTOHB(pDst->subtypes.iidc.iidc_mode, pSrc);
+ OCT_B2DNTOHB(pDst->subtypes.iidc.iidc_rate, pSrc);
+ }
+ else {
+ BIT_B2DNTOHB(pDst->subtypes.iec_61883.sf, pSrc, 0x80, 7, 0);
+ BIT_B2DNTOHB(pDst->subtypes.iec_61883.fmt, pSrc, 0x7e, 1, 1);
+ if (pDst->subtypes.iec_61883.fmt == OPENAVB_AEM_STREAM_FORMAT_FMT_61883_4) {
+ // Nothingn to do
+ }
+ else if (pDst->subtypes.iec_61883.fmt == OPENAVB_AEM_STREAM_FORMAT_FMT_61883_6) {
+ BIT_B2DNTOHB(pDst->subtypes.iec_61883_6.fdf_evt, pSrc, 0xf8, 3, 0);
+ BIT_B2DNTOHB(pDst->subtypes.iec_61883_6.fdf_sfc, pSrc, 0x07, 0, 1);
+ OCT_B2DNTOHB(pDst->subtypes.iec_61883_6.dbs, pSrc);
+ BIT_B2DNTOHB(pDst->subtypes.iec_61883_6.b, pSrc, 0x80, 7, 0);
+ BIT_B2DNTOHB(pDst->subtypes.iec_61883_6.nb, pSrc, 0x40, 6, 1);
+
+ if (pDst->subtypes.iec_61883_6.fdf_evt == OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_32BITS) {
+ // Nothing to do
+ }
+ else if (pDst->subtypes.iec_61883_6.fdf_evt == OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_FLOAT) {
+ // Nothing to do
+ }
+ else if (pDst->subtypes.iec_61883_6.fdf_evt == OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_AM824) {
+ OCT_B2DNTOHB(pDst->subtypes.iec_61883_6_am824.label_iec_60958_cnt, pSrc);
+ OCT_B2DNTOHB(pDst->subtypes.iec_61883_6_am824.label_mbla_cnt, pSrc);
+ BIT_B2DNTOHB(pDst->subtypes.iec_61883_6_am824.label_midi_cnt, pSrc, 0xf0, 4, 0);
+ BIT_B2DNTOHB(pDst->subtypes.iec_61883_6_am824.label_smptecnt, pSrc, 0x0f, 0, 1);
+ }
+ }
+
+ else if (pDst->subtypes.iec_61883.fmt == OPENAVB_AEM_STREAM_FORMAT_FMT_61883_8) {
+ pSrc += 3;
+ OCT_B2DNTOHB(pDst->subtypes.iec_61883_8.video_mode, pSrc);
+ OCT_B2DNTOHB(pDst->subtypes.iec_61883_8.compress_mode, pSrc);
+ OCT_B2DNTOHB(pDst->subtypes.iec_61883_8.color_space, pSrc);
+ }
+ }
+ }
+
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_MMA_SUBTYPE:
+ // Nothing to do
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_AVTP_AUDIO_SUBTYPE:
+ BIT_B2DNTOHB(pDst->subtypes.avtp_audio.nominal_sample_rate, pSrc, 0x0f, 0, 1);
+ OCT_B2DNTOHB(pDst->subtypes.avtp_audio.format, pSrc);
+ OCT_B2DNTOHB(pDst->subtypes.avtp_audio.bit_depth, pSrc);
+ BIT_B2DNTOHL(pDst->subtypes.avtp_audio.channels_per_frame, pSrc, 0xffc00000, 22, 0);
+ BIT_B2DNTOHL(pDst->subtypes.avtp_audio.samples_per_frame, pSrc, 0x003ff000, 12, 4);
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_AVTP_VIDEO_SUBTYPE:
+ OCT_B2DNTOHB(pDst->subtypes.avtp_video.format, pSrc);
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_AVTP_CONTROL_SUBTYPE:
+ BIT_B2DNTOHB(pDst->subtypes.avtp_control.protocol_type, pSrc, 0xf0, 4, 1);
+ OCT_B2DMEMCP(pDst->subtypes.avtp_control.format_id, pSrc);
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_VENDOR_SUBTYPE:
+ pSrc++;
+ OCT_B2DMEMCP(pDst->subtypes.vendor.format_id, pSrc);
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_EXPERIMENTAL_SUBTYPE:
+ // Nothing to do
+ break;
+ }
+ }
+ else {
+ pSrc++;
+ OCT_B2DMEMCP(pDst->subtypes.vendor_specific.format_id, pSrc);
+ }
+}
+
+
+openavbRC openavbAemDescriptorStreamIOFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_STREAM_IO_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_stream_io_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->object_name, pSrc);
+ BIT_B2DNTOHS(pDst->localized_description.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->localized_description.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DNTOHS(pDst->clock_domain_index, pSrc);
+ OCT_B2DNTOHS(pDst->stream_flags, pSrc);
+ x_openavbAemStreamFormatFromBuf(&pDst->current_format, pSrc);
+ pSrc += 8;
+ OCT_B2DNTOHS(pDst->formats_offset, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_formats, pSrc);
+ OCT_B2DMEMCP(pDst->backup_talker_entity_id_0, pSrc);
+ OCT_B2DNTOHS(pDst->backup_talker_unique_id_0, pSrc);
+ OCT_B2DMEMCP(pDst->backup_talker_entity_id_1, pSrc);
+ OCT_B2DNTOHS(pDst->backup_talker_unique_id_1, pSrc);
+ OCT_B2DMEMCP(pDst->backup_talker_entity_id_2, pSrc);
+ OCT_B2DNTOHS(pDst->backup_talker_unique_id_2, pSrc);
+ OCT_B2DMEMCP(pDst->backedup_talker_entity_id, pSrc);
+ OCT_B2DNTOHS(pDst->backedup_talker_unique_id, pSrc);
+ OCT_B2DNTOHS(pDst->avb_interface_index, pSrc);
+ OCT_B2DNTOHL(pDst->buffer_length, pSrc);
+
+ if (bufLength < OPENAVB_DESCRIPTOR_STREAM_IO_BASE_LENGTH + (pDescriptor->number_of_formats * OPENAVB_DESCRIPTOR_STREAM_IO_FORMAT_LENGTH)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ int i1;
+ for (i1 = 0; i1 < pDst->number_of_formats; i1++) {
+ x_openavbAemStreamFormatFromBuf(&pDst->stream_formats[i1], pSrc);
+ pSrc += 8;
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorStreamIOUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_stream_io_t *openavbAemDescriptorStreamInputNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_io_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_stream_io_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorStreamIOToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorStreamIOFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorStreamIOUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT;
+ pDescriptor->formats_offset = OPENAVB_DESCRIPTOR_STREAM_IO_BASE_LENGTH;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ // Will determine the status of this once the Listener has connected to AVDECC.
+ pDescriptor->fast_connect_status = OPENAVB_FAST_CONNECT_STATUS_UNKNOWN;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT openavb_aem_descriptor_stream_io_t *openavbAemDescriptorStreamOutputNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_io_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_stream_io_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorStreamIOToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorStreamIOFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorStreamIOUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT;
+ pDescriptor->formats_offset = OPENAVB_DESCRIPTOR_STREAM_IO_BASE_LENGTH;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ // Talkers won't attempt to fast connect.
+ pDescriptor->fast_connect_status = OPENAVB_FAST_CONNECT_STATUS_NOT_AVAILABLE;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+static void fillInStreamFormat(openavb_aem_descriptor_stream_io_t *pDescriptor, const openavb_avdecc_configuration_cfg_t *pConfig)
+{ // AVDECC_TODO - Specify the stream format information for MMA Stream Format.
+ if (strcmp(pConfig->stream->map_fn,"openavbMapAVTPAudioInitialize") == 0)
+ {
+ pDescriptor->stream_formats[0].v = 0;
+ pDescriptor->stream_formats[0].subtype = OPENAVB_AEM_STREAM_FORMAT_AVTP_AUDIO_SUBTYPE;
+ pDescriptor->stream_formats[0].subtypes.avtp_audio.nominal_sample_rate = 0x05;
+ pDescriptor->stream_formats[0].subtypes.avtp_audio.format = 2;
+ pDescriptor->stream_formats[0].subtypes.avtp_audio.bit_depth = 32;
+ pDescriptor->stream_formats[0].subtypes.avtp_audio.channels_per_frame = 2;
+ pDescriptor->stream_formats[0].subtypes.avtp_audio.samples_per_frame = 6;
+ }
+ else if (strcmp(pConfig->stream->map_fn,"openavbMapUncmpAudioInitialize") == 0)
+ {
+ pDescriptor->stream_formats[0].v = 0;
+ pDescriptor->stream_formats[0].subtype = OPENAVB_AEM_STREAM_FORMAT_61883_IIDC_SUBTYPE;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_iidc.sf = 1;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.fmt = OPENAVB_AEM_STREAM_FORMAT_FMT_61883_6;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.fdf_evt = OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_AM824;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.fdf_sfc = 0x02;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.dbs = 0x08;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.b = 0x00;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.nb = 0x01;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.label_iec_60958_cnt = 0;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.label_mbla_cnt = 8;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.label_midi_cnt = 0;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.label_smptecnt = 0;
+ }
+ else if (strcmp(pConfig->stream->map_fn,"openavbMapCtrlInitialize") == 0)
+ {
+ pDescriptor->stream_formats[0].v = 0;
+ pDescriptor->stream_formats[0].subtype = OPENAVB_AEM_STREAM_FORMAT_AVTP_CONTROL_SUBTYPE;
+ pDescriptor->stream_formats[0].subtypes.avtp_control.protocol_type = 3;
+ pDescriptor->stream_formats[0].subtypes.avtp_control.format_id[0] = 0x90;
+ pDescriptor->stream_formats[0].subtypes.avtp_control.format_id[1] = 0xe0;
+ pDescriptor->stream_formats[0].subtypes.avtp_control.format_id[2] = 0xf0;
+ pDescriptor->stream_formats[0].subtypes.avtp_control.format_id[3] = 0x00;
+ pDescriptor->stream_formats[0].subtypes.avtp_control.format_id[4] = 0x00;
+ pDescriptor->stream_formats[0].subtypes.avtp_control.format_id[5] = 0x00;
+ }
+ else if (strcmp(pConfig->stream->map_fn,"openavbMapMpeg2tsInitialize") == 0)
+ {
+ pDescriptor->stream_formats[0].v = 0;
+ pDescriptor->stream_formats[0].subtype = OPENAVB_AEM_STREAM_FORMAT_61883_IIDC_SUBTYPE;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_4.sf = 1;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_4.fmt = OPENAVB_AEM_STREAM_FORMAT_FMT_61883_4;
+ }
+ else if (strcmp(pConfig->stream->map_fn,"openavbMapMjpegInitialize") == 0 || strcmp(pConfig->stream->map_fn,"openavbMapH264Initialize") == 0)
+ {
+ pDescriptor->stream_formats[0].v = 0;
+ pDescriptor->stream_formats[0].subtype = OPENAVB_AEM_STREAM_FORMAT_AVTP_VIDEO_SUBTYPE;
+ if (strcmp(pConfig->stream->map_fn,"openavbMapMjpegInitialize") == 0)
+ {
+ pDescriptor->stream_formats[0].subtypes.avtp_video.format = OPENAVB_AEM_RTP_PAYLOAD_SUBTYPE_RTP_MJPEG;
+ }
+ else
+ {
+ pDescriptor->stream_formats[0].subtypes.avtp_video.format = OPENAVB_AEM_RTP_PAYLOAD_SUBTYPE_RTP_H264;
+ }
+ }
+ pDescriptor->number_of_formats = 1;
+
+ // Make the current format the first format in the list.
+ memcpy(&(pDescriptor->current_format), &(pDescriptor->stream_formats[0]), sizeof(openavb_aem_stream_format_t));
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorStreamInputInitialize(openavb_aem_descriptor_stream_io_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ (void) nConfigIdx;
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // Specify a name.
+ sprintf((char *)(pDescriptor->object_name), "Stream Input %u", pDescriptor->descriptor_index);
+
+ // Specify the stream flags.
+ // The stream configuration is ignored for Listeners, as Listeners will accept both Class A and Class B.
+ pDescriptor->stream_flags |= ( OPENAVB_AEM_STREAM_FLAG_CLASS_A | OPENAVB_AEM_STREAM_FLAG_CLASS_B );
+
+ // Specify the stream format information.
+ fillInStreamFormat(pDescriptor, pConfig);
+
+ // Save the stream configuration pointer.
+ pDescriptor->stream = pConfig->stream;
+
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorStreamOutputInitialize(openavb_aem_descriptor_stream_io_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ (void) nConfigIdx;
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // Specify a name.
+ sprintf((char *)(pDescriptor->object_name), "Stream Output %u", pDescriptor->descriptor_index);
+
+ // Specify the stream flags.
+ if (pConfig->stream->sr_class == SR_CLASS_A) { pDescriptor->stream_flags |= OPENAVB_AEM_STREAM_FLAG_CLASS_A; }
+ if (pConfig->stream->sr_class == SR_CLASS_B) { pDescriptor->stream_flags |= OPENAVB_AEM_STREAM_FLAG_CLASS_B; }
+
+ // Specify the stream format information.
+ fillInStreamFormat(pDescriptor, pConfig);
+
+ // Save the stream configuration pointer.
+ pDescriptor->stream = pConfig->stream;
+
+ return TRUE;
+}
+
+
+////////////////////////////////
+// Public functions for internal
+// AVDECC use (not exported)
+////////////////////////////////
+
+void openavbAemStreamFormatToBuf(openavb_aem_stream_format_t *pSrc, U8 *pBuf)
+{
+ U8 *pDst = pBuf;
+
+ // Tightly bound to caller not safety checks needed.
+
+ memset(pBuf, 0, 8);
+
+ if (pSrc->v == 0) {
+ BIT_D2BHTONB(pDst, pSrc->v, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtype, 0, 1);
+ switch (pSrc->subtype) {
+ case OPENAVB_AEM_STREAM_FORMAT_61883_IIDC_SUBTYPE:
+ {
+ if (pSrc->subtypes.iec_61883_iidc.sf == OPENAVB_AEM_STREAM_FORMAT_SF_IIDC) {
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iidc.sf, 7, 1);
+ pDst += 3;
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iidc.iidc_format);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iidc.iidc_mode);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iidc.iidc_rate);
+ }
+ else {
+ if (pSrc->subtypes.iec_61883.fmt == OPENAVB_AEM_STREAM_FORMAT_FMT_61883_4) {
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_4.sf, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_4.fmt, 1, 1);
+ }
+ else if (pSrc->subtypes.iec_61883.fmt == OPENAVB_AEM_STREAM_FORMAT_FMT_61883_6) {
+ if (pSrc->subtypes.iec_61883_6.fdf_evt == OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_32BITS) {
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_32bit.sf, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_32bit.fmt, 1, 1);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_32bit.fdf_evt, 3, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_32bit.fdf_sfc, 0, 1);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_32bit.dbs);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_32bit.b, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_32bit.nb, 6, 1);
+ }
+ else if (pSrc->subtypes.iec_61883_6.fdf_evt == OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_FLOAT) {
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_float.sf, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_float.fmt, 1, 1);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_float.fdf_evt, 3, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_float.fdf_sfc, 0, 1);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_float.dbs);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_float.b, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_float.nb, 6, 1);
+ }
+ else if (pSrc->subtypes.iec_61883_6.fdf_evt == OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_AM824) {
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.sf, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.fmt, 1, 1);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.fdf_evt, 3, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.fdf_sfc, 0, 1);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.dbs);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.b, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.nb, 6, 1);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.label_iec_60958_cnt);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.label_mbla_cnt);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.label_midi_cnt, 4, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.label_smptecnt, 0, 1);
+ }
+ }
+ else if (pSrc->subtypes.iec_61883.fmt == OPENAVB_AEM_STREAM_FORMAT_FMT_61883_8) {
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_8.sf, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_8.fmt, 1, 1);
+ pDst += 3;
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_8.video_mode);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_8.compress_mode);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_8.color_space);
+ }
+ }
+ }
+
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_MMA_SUBTYPE:
+ // Nothing to do
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_AVTP_AUDIO_SUBTYPE:
+ BIT_D2BHTONB(pDst, pSrc->subtypes.avtp_audio.nominal_sample_rate, 0, 1);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.avtp_audio.format);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.avtp_audio.bit_depth);
+ BIT_D2BHTONL(pDst, pSrc->subtypes.avtp_audio.channels_per_frame, 22, 0);
+ BIT_D2BHTONL(pDst, pSrc->subtypes.avtp_audio.samples_per_frame, 12, 4);
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_AVTP_VIDEO_SUBTYPE:
+ OCT_D2BHTONB(pDst, pSrc->subtypes.avtp_video.format);
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_AVTP_CONTROL_SUBTYPE:
+ BIT_D2BHTONB(pDst, pSrc->subtypes.avtp_control.protocol_type, 4, 1);
+ OCT_D2BMEMCP(pDst, pSrc->subtypes.avtp_control.format_id);
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_VENDOR_SUBTYPE:
+ pDst++;
+ OCT_D2BMEMCP(pDst, pSrc->subtypes.vendor.format_id);
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_EXPERIMENTAL_SUBTYPE:
+ // Nothing to do
+ break;
+ }
+ }
+ else {
+ BIT_D2BHTONB(pDst, pSrc->v, 7, 1);
+ pDst++;
+ OCT_D2BMEMCP(pDst, pSrc->subtypes.vendor_specific.format_id);
+ }
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_stream_io.h b/lib/avtp_pipeline/aem/openavb_descriptor_stream_io.h
new file mode 100644
index 00000000..b4edc9c4
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_stream_io.h
@@ -0,0 +1,47 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Stream IO Descriptor
+ * MODULE SUMMARY : Interface for the Stream IO Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_STREAM_IO_H
+#define OPENAVB_DESCRIPTOR_STREAM_IO_H 1
+
+#include "openavb_descriptor_stream_io_pub.h"
+
+#define OPENAVB_DESCRIPTOR_STREAM_IO_BASE_LENGTH 132
+#define OPENAVB_DESCRIPTOR_STREAM_IO_FORMAT_LENGTH 8
+
+#endif // OPENAVB_DESCRIPTOR_STREAM_IO_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_stream_io_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_stream_io_pub.h
new file mode 100644
index 00000000..91fc384f
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_stream_io_pub.h
@@ -0,0 +1,111 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Stream IO Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Stream IO Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_STREAM_IO_PUB_H
+#define OPENAVB_DESCRIPTOR_STREAM_IO_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+#include "openavb_tl_pub.h"
+#include "openavb_avdecc_read_ini_pub.h"
+
+#define OPENAVB_DESCRIPTOR_STREAM_IO_MAX_FORMATS (47)
+
+// Possible statuses of the fast connect support for the Listener
+typedef enum {
+ OPENAVB_FAST_CONNECT_STATUS_UNKNOWN = 0, // Still need to determine if something is available
+ OPENAVB_FAST_CONNECT_STATUS_NOT_AVAILABLE, // No fast connects available for the Listener, or is a Talker
+ OPENAVB_FAST_CONNECT_STATUS_IN_PROGRESS, // Attempting fast connect
+ OPENAVB_FAST_CONNECT_STATUS_TIMED_OUT, // Talker did not respond to fast connect attempts
+ OPENAVB_FAST_CONNECT_STATUS_SUCCEEDED, // Fast connect was successful; don't need to try again
+} openavb_fast_connect_status_t;
+
+// STREAM IO Descriptor IEEE Std 1722.1-2013 clause 7.2.6
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U8 object_name[OPENAVB_AEM_STRLEN_MAX];
+ openavb_aem_string_ref_t localized_description;
+ U16 clock_domain_index;
+ U16 stream_flags;
+ openavb_aem_stream_format_t current_format;
+ U16 formats_offset;
+ U16 number_of_formats;
+ U8 backup_talker_entity_id_0[8];
+ U16 backup_talker_unique_id_0;
+ U8 backup_talker_entity_id_1[8];
+ U16 backup_talker_unique_id_1;
+ U8 backup_talker_entity_id_2[8];
+ U16 backup_talker_unique_id_2;
+ U8 backedup_talker_entity_id[8];
+ U16 backedup_talker_unique_id;
+ U16 avb_interface_index;
+ U32 buffer_length;
+ openavb_aem_stream_format_t stream_formats[OPENAVB_DESCRIPTOR_STREAM_IO_MAX_FORMATS];
+
+ // Current status of the fast connect support for the Listener.
+ openavb_fast_connect_status_t fast_connect_status;
+ U8 fast_connect_talker_entity_id[8];
+ struct timespec fast_connect_start_time;
+
+ // OPENAVB_ACMP_FLAG values from CONNECT_TX_RESPONSE or CONNECT_RX_RESPONSE.
+ U16 acmp_flags;
+
+ // Streaming values for GET_STREAM_INFO from CONNECT_TX_RESPONSE or CONNECT_RX_RESPONSE.
+ // These values are currently only used for the Listener, as the Talker can get them from it's current configuration.
+ U8 acmp_stream_id[8];
+ U8 acmp_dest_addr[6];
+ U16 acmp_stream_vlan_id;
+
+ // Also save a pointer to the supplied stream information.
+ const openavb_tl_data_cfg_t *stream;
+
+} openavb_aem_descriptor_stream_io_t;
+
+openavb_aem_descriptor_stream_io_t *openavbAemDescriptorStreamInputNew(void);
+openavb_aem_descriptor_stream_io_t *openavbAemDescriptorStreamOutputNew(void);
+
+bool openavbAemDescriptorStreamInputInitialize(openavb_aem_descriptor_stream_io_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+bool openavbAemDescriptorStreamOutputInitialize(openavb_aem_descriptor_stream_io_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+
+void openavbAemStreamFormatToBuf(openavb_aem_stream_format_t *pSrc, U8 *pBuf);
+
+#endif // OPENAVB_DESCRIPTOR_STREAM_IO_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io.c b/lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io.c
new file mode 100644
index 00000000..007a11cb
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io.c
@@ -0,0 +1,207 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Stream Port IO Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Stream Port IO IEEE Std 1722.1-2013 clause 7.2.13
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_stream_port_io.h"
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorStreamPortIOToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_port_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_STREAM_PORT_IO_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_stream_port_io_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BHTONS(pDst, pSrc->clock_domain_index);
+ OCT_D2BHTONS(pDst, pSrc->port_flags);
+ OCT_D2BHTONS(pDst, pSrc->number_of_controls);
+ OCT_D2BHTONS(pDst, pSrc->base_control);
+ OCT_D2BHTONS(pDst, pSrc->number_of_clusters);
+ OCT_D2BHTONS(pDst, pSrc->base_cluster);
+ OCT_D2BHTONS(pDst, pSrc->number_of_maps);
+ OCT_D2BHTONS(pDst, pSrc->base_map);
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorStreamPortIOFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_port_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_STREAM_PORT_IO_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_stream_port_io_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DNTOHS(pDst->clock_domain_index, pSrc);
+ OCT_B2DNTOHS(pDst->port_flags, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_controls, pSrc);
+ OCT_B2DNTOHS(pDst->base_control, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_clusters, pSrc);
+ OCT_B2DNTOHS(pDst->base_cluster, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_maps, pSrc);
+ OCT_B2DNTOHS(pDst->base_map, pSrc);
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorStreamPortIOUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_port_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_stream_port_io_t *openavbAemDescriptorStreamPortInputNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_port_io_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_stream_port_io_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = FALSE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorStreamPortIOToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorStreamPortIOFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorStreamPortIOUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_STREAM_PORT_INPUT;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT openavb_aem_descriptor_stream_port_io_t *openavbAemDescriptorStreamPortOutputNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_port_io_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_stream_port_io_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = FALSE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorStreamPortIOToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorStreamPortIOFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorStreamPortIOUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_STREAM_PORT_OUTPUT;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io.h b/lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io.h
new file mode 100644
index 00000000..fe331476
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Stream Port IO Descriptor
+ * MODULE SUMMARY : Interface for the Stream Port IO Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_STREAM_PORT_IO_H
+#define OPENAVB_DESCRIPTOR_STREAM_PORT_IO_H 1
+
+#include "openavb_descriptor_stream_port_io_pub.h"
+
+#define OPENAVB_DESCRIPTOR_STREAM_PORT_IO_BASE_LENGTH 20
+
+#endif // OPENAVB_DESCRIPTOR_STREAM_PORT_IO_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io_pub.h
new file mode 100644
index 00000000..000c058d
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io_pub.h
@@ -0,0 +1,65 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Stream Port IO Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Stream Port IO Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_STREAM_PORT_IO_PUB_H
+#define OPENAVB_DESCRIPTOR_STREAM_PORT_IO_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+// STREAM PORT IO Descriptor IEEE Std 1722.1-2013 clause 7.2.13
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U16 clock_domain_index;
+ U16 port_flags;
+ U16 number_of_controls;
+ U16 base_control;
+ U16 number_of_clusters;
+ U16 base_cluster;
+ U16 number_of_maps;
+ U16 base_map;
+} openavb_aem_descriptor_stream_port_io_t;
+
+openavb_aem_descriptor_stream_port_io_t *openavbAemDescriptorStreamPortInputNew(void);
+openavb_aem_descriptor_stream_port_io_t *openavbAemDescriptorStreamPortOutputNew(void);
+
+#endif // OPENAVB_DESCRIPTOR_STREAM_PORT_IO_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_strings.c b/lib/avtp_pipeline/aem/openavb_descriptor_strings.c
new file mode 100644
index 00000000..dc599622
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_strings.c
@@ -0,0 +1,193 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Strings Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Strings IEEE Std 1722.1-2013 clause 7.2.12
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_strings.h"
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorStringsToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_strings_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_STRINGS_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_strings_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ memcpy(pDst, pSrc->string, sizeof(pSrc->string));
+ pDst += sizeof(pSrc->string);
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorStringsFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_strings_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_STRINGS_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_strings_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ memcpy(pDst->string, pSrc, sizeof(pDst->string));
+ pSrc += sizeof(pDst->string);
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorStringsUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_strings_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_strings_t *openavbAemDescriptorStringsNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_strings_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_strings_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = FALSE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorStringsToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorStringsFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorStringsUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_STRINGS;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT const char * openavbAemDescriptorStringsGet_string(openavb_aem_descriptor_strings_t *pDescriptor, U8 index)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || index >= OPENAVB_AEM_NUM_DESCRIPTOR_STRINGS) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ const char *ret = (const char *) (pDescriptor->string[index]);
+ if (*ret == '\0') {
+ /* The string is empty. */
+ ret = NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return ret;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorStringsSet_string(openavb_aem_descriptor_strings_t *pDescriptor, const char *pString, U8 index)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !pString || index >= OPENAVB_AEM_NUM_DESCRIPTOR_STRINGS) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ openavbAemSetString(pDescriptor->string[index], pString);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_strings.h b/lib/avtp_pipeline/aem/openavb_descriptor_strings.h
new file mode 100644
index 00000000..014cb2ac
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_strings.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Strings Descriptor
+ * MODULE SUMMARY : Interface for the Strings Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_STRINGS_H
+#define OPENAVB_DESCRIPTOR_STRINGS_H 1
+
+#include "openavb_descriptor_strings_pub.h"
+
+#define OPENAVB_DESCRIPTOR_STRINGS_BASE_LENGTH 452
+
+#endif // OPENAVB_DESCRIPTOR_STRINGS_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_strings_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_strings_pub.h
new file mode 100644
index 00000000..57218c1b
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_strings_pub.h
@@ -0,0 +1,65 @@
+/*************************************************************************************************************
+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 : AEM - AVDECC Strings Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Strings Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_STRINGS_PUB_H
+#define OPENAVB_DESCRIPTOR_STRINGS_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+#define OPENAVB_AEM_NUM_DESCRIPTOR_STRINGS (7)
+
+// STRINGS Descriptor IEEE Std 1722.1-2013 clause 7.2.12
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 string[OPENAVB_AEM_NUM_DESCRIPTOR_STRINGS][OPENAVB_AEM_STRLEN_MAX];
+} openavb_aem_descriptor_strings_t;
+
+openavb_aem_descriptor_strings_t *openavbAemDescriptorStringsNew(void);
+
+// Returns the descriptor string at the specified index, or NULL if not specified.
+const char * openavbAemDescriptorStringsGet_string(openavb_aem_descriptor_strings_t *pDescriptor, U8 index);
+
+// Set a descriptor string at the specified index.
+bool openavbAemDescriptorStringsSet_string(openavb_aem_descriptor_strings_t *pDescriptor, const char *pString, U8 index);
+
+#endif // OPENAVB_DESCRIPTOR_STRINGS_PUB_H
diff --git a/lib/avtp_pipeline/avdecc/CMakeLists.txt b/lib/avtp_pipeline/avdecc/CMakeLists.txt
new file mode 100644
index 00000000..bccfc799
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc/CMakeLists.txt
@@ -0,0 +1,12 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/avdecc/openavb_avdecc.c
+ ${AVB_OSAL_DIR}/avdecc/openavb_avdecc_osal.c
+ ${AVB_OSAL_DIR}/avdecc/openavb_avdecc_cfg.c
+ ${AVB_OSAL_DIR}/avdecc/openavb_avdecc_read_ini.c
+ ${AVB_OSAL_DIR}/avdecc/openavb_avdecc_pipeline_interaction.c
+ ${AVB_OSAL_DIR}/avdecc/openavb_avdecc_save_state.c
+ ${AVB_OSAL_DIR}/openavb_osal_avdecc.c
+ ${AVB_OSAL_DIR}/openavb_grandmaster_osal.c
+ ${AVB_SRC_DIR}/avdecc_msg/openavb_avdecc_msg_server.c
+ PARENT_SCOPE
+)
diff --git a/lib/avtp_pipeline/avdecc/avdecc.ini b/lib/avtp_pipeline/avdecc/avdecc.ini
new file mode 100644
index 00000000..d4b4bb60
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc/avdecc.ini
@@ -0,0 +1,82 @@
+[network]
+
+# Interface name on which to use AVDECC
+#ifname=eth2
+
+
+[vlan]
+
+# VLAN ID to use for AVDECC traffic.
+# If VLAN support is not desired, comment out this value.
+#vlanID = 2
+
+# VLAN Priority to use for AVDECC traffic.
+# If VLAN support is not desired, comment out this value.
+#vlanPCP = 3
+
+
+[fast_connect]
+
+# If enable (set to 1), the fast_connect option will cause AVDECC-initiated
+# connections to be saved to an avdecc_save.ini file. When the AVDECC client
+# is restarted after an unexpected shutdown, AVDECC Fast Connect will be
+# attempted.
+#
+# The default value is 0, which disabled the AVDECC Fast Connect and Saved
+# State support.
+fast_connect = 1
+
+
+[discovery]
+
+# The valid_time is the amount of time (in seconds) the device will be
+# considered valid by other devices on the network after the last received
+# discovery packet. A smaller valid_time value will cause the device to be
+# recognized as disappearing more quickly if it is unplugged from the network
+# (or stops working), but will result in more background network traffic.
+#
+# Valid values are 2 to 62 seconds, with only even numbers being allowed.
+# The default value is 62 seconds.
+valid_time = 20
+
+
+[descriptor_entity]
+
+# ID value to be combined with the interface MAC Address to generate the
+# entity_id. For example, a device with MAC Address 00:11:22:33:44:55 and
+# avdeccId of 0x9876 would be assigned an entity_id of
+# 00-01-02-98-76-33-44-55.
+# The default ID value is 0xfffe.
+#avdeccId = 0xfffe
+
+# The entity_model_id is a unique vendor-specific 64-bit number used to
+# identify an AVDECC data model.
+entity_model_id = 0x0000000000000000
+
+# The entity_name is a UTF-8 string defining the device's name
+entity_name = "ACME Audio Processor"
+
+# The firmware_version is a UTF-8 string defining the device's firmware
+# version
+firmware_version = "0.0.0.1"
+
+# The group_name is a UTF-8 string defining the name of the device's group
+group_name = "Acme Processors"
+
+# The serial_number is a UTF-8 string defining the device's serial number
+serial_number = "12345"
+
+
+[localization]
+
+# A UTF-8 string defining the localization language to use for localized
+# strings. The format is "language code - region code".
+# Refer to IEEE Std 1722.1-2013 clause 7.2.11 for more details.
+locale_identifier = "en"
+
+# The vendor_name is a localized UTF-8 string defining the vendor's name
+vendor_name = "Acme Audio Inc."
+
+# The model_name is a localized UTF-8 string defining the device's model name
+model_name = "Acme 2400X"
+
diff --git a/lib/avtp_pipeline/avdecc/openavb_avdecc.c b/lib/avtp_pipeline/avdecc/openavb_avdecc.c
new file mode 100644
index 00000000..9c82a648
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc/openavb_avdecc.c
@@ -0,0 +1,509 @@
+/*************************************************************************************************************
+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 : AVDECC - Top level 1722.1 implementation
+ * MODULE SUMMARY : Top level 1722.1 implementation
+ ******************************************************************
+ */
+
+#include "openavb_rawsock.h"
+#include "openavb_avtp.h"
+
+#define AVB_LOG_COMPONENT "AVDECC"
+#include "openavb_log.h"
+
+#include "openavb_aem.h"
+#include "openavb_adp.h"
+#include "openavb_acmp.h"
+#include "openavb_aecp.h"
+
+#include "openavb_endpoint.h"
+
+#define ADDR_PTR(A) (U8*)(&((A)->ether_addr_octet))
+
+openavb_avdecc_cfg_t gAvdeccCfg;
+openavb_tl_data_cfg_t * streamList = NULL;
+openavb_aem_descriptor_configuration_t *pConfiguration = NULL;
+
+static openavb_avdecc_configuration_cfg_t *pFirstConfigurationCfg = NULL;
+static U8 talker_stream_sources = 0;
+static U8 listener_stream_sources = 0;
+static bool first_talker = 1;
+static bool first_listener = 1;
+
+bool openavbAvdeccStartAdp()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ openavbRC rc = openavbAdpStart();
+ if (IS_OPENAVB_FAILURE(rc)) {
+ openavbAdpStop();
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+void openavbAvdeccStopAdp()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+ openavbAdpStop();
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+}
+
+bool openavbAvdeccStartCmp()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ openavbRC rc = openavbAcmpStart();
+ if (IS_OPENAVB_FAILURE(rc)) {
+ openavbAcmpStop();
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+void openavbAvdeccStopCmp()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+ openavbAcmpStop();
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+}
+
+bool openavbAvdeccStartEcp()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ openavbRC rc = openavbAecpStart();
+ if (IS_OPENAVB_FAILURE(rc)) {
+ openavbAecpStop();
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+void openavbAvdeccStopEcp()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+ openavbAecpStop();
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+}
+
+void openavbAvdeccFindMacAddr(void)
+{
+ // Open a rawsock may be the easiest cross platform way to get the MAC address.
+ void *txSock = openavbRawsockOpen(gAvdeccCfg.ifname, FALSE, TRUE, ETHERTYPE_AVTP, 100, 1);
+ if (txSock) {
+ openavbRawsockGetAddr(txSock, gAvdeccCfg.ifmac);
+ openavbRawsockClose(txSock);
+ txSock = NULL;
+ }
+}
+
+bool openavbAvdeccAddConfiguration(openavb_tl_data_cfg_t *stream)
+{
+ bool first_time = 0;
+ // Create a new config to hold the configuration information.
+ openavb_avdecc_configuration_cfg_t *pCfg = malloc(sizeof(openavb_avdecc_configuration_cfg_t));
+ if (!pCfg) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ memset(pCfg, 0, sizeof(openavb_avdecc_configuration_cfg_t));
+
+ // Add a pointer to the supplied stream information.
+ pCfg->stream = stream;
+
+ // Add the new config to the end of the list of configurations.
+ if (pFirstConfigurationCfg == NULL) {
+ pFirstConfigurationCfg = pCfg;
+ } else {
+ openavb_avdecc_configuration_cfg_t *pLast = pFirstConfigurationCfg;
+ while (pLast->next != NULL) {
+ pLast = pLast->next;
+ }
+ pLast->next = pCfg;
+ }
+
+ // Create a new configuration.
+ U16 nConfigIdx = 0;
+ if (pConfiguration == NULL)
+ {
+ first_time = 1;
+ pConfiguration = openavbAemDescriptorConfigurationNew();
+ if (!openavbAemAddDescriptor(pConfiguration, OPENAVB_AEM_DESCRIPTOR_INVALID, &nConfigIdx)) {
+ AVB_LOG_ERROR("Error adding AVDECC configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+ // Specify a default user-friendly name to use.
+ // AVDECC_TODO - Allow the user to specify a friendly name, or use the name if the .INI file.
+ if (pCfg->friendly_name[0] == '\0') {
+ snprintf((char *) pCfg->friendly_name, OPENAVB_AEM_STRLEN_MAX, "Configuration %u", nConfigIdx);
+ }
+
+ // Save the stream information in the configuration.
+ if (!openavbAemDescriptorConfigurationInitialize(pConfiguration, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error initializing AVDECC configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Add the descriptors needed for both talkers and listeners.
+ U16 nResultIdx;
+ if (first_time)
+ {
+ openavb_aem_descriptor_avb_interface_t *pNewAvbInterface = openavbAemDescriptorAvbInterfaceNew();
+ if (!openavbAemAddDescriptor(pNewAvbInterface, nConfigIdx, &nResultIdx) ||
+ !openavbAemDescriptorAvbInterfaceInitialize(pNewAvbInterface, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error adding AVDECC AVB Interface to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ openavb_aem_descriptor_audio_unit_t *pNewAudioUnit = openavbAemDescriptorAudioUnitNew();
+ if (!openavbAemAddDescriptor(pNewAudioUnit, nConfigIdx, &nResultIdx) ||
+ !openavbAemDescriptorAudioUnitInitialize(pNewAudioUnit, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error adding AVDECC Audio Unit to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+ else
+ {
+ openavb_aem_descriptor_audio_unit_t *pAudioUnitDescriptor =
+ (openavb_aem_descriptor_audio_unit_t *) openavbAemGetDescriptor(nConfigIdx, OPENAVB_AEM_DESCRIPTOR_AUDIO_UNIT, 0);
+ if (pAudioUnitDescriptor != NULL)
+ {
+ if (!openavbAemDescriptorAudioUnitInitialize(pAudioUnitDescriptor, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error updating AVDECC Audio Unit to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+ else
+ {
+ AVB_LOG_ERROR("Error getting AVDECC Audio Unit descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+
+ // AVDECC_TODO: Add other descriptors as needed. Future options include:
+ // VIDEO_UNIT
+ // SENSOR_UNIT
+ // CONTROL
+
+ if (stream->role == AVB_ROLE_TALKER) {
+ gAvdeccCfg.bTalker = TRUE;
+
+ openavb_aem_descriptor_stream_io_t *pNewStreamOutput = openavbAemDescriptorStreamOutputNew();
+ if (!openavbAemAddDescriptor(pNewStreamOutput, nConfigIdx, &nResultIdx) ||
+ !openavbAemDescriptorStreamOutputInitialize(pNewStreamOutput, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error adding AVDECC Stream Output to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (first_talker)
+ {
+ first_talker = 0;
+ openavb_aem_descriptor_clock_source_t *pNewClockSource = openavbAemDescriptorClockSourceNew();
+ if (!openavbAemAddDescriptor(pNewClockSource, nConfigIdx, &nResultIdx) ||
+ !openavbAemDescriptorClockSourceInitialize(pNewClockSource, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error adding AVDECC Clock Source to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ openavb_aem_descriptor_clock_domain_t *pNewClockDomain = openavbAemDescriptorClockDomainNew();
+ if (!openavbAemAddDescriptor(pNewClockDomain, nConfigIdx, &nResultIdx) ||
+ !openavbAemDescriptorClockDomainInitialize(pNewClockDomain, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error adding AVDECC Clock Domain to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+
+ // AVDECC_TODO: Add other descriptors as needed. Future options include:
+ // JACK_INPUT
+ talker_stream_sources++;
+
+ // Add the class specific to the talker.
+ if (stream->sr_class == SR_CLASS_A) { gAvdeccCfg.bClassASupported = TRUE; }
+ if (stream->sr_class == SR_CLASS_B) { gAvdeccCfg.bClassBSupported = TRUE; }
+
+ AVB_LOG_DEBUG("AVDECC talker configuration added");
+ }
+ if (stream->role == AVB_ROLE_LISTENER) {
+ gAvdeccCfg.bListener = TRUE;
+
+ openavb_aem_descriptor_stream_io_t *pNewStreamInput = openavbAemDescriptorStreamInputNew();
+ if (!openavbAemAddDescriptor(pNewStreamInput, nConfigIdx, &nResultIdx) ||
+ !openavbAemDescriptorStreamInputInitialize(pNewStreamInput, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error adding AVDECC Stream Input to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (first_listener)
+ {
+ openavb_aem_descriptor_clock_source_t *pNewClockSource = openavbAemDescriptorClockSourceNew();
+ if (!openavbAemAddDescriptor(pNewClockSource, nConfigIdx, &nResultIdx) ||
+ !openavbAemDescriptorClockSourceInitialize(pNewClockSource, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error adding AVDECC Clock Source to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ openavb_aem_descriptor_clock_domain_t *pNewClockDomain = openavbAemDescriptorClockDomainNew();
+ if (!openavbAemAddDescriptor(pNewClockDomain, nConfigIdx, &nResultIdx) ||
+ !openavbAemDescriptorClockDomainInitialize(pNewClockDomain, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error adding AVDECC Clock Domain to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+
+ // AVDECC_TODO: Add other descriptors as needed. Future options include:
+ // JACK_OUTPUT
+ listener_stream_sources++;
+
+ // Listeners support both Class A and Class B.
+ gAvdeccCfg.bClassASupported = TRUE;
+ gAvdeccCfg.bClassBSupported = TRUE;
+
+ AVB_LOG_DEBUG("AVDECC listener configuration added");
+ }
+
+ if (first_time)
+ {
+ // Add the localized strings to the configuration.
+ if (!openavbAemDescriptorLocaleStringsHandlerAddToConfiguration(gAvdeccCfg.pAemDescriptorLocaleStringsHandler, nConfigIdx)) {
+ AVB_LOG_ERROR("Error adding AVDECC locale strings to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT bool openavbAvdeccInitialize()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ gAvdeccCfg.pDescriptorEntity = openavbAemDescriptorEntityNew();
+ if (!gAvdeccCfg.pDescriptorEntity) {
+ AVB_LOG_ERROR("Failed to allocate an AVDECC descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ openavbAvdeccFindMacAddr();
+
+ if (!openavbAemDescriptorEntitySet_entity_id(gAvdeccCfg.pDescriptorEntity, NULL, gAvdeccCfg.ifmac, gAvdeccCfg.avdeccId)) {
+ AVB_LOG_ERROR("Failed to set the AVDECC descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Create the Entity Model
+ openavbRC rc = openavbAemCreate(gAvdeccCfg.pDescriptorEntity);
+ if (IS_OPENAVB_FAILURE(rc)) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Copy the supplied non-localized strings to the descriptor.
+ openavbAemDescriptorEntitySet_entity_model_id(gAvdeccCfg.pDescriptorEntity, gAvdeccCfg.entity_model_id);
+ openavbAemDescriptorEntitySet_entity_name(gAvdeccCfg.pDescriptorEntity, gAvdeccCfg.entity_name);
+ openavbAemDescriptorEntitySet_firmware_version(gAvdeccCfg.pDescriptorEntity, gAvdeccCfg.firmware_version);
+ openavbAemDescriptorEntitySet_group_name(gAvdeccCfg.pDescriptorEntity, gAvdeccCfg.group_name);
+ openavbAemDescriptorEntitySet_serial_number(gAvdeccCfg.pDescriptorEntity, gAvdeccCfg.serial_number);
+
+ // Initialize the localized strings support.
+ gAvdeccCfg.pAemDescriptorLocaleStringsHandler = openavbAemDescriptorLocaleStringsHandlerNew();
+ if (gAvdeccCfg.pAemDescriptorLocaleStringsHandler) {
+ // Add the strings to the locale strings hander.
+ openavbAemDescriptorLocaleStringsHandlerSet_local_string(
+ gAvdeccCfg.pAemDescriptorLocaleStringsHandler, gAvdeccCfg.locale_identifier, gAvdeccCfg.vendor_name, LOCALE_STRING_VENDOR_NAME_INDEX);
+ openavbAemDescriptorLocaleStringsHandlerSet_local_string(
+ gAvdeccCfg.pAemDescriptorLocaleStringsHandler, gAvdeccCfg.locale_identifier, gAvdeccCfg.model_name, LOCALE_STRING_MODEL_NAME_INDEX);
+
+ // Have the descriptor entity reference the locale strings.
+ openavbAemDescriptorEntitySet_vendor_name(gAvdeccCfg.pDescriptorEntity, 0, LOCALE_STRING_VENDOR_NAME_INDEX);
+ openavbAemDescriptorEntitySet_model_name(gAvdeccCfg.pDescriptorEntity, 0, LOCALE_STRING_MODEL_NAME_INDEX);
+ }
+
+ gAvdeccCfg.bTalker = gAvdeccCfg.bListener = FALSE;
+
+ // Add a configuration for each talker or listener stream.
+ openavb_tl_data_cfg_t *current_stream = streamList;
+ while (current_stream != NULL) {
+ // Create a new configuration with the information from this stream.
+ if (!openavbAvdeccAddConfiguration(current_stream)) {
+ AVB_LOG_ERROR("Error adding AVDECC configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Proceed to the next stream.
+ current_stream = current_stream->next;
+ }
+
+ if (!gAvdeccCfg.bTalker && !gAvdeccCfg.bListener) {
+ AVB_LOG_ERROR("No AVDECC Configurations -- Aborting");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Add non-top-level descriptors. These are independent of the configurations.
+ // STRINGS are handled by gAvdeccCfg.pAemDescriptorLocaleStringsHandler, so not included here.
+ U16 nResultIdx;
+ if (!openavbAemAddDescriptor(openavbAemDescriptorAudioClusterNew(), OPENAVB_AEM_DESCRIPTOR_INVALID, &nResultIdx)) {
+ AVB_LOG_ERROR("Error adding AVDECC Audio Cluster");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (gAvdeccCfg.bTalker) {
+ if (!openavbAemAddDescriptor(openavbAemDescriptorStreamPortOutputNew(), OPENAVB_AEM_DESCRIPTOR_INVALID, &nResultIdx)) {
+ AVB_LOG_ERROR("Error adding AVDECC Output Stream Port");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+ if (gAvdeccCfg.bListener) {
+ if (!openavbAemAddDescriptor(openavbAemDescriptorStreamPortInputNew(), OPENAVB_AEM_DESCRIPTOR_INVALID, &nResultIdx)) {
+ AVB_LOG_ERROR("Error adding AVDECC Input Stream Port");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+
+ // AVDECC_TODO: Add other descriptors as needed. Future options include:
+ // EXTERNAL_PORT_INPUT
+ // EXTERNAL_PORT_OUTPUT
+ // INTERNAL_PORT_INPUT
+ // INTERNAL_PORT_OUTPUT
+ // VIDEO_CLUSTER
+ // SENSOR_CLUSTER
+ // AUDIO_MAP
+ // VIDEO_MAP
+ // SENSOR_MAP
+
+ // Fill in the descriptor capabilities.
+ // AVDECC_TODO: Set these based on the available capabilities.
+ if (!gAvdeccCfg.bClassASupported && !gAvdeccCfg.bClassBSupported) {
+ // If the user didn't specify a traffic class, assume both are supported.
+ gAvdeccCfg.bClassASupported = gAvdeccCfg.bClassBSupported = TRUE;
+ }
+ openavbAemDescriptorEntitySet_entity_capabilities(gAvdeccCfg.pDescriptorEntity,
+ OPENAVB_ADP_ENTITY_CAPABILITIES_AEM_SUPPORTED |
+ (gAvdeccCfg.bClassASupported ? OPENAVB_ADP_ENTITY_CAPABILITIES_CLASS_A_SUPPORTED : 0) |
+ (gAvdeccCfg.bClassBSupported ? OPENAVB_ADP_ENTITY_CAPABILITIES_CLASS_B_SUPPORTED : 0) |
+ OPENAVB_ADP_ENTITY_CAPABILITIES_GPTP_SUPPORTED);
+
+ if (gAvdeccCfg.bTalker) {
+ // AVDECC_TODO: Set these based on the available capabilities.
+ openavbAemDescriptorEntitySet_talker_capabilities(gAvdeccCfg.pDescriptorEntity, talker_stream_sources,
+ OPENAVB_ADP_TALKER_CAPABILITIES_IMPLEMENTED |
+ OPENAVB_ADP_TALKER_CAPABILITIES_AUDIO_SOURCE |
+ OPENAVB_ADP_TALKER_CAPABILITIES_MEDIA_CLOCK_SOURCE);
+ }
+ if (gAvdeccCfg.bListener) {
+ // AVDECC_TODO: Set these based on the available capabilities.
+ openavbAemDescriptorEntitySet_listener_capabilities(gAvdeccCfg.pDescriptorEntity, listener_stream_sources,
+ OPENAVB_ADP_LISTENER_CAPABILITIES_IMPLEMENTED |
+ OPENAVB_ADP_LISTENER_CAPABILITIES_AUDIO_SINK);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+// Start the AVDECC protocols.
+extern DLL_EXPORT bool openavbAvdeccStart()
+{
+ if (!openavbAvdeccStartCmp()) {
+ AVB_LOG_ERROR("openavbAvdeccStartCmp() failure!");
+ return FALSE;
+ }
+ if (!openavbAvdeccStartEcp()) {
+ AVB_LOG_ERROR("openavbAvdeccStartEcp() failure!");
+ return FALSE;
+ }
+ if (!openavbAvdeccStartAdp()) {
+ AVB_LOG_ERROR("openavbAvdeccStartAdp() failure!");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// Stop the AVDECC protocols.
+extern DLL_EXPORT void openavbAvdeccStop(void)
+{
+ openavbAvdeccStopCmp();
+ openavbAvdeccStopEcp();
+ openavbAvdeccStopAdp();
+}
+
+extern DLL_EXPORT bool openavbAvdeccCleanup(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ openavbRC rc = openavbAemDestroy();
+
+ while (pFirstConfigurationCfg) {
+ openavb_avdecc_configuration_cfg_t *pDel = pFirstConfigurationCfg;
+ pFirstConfigurationCfg = pFirstConfigurationCfg->next;
+ free(pDel);
+ }
+
+ if (IS_OPENAVB_FAILURE(rc)) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/avdecc/openavb_avdecc.h b/lib/avtp_pipeline/avdecc/openavb_avdecc.h
new file mode 100644
index 00000000..6c32b7e4
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc/openavb_avdecc.h
@@ -0,0 +1,210 @@
+/*************************************************************************************************************
+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 : AVDECC - Top level 1722.1 implementation
+ * MODULE SUMMARY : Top level 1722.1 implementation
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_AVDECC_H
+#define OPENAVB_AVDECC_H 1
+
+#include "openavb_platform.h"
+
+#include "openavb_avdecc_pub.h"
+#include "openavb_avdecc_osal.h"
+#include "openavb_types.h"
+#include "openavb_trace.h"
+
+#ifndef DATA_ALIGNMENT_ADJUSTMENT
+// No Data alignment precaution needed.
+
+// Octet based data 2 buffer macros
+#define OCT_D2BMEMCP(d, s) {size_t data_size = sizeof(s); memcpy(d, s, data_size); d += data_size;} // Uses data_size variable to avoid compiler warnings
+#define OCT_D2BBUFCP(d, s, len) memcpy(d, s, len); d += len;
+#define OCT_D2BHTONB(d, s) *(U8 *)(d) = s; d += sizeof(s);
+#define OCT_D2BHTONS(d, s) *(U16 *)(d) = htons(s); d += sizeof(s);
+#define OCT_D2BHTONL(d, s) *(U32 *)(d) = htonl(s); d += sizeof(s);
+
+// Bit based data 2 buffer macros
+#define BIT_D2BHTONB(d, s, shf, inc) *(U8 *)(d) |= s << shf; d += inc;
+#define BIT_D2BHTONS(d, s, shf, inc) *(U16 *)(d) |= htons((U16)(s << shf)); d += inc;
+#define BIT_D2BHTONL(d, s, shf, inc) *(U32 *)(d) |= htonl((U32)(s << shf)); d += inc;
+
+
+// Octet based buffer 2 data macros
+#define OCT_B2DMEMCP(d, s) {size_t data_size = sizeof(d); memcpy(d, s, data_size); s += data_size;} // Uses data_size variable to avoid compiler warnings
+#define OCT_B2DBUFCP(d, s, len) memcpy(d, s, len); s += len;
+#define OCT_B2DNTOHB(d, s) d = *(U8 *)(s); s += sizeof(d);
+#define OCT_B2DNTOHS(d, s) d = ntohs(*(U16 *)(s)); s += sizeof(d);
+#define OCT_B2DNTOHL(d, s) d = ntohl(*(U32 *)(s)); s += sizeof(d);
+
+// Bit based buffer 2 data macros
+#define BIT_B2DNTOHB(d, s, msk, shf, inc) d = (*(U8 *)(s) & (U8)msk) >> shf; s += inc;
+#define BIT_B2DNTOHS(d, s, msk, shf, inc) d = (ntohs(*(U16 *)(s)) & (U16)msk) >> shf; s += inc;
+#define BIT_B2DNTOHL(d, s, msk, shf, inc) d = (ntohl(*(U32 *)(s)) & (U32)msk) >> shf; s += inc;
+
+#else
+// Data alignment precaution needed.
+
+// Octet based data 2 buffer macros
+#define OCT_D2BMEMCP(d, s) {size_t data_size = sizeof(s); memcpy(d, s, data_size); d += data_size;} // Uses data_size variable to avoid compiler warnings
+
+#define OCT_D2BBUFCP(d, s, len) memcpy(d, s, len); d += len;
+
+//#define OCT_D2BHTONB(d, s) *(U8 *)(d) = s; d += sizeof(s);
+#define OCT_D2BHTONB(d, s) \
+{ \
+memcpy(d, &s, sizeof(U8)); \
+d += sizeof(U8); \
+}
+
+//#define OCT_D2BHTONS(d, s) *(U16 *)(d) = htons(s); d += sizeof(s);
+#define OCT_D2BHTONS(d, s) \
+{ \
+U16 sAlign16 = s; \
+sAlign16 = htons(sAlign16); \
+memcpy(d, &sAlign16, sizeof(U16)); \
+d += sizeof(U16); \
+}
+
+//#define OCT_D2BHTONL(d, s) *(U32 *)(d) = htonl(s); d += sizeof(s);
+#define OCT_D2BHTONL(d, s) \
+{ \
+U32 sAlign32 = s; \
+sAlign32 = htonl(sAlign32); \
+memcpy(d, &sAlign32, sizeof(U32)); \
+d += sizeof(U32); \
+}
+
+// Bit based data 2 buffer macros
+//#define BIT_D2BHTONB(d, s, shf, inc) *(U8 *)(d) |= s << shf; d += inc;
+#define BIT_D2BHTONB(d, s, shf, inc) \
+{ \
+U8 sAlign8 = s << shf; \
+U8 dAlign8; \
+memcpy(&dAlign8, d, sizeof(U8)); \
+dAlign8 |= sAlign8; \
+memcpy(d, &dAlign8, sizeof(U8)); \
+d += inc; \
+}
+
+//#define BIT_D2BHTONS(d, s, shf, inc) *(U16 *)(d) |= htons((U16)(s << shf)); d += inc;
+#define BIT_D2BHTONS(d, s, shf, inc) \
+{ \
+U16 sAlign16 = htons((U16)(s << shf)); \
+U16 dAlign16; \
+memcpy(&dAlign16, d, sizeof(U16)); \
+dAlign16 |= sAlign16; \
+memcpy(d, &dAlign16, sizeof(U16)); \
+d += inc; \
+}
+
+//#define BIT_D2BHTONL(d, s, shf, inc) *(U32 *)(d) |= htonl((U32)(s << shf)); d += inc;
+#define BIT_D2BHTONL(d, s, shf, inc) \
+{ \
+U32 sAlign32 = htonl((U32)(s << shf)); \
+U32 dAlign32; \
+memcpy(&dAlign32, d, sizeof(U32)); \
+dAlign32 |= sAlign32; \
+memcpy(d, &dAlign32, sizeof(U32)); \
+d += inc; \
+}
+
+
+// Octet based buffer 2 data macros
+#define OCT_B2DMEMCP(d, s) {size_t data_size = sizeof(d); memcpy(d, s, data_size); s += data_size;} // Uses data_size variable to avoid compiler warnings
+
+#define OCT_B2DBUFCP(d, s, len) memcpy(d, s, len); s += len;
+
+//#define OCT_B2DNTOHB(d, s) d = *(U8 *)(s); s += sizeof(d);
+#define OCT_B2DNTOHB(d, s) \
+{ \
+memcpy(&d, s, sizeof(U8)); \
+s += sizeof(U8); \
+}
+
+//#define OCT_B2DNTOHS(d, s) d = ntohs(*(U16 *)(s)); s += sizeof(d);
+#define OCT_B2DNTOHS(d, s) \
+{ \
+U16 sAlign16; \
+memcpy(&sAlign16, s, sizeof(U16)); \
+sAlign16 = ntohs(sAlign16); \
+memcpy(&d, &sAlign16, sizeof(U16)); \
+s += sizeof(U16); \
+}
+
+//#define OCT_B2DNTOHL(d, s) d = ntohl(*(U32 *)(s)); s += sizeof(d);
+#define OCT_B2DNTOHL(d, s) \
+{ \
+U32 sAlign32; \
+memcpy(&sAlign32, s, sizeof(U32)); \
+sAlign32 = ntohl(sAlign32); \
+memcpy(&d, &sAlign32, sizeof(U32)); \
+s += sizeof(U32); \
+}
+
+// Bit based buffer 2 data macros
+//#define BIT_B2DNTOHB(d, s, msk, shf, inc) d = (*(U8 *)(s) & (U8)msk) >> shf; s += inc;
+#define BIT_B2DNTOHB(d, s, msk, shf, inc) \
+{ \
+U8 sAlign8; \
+memcpy(&sAlign8, s, sizeof(U8)); \
+sAlign8 = (sAlign8 & (U8)msk) >>shf; \
+memcpy(&d, &sAlign8, sizeof(U8)); \
+s += inc; \
+}
+
+//#define BIT_B2DNTOHS(d, s, msk, shf, inc) d = (ntohs(*(U16 *)(s)) & (U16)msk) >> shf; s += inc;
+#define BIT_B2DNTOHS(d, s, msk, shf, inc) \
+{ \
+U16 sAlign16; \
+memcpy(&sAlign16, s, sizeof(U16)); \
+sAlign16 = (ntohs(sAlign16) & (U16)msk) >> shf; \
+memcpy(&d, &sAlign16, sizeof(U16)); \
+s += inc; \
+}
+
+//#define BIT_B2DNTOHL(d, s, msk, shf, inc) d = (ntohl(*(U32 *)(s)) & (U32)msk) >> shf; s += inc;
+#define BIT_B2DNTOHL(d, s, msk, shf, inc) \
+{ \
+U32 sAlign32; \
+memcpy(&sAlign32, s, sizeof(U32)); \
+sAlign32 = (ntohs(sAlign32) & (U32)msk) >> shf; \
+memcpy(&d, &sAlign32, sizeof(U32)); \
+s += inc; \
+}
+
+#endif
+
+#endif // OPENAVB_AVDECC_H
diff --git a/lib/avtp_pipeline/avdecc/openavb_avdecc_pipeline_interaction_pub.h b/lib/avtp_pipeline/avdecc/openavb_avdecc_pipeline_interaction_pub.h
new file mode 100644
index 00000000..c7edac96
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc/openavb_avdecc_pipeline_interaction_pub.h
@@ -0,0 +1,71 @@
+/*************************************************************************************************************
+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_PIPELINE_INTERACTION_PUB_H
+#define OPENAVB_AVDECC_PIPELINE_INTERACTION_PUB_H 1
+
+#include "openavb_acmp.h"
+#include "openavb_descriptor_stream_io_pub.h"
+#include "openavb_avdecc_msg.h"
+
+
+// Run a single talker or listener.
+bool openavbAVDECCRunListener(openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput, U16 configIdx, openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo);
+bool openavbAVDECCRunTalker(openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput, U16 configIdx, openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo);
+
+// Stop a single talker or listener.
+bool openavbAVDECCStopListener(openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput, U16 configIdx, openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo);
+bool openavbAVDECCStopTalker(openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput, U16 configIdx, openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo);
+
+// Get talker stream details. Structure members in TalkerStreamInfo will be filled.
+bool openavbAVDECCGetTalkerStreamInfo(openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput, U16 configIdx, openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo);
+
+// Set talker stream details. The settings will be passed to the Talker to use for future connections
+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);
+
+// Get the streaming state (stopped, running, paused, etc.) AVDECC told the talker or listener to use.
+openavbAvdeccMsgStateType_t openavbAVDECCGetRequestedState(openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput, U16 configIdx);
+
+// Get the streaming state (stopped, running, paused, etc.) last reported by the talker or listener.
+openavbAvdeccMsgStateType_t openavbAVDECCGetStreamingState(openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput, U16 configIdx);
+
+// Pause or resume the stream.
+void openavbAVDECCPauseStream(openavb_aem_descriptor_stream_io_t *pDescriptor, bool bPause);
+
+// 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);
+
+#endif // OPENAVB_AVDECC_PIPELINE_INTERACTION_PUB_H
diff --git a/lib/avtp_pipeline/avdecc/openavb_avdecc_pub.h b/lib/avtp_pipeline/avdecc/openavb_avdecc_pub.h
new file mode 100644
index 00000000..803438ed
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc/openavb_avdecc_pub.h
@@ -0,0 +1,145 @@
+/*************************************************************************************************************
+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 : AVDECC - Top level AVDECC (1722.1) Public Interface
+ * MODULE SUMMARY : Top level AVDECC (1722.1) Public Interface
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_AVDECC_PUB_H
+#define OPENAVB_AVDECC_PUB_H 1
+
+// Entity Model public includes
+#include "openavb_aem_pub.h"
+#include "openavb_descriptor_entity_pub.h"
+#include "openavb_descriptor_configuration_pub.h"
+#include "openavb_descriptor_audio_unit_pub.h"
+#include "openavb_descriptor_stream_io_pub.h"
+#include "openavb_descriptor_jack_io_pub.h"
+#include "openavb_descriptor_avb_interface_pub.h"
+#include "openavb_descriptor_clock_source_pub.h"
+#include "openavb_descriptor_locale_pub.h"
+#include "openavb_descriptor_strings_pub.h"
+#include "openavb_descriptor_control_pub.h"
+#include "openavb_descriptor_stream_port_io_pub.h"
+#include "openavb_descriptor_external_port_io_pub.h"
+#include "openavb_descriptor_audio_cluster_pub.h"
+#include "openavb_descriptor_audio_map_pub.h"
+#include "openavb_descriptor_clock_domain_pub.h"
+#include "openavb_descriptor_locale_strings_handler_pub.h"
+
+// Discovery protocol public includes
+#include "openavb_adp_pub.h"
+
+// Connection management public includes
+#include "openavb_acmp_pub.h"
+
+// Enumeration and control public includes
+#include "openavb_aecp_pub.h"
+
+// openavb_tl_data_cfg_t definition
+#include "openavb_avdecc_read_ini_pub.h"
+
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+
+// Indexes for localized strings.
+// (These are defined for internal use, and can be changed as needed.)
+#define LOCALE_STRING_VENDOR_NAME_INDEX 0
+#define LOCALE_STRING_MODEL_NAME_INDEX 1
+
+typedef struct {
+
+ char ifname[IFNAMSIZ + 10]; // Include space for the socket type prefix (e.g. "simple:eth0")
+ U8 ifmac[ETH_ALEN];
+
+ bool bListener;
+ bool bTalker;
+ bool bClassASupported;
+ bool bClassBSupported;
+
+ U16 vlanID;
+ U8 vlanPCP;
+
+ bool bFastConnectSupported; // FAST_CONNECT and SAVED_STATE supported
+
+ U8 valid_time; // Number of 2-second units
+
+ // Information to add to the descriptor.
+ unsigned avdeccId;
+ U8 entity_model_id[8];
+ char entity_name[OPENAVB_AEM_STRLEN_MAX];
+ char firmware_version[OPENAVB_AEM_STRLEN_MAX];
+ char group_name[OPENAVB_AEM_STRLEN_MAX];
+ char serial_number[OPENAVB_AEM_STRLEN_MAX];
+
+ // Localization strings.
+ char locale_identifier[OPENAVB_AEM_STRLEN_MAX];
+ char vendor_name[OPENAVB_AEM_STRLEN_MAX];
+ char model_name[OPENAVB_AEM_STRLEN_MAX];
+
+ openavb_aem_descriptor_entity_t *pDescriptorEntity;
+ openavb_aem_descriptor_locale_strings_handler_t *pAemDescriptorLocaleStringsHandler;
+} openavb_avdecc_cfg_t;
+
+typedef struct openavb_avdecc_configuration_cfg {
+ struct openavb_avdecc_configuration_cfg *next; // next link list pointer
+
+ // Pointer to the endpoint information.
+ openavb_tl_data_cfg_t *stream;
+
+ // Friendly name
+ char friendly_name[OPENAVB_AEM_STRLEN_MAX];
+
+ // AVDECC_TODO: Add additional information as needed.
+
+} openavb_avdecc_configuration_cfg_t;
+
+
+// General initialization for AVDECC. This must be called before any other AVDECC APIs including AEM APIs
+bool openavbAvdeccInitialize(void);
+
+// Start the AVDECC protocols.
+bool openavbAvdeccStart(void);
+
+// Stop the AVDECC protocols.
+void openavbAvdeccStop(void);
+
+// General Cleanup for AVDECC.
+bool openavbAvdeccCleanup(void);
+
+#endif // OPENAVB_AVDECC_PUB_H
diff --git a/lib/avtp_pipeline/avdecc/openavb_avdecc_read_ini_pub.h b/lib/avtp_pipeline/avdecc/openavb_avdecc_read_ini_pub.h
new file mode 100644
index 00000000..5c71d5b7
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc/openavb_avdecc_read_ini_pub.h
@@ -0,0 +1,197 @@
+/*************************************************************************************************************
+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 : AVDECC Read INI Public Interface
+*/
+
+#ifndef OPENAVB_AVDECC_READ_INI_PUB_H
+#define OPENAVB_AVDECC_READ_INI_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_avtp_time_pub.h"
+#include "openavb_tl_pub.h"
+
+#define MAX_SAMPLING_RATES_COUNT 91
+
+/** \file
+ * AVDECC Read INI Public Interface.
+ */
+
+struct _avdecc_msg_state;
+typedef struct _avdecc_msg_state avdecc_msg_state_t;
+
+/// Maximum size of the friendly name
+#define FRIENDLY_NAME_SIZE 64
+
+/// Structure containing configuration of the host
+struct openavb_tl_data_cfg {
+ struct openavb_tl_data_cfg *next;
+
+ /// Role of the host
+ avb_role_t role;
+ /// Initial Talker/Listener state
+ tl_init_state_t initial_state;
+ /// MAC address of destination - multicast (talker only if SRP is enabled)
+ cfg_mac_t dest_addr;
+ /// MAC address of the source
+ cfg_mac_t stream_addr;
+ /// Stream UID (has to be unique)
+ U16 stream_uid;
+ /// Maximum number of packets sent during one interval (talker only)
+ U32 max_interval_frames;
+ /// Maximum size of the frame
+ U32 max_frame_size;
+ /// Setting maximum transit time, on talker value is added to PTP Walltime,
+ /// on listener value is validated timestamp range
+ U32 max_transit_usec;
+ /// Maximum transmit deficit in usec - should be set to expected buffer size
+ /// on the listener side (talker only)
+ U32 max_transmit_deficit_usec;
+ /// Specify manual an internal latency (talker only)
+ U32 internal_latency;
+ /// Number of microseconds after which late MediaQItem will be purged as too
+ /// old (listener only)
+ U32 max_stale;
+ /// Number of intervals to handle at once (talker only)
+ U32 batch_factor;
+ /// Statistics reporting frequency
+ U32 report_seconds;
+ /// Start paused
+ bool start_paused;
+ /// Class in which host will operate ::SRClassIdx_t (talker only)
+ U8 sr_class;
+ /// Rank of the stream #SR_RANK_REGULAR or #SR_RANK_EMERGENCY (talker only)
+ U8 sr_rank;
+ /// Number of raw TX buffers that should be used (talker only)
+ U32 raw_tx_buffers;
+ /// Number of raw RX buffers (listener only)
+ U32 raw_rx_buffers;
+ /// Is the interface module blocking in the TX CB.
+ bool tx_blocking_in_intf;
+ /// VLAN ID
+ U16 vlan_id;
+ /// When set incoming packets will trigger a signal to the stream task to wakeup.
+ bool rx_signal_mode;
+ /// Enable fixed timestamping in interface
+ U32 fixed_timestamp;
+ /// Wait for next observation interval by spinning rather than sleeping
+ bool spin_wait;
+ /// Bit mask used for CPU pinning
+ U32 thread_affinity;
+ /// Real time priority of thread.
+ U32 thread_rt_priority;
+ /// The current sample rate of this Audio Unit
+ U32 current_sampling_rate;
+ /// The number of sample rates in the sampling_rates field.
+ U16 sampling_rates_count;
+ /// An array of 4-octet sample rates supported by this Audio Unit
+ U32 sampling_rates[MAX_SAMPLING_RATES_COUNT];
+ /// intf_nv_audio_rate
+ U16 audioRate;
+ /// intf_nv_audio_bit_depth
+ U8 audioBitDepth;
+ /// intf_nv_channels
+ U8 audioChannels;
+ /// Friendly name for this configuration
+ char friendly_name[FRIENDLY_NAME_SIZE];
+ /// The name of the initialize function in the mapper
+ char map_fn[100];
+
+ // Pointer to the client Talker/Listener.
+ // Do not free this item; it is for reference only.
+ const avdecc_msg_state_t * client;
+};
+
+typedef struct openavb_tl_data_cfg openavb_tl_data_cfg_t;
+
+
+/** Read an ini file.
+ *
+ * Parses an input configuration file to populate configuration structures, and
+ * name value pairs. Only used in Operating Systems that have a file system
+ *
+ * \param fileName Pointer to configuration file name
+ * \param pCfg Pointer to configuration structure
+ * \return TRUE on success or FALSE on failure
+ *
+ * \warning Not available on all platforms
+ */
+bool openavbReadTlDataIniFile(const char *fileName, openavb_tl_data_cfg_t *pCfg);
+
+
+/** Save the connection to the saved state
+ *
+ * If fast connect support is enabled, this function is used to save the state
+ * of the connection by a Listener when a connection is successfully made to
+ * a Talker for possible fast connect support later.
+ * #openavbAvdeccClearSavedState() should be called when the connection is closed.
+ *
+ * \param pListener Pointer to configuration for the Listener
+ * \param flags The flags used for the connection (CLASS_B, SUPPORTS_ENCRYPTED, ENCRYPTED_PDU)
+ * \param talker_unique_id The unique id for the Talker
+ * \param talker_entity_id The binary entity id for the Talker
+ * \param controller_entity_id The binary entity id for the Controller that initiated the connection
+ *
+ * \return TRUE on success or FALSE on failure
+ */
+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]);
+
+/** Delete a connection with saved state
+ *
+ * If fast connect support is enabled, this function is used to clear previously
+ * saved state information (from a previous call to #openavbAvdeccSaveState).
+ * This function should be called from the Listener when a Talker/Listener connection is closed
+ * (and fast connects should no longer be attempted in the future).
+ *
+ * \param pListener Pointer to configuration for the Listener
+ *
+ * \return TRUE on success or FALSE on failure
+ */
+bool openavbAvdeccClearSavedState(const openavb_tl_data_cfg_t *pListener);
+
+/** Determine if the connection has a saved state
+ *
+ * If fast connect support is enabled, this function is used to get the last
+ * saved state (from a call to #openavbAvdeccSaveState) for a Listener, if any.
+ *
+ * \param pListener Pointer to configuration for the Listener
+ * \param p_flags Optional pointer to the flags used for the connection (CLASS_B, SUPPORTS_ENCRYPTED, ENCRYPTED_PDU)
+ * \param p_talker_unique_id Optional pointer to the unique id for the Talker
+ * \param p_talker_entity_id Optional pointer to the buffer to fill in the binary entity id for the Talker
+ * \param p_controller_entity_id Optional pointer to the buffer to fill in the binary entity id for the Controller that initiated the connection
+ *
+ * \return TRUE if there is a saved state, or FALSE otherwise
+ */
+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]);
+
+#endif // OPENAVB_AVDECC_READ_INI_PUB_H
diff --git a/lib/avtp_pipeline/avdecc/shutdown_openavb_avdecc.sh b/lib/avtp_pipeline/avdecc/shutdown_openavb_avdecc.sh
new file mode 100755
index 00000000..352e5433
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc/shutdown_openavb_avdecc.sh
@@ -0,0 +1,18 @@
+#! /bin/sh
+#
+# AVB AVDECC clean-up script
+#
+# Only needs to be run if the AVDECC process crashes.
+#
+# Removes resources created/loaded by AVDECC, so that a new
+# instance can run.
+
+IFACES=$(cat /proc/net/dev | grep -- : | cut -d: -f1)
+
+echo "removing AVDECC resources"
+
+killall -s SIGINT openavb_avdecc > /dev/null 2>&1
+killall -s SIGINT openavb_harness > /dev/null 2>&1
+killall -s SIGINT openavb_host > /dev/null 2>&1
+rm -f /tmp/avdecc_msg > /dev/null 2>&1
+
diff --git a/lib/avtp_pipeline/avdecc_msg/CMakeLists.txt b/lib/avtp_pipeline/avdecc_msg/CMakeLists.txt
new file mode 100644
index 00000000..139597f9
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc_msg/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+
diff --git a/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg.c b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg.c
new file mode 100644
index 00000000..f599ecf7
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg.c
@@ -0,0 +1,192 @@
+/*************************************************************************************************************
+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 :
+ *
+ * Stream clients (talkers or listeners) must connect to the central
+ * "avdecc_msg" process to create a reservation for their traffic.
+ *
+ * This code implements functions used by both sides of the IPC.
+ */
+
+
+// We are accessed from multiple threads, so need a mutex
+MUTEX_HANDLE(gAvdeccMsgStateMutex);
+
+static avdecc_msg_state_t *gAvdeccMsgStateList[MAX_AVDECC_MSG_CLIENTS] = { 0 };
+static int nNumInitialized = 0;
+
+EXTERN_DLL_EXPORT bool openavbAvdeccMsgInitialize(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (nNumInitialized++ == 0) {
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "gAvdeccMsgStateMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(gAvdeccMsgStateMutex, mta);
+ MUTEX_LOG_ERR("Error creating mutex");
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+}
+
+// General cleanup of the talker and listener library. Should be called after all Talker and Listeners are closed.
+EXTERN_DLL_EXPORT bool openavbAvdeccMsgCleanup()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (--nNumInitialized <= 0) {
+ nNumInitialized = 0;
+
+ if (AvdeccMsgStateListGetIndex(0)) {
+ AVB_LOG_WARNING("AvdeccMsgStateList not empty on exit");
+ }
+
+ MUTEX_CREATE_ERR();
+ MUTEX_DESTROY(gAvdeccMsgStateMutex);
+ MUTEX_LOG_ERR("Error destroying mutex");
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+}
+
+
+bool AvdeccMsgStateListAdd(avdecc_msg_state_t * pState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (!pState) {
+ AVB_LOG_ERROR("AvdeccMsgStateListAdd invalid param");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ AVDECC_MSG_LOCK();
+ int i1;
+ for (i1 = 0; i1 < MAX_AVDECC_MSG_CLIENTS; i1++) {
+ if (!gAvdeccMsgStateList[i1]) {
+ gAvdeccMsgStateList[i1] = pState;
+ AVDECC_MSG_UNLOCK();
+ AVB_LOGF_DEBUG("AvdeccMsgStateListAdd %d succeeded", pState->avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+ }
+ }
+ AVDECC_MSG_UNLOCK();
+ AVB_LOGF_WARNING("AvdeccMsgStateListAdd %d out of space", pState->avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+}
+
+bool AvdeccMsgStateListRemove(avdecc_msg_state_t * pState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (!pState) {
+ AVB_LOG_ERROR("AvdeccMsgStateListRemove invalid param");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ AVDECC_MSG_LOCK();
+ int i1;
+ for (i1 = 0; i1 < MAX_AVDECC_MSG_CLIENTS; i1++) {
+ if (gAvdeccMsgStateList[i1] == pState) {
+ gAvdeccMsgStateList[i1] = NULL;
+ AVDECC_MSG_UNLOCK();
+ AVB_LOGF_DEBUG("AvdeccMsgStateListRemove %d succeeded", pState->avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+ }
+ }
+ AVDECC_MSG_UNLOCK();
+ AVB_LOGF_WARNING("AvdeccMsgStateListRemove %d not found", pState->avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+}
+
+avdecc_msg_state_t * AvdeccMsgStateListGet(int avdeccMsgHandle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (!avdeccMsgHandle) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ AVB_LOG_ERROR("AvdeccMsgStateListGet invalid param");
+ return NULL;
+ }
+
+ AVDECC_MSG_LOCK();
+ int i1;
+ for (i1 = 0; i1 < MAX_AVDECC_MSG_CLIENTS; i1++) {
+ if (gAvdeccMsgStateList[i1]) {
+ avdecc_msg_state_t *pState = (avdecc_msg_state_t *)gAvdeccMsgStateList[i1];
+ if (pState->avdeccMsgHandle == avdeccMsgHandle) {
+ AVDECC_MSG_UNLOCK();
+ AVB_LOGF_DEBUG("AvdeccMsgStateListGet found index %d, handle %d", i1, pState->avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return pState;
+ }
+ }
+ }
+ AVDECC_MSG_UNLOCK();
+ AVB_LOGF_DEBUG("AvdeccMsgStateListGet %d not found", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return NULL;
+}
+
+avdecc_msg_state_t * AvdeccMsgStateListGetIndex(int nIndex)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ AVDECC_MSG_LOCK();
+ int i1, found = 0;
+ for (i1 = 0; i1 < MAX_AVDECC_MSG_CLIENTS; i1++) {
+ if (gAvdeccMsgStateList[i1]) {
+ if (found++ == nIndex) {
+ avdecc_msg_state_t *pState = (avdecc_msg_state_t *)gAvdeccMsgStateList[i1];
+ AVDECC_MSG_UNLOCK();
+ AVB_LOGF_DEBUG("AvdeccMsgStateListGetIndex found index %d, handle %d for supplied index %d", i1, pState->avdeccMsgHandle, nIndex);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return pState;
+ }
+ }
+ }
+ AVDECC_MSG_UNLOCK();
+ AVB_LOGF_DEBUG("AvdeccMsgStateListGetIndex no match for index %d", nIndex);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return NULL;
+}
diff --git a/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg.h b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg.h
new file mode 100644
index 00000000..5efd90d2
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg.h
@@ -0,0 +1,216 @@
+/*************************************************************************************************************
+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 AVDECC message code.
+*/
+
+#ifndef OPENAVB_AVDECC_MSG_H
+#define OPENAVB_AVDECC_MSG_H
+
+#include "openavb_types.h"
+
+#define AVB_AVDECC_MSG_HANDLE_INVALID (-1)
+#define AVDECC_MSG_RECONNECT_SECONDS 10
+#define AVB_AVDECC_MSG_UNIX_PATH "/tmp/avdecc_msg"
+#define MAX_AVDECC_MSG_CLIENTS 16
+
+
+////////////////
+// AVDECC Msg state mutex
+////////////////
+extern MUTEX_HANDLE(gAvdeccMsgStateMutex);
+#define AVDECC_MSG_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(gAvdeccMsgStateMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define AVDECC_MSG_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(gAvdeccMsgStateMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+
+typedef enum OPENAVB_AVDECC_MSG_VER_STATE
+{
+ OPENAVB_AVDECC_MSG_VER_UNKNOWN = 0,
+ OPENAVB_AVDECC_MSG_VER_INVALID,
+ OPENAVB_AVDECC_MSG_VER_VALID,
+} openavbAvdeccMsgVerState_t;
+
+struct _avdecc_msg_state;
+typedef struct _avdecc_msg_state avdecc_msg_state_t;
+
+
+bool openavbAvdeccMsgInitialize(void);
+bool openavbAvdeccMsgCleanup();
+
+// Functions to save the list of AVDECC Msg clients
+bool AvdeccMsgStateListAdd(avdecc_msg_state_t * pState);
+bool AvdeccMsgStateListRemove(avdecc_msg_state_t * pState);
+avdecc_msg_state_t * AvdeccMsgStateListGet(int avdeccMsgHandle);
+avdecc_msg_state_t * AvdeccMsgStateListGetIndex(int nIndex);
+
+bool openavbAvdeccMsgClntService(int socketHandle, int timeout);
+void openavbAvdeccMsgSrvrService(void);
+
+
+typedef enum {
+ OPENAVB_AVDECC_MSG_UNKNOWN = 0,
+ OPENAVB_AVDECC_MSG_STOPPED,
+ OPENAVB_AVDECC_MSG_STOPPED_UNEXPECTEDLY,
+ OPENAVB_AVDECC_MSG_RUNNING,
+ OPENAVB_AVDECC_MSG_PAUSED,
+} openavbAvdeccMsgStateType_t;
+
+typedef enum {
+ // Client-to-Server messages
+ OPENAVB_AVDECC_MSG_VERSION_REQUEST,
+ OPENAVB_AVDECC_MSG_CLIENT_INIT_IDENTIFY,
+ OPENAVB_AVDECC_MSG_C2S_TALKER_STREAM_ID,
+ OPENAVB_AVDECC_MSG_CLIENT_CHANGE_NOTIFICATION,
+
+ // Server-to-Client messages
+ OPENAVB_AVDECC_MSG_VERSION_CALLBACK,
+ OPENAVB_AVDECC_MSG_LISTENER_STREAM_ID,
+ OPENAVB_AVDECC_MSG_S2C_TALKER_STREAM_ID,
+ OPENAVB_AVDECC_MSG_CLIENT_CHANGE_REQUEST,
+} openavbAvdeccMsgType_t;
+
+//////////////////////////////
+// Client-to-Server message parameters
+//////////////////////////////
+typedef struct {
+} openavbAvdeccMsgParams_VersionRequest_t;
+
+typedef struct {
+ char friendly_name[FRIENDLY_NAME_SIZE];
+ U8 talker;
+} openavbAvdeccMsgParams_ClientInitIdentify_t;
+
+typedef struct {
+ U8 sr_class; // SR_CLASS_A or SR_CLASS_B
+ U8 stream_src_mac[6]; // MAC Address for the Talker
+ U16 stream_uid; // Stream ID value
+ U8 stream_dest_mac[6]; // Multicast address for the stream
+ U16 stream_vlan_id; // VLAN ID of the stream
+} openavbAvdeccMsgParams_C2S_TalkerStreamID_t;
+
+typedef struct {
+ U8 current_state; // Convert to openavbAvdeccMsgStateType_t
+} openavbAvdeccMsgParams_ClientChangeNotification_t;
+
+//////////////////////////////
+// Server-to-Client messages parameters
+//////////////////////////////
+typedef struct {
+ U32 AVBVersion;
+} openavbAvdeccMsgParams_VersionCallback_t;
+
+typedef struct {
+ U8 sr_class; // SR_CLASS_A or SR_CLASS_B
+ U8 stream_src_mac[6]; // MAC Address for the Talker
+ U16 stream_uid; // Stream ID value
+ U8 stream_dest_mac[6]; // Multicast address for the stream
+ U16 stream_vlan_id; // VLAN ID of the stream
+} openavbAvdeccMsgParams_ListenerStreamID_t;
+
+typedef struct {
+ U8 sr_class; // SR_CLASS_A or SR_CLASS_B
+ U8 stream_id_valid; // The stream_src_mac and stream_uid values were supplied
+ U8 stream_src_mac[6]; // MAC Address for the Talker
+ U16 stream_uid; // Stream ID value
+ U8 stream_dest_valid; // The stream_dest_mac value was supplied
+ U8 stream_dest_mac[6]; // Multicast address for the stream
+ U8 stream_vlan_id_valid; // The stream_vlan_id value was supplied
+ U16 stream_vlan_id; // VLAN ID of the stream
+} openavbAvdeccMsgParams_S2C_TalkerStreamID_t;
+
+typedef struct {
+ U8 desired_state; // Convert to openavbAvdeccMsgStateType_t
+} openavbAvdeccMsgParams_ClientChangeRequest_t;
+
+#define OPENAVB_AVDECC_MSG_LEN sizeof(openavbAvdeccMessage_t)
+
+bool openavbAvdeccMsgServerOpen(void);
+void openavbAvdeccMsgServerClose(void);
+
+#include "openavb_avdecc_msg_osal.h"
+
+
+/************************** AVDECC Msg Client-Server *************************/
+// There is a single AVDECC server for the entire talker/listener device
+// There is an AVDECC client for each stream.
+
+// AVDECC client open a connection to AVDECC server.
+// (Note that the server never opens a connection to the client.)
+int openavbAvdeccMsgClntOpenSrvrConnection(void);
+// AVDECC client close its connection to the server.
+void openavbAvdeccMsgClntCloseSrvrConnection(int h);
+// AVDECC server close its connection to the client.
+void openavbAvdeccMsgSrvrCloseClientConnection(int h);
+
+// Immediately after establishing connection with the AVDECC Msg server,
+// the AVDECC Msg client checks that the server's version is the same as its own.
+// The client sends a request to the client for its version.
+// The server handles the request and sends its version to the requesting client.
+// The client compares the received version to its own.
+bool openavbAvdeccMsgClntRequestVersionFromServer(int h);
+bool openavbAvdeccMsgSrvrHndlVerRqstFromClient(int h);
+void openavbAvdeccMsgSrvrSendServerVersionToClient(int h, U32 AVBVersion);
+void openavbAvdeccMsgClntCheckVerMatchesSrvr(int h, U32 AVBVersion);
+
+// Client notify the server of identity (so AVDECC Msg knows client identity)
+bool openavbAvdeccMsgClntInitIdentify(int avdeccMsgHandle, const char * friendly_name, U8 talker);
+bool openavbAvdeccMsgSrvrHndlInitIdentifyFromClient(int avdeccMsgHandle, char * friendly_name, U8 talker);
+
+// Client notify the server of the stream values the Talker will be using.
+bool openavbAvdeccMsgClntTalkerStreamID(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id);
+bool openavbAvdeccMsgSrvrHndlTalkerStreamIDFromClient(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id);
+
+// Server notify the client of the stream values for the Listener to use.
+bool openavbAvdeccMsgSrvrListenerStreamID(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id);
+bool openavbAvdeccMsgClntHndlListenerStreamIDFromServer(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id);
+
+// Server notify the client of the stream values for the Talker to use (supplied by the AVDECC controller).
+bool openavbAvdeccMsgSrvrTalkerStreamID(
+ int avdeccMsgHandle,
+ 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);
+bool openavbAvdeccMsgClntHndlTalkerStreamIDFromServer(
+ int avdeccMsgHandle,
+ 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);
+
+// Server state change requests, and client notifications of state changes.
+bool openavbAvdeccMsgSrvrChangeRequest(int avdeccMsgHandle, openavbAvdeccMsgStateType_t desiredState);
+bool openavbAvdeccMsgClntHndlChangeRequestFromServer(int avdeccMsgHandle, openavbAvdeccMsgStateType_t desiredState);
+bool openavbAvdeccMsgClntChangeNotification(int avdeccMsgHandle, openavbAvdeccMsgStateType_t currentState);
+bool openavbAvdeccMsgSrvrHndlChangeNotificationFromClient(int avdeccMsgHandle, openavbAvdeccMsgStateType_t currentState);
+
+#endif // OPENAVB_AVDECC_MSG_H
diff --git a/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_client.c b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_client.c
new file mode 100644
index 00000000..01c827f3
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_client.c
@@ -0,0 +1,723 @@
+/*************************************************************************************************************
+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 :
+*
+* Stream clients (talkers or listeners) must connect to the central
+* "avdecc_msg" process to support AVDECC control.
+* This code provides the means for them to do so.
+*
+* It provides proxy functions for the process to call. The arguments
+* for those calls are packed into messages, which are unpacked in the
+* avdecc_msg process and then used to call the real functions.
+*
+* Current IPC uses unix sockets. Can change this by creating a new
+* implementations in openavb_avdecc_msg_client.c and openavb_avdecc_msg_server.c
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "openavb_platform.h"
+
+#define AVB_LOG_COMPONENT "AVDECC Msg"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+#include "openavb_trace.h"
+#include "openavb_avdecc_msg_client.h"
+#include "openavb_tl.h"
+#include "openavb_talker.h"
+#include "openavb_listener.h"
+
+// forward declarations
+static bool openavbAvdeccMsgClntReceiveFromServer(int avdeccMsgHandle, openavbAvdeccMessage_t *msg);
+
+// OSAL specific functions
+#include "openavb_avdecc_msg_client_osal.c"
+
+// AvdeccMsgStateListGet() support.
+#include "openavb_avdecc_msg.c"
+
+static bool openavbAvdeccMsgClntReceiveFromServer(int avdeccMsgHandle, openavbAvdeccMessage_t *msg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (!msg || avdeccMsgHandle == AVB_AVDECC_MSG_HANDLE_INVALID) {
+ AVB_LOG_ERROR("Client receive; invalid argument passed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ switch(msg->type) {
+ case OPENAVB_AVDECC_MSG_VERSION_CALLBACK:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_VERSION_CALLBACK");
+ openavbAvdeccMsgClntCheckVerMatchesSrvr(avdeccMsgHandle, ntohl(msg->params.versionCallback.AVBVersion));
+ break;
+ case OPENAVB_AVDECC_MSG_LISTENER_STREAM_ID:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_LISTENER_STREAM_ID");
+ openavbAvdeccMsgClntHndlListenerStreamIDFromServer(avdeccMsgHandle,
+ msg->params.listenerStreamID.sr_class, msg->params.listenerStreamID.stream_src_mac, ntohs(msg->params.listenerStreamID.stream_uid),
+ msg->params.listenerStreamID.stream_dest_mac, ntohs(msg->params.listenerStreamID.stream_vlan_id));
+ break;
+ case OPENAVB_AVDECC_MSG_S2C_TALKER_STREAM_ID:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_S2C_TALKER_STREAM_ID");
+ openavbAvdeccMsgClntHndlTalkerStreamIDFromServer(avdeccMsgHandle,
+ msg->params.s2cTalkerStreamID.sr_class,
+ msg->params.s2cTalkerStreamID.stream_id_valid,
+ msg->params.s2cTalkerStreamID.stream_src_mac,
+ ntohs(msg->params.s2cTalkerStreamID.stream_uid),
+ msg->params.s2cTalkerStreamID.stream_dest_valid,
+ msg->params.s2cTalkerStreamID.stream_dest_mac,
+ msg->params.s2cTalkerStreamID.stream_vlan_id_valid,
+ ntohs(msg->params.s2cTalkerStreamID.stream_vlan_id));
+ break;
+ case OPENAVB_AVDECC_MSG_CLIENT_CHANGE_REQUEST:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_CLIENT_CHANGE_REQUEST");
+ openavbAvdeccMsgClntHndlChangeRequestFromServer(avdeccMsgHandle, (openavbAvdeccMsgStateType_t) msg->params.clientChangeRequest.desired_state);
+ break;
+ default:
+ AVB_LOG_ERROR("Client receive: unexpected message");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+}
+
+bool openavbAvdeccMsgClntRequestVersionFromServer(int avdeccMsgHandle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavbAvdeccMessage_t msgBuf;
+
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_VERSION_REQUEST;
+ bool ret = openavbAvdeccMsgClntSendToServer(avdeccMsgHandle, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+void openavbAvdeccMsgClntCheckVerMatchesSrvr(int avdeccMsgHandle, U32 AVBVersion)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ if (AVBVersion == AVB_CORE_VER_FULL) {
+ pState->verState = OPENAVB_AVDECC_MSG_VER_VALID;
+ AVB_LOG_DEBUG("AVDECC Versions Match");
+ }
+ else {
+ pState->verState = OPENAVB_AVDECC_MSG_VER_INVALID;
+ AVB_LOG_WARNING("AVDECC Versions Do Not Match");
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+bool openavbAvdeccMsgClntInitIdentify(int avdeccMsgHandle, const char * friendly_name, U8 talker)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavbAvdeccMessage_t msgBuf;
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_CLIENT_INIT_IDENTIFY;
+ openavbAvdeccMsgParams_ClientInitIdentify_t * pParams =
+ &(msgBuf.params.clientInitIdentify);
+ strncpy(pParams->friendly_name, friendly_name, sizeof(pParams->friendly_name));
+ pParams->talker = talker;
+ bool ret = openavbAvdeccMsgClntSendToServer(avdeccMsgHandle, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+bool openavbAvdeccMsgClntTalkerStreamID(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavbAvdeccMessage_t msgBuf;
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Send a default stream_vlan_id value if none specified.
+ if (stream_vlan_id == 0) {
+ stream_vlan_id = 2; // SR Class default VLAN Id values per IEEE 802.1Q-2011 Table 9-2
+ }
+
+ // Send the stream information to the server.
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_C2S_TALKER_STREAM_ID;
+ openavbAvdeccMsgParams_C2S_TalkerStreamID_t * pParams =
+ &(msgBuf.params.c2sTalkerStreamID);
+ pParams->sr_class = sr_class;
+ memcpy(pParams->stream_src_mac, stream_src_mac, 6);
+ pParams->stream_uid = htons(stream_uid);
+ memcpy(pParams->stream_dest_mac, stream_dest_mac, 6);
+ pParams->stream_vlan_id = htons(stream_vlan_id);
+ bool ret = openavbAvdeccMsgClntSendToServer(avdeccMsgHandle, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+bool openavbAvdeccMsgClntHndlListenerStreamIDFromServer(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ if (!pState->pTLState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d state not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Determine if the supplied information differs from the current settings.
+ openavb_tl_cfg_t * pCfg = &(pState->pTLState->cfg);
+ if (pCfg->sr_class != sr_class ||
+ memcmp(pCfg->stream_addr.buffer.ether_addr_octet, stream_src_mac, 6) != 0 ||
+ pCfg->stream_uid != stream_uid ||
+ memcmp(pCfg->dest_addr.buffer.ether_addr_octet, stream_dest_mac, 6) != 0 ||
+ pCfg->vlan_id != stream_vlan_id) {
+ // If the Listener is running, stop the Listener before updating the information.
+ if (pState->pTLState->bRunning) {
+ AVB_LOG_DEBUG("Forcing Listener to Stop to change streaming settings");
+ openavbAvdeccMsgClntHndlChangeRequestFromServer(avdeccMsgHandle, OPENAVB_AVDECC_MSG_STOPPED);
+ }
+
+ // Update the stream information supplied by the server.
+ pCfg->sr_class = sr_class;
+ memcpy(pCfg->stream_addr.buffer.ether_addr_octet, stream_src_mac, 6);
+ pCfg->stream_addr.mac = &(pCfg->stream_addr.buffer); // Indicate that the MAC Address is valid.
+ pCfg->stream_uid = stream_uid;
+ memcpy(pCfg->dest_addr.buffer.ether_addr_octet, stream_dest_mac, 6);
+ pCfg->dest_addr.mac = &(pCfg->dest_addr.buffer); // Indicate that the MAC Address is valid.
+ pCfg->vlan_id = stream_vlan_id;
+ }
+
+ AVB_LOGF_DEBUG("AVDECC-supplied (Listener) sr_class: %u", pCfg->sr_class);
+ AVB_LOGF_DEBUG("AVDECC-supplied (Listener) stream_id: " ETH_FORMAT "/%u",
+ ETH_OCTETS(pCfg->stream_addr.buffer.ether_addr_octet), pCfg->stream_uid);
+ AVB_LOGF_DEBUG("AVDECC-supplied (Listener) dest_addr: " ETH_FORMAT,
+ ETH_OCTETS(pCfg->dest_addr.buffer.ether_addr_octet));
+ AVB_LOGF_DEBUG("AVDECC-supplied (Listener) vlan_id: %u", pCfg->vlan_id);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return true;
+}
+
+bool openavbAvdeccMsgClntHndlTalkerStreamIDFromServer(int avdeccMsgHandle,
+ 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_MSG);
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ if (!pState->pTLState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d state not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Update the stream information supplied by the server.
+ openavb_tl_cfg_t * pCfg = &(pState->pTLState->cfg);
+ pCfg->sr_class = sr_class;
+ AVB_LOGF_DEBUG("AVDECC-supplied (Talker) sr_class: %u", pCfg->sr_class);
+ if (stream_id_valid) {
+ if (memcmp(stream_src_mac, "\x00\x00\x00\x00\x00\x00", 6) == 0 && stream_uid == 0) {
+ // Restore from the backup value.
+ if (pCfg->backup_stream_id_valid) {
+ memcpy(pCfg->stream_addr.buffer.ether_addr_octet, pCfg->backup_stream_addr, 6);
+ pCfg->stream_addr.mac = &(pCfg->stream_addr.buffer); // Indicate that the MAC Address is valid.
+ pCfg->stream_uid = pCfg->backup_stream_uid;
+ pCfg->backup_stream_id_valid = FALSE;
+ AVB_LOGF_DEBUG("AVDECC-supplied (Talker) reverted to default stream_id: " ETH_FORMAT "/%u",
+ ETH_OCTETS(pCfg->stream_addr.buffer.ether_addr_octet), pCfg->stream_uid);
+ }
+ }
+ else {
+ // Backup the current value.
+ if (!pCfg->backup_stream_id_valid) {
+ memcpy(pCfg->backup_stream_addr, pCfg->stream_addr.buffer.ether_addr_octet, 6);
+ pCfg->backup_stream_uid = pCfg->stream_uid;
+ pCfg->backup_stream_id_valid = TRUE;
+ }
+
+ // Save the new value.
+ memcpy(pCfg->stream_addr.buffer.ether_addr_octet, stream_src_mac, 6);
+ pCfg->stream_addr.mac = &(pCfg->stream_addr.buffer); // Indicate that the MAC Address is valid.
+ pCfg->stream_uid = stream_uid;
+ AVB_LOGF_DEBUG("AVDECC-supplied (Talker) stream_id: " ETH_FORMAT "/%u",
+ ETH_OCTETS(pCfg->stream_addr.buffer.ether_addr_octet), pCfg->stream_uid);
+ }
+ }
+ if (stream_dest_valid) {
+ if (memcmp(stream_dest_mac, "\x00\x00\x00\x00\x00\x00", 6) == 0) {
+ // Restore from the backup value.
+ if (pCfg->backup_dest_addr_valid) {
+ memcpy(pCfg->dest_addr.buffer.ether_addr_octet, pCfg->backup_dest_addr, 6);
+ pCfg->dest_addr.mac = &(pCfg->dest_addr.buffer); // Indicate that the MAC Address is valid.
+ pCfg->backup_dest_addr_valid = FALSE;
+ AVB_LOGF_DEBUG("AVDECC-supplied (Talker) reverted to default dest_addr: " ETH_FORMAT,
+ ETH_OCTETS(pCfg->dest_addr.buffer.ether_addr_octet));
+ }
+ }
+ else {
+ // Backup the current value.
+ if (!pCfg->backup_dest_addr_valid) {
+ memcpy(pCfg->backup_dest_addr, pCfg->dest_addr.buffer.ether_addr_octet, 6);
+ pCfg->backup_dest_addr_valid = TRUE;
+ }
+
+ // Save the new value.
+ memcpy(pCfg->dest_addr.buffer.ether_addr_octet, stream_dest_mac, 6);
+ pCfg->dest_addr.mac = &(pCfg->dest_addr.buffer); // Indicate that the MAC Address is valid.
+ AVB_LOGF_DEBUG("AVDECC-supplied (Talker) dest_addr: " ETH_FORMAT,
+ ETH_OCTETS(pCfg->dest_addr.buffer.ether_addr_octet));
+ }
+ }
+ if (stream_vlan_id_valid) {
+ if (stream_vlan_id == 0) {
+ // Restore from the backup value.
+ if (pCfg->backup_vlan_id_valid) {
+ pCfg->vlan_id = pCfg->backup_vlan_id;
+ pCfg->backup_vlan_id_valid = FALSE;
+ AVB_LOGF_DEBUG("AVDECC-supplied (Talker) reverted to default vlan_id: %u", pCfg->vlan_id);
+ }
+ }
+ else {
+ // Backup the current value.
+ if (!pCfg->backup_vlan_id_valid) {
+ pCfg->backup_vlan_id_valid = pCfg->vlan_id;
+ pCfg->backup_vlan_id_valid = TRUE;
+ }
+
+ // Save the new value.
+ pCfg->vlan_id = stream_vlan_id;
+ AVB_LOGF_DEBUG("AVDECC-supplied (Talker) vlan_id: %u", pCfg->vlan_id);
+ }
+ }
+
+ // Notify AVDECC of the Talker values to be used after the update.
+ openavbAvdeccMsgClntTalkerStreamID(avdeccMsgHandle, pCfg->sr_class, pCfg->stream_addr.buffer.ether_addr_octet, pCfg->stream_uid, pCfg->dest_addr.buffer.ether_addr_octet, pCfg->vlan_id);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return true;
+}
+
+bool openavbAvdeccMsgClntHndlChangeRequestFromServer(int avdeccMsgHandle, openavbAvdeccMsgStateType_t desiredState)
+{
+ bool ret = false;
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState || !pState->pTLState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ switch (desiredState) {
+ case OPENAVB_AVDECC_MSG_STOPPED:
+ // Stop requested.
+ AVB_LOGF_DEBUG("Stop state requested for client %d", avdeccMsgHandle);
+ if (pState->pTLState->bRunning) {
+ if (openavbTLStop((tl_handle_t) pState->pTLState)) {
+ // NOTE: openavbTLStop() call will cause client change notification if successful.
+ AVB_LOGF_INFO("Client %d state changed to Stopped", avdeccMsgHandle);
+ ret = true;
+ } else {
+ // Notify server of issues.
+ AVB_LOGF_ERROR("Unable to change client %d state to Stopped", avdeccMsgHandle);
+ openavbAvdeccMsgClntChangeNotification(avdeccMsgHandle, OPENAVB_AVDECC_MSG_UNKNOWN);
+ }
+ } else {
+ // Notify server we are already in this state.
+ AVB_LOGF_INFO("Client %d state is already at Stopped", avdeccMsgHandle);
+ openavbAvdeccMsgClntChangeNotification(avdeccMsgHandle, OPENAVB_AVDECC_MSG_STOPPED);
+ ret = true;
+ }
+ break;
+
+ case OPENAVB_AVDECC_MSG_RUNNING:
+ // Run requested.
+ AVB_LOGF_DEBUG("Run state requested for client %d", avdeccMsgHandle);
+ if (!(pState->pTLState->bRunning)) {
+ if (openavbTLRun((tl_handle_t) pState->pTLState)) {
+ // NOTE: openavbTLRun() call will cause client change notification if successful.
+ AVB_LOGF_INFO("Client %d state changed to Running", avdeccMsgHandle);
+ ret = true;
+ } else {
+ // Notify server of issues.
+ AVB_LOGF_ERROR("Unable to change client %d state to Running", avdeccMsgHandle);
+ openavbAvdeccMsgClntChangeNotification(avdeccMsgHandle, OPENAVB_AVDECC_MSG_UNKNOWN);
+ }
+ }
+ else if (pState->pTLState->bRunning && pState->pTLState->bPaused) {
+ if (pState->pTLState->cfg.role == AVB_ROLE_TALKER) {
+ openavbTLPauseTalker(pState->pTLState, FALSE);
+ // NOTE: openavbTLPauseTalker() call will cause Talker change notification.
+ AVB_LOGF_INFO("Talker %d state changed from Paused to Running", avdeccMsgHandle);
+ ret = true;
+ } else {
+ openavbTLPauseListener(pState->pTLState, FALSE);
+ // NOTE: openavbTLPauseListener() call will cause Listener change notification.
+ AVB_LOGF_INFO("Listener %d state changed from Paused to Running", avdeccMsgHandle);
+ ret = true;
+ }
+ }
+ else {
+ // Notify server we are already in this state.
+ AVB_LOGF_INFO("Client %d state is already at Running", avdeccMsgHandle);
+ openavbAvdeccMsgClntChangeNotification(avdeccMsgHandle, OPENAVB_AVDECC_MSG_RUNNING);
+ ret = true;
+ }
+ break;
+
+ case OPENAVB_AVDECC_MSG_PAUSED:
+ // Running with Pause requested.
+ AVB_LOGF_DEBUG("Paused state requested for client %d", avdeccMsgHandle);
+ if (!(pState->pTLState->bRunning)) {
+ // Notify server of issues.
+ AVB_LOGF_ERROR("Client %d attempted to pause the stream while not Running.", avdeccMsgHandle);
+ openavbAvdeccMsgClntChangeNotification(avdeccMsgHandle, OPENAVB_AVDECC_MSG_UNKNOWN);
+ }
+ else if (pState->pTLState->bRunning && !(pState->pTLState->bPaused)) {
+ if (pState->pTLState->cfg.role == AVB_ROLE_TALKER) {
+ openavbTLPauseTalker(pState->pTLState, TRUE);
+ // NOTE: openavbTLPauseTalker() call will cause Talker change notification.
+ AVB_LOGF_INFO("Talker %d state changed from Running to Paused", avdeccMsgHandle);
+ ret = true;
+ } else {
+ openavbTLPauseListener(pState->pTLState, TRUE);
+ // NOTE: openavbTLPauseListener() call will cause Listener change notification.
+ AVB_LOGF_INFO("Listener %d state changed from Running to Paused", avdeccMsgHandle);
+ ret = true;
+ }
+ }
+ else {
+ // Notify server we are already in this state.
+ AVB_LOGF_INFO("Client %d state is already at Paused", avdeccMsgHandle);
+ openavbAvdeccMsgClntChangeNotification(avdeccMsgHandle, OPENAVB_AVDECC_MSG_PAUSED);
+ ret = true;
+ }
+ break;
+
+ default:
+ AVB_LOGF_ERROR("openavbAvdeccMsgClntHndlChangeRequestFromServer invalid state %d", desiredState);
+ break;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+bool openavbAvdeccMsgClntChangeNotification(int avdeccMsgHandle, openavbAvdeccMsgStateType_t currentState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavbAvdeccMessage_t msgBuf;
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_CLIENT_CHANGE_NOTIFICATION;
+ openavbAvdeccMsgParams_ClientChangeNotification_t * pParams =
+ &(msgBuf.params.clientChangeNotification);
+ pParams->current_state = (U8) currentState;
+ bool ret = openavbAvdeccMsgClntSendToServer(avdeccMsgHandle, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+
+// Called from openavbAvdeccMsgThreadFn() which is started from openavbTLRun()
+void openavbAvdeccMsgRunTalker(avdecc_msg_state_t *pState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (!pState) {
+ AVB_LOG_ERROR("Invalid AVDECC Msg State");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ openavb_tl_cfg_t * cfg = &(pState->pTLState->cfg);
+ if (cfg->role != AVB_ROLE_TALKER) {
+ AVB_LOG_ERROR("openavbAvdeccMsgRunTalker() passed a non-Talker state");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ if (!pState->bConnected) {
+ AVB_LOG_WARNING("Failed to connect to AVDECC Msg");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ // Let the AVDECC Msg server know our identity.
+ if (!openavbAvdeccMsgClntInitIdentify(pState->avdeccMsgHandle, cfg->friendly_name, true)) {
+ AVB_LOG_ERROR("openavbAvdeccMsgClntInitIdentify() failed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ // Let the AVDECC Msg server know our stream ID.
+ if (!openavbAvdeccMsgClntTalkerStreamID(pState->avdeccMsgHandle,
+ cfg->sr_class, cfg->stream_addr.buffer.ether_addr_octet, cfg->stream_uid,
+ cfg->dest_addr.buffer.ether_addr_octet, cfg->vlan_id)) {
+ AVB_LOG_ERROR("openavbAvdeccMsgClntTalkerStreamID() failed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ // Let the AVDECC Msg server know our current state.
+ if (!openavbAvdeccMsgClntChangeNotification(pState->avdeccMsgHandle,
+ (pState->pTLState->bRunning ?
+ (pState->pTLState->bPaused ? OPENAVB_AVDECC_MSG_PAUSED : OPENAVB_AVDECC_MSG_RUNNING ) :
+ OPENAVB_AVDECC_MSG_STOPPED))) {
+ AVB_LOG_ERROR("Initial openavbAvdeccMsgClntChangeNotification() failed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ // Do until we are stopped or lose connection to AVDECC Msg server.
+ while (pState->pTLState->bAvdeccMsgRunning && pState->bConnected) {
+
+ // Look for messages from AVDECC Msg.
+ if (!openavbAvdeccMsgClntService(pState->avdeccMsgHandle, 1000)) {
+ AVB_LOG_WARNING("Lost connection to AVDECC Msg");
+ pState->bConnected = FALSE;
+ pState->avdeccMsgHandle = AVB_AVDECC_MSG_HANDLE_INVALID;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+// Called from openavbAvdeccMsgThreadFn() which is started from openavbTLRun()
+void openavbAvdeccMsgRunListener(avdecc_msg_state_t *pState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (!pState && !pState->pTLState) {
+ AVB_LOG_ERROR("Invalid AVDECC Msg State");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ openavb_tl_cfg_t * cfg = &(pState->pTLState->cfg);
+ if (cfg->role != AVB_ROLE_LISTENER) {
+ AVB_LOG_ERROR("openavbAvdeccMsgRunListener() passed a non-Listener state");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ if (!pState->bConnected) {
+ AVB_LOG_WARNING("Failed to connect to AVDECC Msg");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ // Let the AVDECC Msg server know our identity.
+ if (!openavbAvdeccMsgClntInitIdentify(pState->avdeccMsgHandle, cfg->friendly_name, false)) {
+ AVB_LOG_ERROR("openavbAvdeccMsgClntInitIdentify() failed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ // Let the AVDECC Msg server know our current state.
+ if (!openavbAvdeccMsgClntChangeNotification(pState->avdeccMsgHandle,
+ (pState->pTLState->bRunning ?
+ (pState->pTLState->bPaused ? OPENAVB_AVDECC_MSG_PAUSED : OPENAVB_AVDECC_MSG_RUNNING ) :
+ OPENAVB_AVDECC_MSG_STOPPED))) {
+ AVB_LOG_ERROR("Initial openavbAvdeccMsgClntChangeNotification() failed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ // Do until we are stopped or lose connection to AVDECC Msg.
+ while (pState->pTLState->bAvdeccMsgRunning && pState->bConnected) {
+
+ // Look for messages from AVDECC Msg.
+ if (!openavbAvdeccMsgClntService(pState->avdeccMsgHandle, 1000)) {
+ AVB_LOG_WARNING("Lost connection to AVDECC Msg");
+ pState->bConnected = FALSE;
+ pState->avdeccMsgHandle = AVB_AVDECC_MSG_HANDLE_INVALID;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+// AVDECC Msg thread function
+void* openavbAvdeccMsgThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ avdecc_msg_state_t avdeccMsgState;
+
+ // Perform the base initialization.
+ openavbAvdeccMsgInitialize();
+
+ // Initialize our local state structure.
+ memset(&avdeccMsgState, 0, sizeof(avdeccMsgState));
+ avdeccMsgState.pTLState = (tl_state_t *)pv;
+
+ avdeccMsgState.avdeccMsgHandle =
+ avdeccMsgState.pTLState->avdeccMsgHandle = AVB_AVDECC_MSG_HANDLE_INVALID;
+ while (avdeccMsgState.pTLState->bAvdeccMsgRunning) {
+ AVB_TRACE_LINE(AVB_TRACE_AVDECC_MSG_DETAIL);
+
+ if (avdeccMsgState.avdeccMsgHandle == AVB_AVDECC_MSG_HANDLE_INVALID) {
+ avdeccMsgState.avdeccMsgHandle = openavbAvdeccMsgClntOpenSrvrConnection();
+ if (avdeccMsgState.avdeccMsgHandle == AVB_AVDECC_MSG_HANDLE_INVALID) {
+ // error connecting to AVDECC Msg, already logged
+ SLEEP(1);
+ continue;
+ }
+ avdeccMsgState.pTLState->avdeccMsgHandle = avdeccMsgState.avdeccMsgHandle;
+ }
+ AvdeccMsgStateListAdd(&avdeccMsgState);
+
+ // Validate the AVB version for client and server are the same before continuing
+ avdeccMsgState.verState = OPENAVB_AVDECC_MSG_VER_UNKNOWN;
+ avdeccMsgState.bConnected = openavbAvdeccMsgClntRequestVersionFromServer(avdeccMsgState.avdeccMsgHandle);
+ if (avdeccMsgState.pTLState->bAvdeccMsgRunning && avdeccMsgState.bConnected && avdeccMsgState.verState == OPENAVB_AVDECC_MSG_VER_UNKNOWN) {
+ // Check for AVDECC Msg version message. Timeout in 500 msec.
+ if (!openavbAvdeccMsgClntService(avdeccMsgState.avdeccMsgHandle, 500)) {
+ AVB_LOG_WARNING("Lost connection to AVDECC Msg, will retry");
+ avdeccMsgState.bConnected = FALSE;
+ avdeccMsgState.avdeccMsgHandle =
+ avdeccMsgState.pTLState->avdeccMsgHandle = AVB_AVDECC_MSG_HANDLE_INVALID;
+ }
+ }
+ if (avdeccMsgState.verState == OPENAVB_AVDECC_MSG_VER_UNKNOWN) {
+ AVB_LOG_ERROR("AVB core version not reported by AVDECC Msg server. Will reconnect to AVDECC Msg and check again.");
+ } else if (avdeccMsgState.verState == OPENAVB_AVDECC_MSG_VER_INVALID) {
+ AVB_LOG_ERROR("AVB core version is different than AVDECC Msg AVB core version. Will reconnect to AVDECC Msg and check again.");
+ } else {
+ AVB_LOG_DEBUG("AVB core version matches AVDECC Msg AVB core version.");
+ }
+
+ if (avdeccMsgState.bConnected && avdeccMsgState.verState == OPENAVB_AVDECC_MSG_VER_VALID) {
+ if (avdeccMsgState.pTLState->cfg.role == AVB_ROLE_TALKER) {
+ openavbAvdeccMsgRunTalker(&avdeccMsgState);
+ }
+ else {
+ openavbAvdeccMsgRunListener(&avdeccMsgState);
+ }
+ }
+
+ // Close the AVDECC Msg connection.
+ AvdeccMsgStateListRemove(&avdeccMsgState);
+ openavbAvdeccMsgClntCloseSrvrConnection(avdeccMsgState.avdeccMsgHandle);
+ avdeccMsgState.bConnected = FALSE;
+ avdeccMsgState.avdeccMsgHandle =
+ avdeccMsgState.pTLState->avdeccMsgHandle = AVB_AVDECC_MSG_HANDLE_INVALID;
+
+ if (avdeccMsgState.pTLState->bAvdeccMsgRunning && avdeccMsgState.verState == OPENAVB_AVDECC_MSG_VER_VALID) {
+ SLEEP(1);
+ }
+ }
+
+ avdeccMsgState.pTLState = NULL;
+
+ // Perform the base cleanup.
+ openavbAvdeccMsgCleanup();
+
+ THREAD_JOINABLE(avdeccMsgState.pTLState->avdeccMsgThread);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return NULL;
+}
+
+
+// Client-side helper function.
+bool openavbAvdeccMsgClntNotifyCurrentState(tl_state_t *pTLState)
+{
+ if (!pTLState) { return FALSE; }
+ if (!(pTLState->bAvdeccMsgRunning)) { return FALSE; }
+
+ // Find the AVDECC Msg for the supplied tl_state_t pointer.
+ int i;
+ for (i = 0; i < MAX_AVDECC_MSG_CLIENTS; ++i) {
+ avdecc_msg_state_t * pAvdeccMsgState = AvdeccMsgStateListGetIndex(i);
+ if (!pAvdeccMsgState) {
+ // Out of items.
+ break;
+ }
+ if (pAvdeccMsgState->pTLState == pTLState) {
+ // Notify the server regarding the current state.
+ if (pTLState->bRunning) {
+ openavbAvdeccMsgClntChangeNotification(pAvdeccMsgState->avdeccMsgHandle, (pTLState->bPaused ? OPENAVB_AVDECC_MSG_PAUSED : OPENAVB_AVDECC_MSG_RUNNING));
+ } else {
+ openavbAvdeccMsgClntChangeNotification(pAvdeccMsgState->avdeccMsgHandle, OPENAVB_AVDECC_MSG_STOPPED);
+ }
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
diff --git a/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_client.h b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_client.h
new file mode 100644
index 00000000..9fea390e
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_client.h
@@ -0,0 +1,60 @@
+/*************************************************************************************************************
+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_H
+#define OPENAVB_AVDECC_MSG_CLIENT_H
+
+#include "openavb_types.h"
+#include "openavb_tl.h"
+#include "openavb_avdecc_msg.h"
+
+
+struct _avdecc_msg_state {
+
+ // Connected to AVDECC Msg flag. (assumed atomic)
+ bool bConnected;
+
+ // The status of the version check to make sure AVDECC Msg and TL are running the same version.
+ openavbAvdeccMsgVerState_t verState;
+
+ // Pointer to the talker/listener state linked to the AVDECC Msg instance.
+ tl_state_t *pTLState;
+
+ // Handle to the AVDECC Msg handle for the connection to the server.
+ int avdeccMsgHandle;
+
+};
+
+
+// Client-side helper function.
+bool openavbAvdeccMsgClntNotifyCurrentState(tl_state_t *pTLState);
+
+#endif // OPENAVB_AVDECC_MSG_CLIENT_H
diff --git a/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.c b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.c
new file mode 100644
index 00000000..326b64b7
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.c
@@ -0,0 +1,470 @@
+/*************************************************************************************************************
+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 :
+ *
+ * Stream clients (talkers or listeners) must connect to the central
+ * "avdecc_msg" process to create a reservation for their traffic.
+ *
+ * This code implements the server side of the IPC.
+ *
+ * It provides proxy functions for the avdecc_msg to call. The arguments
+ * for those calls are packed into messages, which are unpacked in the
+ * process and then used to call the real functions.
+ *
+ * Current IPC uses unix sockets. Can change this by creating a new
+ * implementations in openavb_avdecc_msg_client.c and openavb_avdecc_msg_server.c
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
+#define AVB_LOG_COMPONENT "AVDECC Msg"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+#include "openavb_avdecc_pub.h"
+#include "openavb_adp.h"
+#include "openavb_acmp_sm_talker.h"
+#include "openavb_acmp_sm_listener.h"
+
+#include "openavb_avdecc_msg_server.h"
+#include "openavb_trace.h"
+
+// forward declarations
+static bool openavbAvdeccMsgSrvrReceiveFromClient(int avdeccMsgHandle, openavbAvdeccMessage_t *msg);
+
+// OSAL specific functions
+#include "openavb_avdecc_msg_server_osal.c"
+
+// AvdeccMsgStateListGet() support.
+#include "openavb_avdecc_msg.c"
+
+// the following are from openavb_avdecc.c
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+extern openavb_tl_data_cfg_t * streamList;
+
+
+static bool openavbAvdeccMsgSrvrReceiveFromClient(int avdeccMsgHandle, openavbAvdeccMessage_t *msg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (!msg) {
+ AVB_LOG_ERROR("Receiving message; invalid argument passed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ bool ret = FALSE;
+ switch (msg->type) {
+ case OPENAVB_AVDECC_MSG_VERSION_REQUEST:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_VERSION_REQUEST");
+ ret = openavbAvdeccMsgSrvrHndlVerRqstFromClient(avdeccMsgHandle);
+ break;
+ case OPENAVB_AVDECC_MSG_CLIENT_INIT_IDENTIFY:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_CLIENT_INIT_IDENTIFY");
+ ret = openavbAvdeccMsgSrvrHndlInitIdentifyFromClient(avdeccMsgHandle,
+ msg->params.clientInitIdentify.friendly_name,
+ msg->params.clientInitIdentify.talker);
+ break;
+ case OPENAVB_AVDECC_MSG_C2S_TALKER_STREAM_ID:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_C2S_TALKER_STREAM_ID");
+ ret = openavbAvdeccMsgSrvrHndlTalkerStreamIDFromClient(avdeccMsgHandle,
+ msg->params.c2sTalkerStreamID.sr_class,
+ msg->params.c2sTalkerStreamID.stream_src_mac,
+ ntohs(msg->params.c2sTalkerStreamID.stream_uid),
+ msg->params.c2sTalkerStreamID.stream_dest_mac,
+ ntohs(msg->params.c2sTalkerStreamID.stream_vlan_id));
+ break;
+ case OPENAVB_AVDECC_MSG_CLIENT_CHANGE_NOTIFICATION:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_CLIENT_CHANGE_NOTIFICATION");
+ ret = openavbAvdeccMsgSrvrHndlChangeNotificationFromClient(avdeccMsgHandle, (openavbAvdeccMsgStateType_t) msg->params.clientChangeNotification.current_state);
+ break;
+ default:
+ AVB_LOG_ERROR("Unexpected message received at server");
+ break;
+ }
+
+ AVB_LOGF_VERBOSE("Message handled, ret=%d", ret);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+void openavbAvdeccMsgSrvrSendServerVersionToClient(int avdeccMsgHandle, U32 AVBVersion)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ openavbAvdeccMessage_t msgBuf;
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_VERSION_CALLBACK;
+ msgBuf.params.versionCallback.AVBVersion = htonl(AVBVersion);
+ openavbAvdeccMsgSrvrSendToClient(avdeccMsgHandle, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+/* Client version request
+ */
+bool openavbAvdeccMsgSrvrHndlVerRqstFromClient(int avdeccMsgHandle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ openavbAvdeccMsgSrvrSendServerVersionToClient(avdeccMsgHandle, AVB_CORE_VER_FULL);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+}
+
+bool openavbAvdeccMsgSrvrHndlInitIdentifyFromClient(int avdeccMsgHandle, char * friendly_name, U8 talker)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavb_tl_data_cfg_t * currentStream;
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (pState) {
+ // The handle was already specified. Something has gone terribly wrong!
+ AVB_LOGF_ERROR("avdeccMsgHandle %d already used", avdeccMsgHandle);
+ AvdeccMsgStateListRemove(pState);
+ free(pState);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Make sure the supplied string is nil-terminated.
+ friendly_name[FRIENDLY_NAME_SIZE - 1] = '\0';
+
+ // Create a structure to hold the client information.
+ pState = (avdecc_msg_state_t *) calloc(1, sizeof(avdecc_msg_state_t));
+ if (!pState) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+ pState->avdeccMsgHandle = avdeccMsgHandle;
+ pState->bTalker = (talker != 0);
+ pState->lastRequestedState = pState->lastReportedState = OPENAVB_AVDECC_MSG_UNKNOWN;
+
+ // Find the state information matching this item.
+ for (currentStream = streamList; currentStream != NULL; currentStream = currentStream->next) {
+ if (strncmp(currentStream->friendly_name, friendly_name, FRIENDLY_NAME_SIZE) == 0)
+ {
+ break;
+ }
+ }
+ if (!currentStream) {
+ AVB_LOGF_WARNING("Ignoring unexpected client %d, friendly_name: %s",
+ avdeccMsgHandle, friendly_name);
+ free(pState);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Keep track of this new state item.
+ if (!AvdeccMsgStateListAdd(pState)) {
+ AVB_LOGF_ERROR("Error saving client identity information %d", avdeccMsgHandle);
+ free(pState);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Associate this Listener instance with the stream information.
+ pState->stream = currentStream;
+ currentStream->client = pState;
+
+ AVB_LOGF_INFO("Client %d Detected, friendly_name: %s",
+ avdeccMsgHandle, friendly_name);
+
+ // Enable ADP support, now that we have at least one Talker/Listener.
+ openavbAdpHaveTL(true);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return true;
+}
+
+bool openavbAvdeccMsgSrvrHndlTalkerStreamIDFromClient(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ openavb_tl_data_cfg_t *pCfg = pState->stream;
+ if (!pCfg) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d stream not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Update the stream information supplied by the client.
+ pCfg->sr_class = sr_class;
+ memcpy(pCfg->stream_addr.buffer.ether_addr_octet, stream_src_mac, 6);
+ pCfg->stream_addr.mac = &(pCfg->stream_addr.buffer); // Indicate that the MAC Address is valid.
+ pCfg->stream_uid = stream_uid;
+ memcpy(pCfg->dest_addr.buffer.ether_addr_octet, stream_dest_mac, 6);
+ pCfg->dest_addr.mac = &(pCfg->dest_addr.buffer); // Indicate that the MAC Address is valid.
+ pCfg->vlan_id = stream_vlan_id;
+ AVB_LOGF_DEBUG("Talker-supplied sr_class: %u", pCfg->sr_class);
+ AVB_LOGF_DEBUG("Talker-supplied stream_id: " ETH_FORMAT "/%u",
+ ETH_OCTETS(pCfg->stream_addr.buffer.ether_addr_octet), pCfg->stream_uid);
+ AVB_LOGF_DEBUG("Talker-supplied dest_addr: " ETH_FORMAT,
+ ETH_OCTETS(pCfg->dest_addr.buffer.ether_addr_octet));
+ AVB_LOGF_DEBUG("Talker-supplied vlan_id: %u", pCfg->vlan_id);
+
+ // Notify the state machine that we received this information.
+ openavbAcmpSMTalker_updateStreamInfo(pCfg);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return true;
+}
+
+bool openavbAvdeccMsgSrvrListenerStreamID(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavbAvdeccMessage_t msgBuf;
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_LISTENER_STREAM_ID;
+ openavbAvdeccMsgParams_ListenerStreamID_t * pParams =
+ &(msgBuf.params.listenerStreamID);
+ pParams->sr_class = sr_class;
+ memcpy(pParams->stream_src_mac, stream_src_mac, 6);
+ pParams->stream_uid = htons(stream_uid);
+ memcpy(pParams->stream_dest_mac, stream_dest_mac, 6);
+ pParams->stream_vlan_id = htons(stream_vlan_id);
+ bool ret = openavbAvdeccMsgSrvrSendToClient(avdeccMsgHandle, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+bool openavbAvdeccMsgSrvrTalkerStreamID(int avdeccMsgHandle,
+ 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_MSG);
+ openavbAvdeccMessage_t msgBuf;
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Send the stream information to the client.
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_S2C_TALKER_STREAM_ID;
+ openavbAvdeccMsgParams_S2C_TalkerStreamID_t * pParams =
+ &(msgBuf.params.s2cTalkerStreamID);
+ pParams->sr_class = sr_class;
+ pParams->stream_id_valid = stream_id_valid;
+ memcpy(pParams->stream_src_mac, stream_src_mac, 6);
+ pParams->stream_uid = htons(stream_uid);
+ pParams->stream_dest_valid = stream_dest_valid;
+ memcpy(pParams->stream_dest_mac, stream_dest_mac, 6);
+ pParams->stream_vlan_id_valid = stream_vlan_id_valid;
+ pParams->stream_vlan_id = htons(stream_vlan_id);
+ bool ret = openavbAvdeccMsgSrvrSendToClient(avdeccMsgHandle, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+bool openavbAvdeccMsgSrvrChangeRequest(int avdeccMsgHandle, openavbAvdeccMsgStateType_t desiredState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavbAvdeccMessage_t msgBuf;
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_CLIENT_CHANGE_REQUEST;
+ openavbAvdeccMsgParams_ClientChangeRequest_t * pParams =
+ &(msgBuf.params.clientChangeRequest);
+ pParams->desired_state = (U8) desiredState;
+ bool ret = openavbAvdeccMsgSrvrSendToClient(avdeccMsgHandle, &msgBuf);
+ if (ret) {
+ // Save the requested state for future reference.
+ pState->lastRequestedState = desiredState;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+static const char * GetStateString(openavbAvdeccMsgStateType_t state)
+{
+ switch (state) {
+ case OPENAVB_AVDECC_MSG_UNKNOWN:
+ return "Unknown";
+ case OPENAVB_AVDECC_MSG_STOPPED:
+ return "Stopped";
+ case OPENAVB_AVDECC_MSG_RUNNING:
+ return "Running";
+ case OPENAVB_AVDECC_MSG_PAUSED:
+ return "Paused";
+ case OPENAVB_AVDECC_MSG_STOPPED_UNEXPECTEDLY:
+ return "Stopped_Unexpectedly";
+ default:
+ return "ERROR";
+ }
+}
+
+bool openavbAvdeccMsgSrvrHndlChangeNotificationFromClient(int avdeccMsgHandle, openavbAvdeccMsgStateType_t currentState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Save the updated state.
+ if (currentState != pState->lastReportedState) {
+ openavbAvdeccMsgStateType_t previousState = pState->lastReportedState;
+ pState->lastReportedState = currentState;
+ AVB_LOGF_INFO("Notified of client %d state change from %s to %s (Last requested: %s)",
+ avdeccMsgHandle, GetStateString(previousState), GetStateString(currentState), GetStateString(pState->lastRequestedState));
+
+ // If AVDECC did not yet set the client state, set the client state to the desired state.
+ if (pState->lastRequestedState == OPENAVB_AVDECC_MSG_UNKNOWN) {
+ if (pState->stream->initial_state == TL_INIT_STATE_RUNNING && pState->lastReportedState != OPENAVB_AVDECC_MSG_RUNNING) {
+ // Have the client be running if the user explicitly requested it to be running.
+ openavbAvdeccMsgSrvrChangeRequest(avdeccMsgHandle, OPENAVB_AVDECC_MSG_RUNNING);
+ }
+ else if (pState->stream->initial_state != TL_INIT_STATE_RUNNING && pState->lastReportedState == OPENAVB_AVDECC_MSG_RUNNING) {
+ // Have the client not be running if the user didn't explicitly request it to be running.
+ openavbAvdeccMsgSrvrChangeRequest(avdeccMsgHandle, OPENAVB_AVDECC_MSG_STOPPED);
+ }
+ else if (gAvdeccCfg.bFastConnectSupported &&
+ !(pState->bTalker) &&
+ pState->lastReportedState == OPENAVB_AVDECC_MSG_STOPPED) {
+ // Listener started as not running, and is not configured to start in the running state.
+ // See if we should do a fast connect using the saved state.
+ openavb_tl_data_cfg_t *pCfg = pState->stream;
+ if (pCfg) {
+ U16 flags, talker_unique_id;
+ U8 talker_entity_id[8], controller_entity_id[8];
+ bool bAvailable = openavbAvdeccGetSaveStateInfo(pCfg, &flags, &talker_unique_id, &talker_entity_id, &controller_entity_id);
+ if (bAvailable) {
+ openavbAcmpSMListenerSet_doFastConnect(pCfg, flags, talker_unique_id, talker_entity_id, controller_entity_id);
+ }
+ }
+ }
+ }
+ else if (currentState == OPENAVB_AVDECC_MSG_STOPPED_UNEXPECTEDLY) {
+ if (previousState != OPENAVB_AVDECC_MSG_STOPPED_UNEXPECTEDLY &&
+ pState->lastRequestedState == OPENAVB_AVDECC_MSG_RUNNING &&
+ gAvdeccCfg.bFastConnectSupported) {
+ // The Talker disappeared. Use fast connect to assist with reconnecting if it reappears.
+ openavb_tl_data_cfg_t *pCfg = pState->stream;
+ if (pCfg) {
+ U16 flags, talker_unique_id;
+ U8 talker_entity_id[8], controller_entity_id[8];
+ bool bAvailable = openavbAvdeccGetSaveStateInfo(pCfg, &flags, &talker_unique_id, &talker_entity_id, &controller_entity_id);
+ if (bAvailable) {
+ // Set the timed-out status for the Listener's descriptor.
+ // The next time the Talker advertises itself, openavbAcmpSMListenerSet_talkerTestFastConnect() should try to reconnect.
+ openavb_aem_descriptor_stream_io_t *pDescriptor;
+ U16 listenerUniqueId;
+ for (listenerUniqueId = 0; listenerUniqueId < 0xFFFF; ++listenerUniqueId) {
+ pDescriptor = openavbAemGetDescriptor(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, listenerUniqueId);
+ if (pDescriptor && pDescriptor->stream &&
+ strcmp(pDescriptor->stream->friendly_name, pCfg->friendly_name) == 0) {
+ // We found a match.
+ AVB_LOGF_INFO("Listener %s waiting to fast connect to flags=0x%04x, talker_unique_id=0x%04x, talker_entity_id=" ENTITYID_FORMAT ", controller_entity_id=" ENTITYID_FORMAT,
+ pCfg->friendly_name,
+ flags,
+ talker_unique_id,
+ ENTITYID_ARGS(talker_entity_id),
+ ENTITYID_ARGS(controller_entity_id));
+ pDescriptor->fast_connect_status = OPENAVB_FAST_CONNECT_STATUS_TIMED_OUT;
+ memcpy(pDescriptor->fast_connect_talker_entity_id, talker_entity_id, sizeof(pDescriptor->fast_connect_talker_entity_id));
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pDescriptor->fast_connect_start_time);
+ pDescriptor->fast_connect_start_time.tv_sec += 5; // Give the Talker some time to shutdown or stabilize
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Now that we have handled this, treat this state as a normal stop.
+ pState->lastReportedState = OPENAVB_AVDECC_MSG_STOPPED;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return true;
+}
+
+
+/* Called if a client closes their end of the IPC
+ */
+void openavbAvdeccMsgSrvrCloseClientConnection(int avdeccMsgHandle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ // Free the state for this handle.
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (pState) {
+ AvdeccMsgStateListRemove(pState);
+ if (streamList && pState->stream) {
+ // Clear the stream pointer to this object.
+ pState->stream = NULL;
+ }
+ free(pState);
+
+ // If there are no more Talkers or Listeners, stop ADP.
+ if (AvdeccMsgStateListGetIndex(0) == NULL) {
+ openavbAdpHaveTL(false);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
diff --git a/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.h b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.h
new file mode 100644
index 00000000..a7b1f037
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.h
@@ -0,0 +1,57 @@
+/*************************************************************************************************************
+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_H
+#define OPENAVB_AVDECC_MSG_SERVER_H
+
+#include "openavb_types.h"
+#include "openavb_avdecc_msg.h"
+
+typedef struct openavb_tl_data_cfg openavb_tl_data_cfg_t;
+
+struct _avdecc_msg_state {
+
+ // Handle to the AVDECC Msg handle for the connection to the server.
+ int avdeccMsgHandle;
+
+ // TRUE if a Talker, FALSE if a Listener.
+ bool bTalker;
+
+ // Local stream that matches the client's Talker/Listener.
+ // Do not free this pointer; it is for reference only.
+ openavb_tl_data_cfg_t * stream;
+
+ // Talker/Listener state information.
+ openavbAvdeccMsgStateType_t lastRequestedState;
+ openavbAvdeccMsgStateType_t lastReportedState;
+};
+
+#endif // OPENAVB_AVDECC_MSG_SERVER_H
diff --git a/lib/avtp_pipeline/avtp/openavb_avtp.c b/lib/avtp_pipeline/avtp/openavb_avtp.c
index 055ed726..82932d23 100644
--- a/lib/avtp_pipeline/avtp/openavb_avtp.c
+++ b/lib/avtp_pipeline/avtp/openavb_avtp.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.
*************************************************************************************************************/
@@ -72,11 +73,8 @@ static openavbRC openAvtpSock(avtp_stream_t *pStream)
}
if (pStream->rawsock != NULL) {
- // Get the socket, so we can poll on it
- pStream->sock = openavbRawsockGetSocket(pStream->rawsock);
-
openavbSetRxSignalMode(pStream->rawsock, pStream->bRxSignalMode);
-
+
if (!pStream->tx) {
// Set the multicast address that we want to receive
openavbRawsockRxMulticast(pStream->rawsock, TRUE, pStream->dest_addr.ether_addr_octet);
@@ -147,6 +145,9 @@ openavbRC openavbAvtpTxInit(
pStream->pMapCB->map_tx_init_cb(pStream->pMediaQ);
pStream->pIntfCB->intf_tx_init_cb(pStream->pMediaQ);
+ if (pStream->pIntfCB->intf_set_stream_uid_cb) {
+ pStream->pIntfCB->intf_set_stream_uid_cb(pStream->pMediaQ, streamID->uniqueID);
+ }
// Set the frame length
pStream->frameLen = pStream->pMapCB->map_max_data_size_cb(pStream->pMediaQ) + ETH_HDR_LEN_VLAN;
@@ -255,7 +256,7 @@ static void inline rxDeliveryStats(avtp_rx_info_t *rxInfo,
static openavbRC fillAvtpHdr(avtp_stream_t *pStream, U8 *pFill)
{
AVB_TRACE_ENTRY(AVB_TRACE_AVTP_DETAIL);
-
+
switch (pStream->pMapCB->map_avtp_version_cb()) {
default:
AVB_RC_LOG_RET(AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVBAVTP_RC_INVALID_AVTP_VERSION));
@@ -341,7 +342,7 @@ openavbRC openavbAvtpTx(void *pv, bool bSend, bool txBlockingInIntf)
// Call mapping module to move data into AVTP frame
txCBResult = pStream->pMapCB->map_tx_cb(pStream->pMediaQ, pAvtpFrame, &avtpFrameLen);
-
+
pStream->bytes += avtpFrameLen;
}
else {
@@ -365,8 +366,9 @@ openavbRC openavbAvtpTx(void *pv, bool bSend, bool txBlockingInIntf)
}
}
- // If we got data from the mapping module, notifiy the raw sockets.
- if (txCBResult != TX_CB_RET_PACKET_NOT_READY) {
+ // If we got data from the mapping module and stream is not paused,
+ // notify the raw sockets.
+ if (txCBResult != TX_CB_RET_PACKET_NOT_READY && !pStream->bPause) {
if (pStream->tsEval) {
processTimestampEval(pStream, pAvtpFrame);
@@ -432,6 +434,9 @@ openavbRC openavbAvtpRxInit(
pStream->pMapCB->map_rx_init_cb(pStream->pMediaQ);
pStream->pIntfCB->intf_rx_init_cb(pStream->pMediaQ);
+ if (pStream->pIntfCB->intf_set_stream_uid_cb) {
+ pStream->pIntfCB->intf_set_stream_uid_cb(pStream->pMediaQ, streamID->uniqueID);
+ }
// Set the frame length
pStream->frameLen = pStream->pMapCB->map_max_data_size_cb(pStream->pMediaQ) + ETH_HDR_LEN_VLAN;
@@ -465,7 +470,7 @@ openavbRC openavbAvtpRxInit(
static void x_avtpRxFrame(avtp_stream_t *pStream, U8 *pFrame, U32 frameLen)
{
AVB_TRACE_ENTRY(AVB_TRACE_AVTP_DETAIL);
- AVB_LOGF_DEBUG("pFrame=%p, len=%u", pFrame, frameLen);
+ IF_LOG_INTERVAL(4096) AVB_LOGF_DEBUG("pFrame=%p, len=%u", pFrame, frameLen);
U8 subtype, flags, flags2, rxSeq, nLost, avtpVersion;
U8 *pRead = pFrame;
@@ -490,7 +495,7 @@ static void x_avtpRxFrame(avtp_stream_t *pStream, U8 *pFrame, U32 frameLen)
else if (pStream->avtp_sequence_num != rxSeq) {
nLost = (rxSeq - pStream->avtp_sequence_num)
+ (rxSeq < pStream->avtp_sequence_num ? 256 : 0);
- AVB_LOGF_DEBUG("AVTP sequence mismatch: expected: %u,\tgot: %u,\tlost %d",
+ AVB_LOGF_INFO("AVTP sequence mismatch: expected: %3u,\tgot: %3u,\tlost %3d",
pStream->avtp_sequence_num, rxSeq, nLost);
pStream->nLost += nLost;
}
@@ -499,8 +504,7 @@ static void x_avtpRxFrame(avtp_stream_t *pStream, U8 *pFrame, U32 frameLen)
pStream->bytes += frameLen;
flags2 = *pRead++;
-
- AVB_LOGF_DEBUG("subtype=%u, sv=%u, ver=%u, mr=%u, tv=%u tu=%u",
+ IF_LOG_INTERVAL(4096) AVB_LOGF_DEBUG("subtype=%u, sv=%u, ver=%u, mr=%u, tv=%u tu=%u",
subtype, flags & 0x80, avtpVersion,
flags & 0x08, flags & 0x01, flags2 & 0x01);
@@ -511,7 +515,7 @@ static void x_avtpRxFrame(avtp_stream_t *pStream, U8 *pFrame, U32 frameLen)
}
pStream->pMapCB->map_rx_cb(pStream->pMediaQ, pFrame, frameLen);
-
+
// NOTE : This is a redundant call. It is handled in avtpTryRx()
// pStream->pIntfCB->intf_rx_cb(pStream->pMediaQ);
@@ -573,7 +577,7 @@ static void avtpTryRx(avtp_stream_t *pStream)
timeout = AVTP_MAX_BLOCK_USEC;
if (timeout < RAWSOCK_MIN_TIMEOUT_USEC)
timeout = RAWSOCK_MIN_TIMEOUT_USEC;
-
+
pBuf = (U8 *)openavbRawsockGetRxFrame(pStream->rawsock, timeout, &offsetToFrame, &frameLen);
if (!pBuf)
pStream->pIntfCB->intf_rx_cb(pStream->pMediaQ);
@@ -694,10 +698,12 @@ void openavbAvtpPause(void *handle, bool bPause)
pStream->bPause = bPause;
+ // AVDECC_TODO: Do something with the bPause value!
+
AVB_TRACE_EXIT(AVB_TRACE_AVTP);
}
-void openavbAvtpShutdown(void *pv)
+void openavbAvtpShutdownTalker(void *pv)
{
AVB_TRACE_ENTRY(AVB_TRACE_AVTP);
AVB_LOG_DEBUG("Shutdown");
@@ -722,3 +728,29 @@ void openavbAvtpShutdown(void *pv)
AVB_TRACE_EXIT(AVB_TRACE_AVTP);
return;
}
+
+void openavbAvtpShutdownListener(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVTP);
+ AVB_LOG_DEBUG("Shutdown");
+
+ avtp_stream_t *pStream = (avtp_stream_t *)pv;
+ if (pStream) {
+ // close the rawsock
+ if (pStream->rawsock) {
+ openavbRawsockClose(pStream->rawsock);
+ pStream->rawsock = NULL;
+ }
+
+ pStream->pIntfCB->intf_end_cb(pStream->pMediaQ);
+ pStream->pMapCB->map_end_cb(pStream->pMediaQ);
+
+ if (pStream->ifname)
+ free(pStream->ifname);
+
+ // free the malloc'd stream info
+ free(pStream);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_AVTP);
+ return;
+}
diff --git a/lib/avtp_pipeline/avtp/openavb_avtp.h b/lib/avtp_pipeline/avtp/openavb_avtp.h
index b7d56b89..13d9a364 100644
--- a/lib/avtp_pipeline/avtp/openavb_avtp.h
+++ b/lib/avtp_pipeline/avtp/openavb_avtp.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
@@ -100,8 +101,6 @@ typedef struct
U16 nbuffers;
// The rawsock library handle. Used to send or receive frames.
void *rawsock;
- // The actual socket used by the rawsock library. Used for poll().
- int sock;
// The streamID - in network form
U8 streamIDnet[8];
// The destination address for stream
@@ -179,7 +178,8 @@ void openavbAvtpConfigTimsstampEval(void *handle, U32 tsInterval, U32 reportInte
void openavbAvtpPause(void *handle, bool bPause);
-void openavbAvtpShutdown(void *handle);
+void openavbAvtpShutdownTalker(void *handle);
+void openavbAvtpShutdownListener(void *handle);
int openavbAvtpTxBufferLevel(void *handle);
diff --git a/lib/avtp_pipeline/avtp/openavb_avtp_time.c b/lib/avtp_pipeline/avtp/openavb_avtp_time.c
index 49581289..93c3aaac 100644
--- a/lib/avtp_pipeline/avtp/openavb_avtp_time.c
+++ b/lib/avtp_pipeline/avtp/openavb_avtp_time.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/avtp/openavb_avtp_time_pub.h b/lib/avtp_pipeline/avtp/openavb_avtp_time_pub.h
index f2e24213..0c429425 100644
--- a/lib/avtp_pipeline/avtp/openavb_avtp_time_pub.h
+++ b/lib/avtp_pipeline/avtp/openavb_avtp_time_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
diff --git a/lib/avtp_pipeline/avtp_avdecc.mk b/lib/avtp_pipeline/avtp_avdecc.mk
new file mode 100644
index 00000000..9a140c03
--- /dev/null
+++ b/lib/avtp_pipeline/avtp_avdecc.mk
@@ -0,0 +1,23 @@
+AVB_FEATURE_AVDECC ?= 1
+PLATFORM_TOOLCHAIN ?= x86_i210_linux
+
+.PHONY: all clean
+
+all: build_avdecc/Makefile
+ $(MAKE) -s -C build_avdecc install
+
+doc: build_avdecc/Makefile
+ $(MAKE) -s -C build_avdecc doc
+ @echo "\n\nTo display documentation use:\n\n" \
+ "\txdg-open $(abspath build_avdecc/documents/api_docs/index.html)\n"
+
+clean:
+ $(RM) -r build_avdecc
+
+build_avdecc/Makefile:
+ mkdir -p build_avdecc && \
+ cd build_avdecc && \
+ cmake -DCMAKE_TOOLCHAIN_FILE=../platform/Linux/$(PLATFORM_TOOLCHAIN).cmake \
+ -DAVB_FEATURE_AVDECC=$(AVB_FEATURE_AVDECC) \
+ ..
+
diff --git a/lib/avtp_pipeline/avtp_pipeline.mk b/lib/avtp_pipeline/avtp_pipeline.mk
index 5851c826..a3ed80e8 100644
--- a/lib/avtp_pipeline/avtp_pipeline.mk
+++ b/lib/avtp_pipeline/avtp_pipeline.mk
@@ -23,4 +23,4 @@ build/Makefile:
-DAVB_FEATURE_ENDPOINT=$(AVB_FEATURE_ENDPOINT) \
-DIGB_LAUNCHTIME_ENABLED=$(IGB_LAUNCHTIME_ENABLED) \
-DAVB_FEATURE_GSTREAMER=$(AVB_FEATURE_GSTREAMER) \
- ..
+ ..
diff --git a/lib/avtp_pipeline/documents/sdk_avtp_interface_module_dev.md b/lib/avtp_pipeline/documents/sdk_avtp_interface_module_dev.md
index 4e6fb69f..aedd7e37 100644
--- a/lib/avtp_pipeline/documents/sdk_avtp_interface_module_dev.md
+++ b/lib/avtp_pipeline/documents/sdk_avtp_interface_module_dev.md
@@ -7,6 +7,7 @@ Interface modules are the components that sit between the core AVB stack and the
platform device drivers that supply access to media hardware.
<br>
+
The Plug-in Architecture {#sdk_avtp_intf_module_plugin}
========================
The OPENAVB AVB stack has a plug-in architecture for the AVTP implementation in the
@@ -63,6 +64,7 @@ callback list for the interface module to call into the media queue to access
and work with the media queue.
<br>
+
Task / Thread Model {#sdk_avtp_intf_module_task}
=================
In the general case the task / threading (hereafter referred to as task) model
@@ -85,6 +87,7 @@ it can only be accessed within the scope of a callback into the interface
module.
<br>
+
Building an Interface Module {#sdk_avtp_intf_module_building}
============================
There should be minimal dependencies for creation of an interface module. The
@@ -96,6 +99,7 @@ handled via callbacks that are available to the interface module in the media
queue structure it receives as a parameter on its own callbacks.
<br>
+
Interface Module in a Talker {#sdk_avtp_intf_module_talker}
============================
An interface module when used in a talker pulls data from a media source and
@@ -103,12 +107,14 @@ pushes it onto the media queue in the format expected by the mapping module
configured for that stream.
<br>
+
Interface Module in a Listener {#sdk_avtp_intf_module_listener}
==============================
When called from a listener it pulls data from the media queue and pushes it to
the media sink for presentation.
<br>
+
Working With the Media Queue {#working_with_mediaq}
============================
The media queue is the conduit between interface modules and mapping modules.
@@ -151,6 +157,7 @@ For a detailed work flow please visit
[Media Queue Usage](@ref sdk_notes_media_queue_usage)
<br>
+
Timestamps {#sdk_avtp_intf_module_timestamps}
==========
For interface modules often the only requirement for timestamps is to assign a
diff --git a/lib/avtp_pipeline/documents/sdk_avtp_stream_cfg.md b/lib/avtp_pipeline/documents/sdk_avtp_stream_cfg.md
index f96d0a0e..f254898b 100644
--- a/lib/avtp_pipeline/documents/sdk_avtp_stream_cfg.md
+++ b/lib/avtp_pipeline/documents/sdk_avtp_stream_cfg.md
@@ -54,7 +54,7 @@ void h264_SampleListenerCfg(openavb_tl_cfg_t *cfg)
// On the talker this value is added to the PTP walltime to create the AVTP Timestamp.
// On the listener this value is used to validate an expected valid timestamp range.
// Note: For the listener the map_nv_item_count value must be set large enough to
- // allow buffering at least as many AVTP packets that can be transmitted during this
+ // allow buffering at least as many AVTP packets that can be transmitted during this
// max transit time.
cfg->max_transit_usec = 2000;
@@ -119,8 +119,8 @@ void h264_SampleListenerCfg(openavb_tl_cfg_t *cfg)
// cfg->libCfgNames[cfgIdx] = "map_nv_tx_rate";
// cfg->libCfgValues[cfgIdx++] = "8000";
- // map_nv_max_payload_size: This is the max RTP payload size. See RFC 6184 for details,
- // 1412 is the default size
+ // map_nv_max_payload_size: This is the max RTP payload size. See RFC 6184 for details,
+ // 1412 is the default size
cfg->libCfgNames[cfgIdx] = "map_nv_max_payload_size";
cfg->libCfgValues[cfgIdx++] = "1412";
@@ -153,109 +153,34 @@ void h264_SampleListenerCfg(openavb_tl_cfg_t *cfg)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<br>
+
Common Stream Configuration {#sdk_avtp_stream_cfg_common}
===========================
These are common stream configuration values.
Name | Description
--------------------|------------
-role |Sets the process as a talker or listener. Valid values are\
- *talker* or *listener*.
-stream_addr |Used on the listener and should be set to the mac address \
- of the talker.
-stream_uid |The unique stream ID. The talker and listener must both \
- have this set the same.
-dest_addr |Destination multicast address for the stream.<br> \
- If using \
- <ul><li><b>with MAAP</b> - dynamic destination addresses \
- are generated automatically by the talker and passed to \
- the listener, and don't need to be configured.</li> \
- <li><b>without MAAP</b>, locally administered (static) \
- addresses must be configured. Those addresses are in the \
- range of: 91:E0:F0:00:FE:00 - 91:E0:F0:00:FE:FF. Typically\
- use :00 for the first stream, :01 for the second, etc. \
- </li></ul> \
- If <b>SRP</b> \
- <ul><li><b>is being</b> used the static destination \
- address only needs to be set in the talker;</li> \
- <li><b>is not being</b> used the destination address need \
- to be set (to the same value) in both the talker and \
- listener.</li></ul> \
- The destination is a multicast address, not a real MAC \
- address, so it does not match the talker or listener's \
- interface MAC. There are several pools of those addresses \
- for use by AVTP defined in 1722.
-max_interval_frames |The maximum number of packets that will be sent during an \
- observation interval. This is only used on the talker.
+role |Sets the process as a talker or listener. Valid values are *talker* or *listener*.
+stream_addr |Used on the listener and should be set to the mac address of the talker. If not specified on the talker, the talker's detected mac address will be used.<br>If AVDECC is being used, this does not need to be specified for the listener, as AVDECC will tell the listener which value to use.
+stream_uid |The unique stream ID. The talker and listener must both have this set the same.<br>If AVDECC is being used, this does not need to be specified for the listener, as AVDECC will tell the listener which value to use.
+dest_addr |Destination multicast address for the stream.<br>If using<ul><li><b>with MAAP</b> - dynamic destination addresses are generated automatically by the talker and passed to the listener, and don't need to be configured.<br>However, it is recommended that a locally administered (static) address still be configured, as the dest_addr will be used if the MAAP daemon is not available.</li><li><b>without MAAP</b>, locally administered (static) addresses must be configured. Those addresses are in the range of: 91:E0:F0:00:FE:00 - 91:E0:F0:00:FE:FF. Typically use :00 for the first stream, :01 for the second, etc. </li></ul> If <b>SRP</b> <ul><li><b>is being</b> used the static destination address only needs to be set in the talker;</li> <li><b>is not being</b> used the destination address need to be set (to the same value) in both the talker and listener.</li></ul> The destination is a multicast address, not a real MAC address, so it does not match the talker or listener's interface MAC. There are several pools of those addresses for use by AVTP defined in 1722.
+max_interval_frames |The maximum number of packets that will be sent during an observation interval. This is only used on the talker.
max_frame_size |Maximum size of the frame
-sr_class |A talker only setting. Values are either A or B. If not \
- set an internal default is used.
-sr_rank |A talker only setting. If not set an internal default is \
- used.
-max_transit_usec |Allows manually specifying a maximum transit time. \
- <ul><li><b>On the talker</b> this value is added to the \
- PTP walltime to create the AVTP Timestamp.</li> \
- <li><b>On the listener</b> this value is used to validate \
- an expected valid timestamp range.</li></ul> \
- <b>Note:</b> For the listener the map_nv_item_count value \
- must be set large enough to allow buffering at least as \
- many AVTP packets that can be transmitted during this max \
- transit time.
-max_transmit_deficit_usec |Allows setting the maximum packet transmit rate \
- deficit that will be recovered when a talker falls behind.\
- <p>When a talker can not keep up with the specified \
- transmit rate it builds up a deficit and will attempt to \
- make up for this deficit by sending more packets. There is\
- normally some variability in the transmit rate because of \
- other demands on the system so this is expected. However, \
- without this bounding value the deficit could grew too \
- large in cases such where more streams are started than \
- the system can support and when the number of streams is \
- reduced the remaining streams will attempt to recover this\
- deficit by sending packets at a higher rate. This can \
- cause a problem at the listener side and significantly \
- delay the recovery time before media playback will return \
- to normal.</p> \
- <p>Typically this value can be set to the expected buffer \
- size (in usec) that listeners are expected to be \
- buffering.<br> \
- For low latency solutions this is normally a small value. \
- For non-live media playback such as video playback the \
- listener side buffers can often be large enough to held \
- many seconds of data.</p> \
- <b>Note:</b> This is only used on a talker side.
-internal_latency |Allows mannually specifying an internal latency time. This\
- is used only on the talker.
-max_stale |The number of microseconds beyond the presentation time \
- that media queue items will be purged because they are too\
- old (past the presentation time).<br> \
- This is only used on listener end stations. \
- <p><b>Note:</b> needing to purge old media queue items is \
- often a sign of some other problem.<br> \
- For example: a delay at stream startup before incoming \
- packets are ready to be processed by the media sink.<br> \
- If this deficit in processing or purging the old (stale) \
- packets is not handled, syncing multiple listeners will be\
- problematic.</p>
-raw_tx_buffers |The number of raw socket transmit buffers. Typically 4 - 8\
- are good values. This is only used by the talker. If not \
- set internal defaults are used.
-raw_rx_buffers |The number of raw socket receive buffers. Typically 50 - \
- 100 are good values. This is only used by the listener. \
- If not set internal defaults are used.
-report_seconds |How often to output stats. Defaults to 10 seconds. 0 turns\
- off the stats.
-tx_blocking_in_intf |The interface module will block until data is available. \
- This is a talker only configuration value and not all interface modules support it.
-pMapInitFn |Pointer to the mapping module initialization function. \
- Since this is a pointer to a function addresss is it not \
- directly set in platforms that use a .ini file.
-IntfInitFn |Pointer to the interface module initialization function. \
- Since this is a pointer to a function addresss is it not \
- directly set in platforms that use a .ini file.
-
+sr_class |A talker only setting. Values are either A or B. If not set an internal default is used.
+sr_rank |A talker only setting. If not set an internal default is used.
+max_transit_usec |Allows manually specifying a maximum transit time. <ul><li><b>On the talker</b> this value is added to the PTP walltime to create the AVTP Timestamp.</li><li><b>On the listener</b> this value is used to validate an expected valid timestamp range.</li></ul><b>Note:</b> For the listener the map_nv_item_count value must be set large enough to allow buffering at least as many AVTP packets that can be transmitted during this max transit time.
+max_transmit_deficit_usec |Allows setting the maximum packet transmit rate deficit that will be recovered when a talker falls behind. <p>When a talker can not keep up with the specified transmit rate it builds up a deficit and will attempt to make up for this deficit by sending more packets. There is normally some variability in the transmit rate because of other demands on the system so this is expected. However, without this bounding value the deficit could grew too large in cases such where more streams are started than the system can support and when the number of streams is reduced the remaining streams will attempt to recover this deficit by sending packets at a higher rate. This can cause a problem at the listener side and significantly delay the recovery time before media playback will return to normal.</p><p>Typically this value can be set to the expected buffer size (in usec) that listeners are expected to be buffering.<br>For low latency solutions this is normally a small value. For non-live media playback such as video playback the listener side buffers can often be large enough to held many seconds of data.</p><b>Note:</b> This is only used on a talker side.
+internal_latency |Allows manually specifying an internal latency time. This is used only on the talker.
+max_stale |The number of microseconds beyond the presentation time that media queue items will be purged because they are too old (past the presentation time).<br>This is only used on listener end stations.<p><b>Note:</b> needing to purge old media queue items is often a sign of some other problem.<br>For example: a delay at stream startup before incoming packets are ready to be processed by the media sink.<br>If this deficit in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.</p>
+raw_tx_buffers |The number of raw socket transmit buffers. Typically 4 - 8 are good values. This is only used by the talker. If not set internal defaults are used.
+raw_rx_buffers |The number of raw socket receive buffers. Typically 50 - 100 are good values. This is only used by the listener. If not set internal defaults are used.
+report_seconds |How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+tx_blocking_in_intf |The interface module will block until data is available. This is a talker only configuration value and not all interface modules support it.
+pMapInitFn |Pointer to the mapping module initialization function. Since this is a pointer to a function address is it not directly set in platforms that use a .ini file.
+IntfInitFn |Pointer to the interface module initialization function. Since this is a pointer to a function address is it not directly set in platforms that use a .ini file.
<br>
+
# Platform Specific Stream Configuration Values
Some platform ports have unique configuration values.
@@ -263,26 +188,13 @@ Some platform ports have unique configuration values.
Name | Description
--------------------------|---------------------------
-map_lib |The name of the library file (commonly a .so file) that \
- implements the Initialize function.<br> \
- Comment out the map_lib name and link in the .c file to \
- the openavb_tl executable to embed the mapper directly into \
- the executable unit. There is no need to change anything \
- else. The Initialize function will still be dynamically \
- linked in.
+map_lib |The name of the library file (commonly a .so file) that implements the Initialize function.<br>Comment out the map_lib name and link in the .c file to the openavb_tl executable to embed the mapper directly into the executable unit. There is no need to change anything else. The Initialize function will still be dynamically linked in.
map_fn |The name of the initialize function in the mapper
-intf_lib | The name of the library file (commonly a .so file) \
- that implements the Initialize function.<br> \
- Comment out the intf_lib name and link in the .c \
- file to the openavb_tl executable to embed the \
- interface directly into the executable unit.<br> \
- There is no need to change anything else. \
- The Initialize function will still be dynamically \
- linked in
+intf_lib | The name of the library file (commonly a .so file) that implements the Initialize function.<br>Comment out the intf_lib name and link in the .c file to the openavb_tl executable to embed the interface directly into the executable unit.<br>There is no need to change anything else. The Initialize function will still be dynamically linked in
intf_fn | The name of the initialize function in the interface
-
<br>
+
Example Interface / Mapping Combinations {#sdk_avtp_stream_cfg_combinations}
========================================
Below are a few interface / mapping module combinations. Notice that a single
@@ -291,28 +203,13 @@ mappings may work with multiple interface modules.
interface module | mapping module | description
----------------------------|-----------------------|------------
-[echo](@ref echo_host_intf) |[pipe](@ref pipe_map) |Demonstration interface \
- used mostly for \
- verification and testing \
- purposes.
-[alsa](@ref alsa_intf) |[uncmp_audio](@ref uncmp_audio_map)|Audio \
- interface created for \
- demonstration on Linux. \
- Can be used to play \
- captured (line in, mic) \
- audio stream via EAVB
-[alsa](@ref alsa_intf) |[aaf_audio](@ref aaf_audio_map)|Audio \
- interface created for \
- demonstration on Linux. \
- Can be used to play \
- captured (line in, mic) \
- audio stream via EAVB
-[wav_file](@ref wav_file_intf)|[uncmp_audio](@ref uncmp_audio_map)| \
- Configuration for playing \
- wave file via EAVB
-
+[echo](@ref echo_host_intf) |[pipe](@ref pipe_map) |Demonstration interface used mostly for verification and testing purposes.
+[alsa](@ref alsa_intf) |[uncmp_audio](@ref uncmp_audio_map)|Audio interface created for demonstration on Linux. Can be used to play captured (line in, mic) audio stream via EAVB
+[alsa](@ref alsa_intf) |[aaf_audio](@ref aaf_audio_map)|Audio interface created for demonstration on Linux. Can be used to play captured (line in, mic) audio stream via EAVB
+[wav_file](@ref wav_file_intf)|[uncmp_audio](@ref uncmp_audio_map)|Configuration for playing wave file via EAVB
<br>
+
Interface and Mapping Module Configuration {#sdk_avtp_stream_cfg_intf_map}
==========================================
diff --git a/lib/avtp_pipeline/documents/sdk_eavb_integration.md b/lib/avtp_pipeline/documents/sdk_eavb_integration.md
index c1200834..e92f07b6 100644
--- a/lib/avtp_pipeline/documents/sdk_eavb_integration.md
+++ b/lib/avtp_pipeline/documents/sdk_eavb_integration.md
@@ -10,6 +10,7 @@ will be active. The details of stream configuration is described in another
section.
<br>
+
AVTP Control {#sdk_integration_avtp_control}
============
Only a handful of functions are needed to control the AVTP component. This is
@@ -23,6 +24,7 @@ general flow is:
close.
<br>
+
Host Application Integration {#sdk_integration_host_app}
============================
Controlling the non-AVTP components of the AVB stack are platform dependent.
diff --git a/lib/avtp_pipeline/documents/sdk_notes_media_queue_usage.md b/lib/avtp_pipeline/documents/sdk_notes_media_queue_usage.md
index aaa4cda8..4c6daaf2 100644
--- a/lib/avtp_pipeline/documents/sdk_notes_media_queue_usage.md
+++ b/lib/avtp_pipeline/documents/sdk_notes_media_queue_usage.md
@@ -9,6 +9,7 @@ and are hidden from interface module implemented. There are also some
simplifications to make description as straightforward as possible.
<br>
+
# Workflow
The following work flow steps will be described.
@@ -22,6 +23,7 @@ and listener streams
the Media Queue
<br>
+
Starting {#media_queue_usage_start}
========
@@ -53,6 +55,7 @@ Now the listener/talker stream is running. See next steps below for details of
Media Queue interaction for the talker and listener.
<br>
+
Talker specific flow {#media_queue_usage_talker}
====================
@@ -71,6 +74,7 @@ function additionally unlocks the head so the @ref openavbMediaQHeadUnlock call
not needed
<br>
+
Listener specific flow {#media_queue_usage_listener}
======================
@@ -90,6 +94,7 @@ additionally unlocks tail, so it is not necessary to call @ref
openavbMediaQTailUnlock.
<br>
+
Stopping {#media_queue_usage_stop}
========
@@ -101,6 +106,7 @@ During the stopping process following action are taken
the memory taken by all internal structures of Media Queue
<br>
+
Guidelines {#media_queue_usage_rules}
==========
diff --git a/lib/avtp_pipeline/documents/sdk_overview.md b/lib/avtp_pipeline/documents/sdk_overview.md
index 75d6f926..2f0f9e76 100644
--- a/lib/avtp_pipeline/documents/sdk_overview.md
+++ b/lib/avtp_pipeline/documents/sdk_overview.md
@@ -4,7 +4,7 @@ EAVB SDK Overview {#sdk_overview}
Introduction {#sdk_overview_introduction}
============
-Symphony Teleca Corporation (OPENAVB) has developed a software Protocol Stack to
+Harman International Industries, Inc. has developed a software Protocol Stack to
support Ethernet Audio Video Bridging (EAVB or AVB) on a variety of platforms.
The software includes explicit Operating System and Hardware Abstraction Layers
(OSAL and HAL) to facilitate rapid and efficient porting of the generic stack to
@@ -30,6 +30,7 @@ guides are separated into four sections:
This overview section will cover general architecture.
<br>
+
Glossary {#sdk_overview_glossary}
========
**AAF:** AVTP Audio Format
@@ -97,8 +98,6 @@ interface modules and mapping modules communicate.
**SRP:** Stream Reservation Protocol
-**OPENAVB:** Symphony Teleca Corporation
-
**Stream:** A series of AVTP data packets
**Talker:** Takes an audio or video source and transmits it as an AVTP stream on
@@ -106,6 +105,7 @@ the AVB network. It consists of a dedicated task and uses functionality in the
AVTP module, one mapping module and one interface module.
<br>
+
Architecture {#sdk_overview_architecture}
============
@@ -117,6 +117,7 @@ What follows in this section are details that more directly effect the use and
understanding of the SDK.
<br>
+
Below is the component diagram of the Core AVB stack. Notice that the interface
modules are not shown as part of the formal core stack but instead the
interfaces that they use in the core stack are shown. This is also true for the
@@ -126,6 +127,7 @@ interfaces the host application will use (TL APIs).
@image latex Core_AVB.png "Core AVB" width=15cm
<br>
+
General Purpose OSes will generally have the core AVB stack split across
multiple processes. Whereas in an RTOS everything sits within a single execution
image. Here is a process diagram of the components split across processes in the
@@ -135,18 +137,20 @@ Linux reference implementation.
@image latex fig1.png "AVB Components" width=15cm
As shown above the AVTP component of AVB is present in the application task.
-The libopenavbAVBStack library gets initialized and loaded via the APIs exposed and
+The AVB stack library gets initialized and loaded via the APIs exposed and
documented here. This static library implements that AVTP functionality as well
as controlling talker and listener initialization and life cycle. The PTP task
initialization is handled during stack initialization.
<br>
+
The common AVTP stream data flow is shown here.
@image html AVTP_Data_Flow.png "AVTP Data Flow"
@image latex AVTP_Data_Flow.png "AVPT Data Flow" width=15cm
<br>
+
The diagram below shows an audio stream flowing through the AVB system on the
Linux platform. Typically the talker and listener will be in different tasks and
may use different interfaces.
@@ -155,6 +159,7 @@ may use different interfaces.
@image latex fig2.png "AVB Audio Stream Flow" width=15cm
<br>
+
Understanding the stream life-cycle is important for use of this SDK. Below are
sequence diagrams that show the component interaction for key stream use cases.
@@ -162,14 +167,17 @@ sequence diagrams that show the component interaction for key stream use cases.
@image latex Stream_Initialize.png "Stream Initialization" width=15cm
<br>
+
@image html Talker_Stream_Data_Flow.png "Talker Stream Data Flow"
@image latex Talker_Stream_Data_Flow.png "Talker Stream Data Flow" width=15cm
<br>
+
@image html Listener_Stream_Data_Flow.png "Listener Stream Data Flow"
@image latex Listener_Stream_Data_Flow.png "Listener Stream Data Flow" width=15cm
<br>
+
Integration, Extension and Configuration {#sdk_overview_integration}
========================================
Three distinct uses of the SDK are as follows.
@@ -195,6 +203,7 @@ area of configuration is related to stream. See the section [AVTP Stream
Configuration](@ref sdk_avtp_stream_cfg) for more details.
<br>
+
Platform Specific Considerations {#sdk_overview_platform}
================================
The OPENAVB AVB stack is designed for portability covering both general purpose OSes
diff --git a/lib/avtp_pipeline/endpoint/CMakeLists.txt b/lib/avtp_pipeline/endpoint/CMakeLists.txt
index 5960d371..348b904d 100644
--- a/lib/avtp_pipeline/endpoint/CMakeLists.txt
+++ b/lib/avtp_pipeline/endpoint/CMakeLists.txt
@@ -1,6 +1,10 @@
SET (SRC_FILES ${SRC_FILES}
${AVB_SRC_DIR}/endpoint/openavb_endpoint.c
${AVB_OSAL_DIR}/endpoint/openavb_endpoint_osal.c
+ ${AVB_OSAL_DIR}/endpoint/openavb_endpoint_osal_maap.c
+ ${AVB_OSAL_DIR}/endpoint/openavb_endpoint_osal_ptp.c
+ ${AVB_OSAL_DIR}/endpoint/openavb_endpoint_osal_shaper.c
+ ${AVB_OSAL_DIR}/endpoint/openavb_endpoint_osal_srp.c
${AVB_SRC_DIR}/endpoint/openavb_endpoint_server.c
${AVB_OSAL_DIR}/endpoint/openavb_endpoint_cfg.c
PARENT_SCOPE
diff --git a/lib/avtp_pipeline/endpoint/endpoint.ini b/lib/avtp_pipeline/endpoint/endpoint.ini
index 5138c661..aa69f13d 100644
--- a/lib/avtp_pipeline/endpoint/endpoint.ini
+++ b/lib/avtp_pipeline/endpoint/endpoint.ini
@@ -35,6 +35,35 @@ start_options = -u 60
# mode is AVB_SHAPER_SW.
#mode = 4
+[maap]
+
+# The endpoint can use the MAAP daemon to allocate a multicast address for
+# each stream, using the dest_addr value from the Talker configuration file
+# only as a backup in case the MAAP daemon is not available.
+# Set port to the localhost port used by the MAAP daemon if MAAP support is
+# desired.
+# If port is 0 (the default value), then the MAAP daemon is not used and the
+# endpoint always uses the dest_addr value.
+# Note that if the MAAP daemon is not available, and a dest_addr value is not
+# specified, then an address from beginning of the MAAP locally administered
+# Pool will be used. Due to the high likelihood of address conflicts,
+# relying on this backup method is not recommended.
+port=15364
+
+[shaper]
+
+# The endpoint can use the Shaper daemon to smooth the transmission of packets.
+# This is useful for situations where the batch_factor value in the Talker INI
+# file is set to a value greater than 1, and multiple frames are being
+# generated during the same callback. The batch_factor and Shaper daemon are
+# useful for situations where the CPU load needs to be reduced or callback
+# timing for the frame generation functions is unreliable.
+# Set port to the localhost port used by the Shaper daemon if Shaper support is
+# desired.
+# If port is 0 (the default value), then the Shaper daemon is not used and the
+# endpoint frames are transmitted at the time they are generated.
+#port=15365
+
[srp]
# To disable dynamic SRP operation in the case of manually preconfigured streams
diff --git a/lib/avtp_pipeline/endpoint/openavb_endpoint.c b/lib/avtp_pipeline/endpoint/openavb_endpoint.c
index 5a4dfe17..30d8114a 100644
--- a/lib/avtp_pipeline/endpoint/openavb_endpoint.c
+++ b/lib/avtp_pipeline/endpoint/openavb_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.
*************************************************************************************************************/
@@ -33,7 +34,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
* It includes the SRP and QMgr libraries which handle SRP reservations
* and TX queuing.
*
-* The actual AVTP talker/listener work is done in a separate processs.
+* The actual AVTP talker/listener work is done in a separate process.
* The aim of using separate processes is to (1) reduce the
* complexity in the central process; and (2) to allow multiple types
* of children for different AVTP encapsulations and data sources.
@@ -59,6 +60,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_avtp.h"
#include "openavb_qmgr.h"
#include "openavb_maap.h"
+#include "openavb_shaper.h"
#define AVB_LOG_COMPONENT "Endpoint"
#include "openavb_pub.h"
@@ -72,7 +74,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
clientStream_t* x_streamList;
// true until we are signalled to stop
bool endpointRunning = TRUE;
-// data from our configuation file
+// data from our configuration file
openavb_endpoint_cfg_t x_cfg;
/*************************************************************
@@ -135,7 +137,7 @@ clientStream_t* addStream(int h, AVBStreamID_t *streamID)
newClientStream->streamID.uniqueID = streamID->uniqueID;
newClientStream->clientHandle = h;
newClientStream->fwmark = INVALID_FWMARK;
-
+
if(x_streamList == NULL) {
x_streamList = newClientStream;
}else {
@@ -213,7 +215,7 @@ static clientStream_t* findStreamMaap(void* hndMaap)
{
AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
clientStream_t* ps = NULL;
-
+
clientStream_t **lpp;
for(lpp = &x_streamList; *lpp != NULL; lpp = &(*lpp)->next) {
if ((*lpp)->hndMaap == hndMaap)
@@ -229,7 +231,7 @@ static clientStream_t* findStreamMaap(void* hndMaap)
/*************************************************************
*
* Internal function to cleanup streams
- *
+ *
*/
bool x_talkerDeregister(clientStream_t *ps)
{
@@ -253,7 +255,13 @@ bool x_talkerDeregister(clientStream_t *ps)
openavbMaapRelease(ps->hndMaap);
ps->hndMaap = NULL;
}
-
+
+ // Finish Shaping
+ if (ps->hndShaper) {
+ openavbShaperRelease(ps->hndShaper);
+ ps->hndShaper = NULL;
+ }
+
// remove record
delStream(ps);
@@ -304,7 +312,7 @@ openavbRC strmAttachCb(void* pv,
|| lsnrDecl == openavbSrp_LDSt_Ready_Failed)
{
// Somebody is listening - get ready to stream
-
+
if (ps->fwmark != INVALID_FWMARK) {
AVB_LOG_DEBUG("attach callback: already setup queues");
rc = OPENAVB_SUCCESS;
@@ -346,6 +354,7 @@ openavbRC strmAttachCb(void* pv,
x_cfg.ifname,
ps->destAddr,
lsnrDecl,
+ ps->srClass,
ps->classRate,
ps->vlanID,
ps->priority,
@@ -397,7 +406,7 @@ openavbRC strmRegCb(void *pv,
*
* A better way to handle this would require SRP and the
* talkers/listeners to look at destination addresses (in addition
- * to StreamID and talker/listner declaration) and explicitly handle
+ * to StreamID and talker/listener declaration) and explicitly handle
* destination address changes.
*/
static void maapRestartCallback(void* handle, struct ether_addr *addr)
@@ -449,7 +458,7 @@ int avbEndpointLoop(void)
do {
if (!x_cfg.bypassAsCapableCheck && (startPTP() < 0)) {
- // make sure ptp, a seperate process, starts and is using the same interface as endpoint
+ // make sure ptp, a separate process, starts and is using the same interface as endpoint
AVB_LOG_ERROR("PTP failed to start - Exiting");
break;
} else if(x_cfg.bypassAsCapableCheck) {
@@ -457,7 +466,7 @@ int avbEndpointLoop(void)
AVB_LOG_WARNING("Configuration 'gptp_asCapable_not_required = 1' is set.");
AVB_LOG_WARNING("This configuration bypasses the requirement for gPTP");
AVB_LOG_WARNING("and openavb_gptp is not started automatically.");
- AVB_LOG_WARNING("An appropriate ptp MUST be started seperately.");
+ AVB_LOG_WARNING("An appropriate ptp MUST be started separately.");
AVB_LOG_WARNING("Any network which does not use ptp to synchronize time");
AVB_LOG_WARNING("on each and every network device is NOT an AVB network.");
AVB_LOG_WARNING("Such a network WILL NOT FUNCTION PROPERLY.");
@@ -471,12 +480,19 @@ int avbEndpointLoop(void)
break;
}
- if (!openavbMaapInitialize(x_cfg.ifname, maapRestartCallback)) {
+ if (!openavbMaapInitialize(x_cfg.ifname, x_cfg.maapPort, &(x_cfg.maap_preferred), maapRestartCallback)) {
AVB_LOG_ERROR("Failed to initialize MAAP");
openavbQmgrFinalize();
break;
}
+ if (!openavbShaperInitialize(x_cfg.ifname, x_cfg.shaperPort)) {
+ AVB_LOG_ERROR("Failed to initialize Shaper");
+ openavbMaapFinalize();
+ openavbQmgrFinalize();
+ break;
+ }
+
if(!x_cfg.noSrp) {
// Initialize SRP
rc = openavbSrpInitialize(strmAttachCb, strmRegCb, x_cfg.ifname, x_cfg.link_kbit, x_cfg.bypassAsCapableCheck);
@@ -493,6 +509,7 @@ int avbEndpointLoop(void)
if (!IS_OPENAVB_SUCCESS(rc)) {
AVB_LOG_ERROR("Failed to initialize SRP");
+ openavbShaperFinalize();
openavbMaapFinalize();
openavbQmgrFinalize();
break;
@@ -500,23 +517,24 @@ int avbEndpointLoop(void)
if (openavbEndpointServerOpen()) {
+ retVal = 0;
+
while (endpointRunning) {
openavbEptSrvrService();
}
openavbEndpointServerClose();
}
-
+
if(!x_cfg.noSrp) {
// Shutdown SRP
openavbSrpShutdown();
}
+ openavbShaperFinalize();
openavbMaapFinalize();
openavbQmgrFinalize();
- retVal = 0;
-
} while (0);
if (!x_cfg.bypassAsCapableCheck && (stopPTP() < 0)) {
diff --git a/lib/avtp_pipeline/endpoint/openavb_endpoint.h b/lib/avtp_pipeline/endpoint/openavb_endpoint.h
index a807eba8..a3f82078 100644
--- a/lib/avtp_pipeline/endpoint/openavb_endpoint.h
+++ b/lib/avtp_pipeline/endpoint/openavb_endpoint.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.
*************************************************************************************************************/
@@ -74,10 +75,12 @@ typedef enum {
//////////////////////////////
typedef struct {
U8 destAddr[ETH_ALEN];
+ U8 noMaapAllocate;
AVBTSpec_t tSpec;
U8 srClass;
U8 srRank;
U32 latency;
+ U32 txRate;
} openavbEndpointParams_TalkerRegister_t;
typedef struct {
@@ -94,9 +97,10 @@ typedef struct {
// Server messages parameters
//////////////////////////////
typedef struct {
- char ifname[IFNAMSIZ];
- U8 destAddr[ETH_ALEN];
+ char ifname[IFNAMSIZ + 10]; // Include space for the socket type prefix (e.g. "simple:eth0")
+ U8 destAddr[ETH_ALEN];
openavbSrpLsnrDeclSubtype_t lsnrDecl;
+ U8 srClass;
U32 classRate;
U16 vlanID;
U8 priority;
@@ -105,13 +109,13 @@ typedef struct {
typedef struct {
openavbSrpAttribType_t tlkrDecl;
- char ifname[IFNAMSIZ];
+ char ifname[IFNAMSIZ + 10]; // Include space for the socket type prefix (e.g. "simple:eth0")
U8 destAddr[ETH_ALEN];
AVBTSpec_t tSpec;
U8 srClass;
U32 latency;
openavbSrpFailInfo_t failInfo;
-} openavbEndpointParams_ListenerCallback_t;
+} openavbEndpointParams_ListenerCallback_t;
typedef struct {
U32 AVBVersion;
@@ -133,7 +137,8 @@ typedef struct clientStream_t {
SRClassIdx_t srClass; // AVB class
U8 srRank; // AVB rank
U32 latency; // internal latency
-
+ U32 txRate; // frames per second
+
// Information provided by SRP
U8 priority; // AVB priority to use for stream
U16 vlanID; // VLAN ID to use for stream
@@ -143,6 +148,9 @@ typedef struct clientStream_t {
void *hndMaap; // handle for MAAP address allocation
U8 destAddr[ETH_ALEN]; // destination MAC address (from config or MAAP)
+ // Information provided by Shaper
+ void *hndShaper; // handle for Shaping configuration
+
// Information provided by QMgr
int fwmark; // mark to identify packets of this stream
} clientStream_t;
@@ -203,17 +211,21 @@ void openavbEptClntCheckVerMatchesSrvr(int h, U32 AVBVersion);
bool openavbEptClntRegisterStream(int h,
AVBStreamID_t *streamID,
U8 destAddr[],
+ U8 noMaapAllocation,
AVBTSpec_t *tSpec,
U8 srClass,
U8 srRank,
- U32 latency);
+ U32 latency,
+ U32 txRate);
bool openavbEptSrvrRegisterStream(int h,
AVBStreamID_t *streamID,
U8 destAddr[],
+ U8 noMaapAllocation,
AVBTSpec_t *tSpec,
U8 srClass,
U8 srRank,
- U32 latency);
+ U32 latency,
+ U32 txRate);
// Each lister attaches to the stream it wants to receive;
// specifically the listener indicates interest / declaration to SRP.
@@ -233,6 +245,7 @@ void openavbEptSrvrNotifyTlkrOfSrpCb(int h,
char *ifname,
U8 destAddr[],
openavbSrpLsnrDeclSubtype_t lsnrDecl,
+ U8 srClass,
U32 classRate,
U16 vlanID,
U8 priority,
@@ -242,6 +255,7 @@ void openavbEptClntNotifyTlkrOfSrpCb(int h,
char *ifname,
U8 destAddr[],
openavbSrpLsnrDeclSubtype_t lsnrDecl,
+ U8 srClass,
U32 classRate,
U16 vlanID,
U8 priority,
@@ -270,8 +284,8 @@ void openavbEptClntNotifyLstnrOfSrpCb(int h,
// A talker can withdraw its stream registration at any time;
-// a listener can withdraw its stream attachement at any time;
-// in ether case, endpoint communication is from client to server
+// a listener can withdraw its stream attachment at any time;
+// in either case, endpoint communication is from client to server
bool openavbEptClntStopStream(int h, AVBStreamID_t *streamID);
bool openavbEptSrvrStopStream(int h, AVBStreamID_t *streamID);
diff --git a/lib/avtp_pipeline/endpoint/openavb_endpoint_client.c b/lib/avtp_pipeline/endpoint/openavb_endpoint_client.c
index 50cb3439..27d08cee 100644
--- a/lib/avtp_pipeline/endpoint/openavb_endpoint_client.c
+++ b/lib/avtp_pipeline/endpoint/openavb_endpoint_client.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,7 +37,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
* This code provides the means for them to do so.
*
* This source file is compiled into the streamer executable.
-*
+*
* It provides proxy functions for the streamer to call. The arguments
* for those calls are packed into messages, which are unpacked in the
* endpoint process and then used to call the real functions.
@@ -80,13 +81,14 @@ static bool openavbEptClntReceiveFromServer(int h, openavbEndpointMessage_t *msg
msg->params.talkerCallback.ifname,
msg->params.talkerCallback.destAddr,
msg->params.talkerCallback.lsnrDecl,
+ msg->params.talkerCallback.srClass,
msg->params.talkerCallback.classRate,
msg->params.talkerCallback.vlanID,
msg->params.talkerCallback.priority,
msg->params.talkerCallback.fwmark);
break;
case OPENAVB_ENDPOINT_LISTENER_CALLBACK:
- openavbEptClntNotifyLstnrOfSrpCb(h,
+ openavbEptClntNotifyLstnrOfSrpCb(h,
&msg->streamID,
msg->params.listenerCallback.ifname,
msg->params.listenerCallback.destAddr,
@@ -111,10 +113,12 @@ static bool openavbEptClntReceiveFromServer(int h, openavbEndpointMessage_t *msg
bool openavbEptClntRegisterStream(int h,
AVBStreamID_t *streamID,
U8 destAddr[],
+ U8 noMaapAllocate,
AVBTSpec_t *tSpec,
U8 srClass,
U8 srRank,
- U32 latency)
+ U32 latency,
+ U32 txRate)
{
AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
openavbEndpointMessage_t msgBuf;
@@ -129,13 +133,16 @@ bool openavbEptClntRegisterStream(int h,
memset(&msgBuf, 0, OPENAVB_ENDPOINT_MSG_LEN);
msgBuf.type = OPENAVB_ENDPOINT_TALKER_REGISTER;
memcpy(&(msgBuf.streamID), streamID, sizeof(AVBStreamID_t));
- if (destAddr)
+ if (destAddr) {
memcpy(msgBuf.params.talkerRegister.destAddr, destAddr, ETH_ALEN);
+ msgBuf.params.talkerRegister.noMaapAllocate = noMaapAllocate;
+ }
msgBuf.params.talkerRegister.tSpec.maxFrameSize = tSpec->maxFrameSize;
msgBuf.params.talkerRegister.tSpec.maxIntervalFrames = tSpec->maxIntervalFrames;
msgBuf.params.talkerRegister.srClass = srClass;
msgBuf.params.talkerRegister.srRank = srRank;
msgBuf.params.talkerRegister.latency = latency;
+ msgBuf.params.talkerRegister.txRate = txRate;
bool ret = openavbEptClntSendToServer(h, &msgBuf);
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
@@ -153,7 +160,7 @@ bool openavbEptClntAttachStream(int h, AVBStreamID_t *streamID,
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return FALSE;
}
-
+
memset(&msgBuf, 0, OPENAVB_ENDPOINT_MSG_LEN);
msgBuf.type = OPENAVB_ENDPOINT_LISTENER_ATTACH;
memcpy(&(msgBuf.streamID), streamID, sizeof(AVBStreamID_t));
@@ -183,7 +190,7 @@ bool openavbEptClntStopStream(int h, AVBStreamID_t *streamID)
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return ret;
}
-
+
bool openavbEptClntRequestVersionFromServer(int h)
{
AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
@@ -196,4 +203,4 @@ bool openavbEptClntRequestVersionFromServer(int h)
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return ret;
}
-
+
diff --git a/lib/avtp_pipeline/endpoint/openavb_endpoint_server.c b/lib/avtp_pipeline/endpoint/openavb_endpoint_server.c
index 5d3c535b..005d30d7 100644
--- a/lib/avtp_pipeline/endpoint/openavb_endpoint_server.c
+++ b/lib/avtp_pipeline/endpoint/openavb_endpoint_server.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.
*************************************************************************************************************/
@@ -35,7 +36,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
* "endpoint" process to create a reservation for their traffic.
*
* This code implements the endpoint (server) side of the IPC.
- *
+ *
* It provides proxy functions for the endpoint to call. The arguments
* for those calls are packed into messages, which are unpacked in the
* streamer processes and then used to call the real functions.
@@ -56,6 +57,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_log.h"
#include "openavb_qmgr.h" // for INVALID_FWMARK
#include "openavb_maap.h"
+#include "openavb_shaper.h"
// forward declarations
static bool openavbEptSrvrReceiveFromClient(int h, openavbEndpointMessage_t *msg);
@@ -76,17 +78,19 @@ static bool openavbEptSrvrReceiveFromClient(int h, openavbEndpointMessage_t *msg
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return FALSE;
}
-
+
bool ret = FALSE;
switch (msg->type) {
case OPENAVB_ENDPOINT_TALKER_REGISTER:
AVB_LOGF_DEBUG("TalkerRegister from client uid=%d", msg->streamID.uniqueID);
ret = openavbEptSrvrRegisterStream(h, &msg->streamID,
- msg->params.talkerRegister.destAddr,
- &msg->params.talkerRegister.tSpec,
- msg->params.talkerRegister.srClass,
- msg->params.talkerRegister.srRank,
- msg->params.talkerRegister.latency);
+ msg->params.talkerRegister.destAddr,
+ msg->params.talkerRegister.noMaapAllocate,
+ &msg->params.talkerRegister.tSpec,
+ msg->params.talkerRegister.srClass,
+ msg->params.talkerRegister.srRank,
+ msg->params.talkerRegister.latency,
+ msg->params.talkerRegister.txRate);
break;
case OPENAVB_ENDPOINT_LISTENER_ATTACH:
AVB_LOGF_DEBUG("ListenerAttach from client uid=%d", msg->streamID.uniqueID);
@@ -116,10 +120,11 @@ void openavbEptSrvrNotifyTlkrOfSrpCb(int h,
char *ifname,
U8 destAddr[ETH_ALEN],
openavbSrpLsnrDeclSubtype_t lsnrDecl,
+ U8 srClass,
U32 classRate,
U16 vlanID,
U8 priority,
- U16 fwmark)
+ U16 fwmark)
{
AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
openavbEndpointMessage_t msgBuf;
@@ -133,9 +138,10 @@ void openavbEptSrvrNotifyTlkrOfSrpCb(int h,
memset(&msgBuf, 0, OPENAVB_ENDPOINT_MSG_LEN);
msgBuf.type = OPENAVB_ENDPOINT_TALKER_CALLBACK;
memcpy(&(msgBuf.streamID), streamID, sizeof(AVBStreamID_t));
- strncpy(msgBuf.params.talkerCallback.ifname, ifname, IFNAMSIZ - 1);
+ strncpy(msgBuf.params.talkerCallback.ifname, ifname, sizeof(msgBuf.params.talkerCallback.ifname) - 1);
memcpy(msgBuf.params.talkerCallback.destAddr, destAddr, ETH_ALEN);
msgBuf.params.talkerCallback.lsnrDecl = lsnrDecl;
+ msgBuf.params.talkerCallback.srClass = srClass;
msgBuf.params.talkerCallback.classRate = classRate;
msgBuf.params.talkerCallback.vlanID = vlanID;
msgBuf.params.talkerCallback.priority = priority;
@@ -159,7 +165,7 @@ void openavbEptSrvrNotifyLstnrOfSrpCb(int h,
openavbEndpointMessage_t msgBuf;
// Check for valid parameters. DestAddr is optional and checked later.
- if (!streamID || !ifname) {
+ if (!streamID || !ifname) {
AVB_LOG_ERROR("Listener callback; invalid argument passed");
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return;
@@ -168,8 +174,8 @@ void openavbEptSrvrNotifyLstnrOfSrpCb(int h,
memset(&msgBuf, 0, OPENAVB_ENDPOINT_MSG_LEN);
msgBuf.type = OPENAVB_ENDPOINT_LISTENER_CALLBACK;
memcpy(&(msgBuf.streamID), streamID, sizeof(AVBStreamID_t));
- strncpy(msgBuf.params.listenerCallback.ifname, ifname, IFNAMSIZ - 1);
- if (destAddr)
+ strncpy(msgBuf.params.listenerCallback.ifname, ifname, sizeof(msgBuf.params.listenerCallback.ifname) - 1);
+ if (destAddr)
memcpy(msgBuf.params.listenerCallback.destAddr, destAddr, ETH_ALEN);
msgBuf.params.listenerCallback.tlkrDecl = tlkrDecl;
if (tSpec)
@@ -200,17 +206,19 @@ void openavbEptSrvrSendServerVersionToClient(int h, U32 AVBVersion)
bool openavbEptSrvrRegisterStream(int h,
AVBStreamID_t *streamID,
U8 destAddr[],
+ U8 noMaapAllocation,
AVBTSpec_t *tSpec,
U8 srClass,
U8 srRank,
- U32 latency)
+ U32 latency,
+ U32 txRate)
{
openavbRC rc = OPENAVB_SUCCESS;
AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
clientStream_t *ps = findStream(streamID);
-
+
if (ps && ps->clientHandle != h) {
AVB_LOGF_ERROR("Error registering talker; multiple clients for stream %d", streamID->uniqueID);
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
@@ -228,10 +236,12 @@ bool openavbEptSrvrRegisterStream(int h,
ps->srClass = (SRClassIdx_t)srClass;
ps->srRank = srRank;
ps->latency = latency;
+ ps->txRate = txRate;
ps->fwmark = INVALID_FWMARK;
- if (memcmp(ps->destAddr, destAddr, ETH_ALEN) == 0) {
- // no client-supplied address, use MAAP
+ // If MAAP is available, or no client-supplied address, allocate an address.
+ if ((!noMaapAllocation && openavbMaapDaemonAvailable()) ||
+ memcmp(ps->destAddr, destAddr, ETH_ALEN) == 0) {
struct ether_addr addr;
ps->hndMaap = openavbMaapAllocate(1, &addr);
if (ps->hndMaap) {
@@ -251,11 +261,24 @@ bool openavbEptSrvrRegisterStream(int h,
ps->hndMaap = NULL;
}
+ // If the Shaper is available, enable it.
+ if (openavbShaperDaemonAvailable() && ps->txRate) {
+ ps->hndShaper = openavbShaperHandle(
+ ps->srClass,
+ MICROSECONDS_PER_SECOND / ps->txRate, /* Note that division rounds down, which is what we want. */
+ tSpec->maxFrameSize + 18 /* Header size */,
+ 1,
+ ps->destAddr);
+ if (!ps->hndShaper) {
+ AVB_LOG_ERROR("Unable to start Shaping");
+ }
+ }
+
// Do SRP talker register
- AVB_LOGF_DEBUG("REGISTER: ps=%p, streamID=%d, tspec=%d,%d, srClass=%d, srRank=%d, latency=%d, da="ETH_FORMAT"",
+ AVB_LOGF_DEBUG("REGISTER: ps=%p, streamID=%d, tspec=%d,%d, srClass=%d, srRank=%d, latency=%d, tsRate=%d, da="ETH_FORMAT"",
ps, streamID->uniqueID,
tSpec->maxFrameSize, tSpec->maxIntervalFrames,
- ps->srClass, ps->srRank, ps->latency,
+ ps->srClass, ps->srRank, ps->latency, ps->txRate,
ETH_OCTETS(ps->destAddr));
@@ -273,12 +296,14 @@ bool openavbEptSrvrRegisterStream(int h,
if (!IS_OPENAVB_SUCCESS(rc)) {
if (ps->hndMaap)
openavbMaapRelease(ps->hndMaap);
+ if (ps->hndShaper)
+ openavbShaperRelease(ps->hndShaper);
delStream(ps);
}
}
openavbEndPtLogAllStaticStreams();
-
+
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return IS_OPENAVB_SUCCESS(rc);
}
@@ -372,7 +397,7 @@ bool openavbEptSrvrHndlVerRqstFromClient(int h)
return TRUE;
}
-/* Called if a client closes their end of the IPC
+/* Called if a client closes their end of the IPC
*/
void openavbEptSrvrCloseClientConnection(int h)
{
diff --git a/lib/avtp_pipeline/include/avb_sched.h b/lib/avtp_pipeline/include/avb_sched.h
index a4c7106c..5eaa3e81 100644
--- a/lib/avtp_pipeline/include/avb_sched.h
+++ b/lib/avtp_pipeline/include/avb_sched.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/include/openavb_audio_pub.h b/lib/avtp_pipeline/include/openavb_audio_pub.h
index 769481ff..1e50d45a 100644
--- a/lib/avtp_pipeline/include/openavb_audio_pub.h
+++ b/lib/avtp_pipeline/include/openavb_audio_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.
*************************************************************************************************************/
@@ -50,6 +51,8 @@ typedef enum {
AVB_AUDIO_RATE_16KHZ = 16000,
/// 22050
AVB_AUDIO_RATE_22_05KHZ = 22050,
+ /// 24000
+ AVB_AUDIO_RATE_24KHZ = 24000,
/// 32000
AVB_AUDIO_RATE_32KHZ = 32000,
/// 44100
diff --git a/lib/avtp_pipeline/include/openavb_intf_pub.h b/lib/avtp_pipeline/include/openavb_intf_pub.h
index 5b57c033..fea0ffb1 100755
--- a/lib/avtp_pipeline/include/openavb_intf_pub.h
+++ b/lib/avtp_pipeline/include/openavb_intf_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
@@ -65,20 +66,6 @@ typedef void (*openavb_intf_cfg_cb_t)(media_q_t *pMediaQ, const char *name, cons
*/
typedef void (*openavb_intf_gen_init_cb_t)(media_q_t *pMediaQ);
-/** AVDECC initialize callback for both a talker or listener.
- *
- * Entity model based configuration can be processed at this time.
- * This callback is optional and only executed when AVDECC is used to connect
- * streams.
- *
- * \param pMediaQ A pointer to the media queue for this stream
- * \param configIdx current configuration descriptor index for the Entity Model
- * \param descriptorType The descriptorType is expected to be of STREAM_INPUT
- * for listeners and STREAM_OUTPUT for talkers.
- * \param descriptorIdx descriptor index in the Entity Model
- */
-typedef void (*openavb_intf_avdecc_init_cb_t)(media_q_t *pMediaQ, U16 configIdx, U16 descriptorType, U16 descriptorIdx);
-
/** Initialize transmit callback into the interface module.
*
* This callback function is called anytime a stream reservation has completed
@@ -170,6 +157,15 @@ typedef void (*openavb_intf_gen_end_cb_t)(media_q_t *pMediaQ);
*/
typedef unsigned int (*openavb_intf_get_src_bitrate_t)(media_q_t *pMediaQ);
+/** Inform interface about stream_uid.
+ *
+ * Will be used for logging to distinguish information logged from different streams
+ * using the same interface.
+ * \param pMediaQ A pointer to the media queue for this stream
+ * \param stream_uid stream unique ID (last two bytes of streamID)
+ */
+typedef void (*openavb_intf_set_stream_uid_t)(media_q_t *pMediaQ, U16 stream_uid);
+
/** Enable fixed timestamping in interface.
*
* Everytime interface needs to set media_q_item_t.pAvtpTime it calls openavbAvtpTimeSetToWallTime() to set.
@@ -199,8 +195,6 @@ typedef struct {
openavb_intf_cfg_cb_t intf_cfg_cb;
/// General initialize callback.
openavb_intf_gen_init_cb_t intf_gen_init_cb;
- /// AVDECC initialize callback.
- openavb_intf_avdecc_init_cb_t intf_avdecc_init_cb;
/// Initialize transmit callback.
openavb_intf_tx_init_cb_t intf_tx_init_cb;
/// Transmit callback.
@@ -219,6 +213,8 @@ typedef struct {
void * intf_host_cb_list;
/// Source bit rate callback.
openavb_intf_get_src_bitrate_t intf_get_src_bitrate_cb;
+ /// Callback for setting stream uid
+ openavb_intf_set_stream_uid_t intf_set_stream_uid_cb;
/// Enable fixed timestamp callback
openavb_intf_enable_fixed_timestamp intf_enable_fixed_timestamp;
} openavb_intf_cb_t;
diff --git a/lib/avtp_pipeline/include/openavb_log.h b/lib/avtp_pipeline/include/openavb_log.h
index d5069111..fbcc91f2 100644
--- a/lib/avtp_pipeline/include/openavb_log.h
+++ b/lib/avtp_pipeline/include/openavb_log.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/include/openavb_log_pub.h b/lib/avtp_pipeline/include/openavb_log_pub.h
index 9ae5f1e0..846c169e 100644
--- a/lib/avtp_pipeline/include/openavb_log_pub.h
+++ b/lib/avtp_pipeline/include/openavb_log_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,16 +22,16 @@ 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 : A simple logging facility for use during
-* development.
+* development.
*/
#ifndef OPENAVB_LOG_PUB_H
@@ -122,11 +123,11 @@ static const bool OPENAVB_LOG_THREAD_INFO = FALSE;
//#define AVB_LOG_OUTPUT_FD stdout
// When OPENAVB_LOG_FROM_THREAD the message output will be output from a separate thread/task
-// Primary intended use is for debugging.
+// Primary intended use is for debugging.
// It is expected that OPENAVB_LOG_PULL_MODE will not be used at the same time as this optoin.
static const bool OPENAVB_LOG_FROM_THREAD = TRUE;
-// When OPENAVB_LOG_PULL_MODE the messages will be queued and can be pulled using the
+// When OPENAVB_LOG_PULL_MODE the messages will be queued and can be pulled using the
// avbLogGetMsg() call. This could be from an logger interface module or host application.
// It is expected that OPENAVB_LOG_FROM_THREAD will not be used at the same time as this option.
static const bool OPENAVB_LOG_PULL_MODE = FALSE;
@@ -159,19 +160,24 @@ typedef enum {
#define LOG_VARX(x, y) x ## y
#define LOG_VAR(x, y) LOG_VARX(x, y)
-// Log a message once. Technically once every 4.2 billion attempts. Usage: LOG_ONCE AVB_LOG_INFO(...)
-#define IF_LOG_ONCE() static U32 LOG_VAR(logOnce,__LINE__); if (!LOG_VAR(logOnce,__LINE__)++)
+// Log a message once. Technically once every 4.2 billion attempts. Usage: IF_LOG_ONCE() AVB_LOG_INFO(...)
+#define IF_LOG_ONCE() static U32 LOG_VAR(logOnce,__LINE__) = 0; if (!LOG_VAR(logOnce,__LINE__)++)
-// Log a message at an interval. Usage: LOG_INTERVAL(100) AVB_LOG_INFO(...)
-#define IF_LOG_INTERVAL(x) static U32 LOG_VAR(logOnce,__LINE__); if (!(LOG_VAR(logOnce,__LINE__)++ % (x - 1)))
+// Log a message at an interval. Usage: IF_LOG_INTERVAL(100) AVB_LOG_INFO(...)
+#define IF_LOG_INTERVAL(x) static U32 LOG_VAR(logOnce,__LINE__) = 0; if (!(LOG_VAR(logOnce,__LINE__)++ % (x)))
#define ETH_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x"
#define ETH_OCTETS(a) (a)[0],(a)[1],(a)[2],(a)[3],(a)[4],(a)[5]
-#define STREAMID_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x/%d"
+#define STREAMID_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x/%u"
#define STREAMID_ARGS(s) (s)->addr[0],(s)->addr[1],(s)->addr[2],(s)->addr[3],(s)->addr[4],(s)->addr[5],(s)->uniqueID
+#define ENTITYID_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
+#define ENTITYID_ARGS(a) (a)[0],(a)[1],(a)[2],(a)[3],(a)[4],(a)[5],(a)[6],(a)[7]
+
+void avbLogInitEx(FILE *file);
+
void avbLogInit(void);
void avbLogExit(void);
@@ -188,12 +194,34 @@ void avbLogFn(
void avbLogRT(int level, bool bBegin, bool bItem, bool bEnd, char *pFormat, log_rt_datatype_t dataType, void *pVar);
+void avbLogBuffer(
+ int level,
+ const U8 *pData,
+ int dataLen,
+ int lineLen,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line);
+
#define avbLogFn2(level, tag, company, component, path, line, fmt, ...) \
- ({\
+ {\
if (level <= AVB_LOG_LEVEL) \
avbLogFn(0, tag, company, component, path, line, fmt, __VA_ARGS__); \
- })
+ }
+
+#define avbLogRT2(level, bBegin, bItem, bEnd, pFormat, dataType, pVar) \
+ {\
+ if (level <= AVB_LOG_LEVEL) \
+ avbLogRT(0, bBegin, bItem, bEnd, pFormat, dataType, pVar); \
+ }
+
+#define avbLogBuffer2(level, pData, dataLen, lineLen, company, component, path, line) \
+ {\
+ if (level <= AVB_LOG_LEVEL) \
+ avbLogBuffer(0, pData, dataLen, lineLen, company, component, path, line); \
+ }
#ifdef AVB_LOG_ON
#define AVB_LOGF_DEV(LEVEL, FMT, ...) avbLogFn2(LEVEL, "DEV", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
@@ -203,19 +231,20 @@ void avbLogRT(int level, bool bBegin, bool bItem, bool bEnd, char *pFormat, log_
#define AVB_LOGF_STATUS(FMT, ...) avbLogFn2(AVB_LOG_LEVEL_STATUS, "STATUS", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
#define AVB_LOGF_DEBUG(FMT, ...) avbLogFn2(AVB_LOG_LEVEL_DEBUG, "DEBUG", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
#define AVB_LOGF_VERBOSE(FMT, ...) avbLogFn2(AVB_LOG_LEVEL_VERBOSE, "VERBOSE", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
-#define AVB_LOG_DEV(LEVEL, FMT, ...) avbLogFn2(LEVEL, "DEV", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define AVB_LOG_DEV(LEVEL, MSG) avbLogFn2(LEVEL, "DEV", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
#define AVB_LOG_ERROR(MSG) avbLogFn2(AVB_LOG_LEVEL_ERROR, "ERROR", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
#define AVB_LOG_WARNING(MSG) avbLogFn2(AVB_LOG_LEVEL_WARNING, "WARNING", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
#define AVB_LOG_INFO(MSG) avbLogFn2(AVB_LOG_LEVEL_INFO, "INFO", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
#define AVB_LOG_STATUS(MSG) avbLogFn2(AVB_LOG_LEVEL_STATUS, "STATUS", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
#define AVB_LOG_DEBUG(MSG) avbLogFn2(AVB_LOG_LEVEL_DEBUG, "DEBUG", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
#define AVB_LOG_VERBOSE(MSG) avbLogFn2(AVB_LOG_LEVEL_VERBOSE, "VERBOSE", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
-#define AVB_LOGRT_ERROR(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT(AVB_LOG_LEVEL_ERROR, BEGIN, ITEM, END, FMT, TYPE, VAL)
-#define AVB_LOGRT_WARNING(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT(AVB_LOG_LEVEL_WARNING, BEGIN, ITEM, END, FMT, TYPE, VAL)
-#define AVB_LOGRT_INFO(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT(AVB_LOG_LEVEL_INFO, BEGIN, ITEM, END, FMT, TYPE, VAL)
-#define AVB_LOGRT_STATUS(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT(AVB_LOG_LEVEL_STATUS, BEGIN, ITEM, END, FMT, TYPE, VAL)
-#define AVB_LOGRT_DEBUG(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT(AVB_LOG_LEVEL_DEBUG, BEGIN, ITEM, END, FMT, TYPE, VAL)
-#define AVB_LOGRT_VERBOSE(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT(AVB_LOG_LEVEL_VERBOSE, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOGRT_ERROR(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT2(AVB_LOG_LEVEL_ERROR, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOGRT_WARNING(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT2(AVB_LOG_LEVEL_WARNING, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOGRT_INFO(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT2(AVB_LOG_LEVEL_INFO, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOGRT_STATUS(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT2(AVB_LOG_LEVEL_STATUS, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOGRT_DEBUG(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT2(AVB_LOG_LEVEL_DEBUG, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOGRT_VERBOSE(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT2(AVB_LOG_LEVEL_VERBOSE, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOG_BUFFER(LEVEL, DATA, DATALEN, LINELINE) avbLogBuffer2(LEVEL, DATA, DATALEN, LINELINE, AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__)
#else
#define AVB_LOGF_DEV(LEVEL, FMT, ...)
#define AVB_LOGF_ERROR(FMT, ...)
@@ -237,9 +266,10 @@ void avbLogRT(int level, bool bBegin, bool bItem, bool bEnd, char *pFormat, log_
#define AVB_LOGRT_STATUS(BEGIN, ITEM, END, FMT, TYPE, VAL)
#define AVB_LOGRT_DEBUG(BEGIN, ITEM, END, FMT, TYPE, VAL)
#define AVB_LOGRT_VERBOSE(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOG_BUFFER(LEVEL, DATA, DATALEN, LINELINE)
#endif // AVB_LOG_ON
-// Get a queued log message. Intended to be used with the OPENAVB_LOG_PULL_MODE option.
+// Get a queued log message. Intended to be used with the OPENAVB_LOG_PULL_MODE option.
// Message will not be null terminated.
U32 avbLogGetMsg(U8 *pBuf, U32 bufSize);
diff --git a/lib/avtp_pipeline/include/openavb_map_pub.h b/lib/avtp_pipeline/include/openavb_map_pub.h
index ff5e2a72..02a58957 100755
--- a/lib/avtp_pipeline/include/openavb_map_pub.h
+++ b/lib/avtp_pipeline/include/openavb_map_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
@@ -103,22 +104,6 @@ typedef U32(*openavb_map_transmit_interval_cb_t)(media_q_t *pMediaQ);
*/
typedef void (*openavb_map_gen_init_cb_t)(media_q_t *pMediaQ);
-/** AVDECC initialize callback for both a talker or listener.
- *
- * Entity model based configuration can be processed at this time. This
- * callback is optional and only executed when AVDECC is used to connect
- * streams. The descriptorType is expected to be of STREAM_INPUT for listeners
- * and STREAM_OUTPUT for talkers.
- *
- * \param pMediaQ A pointer to the media queue for this stream
- * \param configIdx current configuration descriptor index for the Entity Model
- * \param descriptorType The descriptorType is expected to be of STREAM_INPUT
- * for listeners and STREAM_OUTPUT for talkers.
- * \param descriptorIdx descriptor index in the Entity Model
- * \see openavb_intf_avdecc_init_cb_t
- */
-typedef void (*openavb_map_avdecc_init_cb_t)(media_q_t *pMediaQ, U16 configIdx, U16 descriptorType, U16 descriptorIdx);
-
/** A call to this callback indicates that this mapping module will be a talker.
*
* Any talker initialization can be done in this function.
@@ -207,8 +192,6 @@ typedef struct {
openavb_map_transmit_interval_cb_t map_transmit_interval_cb;
/// General initialize callback.
openavb_map_gen_init_cb_t map_gen_init_cb;
- /// AVDECC initialize callback.
- openavb_map_avdecc_init_cb_t map_avdecc_init_cb;
/// Initialize transmit callback.
openavb_map_tx_init_cb_t map_tx_init_cb;
/// Transmit callback.
diff --git a/lib/avtp_pipeline/include/openavb_platform.h b/lib/avtp_pipeline/include/openavb_platform.h
index fb079d51..52a222ec 100644
--- a/lib/avtp_pipeline/include/openavb_platform.h
+++ b/lib/avtp_pipeline/include/openavb_platform.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/include/openavb_platform_pub.h b/lib/avtp_pipeline/include/openavb_platform_pub.h
index 8be98866..1d91cc5b 100644
--- a/lib/avtp_pipeline/include/openavb_platform_pub.h
+++ b/lib/avtp_pipeline/include/openavb_platform_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
diff --git a/lib/avtp_pipeline/include/openavb_pub.h b/lib/avtp_pipeline/include/openavb_pub.h
index 1f67f10e..9e530cef 100644
--- a/lib/avtp_pipeline/include/openavb_pub.h
+++ b/lib/avtp_pipeline/include/openavb_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,13 +43,15 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
//
// These must NOT be edited for project related work
/////////////////////////////////////////////////////////
-#define AVB_CORE_NAME "AVTP Pipeline"
+#if defined(AVB_FEATURE_AVDECC) && (AVB_FEATURE_AVDECC)
+ #define AVB_CORE_NAME "AVTP AVDECC"
+#else
+ #define AVB_CORE_NAME "AVTP Pipeline"
+#endif
#define AVB_CORE_VER_MAJOR (0)
#define AVB_CORE_VER_MINOR (1)
-#define AVB_CORE_VER_REVISION (0)
-
-#define AVB_CORE_VER_FULL (AVB_CORE_VER_MAJOR << 16 | AVB_CORE_VER_MINOR << 8 | AVB_CORE_VER_REVISION)
+#define AVB_CORE_VER_REVISION (3)
// Standard release designations. Uncomment one AVB_RELEASE_TYPE
#define AVB_CORE_RELEASE_TYPE "Development"
@@ -56,6 +59,8 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
//#define AVB_CORE_RELEASE_TYPE "Beta"
//#define AVB_CORE_RELEASE_TYPE "Release"
+#define AVB_CORE_VER_FULL (AVB_CORE_VER_MAJOR << 16 | AVB_CORE_VER_MINOR << 8 | AVB_CORE_VER_REVISION)
+
#define LOG_EAVB_CORE_VERSION() AVB_LOGF_INFO("%s: %i.%i.%i (%s)", AVB_CORE_NAME, AVB_CORE_VER_MAJOR, AVB_CORE_VER_MINOR, AVB_CORE_VER_REVISION, AVB_CORE_RELEASE_TYPE)
diff --git a/lib/avtp_pipeline/include/openavb_trace.h b/lib/avtp_pipeline/include/openavb_trace.h
index fd58cde6..759d55ae 100644
--- a/lib/avtp_pipeline/include/openavb_trace.h
+++ b/lib/avtp_pipeline/include/openavb_trace.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/include/openavb_trace_pub.h b/lib/avtp_pipeline/include/openavb_trace_pub.h
index c90a83d3..c5ba1ac6 100644
--- a/lib/avtp_pipeline/include/openavb_trace_pub.h
+++ b/lib/avtp_pipeline/include/openavb_trace_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
diff --git a/lib/avtp_pipeline/include/openavb_types.h b/lib/avtp_pipeline/include/openavb_types.h
index c042c24c..9a33fc4d 100644
--- a/lib/avtp_pipeline/include/openavb_types.h
+++ b/lib/avtp_pipeline/include/openavb_types.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/include/openavb_types_base.h b/lib/avtp_pipeline/include/openavb_types_base.h
index 1a3e2628..1edf2d0d 100644
--- a/lib/avtp_pipeline/include/openavb_types_base.h
+++ b/lib/avtp_pipeline/include/openavb_types_base.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/include/openavb_types_base_pub.h b/lib/avtp_pipeline/include/openavb_types_base_pub.h
index 1d03e80a..4f86364a 100644
--- a/lib/avtp_pipeline/include/openavb_types_base_pub.h
+++ b/lib/avtp_pipeline/include/openavb_types_base_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
diff --git a/lib/avtp_pipeline/include/openavb_types_pub.h b/lib/avtp_pipeline/include/openavb_types_pub.h
index 02e61466..da58b211 100644
--- a/lib/avtp_pipeline/include/openavb_types_pub.h
+++ b/lib/avtp_pipeline/include/openavb_types_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
diff --git a/lib/avtp_pipeline/inih/ini.c b/lib/avtp_pipeline/inih/ini.c
index 0f32fa56..d38006c9 100644
--- a/lib/avtp_pipeline/inih/ini.c
+++ b/lib/avtp_pipeline/inih/ini.c
@@ -79,6 +79,7 @@ int ini_parse_file(FILE* file,
char* value;
int lineno = 0;
int error = 0;
+ int value_quoted = 0;
#if !INI_USE_STACK
line = (char*)malloc(INI_MAX_LINE);
@@ -140,9 +141,18 @@ int ini_parse_file(FILE* file,
*end = '\0';
rstrip(value);
+ /* If the value starts and ends with a quote character, extract the string from inside the quotes. */
+ if (value[0] == '\"') {
+ char *end_quote = strchr(value + 1, '\"');
+ if (end_quote) {
+ *end_quote = '\0';
+ value_quoted = 1;
+ }
+ }
+
/* Valid name[=:]value pair found, call handler */
strncpy0(prev_name, name, sizeof(prev_name));
- if (!handler(user, section, name, value) && !error)
+ if (!handler(user, section, name, (value_quoted ? value + 1 : value)) && !error)
error = lineno;
}
else if (!error) {
diff --git a/lib/avtp_pipeline/intf_ctrl/ctrl_listener.ini b/lib/avtp_pipeline/intf_ctrl/ctrl_listener.ini
index 08c509a5..1ba2b6ba 100644
--- a/lib/avtp_pipeline/intf_ctrl/ctrl_listener.ini
+++ b/lib/avtp_pipeline/intf_ctrl/ctrl_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/intf_ctrl/ctrl_mux_listener.ini b/lib/avtp_pipeline/intf_ctrl/ctrl_mux_listener.ini
index 19d6be55..1c01df87 100644
--- a/lib/avtp_pipeline/intf_ctrl/ctrl_mux_listener.ini
+++ b/lib/avtp_pipeline/intf_ctrl/ctrl_mux_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/intf_ctrl/ctrl_mux_talker.ini b/lib/avtp_pipeline/intf_ctrl/ctrl_mux_talker.ini
index ad4c0716..2926d9b5 100644
--- a/lib/avtp_pipeline/intf_ctrl/ctrl_mux_talker.ini
+++ b/lib/avtp_pipeline/intf_ctrl/ctrl_mux_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/intf_ctrl/ctrl_talker.ini b/lib/avtp_pipeline/intf_ctrl/ctrl_talker.ini
index 747ff19b..33a150a6 100644
--- a/lib/avtp_pipeline/intf_ctrl/ctrl_talker.ini
+++ b/lib/avtp_pipeline/intf_ctrl/ctrl_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/intf_ctrl/openavb_intf_ctrl.c b/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl.c
index 3a7ddec0..74e6dbb5 100755
--- a/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl.c
+++ b/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl.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/intf_ctrl/openavb_intf_ctrl_pub.h b/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl_pub.h
index 6f4fc104..1cc242a7 100755
--- a/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl_pub.h
+++ b/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl_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
diff --git a/lib/avtp_pipeline/intf_echo/echo_listener.ini b/lib/avtp_pipeline/intf_echo/echo_listener.ini
index e926dd5b..73e8cf00 100644
--- a/lib/avtp_pipeline/intf_echo/echo_listener.ini
+++ b/lib/avtp_pipeline/intf_echo/echo_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/intf_echo/echo_listener_auto.ini b/lib/avtp_pipeline/intf_echo/echo_listener_auto.ini
index b3a9642e..5fa3df3d 100644
--- a/lib/avtp_pipeline/intf_echo/echo_listener_auto.ini
+++ b/lib/avtp_pipeline/intf_echo/echo_listener_auto.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/intf_echo/echo_talker.ini b/lib/avtp_pipeline/intf_echo/echo_talker.ini
index 6987e03c..28e22d5f 100644
--- a/lib/avtp_pipeline/intf_echo/echo_talker.ini
+++ b/lib/avtp_pipeline/intf_echo/echo_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 = a0:36:9f:66:8c:9f
diff --git a/lib/avtp_pipeline/intf_echo/echo_talker_auto.ini b/lib/avtp_pipeline/intf_echo/echo_talker_auto.ini
index 66326964..affa10a7 100644
--- a/lib/avtp_pipeline/intf_echo/echo_talker_auto.ini
+++ b/lib/avtp_pipeline/intf_echo/echo_talker_auto.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/intf_echo/openavb_intf_echo.c b/lib/avtp_pipeline/intf_echo/openavb_intf_echo.c
index bee8aef3..9385bb9f 100755
--- a/lib/avtp_pipeline/intf_echo/openavb_intf_echo.c
+++ b/lib/avtp_pipeline/intf_echo/openavb_intf_echo.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
@@ -194,7 +195,7 @@ bool openavbIntfEchoTxCB(media_q_t *pMediaQ)
media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
if (pMediaQItem) {
- if (pMediaQItem->itemSize >= pPvtData->increment ? pPvtData->echoStringLen + 16 : pPvtData->echoStringLen) {
+ if (pMediaQItem->itemSize >= (pPvtData->increment ? pPvtData->echoStringLen + 16 : pPvtData->echoStringLen)) {
if (pPvtData->increment) {
int len = sprintf(pMediaQItem->pPubData, "%s %u", pPvtData->pEchoString, pPvtData->Counter++);
pMediaQItem->dataLen = len;
diff --git a/lib/avtp_pipeline/intf_logger/openavb_intf_logger.c b/lib/avtp_pipeline/intf_logger/openavb_intf_logger.c
index 91417d0c..dae91fce 100644
--- a/lib/avtp_pipeline/intf_logger/openavb_intf_logger.c
+++ b/lib/avtp_pipeline/intf_logger/openavb_intf_logger.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/intf_null/null_listener.ini b/lib/avtp_pipeline/intf_null/null_listener.ini
index 2645f0fa..f44dc602 100644
--- a/lib/avtp_pipeline/intf_null/null_listener.ini
+++ b/lib/avtp_pipeline/intf_null/null_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/intf_null/null_talker.ini b/lib/avtp_pipeline/intf_null/null_talker.ini
index 3f440cbd..408fc6af 100644
--- a/lib/avtp_pipeline/intf_null/null_talker.ini
+++ b/lib/avtp_pipeline/intf_null/null_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/intf_null/openavb_intf_null.c b/lib/avtp_pipeline/intf_null/openavb_intf_null.c
index 6ce7bc42..b633bde9 100755
--- a/lib/avtp_pipeline/intf_null/openavb_intf_null.c
+++ b/lib/avtp_pipeline/intf_null/openavb_intf_null.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/intf_tonegen/openavb_intf_tonegen.c b/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.c
index 66ff499b..b6e0951d 100644
--- a/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.c
+++ b/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.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,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
+#include <endian.h>
#include "openavb_platform_pub.h"
#include "openavb_osal_pub.h"
#include "openavb_types_pub.h"
@@ -396,6 +398,61 @@ void openavbIntfToneGenTxInitCB(media_q_t *pMediaQ)
AVB_TRACE_EXIT(AVB_TRACE_INTF);
}
+
+#define SWAPU16(x) (((x) >> 8) | ((x) << 8))
+static U16 convertToDesiredEndianOrder16(U16 hostData, avb_audio_endian_t audioEndian)
+{
+#if defined __BYTE_ORDER && defined __BIG_ENDIAN && defined __LITTLE_ENDIAN
+#if __BYTE_ORDER == __BIG_ENDIAN
+ if (audioEndian == AVB_AUDIO_ENDIAN_LITTLE) { hostData = SWAPU16(hostData); }
+ return hostData;
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ if (audioEndian == AVB_AUDIO_ENDIAN_BIG) { hostData = SWAPU16(hostData); }
+ return hostData;
+#else
+ #error Unsupported Endian format
+#endif
+#else
+ U16 test_var = 1;
+ unsigned char test_endian* = (unsigned char*)&test_var;
+ if (test_endian[0] == 0) {
+ // This is big-endian.
+ if (audioEndian == AVB_AUDIO_ENDIAN_LITTLE) { hostData = SWAPU16(hostData); }
+ } else {
+ // This is little-endian.
+ if (audioEndian == AVB_AUDIO_ENDIAN_BIG) { hostData = SWAPU16(hostData); }
+ }
+ return hostData;
+#endif
+}
+
+#define SWAPU32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | ((x) << 24))
+static U32 convertToDesiredEndianOrder32(U32 hostData, avb_audio_endian_t audioEndian)
+{
+#if defined __BYTE_ORDER && defined __BIG_ENDIAN && defined __LITTLE_ENDIAN
+#if __BYTE_ORDER == __BIG_ENDIAN
+ if (audioEndian == AVB_AUDIO_ENDIAN_LITTLE) { hostData = SWAPU32(hostData); }
+ return hostData;
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ if (audioEndian == AVB_AUDIO_ENDIAN_BIG) { hostData = SWAPU32(hostData); }
+ return hostData;
+#else
+ #error Unsupported Endian format
+#endif
+#else
+ U16 test_var = 1;
+ unsigned char test_endian* = (unsigned char*)&test_var;
+ if (test_endian[0] == 0) {
+ // This is big-endian.
+ if (audioEndian == AVB_AUDIO_ENDIAN_LITTLE) { hostData = SWAPU32(hostData); }
+ } else {
+ // This is little-endian.
+ if (audioEndian == AVB_AUDIO_ENDIAN_BIG) { hostData = SWAPU32(hostData); }
+ }
+ return hostData;
+#endif
+}
+
// This callback will be called for each AVB transmit interval. Commonly this will be
// 4000 or 8000 times per second.
bool openavbIntfToneGenTxCB(media_q_t *pMediaQ)
@@ -467,17 +524,21 @@ bool openavbIntfToneGenTxCB(media_q_t *pMediaQ)
if (pPvtData->audioType == AVB_AUDIO_TYPE_INT) {
if (pPvtData->audioBitDepth == 32) {
S32 sample32 = (S32)(value * (32000 << 16));
- S32 tmp32 = htonl(sample32);
+ S32 tmp32 = convertToDesiredEndianOrder32(sample32, pPvtData->audioEndian);
memcpy(pData, (U8 *)&tmp32, 4);
pData += 4;
} else if (pPvtData->audioBitDepth == 24) {
S32 sample24 = (S32)(value * (32000 << 16));
- S32 tmp24 = htonl(sample24);
- memcpy(pData, (U8 *)&tmp24, 3);
+ S32 tmp24 = convertToDesiredEndianOrder32(sample24, pPvtData->audioEndian);
+ if (pPvtData->audioEndian == AVB_AUDIO_ENDIAN_BIG) {
+ memcpy(pData, (U8 *)&tmp24, 3);
+ } else {
+ memcpy(pData, ((U8 *)&tmp24) + 1, 3);
+ }
pData += 3;
} else if (pPvtData->audioBitDepth == 16) {
S16 sample16 = (S32)(value * 32000);
- S16 tmp16 = htons(sample16);
+ S16 tmp16 = convertToDesiredEndianOrder16(sample16, pPvtData->audioEndian);
memcpy(pData, (U8 *)&tmp16, 2);
pData += 2;
}
@@ -485,7 +546,7 @@ bool openavbIntfToneGenTxCB(media_q_t *pMediaQ)
U32 tmp32f;
// value *= .75; // attenuate value
memcpy((U8 *)&tmp32f, (U8 *)&value, 4); // done so no warning with -Wstrict-aliasing
- tmp32f = htonl(tmp32f);
+ tmp32f = convertToDesiredEndianOrder32(tmp32f, pPvtData->audioEndian);
memcpy(pData, (U8 *)&tmp32f, 4);
pData += 4;
} else {
@@ -498,13 +559,13 @@ bool openavbIntfToneGenTxCB(media_q_t *pMediaQ)
if (pPvtData->audioType == AVB_AUDIO_TYPE_INT) {
if (pPvtData->audioBitDepth == 32) {
if (pPvtData->fv1Enabled) {
- S32 tmp32 = htonl(pPvtData->fv1);
+ S32 tmp32 = convertToDesiredEndianOrder32(pPvtData->fv1, pPvtData->audioEndian);
memcpy(pData, (U8 *)&tmp32, 4);
pData += 4;
}
if (pPvtData->fv2Enabled) {
- S32 tmp32 = htonl(pPvtData->fv2);
+ S32 tmp32 = convertToDesiredEndianOrder32(pPvtData->fv2, pPvtData->audioEndian);
memcpy(pData, (U8 *)&tmp32, 4);
pData += 4;
}
@@ -570,13 +631,26 @@ void openavbIntfToneGenGenEndCB(media_q_t *pMediaQ)
void openavbIntfToneGenEnableFixedTimestamp(media_q_t *pMediaQ, bool enabled, U32 transmitInterval, U32 batchFactor)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
- if (pMediaQ && pMediaQ->pPvtIntfInfo) {
+ 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) {
- openavbMcsInit(&pPvtData->mcs, NANOSECONDS_PER_SECOND/transmitInterval);
- AVB_LOG_INFO("Fixed timestamping enabled");
+ U32 per, rate, rem;
+ /* 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;
+ 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);
}
if (batchFactor != 1) {
diff --git a/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.md b/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.md
index 6afd810a..ce0d3b12 100644
--- a/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.md
+++ b/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.md
@@ -14,17 +14,11 @@ Name | Description
-----------------------------|---------------------------
intf_nv_tone_hz | The frequency of the generated tone
intf_nv_on_off_interval_msec | How many millisecs to turn on and off the tone
-intf_nv_melody_string | A simple melody to play. When a melody string is \
- set the on/off tone hz is not used. The string \
- holds the notes in a 2 octave range with the use \
- of letters A B C D E F G a b c d e f g followed \
- by a duration of the note. For example the full \
- scale is A4B4C4D4E4F4G4a4b4c4d4e4f4g4.
-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_channels | Number of audio channels, numeric values should \
- be within range of values in \
- @ref avb_audio_channels_t
-
+intf_nv_melody_string | A simple melody to play. When a melody string is set the on/off tone hz is not used. The string holds the notes in a 2 octave range with the use of letters A B C D E F G a b c d e f g followed by a duration of the note. For example the full scale is A4B4C4D4E4F4G4a4b4c4d4e4f4g4.
+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_channels | Number of audio channels, numeric values should be within range of values in @ref avb_audio_channels_t
+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_volume | The volune of the tone generation PCM in dB
+intf_nv_fv1 and intf_nv_fv2 | Optionally replace the last channel, or last two channels if both are defined, with fixed 32-bit sample values
diff --git a/lib/avtp_pipeline/intf_tonegen/tonegen_talker.ini b/lib/avtp_pipeline/intf_tonegen/tonegen_talker.ini
index 0efe3aca..ece6eec2 100644
--- a/lib/avtp_pipeline/intf_tonegen/tonegen_talker.ini
+++ b/lib/avtp_pipeline/intf_tonegen/tonegen_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
@@ -118,7 +124,7 @@ map_nv_packing_factor = 1
intf_lib = ./libopenavb_intf_tonegen.so
# intf_fn: The name of the initialize function in the interface.
-intf_fn = openavbIntfTonegenInitialize
+intf_fn = openavbIntfToneGenInitialize
# intf_nv_tone_hz: The frequence of the tone
intf_nv_tone_hz = 261
diff --git a/lib/avtp_pipeline/intf_tonegen/tonegen_talker_lowlatency.ini b/lib/avtp_pipeline/intf_tonegen/tonegen_talker_lowlatency.ini
index 2c4846c4..1696c363 100644
--- a/lib/avtp_pipeline/intf_tonegen/tonegen_talker_lowlatency.ini
+++ b/lib/avtp_pipeline/intf_tonegen/tonegen_talker_lowlatency.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
@@ -127,7 +133,7 @@ map_nv_packing_factor = 1
intf_lib = ./libopenavb_intf_tonegen.so
# intf_fn: The name of the initialize function in the interface.
-intf_fn = openavbIntfTonegenInitialize
+intf_fn = openavbIntfToneGenInitialize
# intf_nv_tone_hz: The frequence of the tone
intf_nv_tone_hz = 261
diff --git a/lib/avtp_pipeline/intf_viewer/latency_listener.ini b/lib/avtp_pipeline/intf_viewer/latency_listener.ini
index b85d4e18..ff003baa 100644
--- a/lib/avtp_pipeline/intf_viewer/latency_listener.ini
+++ b/lib/avtp_pipeline/intf_viewer/latency_listener.ini
@@ -15,6 +15,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:8F:DE
diff --git a/lib/avtp_pipeline/intf_viewer/latency_talker.ini b/lib/avtp_pipeline/intf_viewer/latency_talker.ini
index f69a6673..515e7b22 100644
--- a/lib/avtp_pipeline/intf_viewer/latency_talker.ini
+++ b/lib/avtp_pipeline/intf_viewer/latency_talker.ini
@@ -15,6 +15,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/intf_viewer/openavb_intf_viewer.c b/lib/avtp_pipeline/intf_viewer/openavb_intf_viewer.c
index 0e406dc6..c942089f 100755
--- a/lib/avtp_pipeline/intf_viewer/openavb_intf_viewer.c
+++ b/lib/avtp_pipeline/intf_viewer/openavb_intf_viewer.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/intf_viewer/viewer_listener.ini b/lib/avtp_pipeline/intf_viewer/viewer_listener.ini
index 01e4f726..378a1e2c 100644
--- a/lib/avtp_pipeline/intf_viewer/viewer_listener.ini
+++ b/lib/avtp_pipeline/intf_viewer/viewer_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/maap/openavb_maap.h b/lib/avtp_pipeline/maap/openavb_maap.h
index acf9ffcc..277ae4a7 100644
--- a/lib/avtp_pipeline/maap/openavb_maap.h
+++ b/lib/avtp_pipeline/maap/openavb_maap.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
@@ -27,35 +28,25 @@ Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyrig
Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
+
#ifndef OPENAVB_MAAP_H
#define OPENAVB_MAAP_H 1
#include "openavb_types.h"
typedef void (openavbMaapRestartCb_t)(void *handle, struct ether_addr *addr);
-typedef enum {
- MAAP_ALLOC_GENERATE, // normal, random allocation
- MAAP_ALLOC_PROBE, // specify address to be allocated
- MAAP_ALLOC_DEFEND // specify address, and skip to DEFEND state
-} openavbMaapAllocAction_t;
-
// MAAP library lifecycle
-bool openavbMaapInitialize(const char *ifname, openavbMaapRestartCb_t* cbfn);
+bool openavbMaapInitialize(const char *ifname, unsigned int maapPort, struct ether_addr *maapPrefAddr, openavbMaapRestartCb_t* cbfn);
void openavbMaapFinalize();
+bool openavbMaapDaemonAvailable(void);
+
// Normal address allocation
-void* openavbMaapAllocate(int count,
- /* out */ struct ether_addr *addr);
-// Extended address allocation (testing)
-void* openavbMaapExtAlloc(int count,
- openavbMaapAllocAction_t action,
- /* in/out */ struct ether_addr *addr);
+// Will allocate the daemon-reserved address if available,
+// or one from the MAAP locally administered Pool otherwise.
+void* openavbMaapAllocate(int count, /* out */ struct ether_addr *addr);
+
// Release an allocated address range
void openavbMaapRelease(void* handle);
-// Dump state info for MAAP
-void openavbMaapListAllocs();
-// Dump heard announcements
-void openavbMaapListHeard();
-
#endif // OPENAVB_MAAP_H
diff --git a/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c b/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c
index d17788f1..f9501750 100755
--- a/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c
+++ b/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.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,17 +22,17 @@ 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 : Implementation for AAF mapping module
*
- * AAF is defined in IEEE 1722-rev1/D12 (still in draft as of Feb 2015).
+ * AAF (AVTP Audio Format) is defined in IEEE 1722-2016 Clause 7.
*/
#include <stdlib.h>
@@ -57,6 +58,9 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
// - 1 Byte - TV bit (timestamp valid)
#define HIDX_AVTP_HIDE7_TV1 1
+// - 1 Byte - Sequence number
+#define HIDX_AVTP_SEQ_NUM 2
+
// - 1 Byte - TU bit (timestamp uncertain)
#define HIDX_AVTP_HIDE7_TU1 3
@@ -78,6 +82,7 @@ typedef enum {
AAF_RATE_96K,
AAF_RATE_176K4,
AAF_RATE_192K,
+ AAF_RATE_24K,
} aaf_nominal_sample_rate_t;
typedef enum {
@@ -86,6 +91,7 @@ typedef enum {
AAF_FORMAT_INT_32,
AAF_FORMAT_INT_24,
AAF_FORMAT_INT_16,
+ AAF_FORMAT_AES3_32, // AVDECC_TODO: Implement this
} aaf_sample_format_t;
typedef enum {
@@ -97,6 +103,13 @@ typedef enum {
AAF_MAX_CHANNELS_LAYOUT = 15,
} aaf_automotive_channels_layout_t;
+typedef enum {
+ // Disabled - timestamp is valid in every avtp packet
+ TS_SPARSE_MODE_DISABLED = 0,
+ // Enabled - timestamp is valid in every 8th avtp packet
+ TS_SPARSE_MODE_ENABLED = 1
+} avb_audio_sparse_mode_t;
+
typedef struct {
/////////////
// Config data
@@ -114,12 +127,12 @@ typedef struct {
// MCR mode
avb_audio_mcr_t audioMcr;
- // MCR timestamp interval
+ // MCR timestamp interval
U32 mcrTimestampInterval;
- // MCR clock recovery interval
+ // MCR clock recovery interval
U32 mcrRecoveryInterval;
-
+
/////////////
// Variable data
/////////////
@@ -129,6 +142,8 @@ typedef struct {
aaf_sample_format_t aaf_format;
U8 aaf_bit_depth;
U32 payloadSize;
+ U32 payloadSizeMaxTalker, payloadSizeMaxListener;
+ bool isTalker;
U8 aaf_event_field;
@@ -136,7 +151,7 @@ typedef struct {
U32 intervalCounter;
- U32 sparseMode;
+ avb_audio_sparse_mode_t sparseMode;
bool mediaQItemSyncTS;
@@ -161,6 +176,9 @@ static void x_calculateSizes(media_q_t *pMediaQ)
case AVB_AUDIO_RATE_16KHZ:
pPvtData->aaf_rate = AAF_RATE_16K;
break;
+ case AVB_AUDIO_RATE_24KHZ:
+ pPvtData->aaf_rate = AAF_RATE_24K;
+ break;
case AVB_AUDIO_RATE_32KHZ:
pPvtData->aaf_rate = AAF_RATE_32K;
break;
@@ -261,13 +279,19 @@ static void x_calculateSizes(media_q_t *pMediaQ)
// AAF packet size calculations
pPubMapInfo->packetFrameSizeBytes = pPubMapInfo->packetSampleSizeBytes * pPubMapInfo->audioChannels;
- pPvtData->payloadSize = pPubMapInfo->framesPerPacket * pPubMapInfo->packetFrameSizeBytes;
+ pPvtData->payloadSize = pPvtData->payloadSizeMaxTalker = pPvtData->payloadSizeMaxListener =
+ pPubMapInfo->framesPerPacket * pPubMapInfo->packetFrameSizeBytes;
AVB_LOGF_INFO("packet: sampleSz=%d * channels=%d => frameSz=%d * %d => payloadSz=%d",
pPubMapInfo->packetSampleSizeBytes,
pPubMapInfo->audioChannels,
pPubMapInfo->packetFrameSizeBytes,
pPubMapInfo->framesPerPacket,
pPvtData->payloadSize);
+ if (pPvtData->aaf_format >= AAF_FORMAT_INT_32 && pPvtData->aaf_format <= AAF_FORMAT_INT_16) {
+ // Determine the largest size we could receive before adjustments.
+ pPvtData->payloadSizeMaxListener = 4 * pPubMapInfo->audioChannels * pPubMapInfo->framesPerPacket;
+ AVB_LOGF_DEBUG("packet: payloadSizeMaxListener=%d", pPvtData->payloadSizeMaxListener);
+ }
// MediaQ item size calculations
pPubMapInfo->packingFactor = pPvtData->packingFactor;
@@ -365,8 +389,17 @@ U16 openavbMapAVTPAudioMaxDataSizeCB(media_q_t *pMediaQ)
return 0;
}
+ // Return the largest size a frame payload could be.
+ // If we don't yet know if we are a Talker or Listener, the larger Listener max will be returned.
+ U16 payloadSizeMax;
+ if (pPvtData->isTalker) {
+ payloadSizeMax = pPvtData->payloadSizeMaxTalker + TOTAL_HEADER_SIZE;
+ }
+ else {
+ payloadSizeMax = pPvtData->payloadSizeMaxListener + TOTAL_HEADER_SIZE;
+ }
AVB_TRACE_EXIT(AVB_TRACE_MAP);
- return pPvtData->payloadSize + TOTAL_HEADER_SIZE;
+ return payloadSizeMax;
}
AVB_TRACE_EXIT(AVB_TRACE_MAP);
return 0;
@@ -405,13 +438,6 @@ void openavbMapAVTPAudioGenInitCB(media_q_t *pMediaQ)
openavbMediaQSetSize(pMediaQ, pPvtData->itemCount, pPubMapInfo->itemSize);
pPvtData->dataValid = TRUE;
-
- pPubMapInfo->sparseMode = pPvtData->sparseMode;
- if (pPubMapInfo->sparseMode == TS_SPARSE_MODE_ENABLED) {
- AVB_LOG_INFO("Sparse timestamping mode: enabled");
- } else {
- AVB_LOG_INFO("Sparse timestamping mode: disabled");
- }
}
AVB_TRACE_EXIT(AVB_TRACE_MAP);
}
@@ -421,10 +447,16 @@ void openavbMapAVTPAudioGenInitCB(media_q_t *pMediaQ)
void openavbMapAVTPAudioTxInitCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (pPvtData) {
+ pPvtData->isTalker = TRUE;
+ }
+ }
AVB_TRACE_EXIT(AVB_TRACE_MAP);
}
-// CORE_TODO: This callback should be updated to work in a similiar way the uncompressed audio mapping. With allowing AVTP packets to be built
+// CORE_TODO: This callback should be updated to work in a similar way the uncompressed audio mapping. With allowing AVTP packets to be built
// from multiple media queue items. This allows interface to set into the media queue blocks of audio frames to properly correspond to
// a SYT_INTERVAL. Additionally the public data member sytInterval needs to be set in the same way the uncompressed audio mapping does.
// This talker callback will be called for each AVB observation interval.
@@ -433,30 +465,68 @@ tx_cb_ret_t openavbMapAVTPAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen)
media_q_item_t *pMediaQItem = NULL;
AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ if (!pMediaQ) {
+ AVB_LOG_ERROR("Mapping module invalid MediaQ");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
if (!pData || !dataLen) {
AVB_LOG_ERROR("Mapping module data or data length argument incorrect.");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ media_q_pub_map_aaf_audio_info_t *pPubMapInfo = pMediaQ->pPubMapInfo;
+
+ U32 bytesNeeded = pPubMapInfo->itemFrameSizeBytes * pPubMapInfo->framesPerPacket;
+ if (!openavbMediaQIsAvailableBytes(pMediaQ, pPubMapInfo->itemFrameSizeBytes * pPubMapInfo->framesPerPacket, TRUE)) {
+ AVB_LOG_VERBOSE("Not enough bytes are ready");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ openavbMediaQTailUnlock(pMediaQ);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
return TX_CB_RET_PACKET_NOT_READY;
}
- if (pMediaQ)
+ if ((*dataLen - TOTAL_HEADER_SIZE) < pPvtData->payloadSize) {
+ AVB_LOG_ERROR("Not enough room in packet for payload");
+ openavbMediaQTailUnlock(pMediaQ);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ U32 tmp32;
+ U8 *pHdrV0 = pData;
+ U32 *pHdr = (U32 *)(pData + AVTP_V0_HEADER_SIZE);
+ U8 *pPayload = pData + TOTAL_HEADER_SIZE;
+
+ U32 bytesProcessed = 0;
+ while (bytesProcessed < bytesNeeded) {
pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
+ if (pMediaQItem && pMediaQItem->pPubData && pMediaQItem->dataLen > 0) {
- if (pMediaQItem) {
- if (pMediaQItem->dataLen > 0) {
-
- U32 tmp32;
- U8 *pHdrV0 = pData;
- U32 *pHdr = (U32 *)(pData + AVTP_V0_HEADER_SIZE);
- U8 *pPayload = pData + TOTAL_HEADER_SIZE;
- media_q_pub_map_aaf_audio_info_t *pPubMapInfo = pMediaQ->pPubMapInfo;
- pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
- if (!pPvtData) {
- AVB_LOG_ERROR("Private mapping module data not allocated.");
- return TX_CB_RET_PACKET_NOT_READY;
- }
// timestamp set in the interface module, here just validate
- if (openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime)) {
-
+ // In sparse mode, the timestamp valid flag should be set every eighth AAF AVPTDU.
+ if (pPvtData->sparseMode == TS_SPARSE_MODE_ENABLED && (pHdrV0[HIDX_AVTP_SEQ_NUM] & 0x07) != 0) {
+ // Skip over this timestamp, as using sparse mode.
+ pHdrV0[HIDX_AVTP_HIDE7_TV1] &= ~0x01;
+ pHdrV0[HIDX_AVTP_HIDE7_TU1] &= ~0x01;
+ *pHdr++ = 0; // Clear the timestamp field
+ }
+ else if (!openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime)) {
+ // Error getting the timestamp. Clear timestamp valid flag.
+ AVB_LOG_ERROR("Unable to get the timestamp value");
+ pHdrV0[HIDX_AVTP_HIDE7_TV1] &= ~0x01;
+ pHdrV0[HIDX_AVTP_HIDE7_TU1] &= ~0x01;
+ *pHdr++ = 0; // Clear the timestamp field
+ }
+ else {
// Add the max transit time.
openavbAvtpTimeAddUSec(pMediaQItem->pAvtpTime, pPvtData->maxTransitUsec);
@@ -473,11 +543,6 @@ tx_cb_ret_t openavbMapAVTPAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen)
openavbAvtpTimeSetTimestampValid(pMediaQItem->pAvtpTime, FALSE);
}
- else {
- // Clear timestamp valid flag
- pHdrV0[HIDX_AVTP_HIDE7_TV1] &= ~0x01;
- pHdr++; // Move past the timestamp field
- }
// - 4 bytes format info (format, sample rate, channels per frame, bit depth)
tmp32 = pPvtData->aaf_format << 24;
@@ -498,12 +563,6 @@ tx_cb_ret_t openavbMapAVTPAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen)
pHdrV0[HIDX_AVTP_HIDE7_SP] &= ~SP_M0_BIT;
}
- if ((*dataLen - TOTAL_HEADER_SIZE) < pPvtData->payloadSize) {
- AVB_LOG_ERROR("Not enough room in packet for payload");
- AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
- return TX_CB_RET_PACKET_NOT_READY;
- }
-
if ((pMediaQItem->dataLen - pMediaQItem->readIdx) < pPvtData->payloadSize) {
// This should not happen so we will just toss it away.
AVB_LOG_ERROR("Not enough data in media queue item for packet");
@@ -513,6 +572,7 @@ tx_cb_ret_t openavbMapAVTPAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen)
}
memcpy(pPayload, (uint8_t *)pMediaQItem->pPubData + pMediaQItem->readIdx, pPvtData->payloadSize);
+ bytesProcessed += pPvtData->payloadSize;
pMediaQItem->readIdx += pPvtData->payloadSize;
if (pMediaQItem->readIdx >= pMediaQItem->dataLen) {
@@ -523,23 +583,17 @@ tx_cb_ret_t openavbMapAVTPAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen)
// More to read next interval
openavbMediaQTailUnlock(pMediaQ);
}
-
- // Set outbound data length (entire packet length)
- *dataLen = pPvtData->payloadSize + TOTAL_HEADER_SIZE;
-
- AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
- return TX_CB_RET_PACKET_READY;
}
else {
openavbMediaQTailPull(pMediaQ);
- AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
- return TX_CB_RET_PACKET_NOT_READY; // No payload
}
-
}
+ // Set out bound data length (entire packet length)
+ *dataLen = bytesNeeded + TOTAL_HEADER_SIZE;
+
AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
- return TX_CB_RET_PACKET_NOT_READY;
+ return TX_CB_RET_PACKET_READY;
}
// A call to this callback indicates that this mapping module will be
@@ -553,6 +607,7 @@ void openavbMapAVTPAudioRxInitCB(media_q_t *pMediaQ)
AVB_LOG_ERROR("Private mapping module data not allocated.");
return;
}
+ pPvtData->isTalker = FALSE;
if (pPvtData->audioMcr != AVB_MCR_NONE) {
HAL_INIT_MCR_V2(pPvtData->txInterval, pPvtData->packingFactor, pPvtData->mcrTimestampInterval, pPvtData->mcrRecoveryInterval);
}
@@ -561,12 +616,16 @@ void openavbMapAVTPAudioRxInitCB(media_q_t *pMediaQ)
// sparse mode enabled so check packing factor
// listener should work correct for packing_factors:
// 1, 2, 4, 8, 16, 24, 32, 40, 48, (+8) ...
- if (pPvtData->packingFactor < 8) {
+ if (pPvtData->packingFactor == 0) {
+ badPckFctrValue = TRUE;
+ }
+ else if (pPvtData->packingFactor < 8) {
// check if power of 2
if ((pPvtData->packingFactor & (pPvtData->packingFactor - 1)) != 0) {
badPckFctrValue = TRUE;
}
- } else {
+ }
+ else {
// check if multiple of 8
if (pPvtData->packingFactor % 8 != 0) {
badPckFctrValue = TRUE;
@@ -595,8 +654,11 @@ bool openavbMapAVTPAudioRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen)
return FALSE;
}
+ aaf_sample_format_t incoming_aaf_format;
+ U8 incoming_bit_depth;
int tmp;
bool dataValid = TRUE;
+ bool dataConversionEnabled = FALSE;
U32 timestamp = ntohl(*pHdr++);
U32 format_info = ntohl(*pHdr++);
@@ -606,18 +668,26 @@ bool openavbMapAVTPAudioRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen)
bool streamSparseMode = (pHdrV0[HIDX_AVTP_HIDE7_SP] & SP_M0_BIT) ? TRUE : FALSE;
U16 payloadLen = ntohs(*(U16 *)(&pHdrV0[HIDX_STREAM_DATA_LEN16]));
- if (payloadLen > dataLen - TOTAL_HEADER_SIZE) {
+ if (payloadLen > dataLen - TOTAL_HEADER_SIZE) {
if (pPvtData->dataValid)
AVB_LOGF_ERROR("header data len %d > actual data len %d",
payloadLen, dataLen - TOTAL_HEADER_SIZE);
dataValid = FALSE;
}
- if ((tmp = ((format_info >> 24) & 0xFF)) != pPvtData->aaf_format) {
- if (pPvtData->dataValid)
- AVB_LOGF_ERROR("Listener format %d doesn't match received data (%d)",
- pPvtData->aaf_format, tmp);
- dataValid = FALSE;
+ if ((incoming_aaf_format = (aaf_sample_format_t) ((format_info >> 24) & 0xFF)) != pPvtData->aaf_format) {
+ // Check if we can convert the incoming data.
+ if (incoming_aaf_format >= AAF_FORMAT_INT_32 && incoming_aaf_format <= AAF_FORMAT_INT_16 &&
+ pPvtData->aaf_format >= AAF_FORMAT_INT_32 && pPvtData->aaf_format <= AAF_FORMAT_INT_16) {
+ // Integer conversion should be supported.
+ dataConversionEnabled = TRUE;
+ }
+ else {
+ if (pPvtData->dataValid)
+ AVB_LOGF_ERROR("Listener format %d doesn't match received data (%d)",
+ pPvtData->aaf_format, incoming_aaf_format);
+ dataValid = FALSE;
+ }
}
if ((tmp = ((format_info >> 20) & 0x0F)) != pPvtData->aaf_rate) {
if (pPvtData->dataValid)
@@ -631,28 +701,44 @@ bool openavbMapAVTPAudioRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen)
pPubMapInfo->audioChannels, tmp);
dataValid = FALSE;
}
- if ((tmp = (format_info & 0xFF)) != pPvtData->aaf_bit_depth) {
+ if ((incoming_bit_depth = (U8) (format_info & 0xFF)) == 0) {
if (pPvtData->dataValid)
- AVB_LOGF_ERROR("Listener bit depth (%d) doesn't match received data (%d)",
- pPvtData->aaf_bit_depth, tmp);
+ AVB_LOGF_ERROR("Listener bit depth (%d) not valid",
+ incoming_bit_depth);
dataValid = FALSE;
}
if ((tmp = ((packet_info >> 16) & 0xFFFF)) != pPvtData->payloadSize) {
- if (pPvtData->dataValid)
- AVB_LOGF_ERROR("Listener payload size (%d) doesn't match received data (%d)",
- pPvtData->payloadSize, tmp);
- dataValid = FALSE;
+ if (!dataConversionEnabled) {
+ if (pPvtData->dataValid)
+ AVB_LOGF_ERROR("Listener payload size (%d) doesn't match received data (%d)",
+ pPvtData->payloadSize, tmp);
+ dataValid = FALSE;
+ }
+ else {
+ int nInSampleLength = 6 - incoming_aaf_format; // Calculate the number of integer bytes per sample received
+ int nOutSampleLength = 6 - pPvtData->aaf_format; // Calculate the number of integer bytes per sample we want
+ if (tmp / nInSampleLength != pPvtData->payloadSize / nOutSampleLength) {
+ if (pPvtData->dataValid)
+ AVB_LOGF_ERROR("Listener payload samples (%d) doesn't match received data samples (%d)",
+ pPvtData->payloadSize / nOutSampleLength, tmp / nInSampleLength);
+ dataValid = FALSE;
+ }
+ }
}
if ((tmp = ((packet_info >> 8) & 0x0F)) != pPvtData->aaf_event_field) {
if (pPvtData->dataValid)
AVB_LOGF_ERROR("Listener event field (%d) doesn't match received data (%d)",
pPvtData->aaf_event_field, tmp);
}
- if (streamSparseMode != listenerSparseMode) {
- if (pPvtData->dataValid)
- AVB_LOGF_ERROR("Listener sparse mode (%d) doesn't match stream sparse mode (%d)",
- listenerSparseMode, streamSparseMode);
- dataValid = FALSE;
+ if (streamSparseMode && !listenerSparseMode) {
+ AVB_LOG_INFO("Listener enabling sparse mode to match incoming stream");
+ pPvtData->sparseMode = TS_SPARSE_MODE_ENABLED;
+ listenerSparseMode = TRUE;
+ }
+ if (!streamSparseMode && listenerSparseMode) {
+ AVB_LOG_INFO("Listener disabling sparse mode to match incoming stream");
+ pPvtData->sparseMode = TS_SPARSE_MODE_DISABLED;
+ listenerSparseMode = FALSE;
}
if (dataValid) {
@@ -689,11 +775,53 @@ bool openavbMapAVTPAudioRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen)
}
}
if (dataValid) {
- if (pPubMapInfo->intf_rx_translate_cb) {
- pPubMapInfo->intf_rx_translate_cb(pMediaQ, pPayload, pPvtData->payloadSize);
+ if (!dataConversionEnabled) {
+ // Just use the raw incoming data, and ignore the incoming bit_depth.
+ if (pPubMapInfo->intf_rx_translate_cb) {
+ pPubMapInfo->intf_rx_translate_cb(pMediaQ, pPayload, pPvtData->payloadSize);
+ }
+
+ memcpy((uint8_t *)pMediaQItem->pPubData + pMediaQItem->dataLen, pPayload, pPvtData->payloadSize);
+ }
+ else {
+ static U8 s_audioBuffer[1500];
+ U8 *pInData = pPayload;
+ U8 *pInDataEnd = pPayload + payloadLen;
+ U8 *pOutData = s_audioBuffer;
+ int nInSampleLength = 6 - incoming_aaf_format; // Calculate the number of integer bytes per sample received
+ int nOutSampleLength = 6 - pPvtData->aaf_format; // Calculate the number of integer bytes per sample we want
+ int i;
+ if (nInSampleLength < nOutSampleLength) {
+ // We need to pad the data supplied.
+ while (pInData < pInDataEnd) {
+ for (i = 0; i < nInSampleLength; ++i) {
+ *pOutData++ = *pInData++;
+ }
+ for ( ; i < nOutSampleLength; ++i) {
+ *pOutData++ = 0; // Value specified in Clause 7.3.4.
+ }
+ }
+ }
+ else {
+ // We need to truncate the data supplied.
+ while (pInData < pInDataEnd) {
+ for (i = 0; i < nOutSampleLength; ++i) {
+ *pOutData++ = *pInData++;
+ }
+ pInData += (nInSampleLength - nOutSampleLength);
+ }
+ }
+ if (pOutData - s_audioBuffer != pPvtData->payloadSize) {
+ AVB_LOGF_ERROR("Output not expected size (%d instead of %d)", pOutData - s_audioBuffer, pPvtData->payloadSize);
+ }
+
+ if (pPubMapInfo->intf_rx_translate_cb) {
+ pPubMapInfo->intf_rx_translate_cb(pMediaQ, s_audioBuffer, pPvtData->payloadSize);
+ }
+
+ memcpy((uint8_t *)pMediaQItem->pPubData + pMediaQItem->dataLen, s_audioBuffer, pPvtData->payloadSize);
}
- memcpy((uint8_t *)pMediaQItem->pPubData + pMediaQItem->dataLen, pPayload, pPvtData->payloadSize);
pMediaQItem->dataLen += pPvtData->payloadSize;
}
@@ -751,8 +879,8 @@ void openavbMapAVTPAudioEndCB(media_q_t *pMediaQ)
void openavbMapAVTPAudioGenEndCB(media_q_t *pMediaQ)
{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
}
// Initialization entry point into the mapping module. Will need to be included in the .ini file.
diff --git a/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio_pub.h b/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio_pub.h
index c7761b80..213f3bb6 100755
--- a/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio_pub.h
+++ b/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio_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,17 +22,17 @@ 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.
*************************************************************************************************************/
/*
* HEADER SUMMARY : AVTP Audio Format mapping module public interface
*
- * AAF is defined in IEEE 1722a (still in draft as of Feb 2015).
+ * AAF (AVTP Audio Format) is defined in IEEE 1722-2016 Clause 7.
*
* map_nv_tx_rate must be set in the .ini file.
*/
diff --git a/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl.c b/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl.c
index 34a353e8..8237f29f 100755
--- a/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl.c
+++ b/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl.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/map_ctrl/openavb_map_ctrl_pub.h b/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl_pub.h
index a89429b0..41ae5430 100755
--- a/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl_pub.h
+++ b/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl_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
diff --git a/lib/avtp_pipeline/map_h264/openavb_map_h264.c b/lib/avtp_pipeline/map_h264/openavb_map_h264.c
index 6898a5ad..5fd114ac 100755
--- a/lib/avtp_pipeline/map_h264/openavb_map_h264.c
+++ b/lib/avtp_pipeline/map_h264/openavb_map_h264.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/map_h264/openavb_map_h264_pub.h b/lib/avtp_pipeline/map_h264/openavb_map_h264_pub.h
index c685d967..307b4ba1 100755
--- a/lib/avtp_pipeline/map_h264/openavb_map_h264_pub.h
+++ b/lib/avtp_pipeline/map_h264/openavb_map_h264_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
diff --git a/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg.c b/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg.c
index a348439a..4f53904f 100755
--- a/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg.c
+++ b/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg.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/map_mjpeg/openavb_map_mjpeg_pub.h b/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg_pub.h
index 41cf34f0..fc5aaded 100755
--- a/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg_pub.h
+++ b/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg_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
diff --git a/lib/avtp_pipeline/map_mpeg2ts/demo_listener.ini b/lib/avtp_pipeline/map_mpeg2ts/demo_listener.ini
index f48dbba4..7a30e9b1 100644
--- a/lib/avtp_pipeline/map_mpeg2ts/demo_listener.ini
+++ b/lib/avtp_pipeline/map_mpeg2ts/demo_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:25:64:48:ca:a8
diff --git a/lib/avtp_pipeline/map_mpeg2ts/demo_talker.ini b/lib/avtp_pipeline/map_mpeg2ts/demo_talker.ini
index 77e6d698..a805e1b6 100644
--- a/lib/avtp_pipeline/map_mpeg2ts/demo_talker.ini
+++ b/lib/avtp_pipeline/map_mpeg2ts/demo_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/map_mpeg2ts/openavb_map_mpeg2ts.c b/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts.c
index 8b12bdb3..ba039b99 100755
--- a/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts.c
+++ b/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts.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/map_mpeg2ts/openavb_map_mpeg2ts_pub.h b/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts_pub.h
index 7f4257dd..b54e998c 100755
--- a/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts_pub.h
+++ b/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts_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
diff --git a/lib/avtp_pipeline/map_mpeg2ts/ts_packet_size.c b/lib/avtp_pipeline/map_mpeg2ts/ts_packet_size.c
index a9b30998..cca41d3a 100644
--- a/lib/avtp_pipeline/map_mpeg2ts/ts_packet_size.c
+++ b/lib/avtp_pipeline/map_mpeg2ts/ts_packet_size.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/map_null/openavb_map_null.c b/lib/avtp_pipeline/map_null/openavb_map_null.c
index 7dd24556..5efb4359 100755
--- a/lib/avtp_pipeline/map_null/openavb_map_null.c
+++ b/lib/avtp_pipeline/map_null/openavb_map_null.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/map_null/openavb_map_null_pub.h b/lib/avtp_pipeline/map_null/openavb_map_null_pub.h
index 7fb086c6..4c5da720 100755
--- a/lib/avtp_pipeline/map_null/openavb_map_null_pub.h
+++ b/lib/avtp_pipeline/map_null/openavb_map_null_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
diff --git a/lib/avtp_pipeline/map_pipe/openavb_map_pipe.c b/lib/avtp_pipeline/map_pipe/openavb_map_pipe.c
index 016bb8d4..d65eb38a 100755
--- a/lib/avtp_pipeline/map_pipe/openavb_map_pipe.c
+++ b/lib/avtp_pipeline/map_pipe/openavb_map_pipe.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
@@ -182,7 +183,7 @@ void openavbMapPipeCfgCB(media_q_t *pMediaQ, const char *name, const char *value
char *pEnd;
pPvtData->maxPayloadSize = strtol(value, &pEnd, 10);
pPvtData->maxDataSize = (pPvtData->maxPayloadSize + TOTAL_HEADER_SIZE);
- pPvtData->itemSize = pPvtData->maxDataSize;
+ pPvtData->itemSize = pPvtData->maxPayloadSize;
}
else if (strcmp(name, "map_nv_push_header") == 0) {
char *pEnd;
diff --git a/lib/avtp_pipeline/map_pipe/openavb_map_pipe_pub.h b/lib/avtp_pipeline/map_pipe/openavb_map_pipe_pub.h
index 66e5f338..082f79bf 100755
--- a/lib/avtp_pipeline/map_pipe/openavb_map_pipe_pub.h
+++ b/lib/avtp_pipeline/map_pipe/openavb_map_pipe_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
diff --git a/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio.c b/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio.c
index 7c3ff8aa..ca342b2b 100755
--- a/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio.c
+++ b/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio.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.
*************************************************************************************************************/
@@ -38,10 +39,6 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_trace_pub.h"
#include "openavb_avtp_time_pub.h"
#include "openavb_mediaq_pub.h"
-
-// TODO_OPENAVB : Is this needed?
-//#include "openavb_avdecc_pub.h"
-
#include "openavb_map_pub.h"
#include "openavb_map_uncmp_audio_pub.h"
@@ -204,7 +201,7 @@ static void x_calculateSizes(media_q_t *pMediaQ)
break;
default:
- AVB_LOG_ERROR("Invalid audio frequency configured.");
+ AVB_LOGF_ERROR("Invalid audio frequency configured: %u", pPubMapInfo->audioRate);
pPvtData->cip_sfc = 2;
pPubMapInfo->sytInterval = 8;
break;
@@ -224,16 +221,13 @@ static void x_calculateSizes(media_q_t *pMediaQ)
if (pPubMapInfo->packingFactor > 1) {
// Packing multiple packets of sampling into a media queue item
pPubMapInfo->framesPerItem = pPubMapInfo->framesPerPacket * pPvtData->packingFactor;
- if (pPubMapInfo->framesPerItem < 1) {
- pPubMapInfo->framesPerItem = 1;
- }
}
else {
// No packing. SYT_INTERVAL is used for media queue item size.
pPubMapInfo->framesPerItem = pPubMapInfo->sytInterval;
- if (pPubMapInfo->framesPerItem < 1) {
- pPubMapInfo->framesPerItem = 1;
- }
+ }
+ if (pPubMapInfo->framesPerItem < 1) {
+ pPubMapInfo->framesPerItem = 1;
}
pPubMapInfo->packetSampleSizeBytes = 4;
@@ -281,7 +275,7 @@ static void x_calculateSizes(media_q_t *pMediaQ)
break;
default:
- AVB_LOG_ERROR("Invalid audio format configured.");
+ AVB_LOGF_ERROR("Invalid audio bit depth configured: %u", pPubMapInfo->audioBitDepth);
pPvtData->AM824_label = 0x40000000;
break;
}
@@ -474,14 +468,15 @@ tx_cb_ret_t openavbMapUncmpAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen
U32 framesProcessed = 0;
U8 *pAVTPDataUnit = pPayload;
bool timestampSet = FALSE; // index of the timestamp
+ U32 sytInt = pPubMapInfo->sytInterval;
+ U8 dbc = pPvtData->DBC;
while (framesProcessed < pPubMapInfo->framesPerPacket) {
pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
+ if (pMediaQItem && pMediaQItem->pPubData && pMediaQItem->dataLen > 0) {
+ U8 *pItemData = (U8 *)pMediaQItem->pPubData + pMediaQItem->readIdx;
- if (pMediaQItem && pMediaQItem->dataLen > 0) {
if (pMediaQItem->readIdx == 0) {
- // Timestamp from the media queue is always assoicated with the first data point.
-
- // Update time stamp
+ // Timestamp from the media queue is always associated with the first data point.
// PTP walltime already set in the interface module. Just add the max transit time.
openavbAvtpTimeAddUSec(pMediaQItem->pAvtpTime, pPvtData->maxTransitUsec);
@@ -496,14 +491,11 @@ tx_cb_ret_t openavbMapUncmpAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen
// Set timestamp uncertain flag
if (openavbAvtpTimeTimestampIsUncertain(pMediaQItem->pAvtpTime))
pHdr[HIDX_AVTP_HIDE7_TU1] |= 0x01; // Set
- else pHdr[HIDX_AVTP_HIDE7_TU1] &= ~0x01; // Clear
+ else
+ pHdr[HIDX_AVTP_HIDE7_TU1] &= ~0x01; // Clear
- *(U32 *)(&pHdr[HIDX_AVTP_TIMESTAMP32]) = htonl(openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime));
-
- timestampSet = TRUE;
}
- U8 *pItemData = (U8 *)pMediaQItem->pPubData + pMediaQItem->readIdx;
while (framesProcessed < pPubMapInfo->framesPerPacket && pMediaQItem->readIdx < pMediaQItem->dataLen) {
int i1;
for (i1 = 0; i1 < pPubMapInfo->audioChannels; i1++) {
@@ -528,6 +520,12 @@ tx_cb_ret_t openavbMapUncmpAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen
}
}
framesProcessed++;
+ if (dbc % sytInt == 0) {
+ *(U32 *)(&pHdr[HIDX_AVTP_TIMESTAMP32]) = htonl(openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime));
+
+ timestampSet = TRUE;
+ }
+ dbc++;
pMediaQItem->readIdx += pPubMapInfo->itemFrameSizeBytes;
}
@@ -548,12 +546,12 @@ tx_cb_ret_t openavbMapUncmpAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen
// Check if timestamp was set
if (!timestampSet) {
// Timestamp wasn't set so mark it as invalid
- pHdr[HIDX_AVTP_HIDE7_TV1] &= ~0x01;
+ pHdr[HIDX_AVTP_HIDE7_TV1] &= ~0x01;
}
// Set the block continutity and data length
pHdr[HIDX_DBC8] = pPvtData->DBC;
- pPvtData->DBC += pPubMapInfo->framesPerPacket;
+ pPvtData->DBC = dbc;
*(U16 *)(&pHdr[HIDX_DATALEN16]) = htons((pPubMapInfo->framesPerPacket * pPubMapInfo->packetFrameSizeBytes) + CIP_HEADER_SIZE);
@@ -631,7 +629,7 @@ bool openavbMapUncmpAudioRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen)
if (pMediaQItem->dataLen == 0) {
// This is the first set of frames for the media queue item, must align based on SYT_INTERVAL for proper synchronization of listeners
if (dbcIdx > 0) {
- // Failed to make alignment with this packet. This AVTP packet will be tossed. Once alignment is reached
+ // Failed to make alignment with this packet. This AVTP packet will be tossed. Once alignment is reached
// it is expected not to need to toss packets anymore.
openavbMediaQHeadUnlock(pMediaQ);
AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
@@ -726,7 +724,6 @@ extern DLL_EXPORT bool openavbMapUncmpAudioInitialize(media_q_t *pMediaQ, openav
}
pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
- media_q_pub_map_uncmp_audio_info_t *pPubMapInfo = pMediaQ->pPubMapInfo;
pMapCB->map_cfg_cb = openavbMapUncmpAudioCfgCB;
pMapCB->map_subtype_cb = openavbMapUncmpAudioSubtypeCB;
@@ -734,7 +731,6 @@ extern DLL_EXPORT bool openavbMapUncmpAudioInitialize(media_q_t *pMediaQ, openav
pMapCB->map_max_data_size_cb = openavbMapUncmpAudioMaxDataSizeCB;
pMapCB->map_transmit_interval_cb = openavbMapUncmpAudioTransmitIntervalCB;
pMapCB->map_gen_init_cb = openavbMapUncmpAudioGenInitCB;
- pMapCB->map_avdecc_init_cb = openavbMapUncmpAudioAVDECCInitCB;
pMapCB->map_tx_init_cb = openavbMapUncmpAudioTxInitCB;
pMapCB->map_tx_cb = openavbMapUncmpAudioTxCB;
pMapCB->map_rx_init_cb = openavbMapUncmpAudioRxInitCB;
@@ -749,8 +745,6 @@ extern DLL_EXPORT bool openavbMapUncmpAudioInitialize(media_q_t *pMediaQ, openav
pPvtData->DBC = 0;
pPvtData->audioMcr = AVB_MCR_NONE;
- pPubMapInfo->sparseMode = TS_SPARSE_MODE_UNSPEC;
-
openavbMediaQSetMaxLatency(pMediaQ, inMaxTransitUsec);
}
diff --git a/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio_pub.h b/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio_pub.h
index 7a324d46..aab1f973 100755
--- a/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio_pub.h
+++ b/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio_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,20 +22,20 @@ 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.
*************************************************************************************************************/
/*
* HEADER SUMMARY : Uncompressed Audio mapping module public interface
-*
+*
* Refer to IEC 61883-6 for details of the "source packet" structure.
-*
+*
* The protocol_specific_header and CIP header.
-*
+*
* map_nv_tx_rate must be set in the .ini file.
*/
@@ -59,19 +60,6 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*/
#define MapUncmpAudioMediaQDataFormat "UncmpAudio"
-/** Defines AAF timestamping mode:
- * - TS_SPARSE_MODE_DISABLED - timestamp is valid in every avtp packet
- * - TS_SPARSE_MODE_ENABLED - timestamp is valid in every 8th avtp packet
- */
-typedef enum {
- /// Unspecified
- TS_SPARSE_MODE_UNSPEC = 0,
- /// Disabled
- TS_SPARSE_MODE_DISABLED = 1,
- /// Enabled
- TS_SPARSE_MODE_ENABLED = 8
-} avb_audio_sparse_mode_t;
-
/** Contains detailed information of the audio format.
* \note Interface module has to set during the RX and TX init callbacks:
* - audioRate,
@@ -79,7 +67,6 @@ typedef enum {
* - audioBitDepth,
* - audioEndian,
* - audioChannels,
- * - sparseMode.
* \note The rest of fields mapping module will set these during the RX and TX
* init callbacks. The interface module can use these during the RX and TX
* callbacks.
@@ -95,8 +82,6 @@ typedef struct {
avb_audio_endian_t audioEndian;
/// Number of channels
avb_audio_channels_t audioChannels;
- /// Sparse timestamping mode
- avb_audio_sparse_mode_t sparseMode;
// The mapping module will set these during the RX and TX init callbacks
// The interface module can use these during the RX and TX callbacks.
@@ -121,12 +106,12 @@ typedef struct {
/// synchronization time interval
U32 sytInterval;
- /// CB for interface modules to do translations in place before data is moved into the mediaQ on rx.
+ /// CB for interface modules to do translations in place before data is moved into the mediaQ on rx.
openavb_intf_rx_translate_cb_t intf_rx_translate_cb;
/// Interface Module may set this presentation latency which listener mapping modules will use to adjust the presetnation time
S32 presentationLatencyUSec;
-
+
} media_q_pub_map_uncmp_audio_info_t;
#endif // OPENAVB_MAP_UNCMP_AUDIO_PUB_H
diff --git a/lib/avtp_pipeline/map_uncmp_audio/uncmp_audio_map.md b/lib/avtp_pipeline/map_uncmp_audio/uncmp_audio_map.md
index f826249c..862241b6 100644
--- a/lib/avtp_pipeline/map_uncmp_audio/uncmp_audio_map.md
+++ b/lib/avtp_pipeline/map_uncmp_audio/uncmp_audio_map.md
@@ -41,8 +41,6 @@ audioType |How the data is organized - what is the data type of \
samples @ref avb_audio_type_t
audioBitDepth |What is the bit depth of audio @ref avb_audio_bit_depth_t
audioChannels |How many channels there are @ref avb_audio_channels_t
-sparseMode |Timestamping mode @ref avb_audio_sparse_mode_t \
- (not used in this mapping module)
Below you can find description of how to set up those variables in interfaces
* [wav file interface](@ref wav_file_intf)
diff --git a/lib/avtp_pipeline/mcr/openavb_mcr_hal_pub.h b/lib/avtp_pipeline/mcr/openavb_mcr_hal_pub.h
index e1d19b43..d474d084 100644
--- a/lib/avtp_pipeline/mcr/openavb_mcr_hal_pub.h
+++ b/lib/avtp_pipeline/mcr/openavb_mcr_hal_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
diff --git a/lib/avtp_pipeline/mcs/openavb_mcs.c b/lib/avtp_pipeline/mcs/openavb_mcs.c
index d58d46d8..51d7fe9a 100644
--- a/lib/avtp_pipeline/mcs/openavb_mcs.c
+++ b/lib/avtp_pipeline/mcs/openavb_mcs.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
-Copyright (c) 2016, Harman International Industries, Incorporated
+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
@@ -21,6 +22,11 @@ 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.
*************************************************************************************************************/
/*
@@ -32,30 +38,40 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "openavb_log_pub.h"
#include "openavb_mcs.h"
-void openavbMcsInit(mcs_t *mediaClockSynth, U64 nsPerAdvance)
+void openavbMcsInit(mcs_t *mediaClockSynth, U64 nsPerAdvance, S32 correctionAmount, U32 correctionInterval)
{
- mediaClockSynth->firstTimeSet = FALSE;
- mediaClockSynth->nsPerAdvance = nsPerAdvance;
- mediaClockSynth->edgeTime = 0;
+ mediaClockSynth->firstTimeSet = FALSE;
+ mediaClockSynth->nsPerAdvance = nsPerAdvance;
+ mediaClockSynth->correctionAmount = correctionAmount;
+ mediaClockSynth->correctionInterval = correctionInterval;
+ mediaClockSynth->startTime = 0;
+ mediaClockSynth->tickCount = 0;
+ mediaClockSynth->edgeTime = 0;
}
void openavbMcsAdvance(mcs_t *mediaClockSynth)
{
- if (mediaClockSynth->firstTimeSet == FALSE) {
- CLOCK_GETTIME64(OPENAVB_CLOCK_WALLTIME, &mediaClockSynth->edgeTime);
- if (mediaClockSynth->edgeTime) {
- mediaClockSynth->firstTimeSet = TRUE;
- }
- }
- else {
- mediaClockSynth->edgeTime += mediaClockSynth->nsPerAdvance;
+ if (mediaClockSynth->firstTimeSet == FALSE) {
+ CLOCK_GETTIME64(OPENAVB_CLOCK_WALLTIME, &mediaClockSynth->edgeTime);
+ if (mediaClockSynth->edgeTime) {
+ mediaClockSynth->firstTimeSet = TRUE;
+ mediaClockSynth->startTime = mediaClockSynth->edgeTime;
+ }
+ }
+ else
+ {
+ mediaClockSynth->edgeTime += mediaClockSynth->nsPerAdvance;
+ mediaClockSynth->tickCount++;
+ if (mediaClockSynth->tickCount % mediaClockSynth->correctionInterval == 0) {
+ mediaClockSynth->edgeTime += mediaClockSynth->correctionAmount;
+ }
#if !IGB_LAUNCHTIME_ENABLED
- IF_LOG_INTERVAL(8000) {
- U64 nowNS;
- CLOCK_GETTIME64(OPENAVB_CLOCK_WALLTIME, &nowNS);
- S64 fixedRealDelta = mediaClockSynth->edgeTime - nowNS;
- AVB_LOGF_INFO("Fixed/Real TS Delta: %llu", fixedRealDelta);
- }
+ IF_LOG_INTERVAL(8000) {
+ U64 nowNS;
+ CLOCK_GETTIME64(OPENAVB_CLOCK_WALLTIME, &nowNS);
+ S64 fixedRealDelta = mediaClockSynth->edgeTime - nowNS;
+ AVB_LOGF_INFO("Fixed/Real TS Delta: %lld", fixedRealDelta);
+ }
#endif
- }
+ }
}
diff --git a/lib/avtp_pipeline/mcs/openavb_mcs.h b/lib/avtp_pipeline/mcs/openavb_mcs.h
index 1d448961..1ae8f7de 100644
--- a/lib/avtp_pipeline/mcs/openavb_mcs.h
+++ b/lib/avtp_pipeline/mcs/openavb_mcs.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
-Copyright (c) 2016, Harman International Industries, Incorporated
+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
@@ -21,6 +22,11 @@ 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.
*************************************************************************************************************/
/*
@@ -31,12 +37,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define OPENAVB_MCS_H
typedef struct {
- bool firstTimeSet;
- U64 nsPerAdvance;
- U64 edgeTime;
+ bool firstTimeSet;
+ U64 nsPerAdvance;
+ U64 startTime;
+ U64 tickCount;
+ S32 correctionAmount;
+ U32 correctionInterval;
+ U64 edgeTime;
} mcs_t;
-void openavbMcsInit(mcs_t *mediaClockSynth, U64 nsPerAdvance);
+void openavbMcsInit(mcs_t *mediaClockSynth, U64 nsPerAdvance, S32 correctionAmount, U32 correctionInterval);
void openavbMcsAdvance(mcs_t *mediaClockSynth);
#endif
diff --git a/lib/avtp_pipeline/mediaq/openavb_mediaq.c b/lib/avtp_pipeline/mediaq/openavb_mediaq.c
index 463b15c2..eda2c68d 100644
--- a/lib/avtp_pipeline/mediaq/openavb_mediaq.c
+++ b/lib/avtp_pipeline/mediaq/openavb_mediaq.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
@@ -40,8 +41,6 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_mediaq.h"
#include "openavb_avtp_time_pub.h"
-#include "openavb_printbuf.h"
-
#define AVB_LOG_COMPONENT "Media Queue"
#include "openavb_log.h"
@@ -49,10 +48,6 @@ static MUTEX_HANDLE(gMediaQMutex);
#define MEDIAQ_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(gMediaQMutex); MUTEX_LOG_ERR("Mutex Lock failure"); }
#define MEDIAQ_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(gMediaQMutex); MUTEX_LOG_ERR("Mutex Unlock failure"); }
-// CORE_TODO : Currently this first future logic for purge the media queue and incoming items
-// may be too aggressive and can result in never catching up. Therefore it is disabled for now
-//#define ENABLE_FIRST_FUTURE 1
-
//#define DUMP_HEAD_PUSH 1
//#define DUMP_TAIL_PULL 1
@@ -85,9 +80,6 @@ typedef struct {
// True is next item to be pulled is locked
bool tailLocked;
- // set if timestamp is ever in the future
- bool firstFuture;
-
// Maximum latency
U32 maxLatencyUsec;
@@ -167,18 +159,6 @@ void x_openavbMediaQPurgeStaleTail(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ_DETAIL);
-#if 0 // debug
- // Debug code to report delta from TS
- static bool init = TRUE;
- static U32 cnt = 0;
- static openavb_printbuf_t printBuf;
- if (init) {
- printBuf = openavbPrintbufNew(2000, 20);
- init = FALSE;
- }
-#endif
-
-
if (pMediaQ) {
if (pMediaQ->pPvtMediaQInfo) {
media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
@@ -196,14 +176,12 @@ void x_openavbMediaQPurgeStaleTail(media_q_t *pMediaQ)
pMediaQInfo->tailLocked = TRUE;
bool bPurge = FALSE;
-#ifdef ENABLE_FIRST_FUTURE
if (bFirst) {
S32 delta = openavbAvtpTimeUsecDelta(pTail->pAvtpTime);
S32 maxStale = (S32)(0 - pMediaQInfo->maxStaleTailUsec);
if (delta < maxStale) {
- IF_LOG_INTERVAL(100) AVB_LOGF_INFO("Purging stale MediaQ items: delta:%dus maxStale%dus", delta, maxStale);
-
+ AVB_LOGF_DEBUG("Purging stale MediaQ items: delta %d us, maxStale %d us", delta, maxStale);
bPurge = TRUE;
}
bFirst = FALSE;
@@ -211,6 +189,7 @@ void x_openavbMediaQPurgeStaleTail(media_q_t *pMediaQ)
else {
// Once we have triggered a stale tail purge everything past presentation time.
if (openavbAvtpTimeIsPast(pTail->pAvtpTime)) {
+ AVB_LOG_DEBUG("Purging stale MediaQ items");
bPurge = TRUE;
}
}
@@ -224,46 +203,6 @@ void x_openavbMediaQPurgeStaleTail(media_q_t *pMediaQ)
pMediaQInfo->tailLocked = FALSE;
pTail = NULL;
}
-#else // ENABLE_FIRST_FUTURE
- if (bFirst) {
- S32 delta = openavbAvtpTimeUsecDelta(pTail->pAvtpTime);
- S32 maxStale = (S32)(0 - pMediaQInfo->maxStaleTailUsec);
- if(delta >= 0) {
- pMediaQInfo->firstFuture = TRUE;
- }
- else if (delta < maxStale) {
- bPurge = TRUE;
- pMediaQInfo->firstFuture = FALSE;
- }
-
- bFirst = FALSE;
- }
- else {
- // Once we have triggered a stale tail purge everything past presentation time.
- if (openavbAvtpTimeIsPast(pTail->pAvtpTime)) {
-#if 0 // debug
- if (!(++cnt % 1)) {
- openavbPrintbufPrintf(printBuf, "Purge More\n");
- }
-#endif
- bPurge = TRUE;
- }
- else {
- pMediaQInfo->firstFuture = TRUE;
- }
- }
-
- if (bPurge || (pMediaQInfo->firstFuture == FALSE)) {
- openavbMediaQTailPull(pMediaQ);
- pTail = NULL;
- bMore = TRUE;
- }
- else {
- pMediaQInfo->tailLocked = FALSE;
- pTail = NULL;
- }
-#endif // ENABLE_FIRST_FUTURE
-
}
}
}
@@ -292,7 +231,6 @@ media_q_t* openavbMediaQCreate()
pMediaQInfo->headLocked = FALSE;
pMediaQInfo->tail = -1;
pMediaQInfo->tailLocked = FALSE;
- pMediaQInfo->firstFuture = TRUE;
pMediaQInfo->maxLatencyUsec = 0;
pMediaQInfo->threadSafeOn = FALSE;
pMediaQInfo->maxStaleTailUsec = MICROSECONDS_PER_SECOND;
@@ -347,7 +285,7 @@ bool openavbMediaQSetSize(media_q_t *pMediaQ, int itemCount, int itemSize)
int i1;
for (i1 = 0; i1 < itemCount; i1++) {
pMediaQInfo->pItems[i1].pAvtpTime = openavbAvtpTimeCreate(pMediaQInfo->maxLatencyUsec);
- pMediaQInfo->pItems[i1].pPubData = calloc(1, itemSize);
+ pMediaQInfo->pItems[i1].pPubData = calloc(1, itemSize + 4 /* Just in case */);
pMediaQInfo->pItems[i1].dataLen = 0;
pMediaQInfo->pItems[i1].itemSize = itemSize;
if (!pMediaQInfo->pItems[i1].pPubData) {
@@ -399,7 +337,7 @@ bool openavbMediaQAllocItemMapData(media_q_t *pMediaQ, int itemPubMapSize, int i
}
}
else {
- AVB_LOG_ERROR("Attemping to reallocate public map data");
+ AVB_LOG_ERROR("Attempting to reallocate public map data");
AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
return FALSE;
}
@@ -413,7 +351,7 @@ bool openavbMediaQAllocItemMapData(media_q_t *pMediaQ, int itemPubMapSize, int i
}
}
else {
- AVB_LOG_ERROR("Attemping to reallocate private map data");
+ AVB_LOG_ERROR("Attempting to reallocate private map data");
AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
return FALSE;
}
@@ -449,7 +387,7 @@ bool openavbMediaQAllocItemIntfData(media_q_t *pMediaQ, int itemIntfSize)
}
}
else {
- AVB_LOG_ERROR("Attemping to reallocate private interface data");
+ AVB_LOG_ERROR("Attempting to reallocate private interface data");
AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
return FALSE;
}
@@ -699,13 +637,14 @@ media_q_item_t* openavbMediaQTailLock(media_q_t *pMediaQ, bool ignoreTimestamp)
if (pMediaQInfo->threadSafeOn) {
MEDIAQ_UNLOCK();
}
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
return NULL;
}
}
pMediaQInfo->tailLocked = TRUE;
- AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
// Mutex (LOCK()) if acquired stays locked
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
return pTail;
}
}
diff --git a/lib/avtp_pipeline/mediaq/openavb_mediaq.h b/lib/avtp_pipeline/mediaq/openavb_mediaq.h
index 4a2c031c..ec69a84a 100644
--- a/lib/avtp_pipeline/mediaq/openavb_mediaq.h
+++ b/lib/avtp_pipeline/mediaq/openavb_mediaq.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/mediaq/openavb_mediaq_pub.h b/lib/avtp_pipeline/mediaq/openavb_mediaq_pub.h
index 4e479f9d..16d8c0ac 100644
--- a/lib/avtp_pipeline/mediaq/openavb_mediaq_pub.h
+++ b/lib/avtp_pipeline/mediaq/openavb_mediaq_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.
*************************************************************************************************************/
@@ -73,7 +74,7 @@ typedef struct {
void *pPubMapData;
/// For use internally by mapping modules. Often may not be used.
- void *pPvtMapData;
+ void *pPvtMapData;
/// For use internally by the interface. Often may not be used.
void *pPvtIntfData;
@@ -125,7 +126,7 @@ media_q_t* openavbMediaQCreate();
/** Enable thread safe access for this media queue.
*
* In the default case a media queue is only accessed from a single thread and
- * therefore multi-threaded synchronication isn't needed. In situations where a
+ * therefore multi-threaded synchronization isn't needed. In situations where a
* media queue can be accessed from multiple threads calling this function will
* enable mutex protection on the head and tail related functions. Once enabled
* for a media queue it can not be disabled.
@@ -238,7 +239,7 @@ media_q_item_t *openavbMediaQHeadLock(media_q_t *pMediaQ);
*
* Unlock a locked media queue item from the head of the queue. The item will
* not become available for use in the queue and the data will not be cleared.
- * Subsequent calls to openavbMediaQHeadLock will return the same item storage
+ * Subsequent calls to openavbMediaQHeadLock will return the same item storage
* with the same data values. An interface module will use this function when
* running as a talker when it must release a previously locked media queue head
* item.
@@ -264,9 +265,9 @@ bool openavbMediaQHeadPush(media_q_t *pMediaQ);
* Lock the next available tail item in the media queue. Available is based on
* the timestamp that is associated with the item when it was a placed into the
* media queue. The interface module running on a listener uses this function
- * to access the data items place into the media queue by the mapping module.
+ * to access the data items placed into the media queue by the mapping module.
* At some point after this function call the item must be unlocked with either
- * openavbMediaQTailUnlockor openavbMediaQTailPull on the same callback or a subsequent
+ * openavbMediaQTailUnlock or openavbMediaQTailPull on the same callback or a subsequent
* callback.
*
* \param pMediaQ A pointer to the media_q_t structure.
@@ -343,7 +344,7 @@ bool openavbMediaQIsAvailableBytes(media_q_t *pMediaQ, U32 bytes, bool ignoreTim
/** Count number of available MediaQ items.
*
- * Count the number of available MediaQ items.
+ * Count the number of available MediaQ items.
*
* \param pMediaQ A pointer to the media_q_t structure.
* \param ignoreTimestamp Ignore timestamp for byte accumulation.
diff --git a/lib/avtp_pipeline/openavb_common/mrp_client.c b/lib/avtp_pipeline/openavb_common/mrp_client.c
index da1afba8..1a285b5f 100644
--- a/lib/avtp_pipeline/openavb_common/mrp_client.c
+++ b/lib/avtp_pipeline/openavb_common/mrp_client.c
@@ -85,7 +85,6 @@ int send_mrp_msg(char *notify_data, int notify_len)
int process_mrp_msg(char *buf, int buflen)
{
-
/*
* 1st character indicates application
* [MVS] - MAC, VLAN or STREAM
@@ -97,180 +96,63 @@ int process_mrp_msg(char *buf, int buflen)
unsigned int max_interval_frames;
unsigned int priority_and_rank;
unsigned int latency;
- int i, j, k;
+ int i, j;
unsigned int substate;
unsigned char recovered_streamid[8];
unsigned char dest_addr[6];
- k = 0;
- next_line:if (k >= buflen)
- return 0;
- switch (buf[k]) {
- case 'E':
- AVB_LOGF_DEBUG("%s from mrpd", buf);
- mrp_error = 1;
- break;
- case 'O':
- mrp_okay = 1;
- break;
- case 'M':
- case 'V':
- AVB_LOGF_DEBUG("%s unhandled from mrpd", buf);
- /* unhandled for now */
- break;
- case 'L':
-
- /* parse a listener attribute - see if it matches our monitor_stream_id */
- i = k;
- while (buf[i] != 'D')
- i++;
- i += 2; /* skip the ':' */
- sscanf(&(buf[i]), "%d", &substate);
- while (buf[i] != 'S')
- i++;
- i += 2; /* skip the ':' */
- for (j = 0; j < 8; j++) {
- sscanf(&(buf[i + 2 * j]), "%02x", &id);
- recovered_streamid[j] = (unsigned char)id;
- }
- AVB_LOGF_DEBUG
- ("FOUND STREAM ID=%02x%02x%02x%02x%02x%02x%02x%02x ",
- recovered_streamid[0], recovered_streamid[1],
- recovered_streamid[2], recovered_streamid[3],
- recovered_streamid[4], recovered_streamid[5],
- recovered_streamid[6], recovered_streamid[7]);
- switch (substate) {
- case 0:
- AVB_LOG_DEBUG("with state ignore");
- break;
- case 1:
- AVB_LOG_DEBUG("with state askfailed");
- break;
- case 2:
- AVB_LOG_DEBUG("with state ready");
+ int offset = 0;
+
+#if (AVB_LOG_LEVEL_DEBUG <= AVB_LOG_LEVEL)
+ // Display this response in a user-friendly format.
+ static char szMrpData[MAX_MRPD_CMDSZ];
+ int nMrpDataLength = (buflen < MAX_MRPD_CMDSZ - 1 ? buflen : MAX_MRPD_CMDSZ - 1);
+ strncpy(szMrpData, buf, nMrpDataLength);
+ szMrpData[nMrpDataLength] = '\0';
+ while (nMrpDataLength > 0 &&
+ (buf[nMrpDataLength - 1] == '\0' || buf[nMrpDataLength - 1] == '\r' || buf[nMrpDataLength - 1] == '\n')) {
+ // Remove the trailing whitespace.
+ szMrpData[--nMrpDataLength] = '\0';
+ }
+ AVB_LOGF_DEBUG("MRP Response: %s", szMrpData);
+#endif
+
+ while (offset < buflen && buf[offset] != '\0') {
+
+ switch (buf[offset]) {
+ case 'E':
+ mrp_error = 1;
break;
- case 3:
- AVB_LOG_DEBUG("with state readyfail");
+
+ case 'O':
+ mrp_okay = 1;
break;
- default:
- AVB_LOGF_DEBUG("with state UNKNOWN (%d)", substate);
+
+ case 'M':
+ case 'V':
+ /* unhandled for now */
break;
- }
- mrp_attach_cb(recovered_streamid, substate);
- if (substate > MSRP_LISTENER_ASKFAILED) {
- if (memcmp
- (recovered_streamid, monitor_stream_id,
- sizeof(recovered_streamid)) == 0) {
- listeners = 1;
- AVB_LOG_DEBUG("added listener");
- }
- }
- /* try to find a newline ... */
- while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0'))
- i++;
- if (i == buflen)
- return 0;
- if (buf[i] == '\0')
- return 0;
- i++;
- k = i;
- goto next_line;
- break;
- case 'D':
- i = k + 4;
-
- /* save the domain attribute */
- sscanf(&(buf[i]), "%d", &id);
- while (buf[i] != 'P')
- i++;
- i += 2; /* skip the ':' */
- sscanf(&(buf[i]), "%d", &priority);
- while (buf[i] != 'V')
- i++;
- i += 2; /* skip the ':' */
- sscanf(&(buf[i]), "%x", &vid);
- if (id == 6) {
- domain_class_a_id = id;
- domain_class_a_priority = priority;
- domain_class_a_vid = vid;
- domain_a_valid = 1;
- } else {
- domain_class_b_id = id;
- domain_class_b_priority = priority;
- domain_class_b_vid = vid;
- domain_b_valid = 1;
- }
- while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0'))
- i++;
- if ((i == buflen) || (buf[i] == '\0'))
- return 0;
- i++;
- k = i;
- goto next_line;
- break;
- case 'T':
- i = k;
- while (buf[i] != 'S')
- i++;
- // skip S=
- i += 2;
- for (j = 0; j < 8; j++) {
- sscanf(&(buf[i + 2 * j]), "%02x", &id);
- recovered_streamid[j] = (unsigned char)id;
- }
- while (buf[i] != 'A')
- i++;
- // skip A=
- i += 2;
- for (j = 0; j < 6; j++) {
- sscanf(&(buf[i + 2 * j]), "%02x", &id);
- dest_addr[j] = (unsigned char)id;
- }
- i+= j*2 + 1;
-
- sscanf(&(buf[i]), "V=%d,Z=%d,I=%d,P=%d,L=%d",
- &vid,
- &max_frame_size,
- &max_interval_frames,
- &priority_and_rank,
- &latency);
-
- mrp_register_cb(recovered_streamid, 0, dest_addr, max_frame_size, max_interval_frames, vid, latency);
-
- while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0'))
- i++;
-
- if (i == buflen)
- return 0;
- if (buf[i] == '\0')
- return 0;
- i++;
- k = i;
- goto next_line;
- break;
- case 'S':
-
- /* handle the leave/join events */
- switch (buf[k + 4]) {
case 'L':
- i = k + 5;
+
+ /* parse a listener attribute - see if it matches our monitor_stream_id */
+ i = offset;
while (buf[i] != 'D')
i++;
- i += 2; /* skip the ':' */
+ i += 2; /* skip the ':' */
sscanf(&(buf[i]), "%d", &substate);
while (buf[i] != 'S')
i++;
- i += 2; /* skip the ':' */
+ i += 2; /* skip the ':' */
for (j = 0; j < 8; j++) {
sscanf(&(buf[i + 2 * j]), "%02x", &id);
recovered_streamid[j] = (unsigned char)id;
}
AVB_LOGF_DEBUG
- ("EVENT on STREAM ID=%02x%02x%02x%02x%02x%02x%02x%02x ",
- recovered_streamid[0], recovered_streamid[1],
- recovered_streamid[2], recovered_streamid[3],
- recovered_streamid[4], recovered_streamid[5],
- recovered_streamid[6], recovered_streamid[7]);
+ ("FOUND STREAM ID=%02x%02x%02x%02x%02x%02x%02x%02x ",
+ recovered_streamid[0], recovered_streamid[1],
+ recovered_streamid[2], recovered_streamid[3],
+ recovered_streamid[4], recovered_streamid[5],
+ recovered_streamid[6], recovered_streamid[7]);
switch (substate) {
case 0:
AVB_LOG_DEBUG("with state ignore");
@@ -288,34 +170,45 @@ int process_mrp_msg(char *buf, int buflen)
AVB_LOGF_DEBUG("with state UNKNOWN (%d)", substate);
break;
}
- switch (buf[k + 1]) {
- case 'L':
- mrp_attach_cb(recovered_streamid, substate);
- AVB_LOGF_DEBUG("got a leave indication substate %d", substate);
+ mrp_attach_cb(recovered_streamid, substate);
+ if (substate > MSRP_LISTENER_ASKFAILED) {
if (memcmp
- (recovered_streamid, monitor_stream_id,
- sizeof(recovered_streamid)) == 0) {
- listeners = 0;
- AVB_LOG_DEBUG("listener left");
+ (recovered_streamid, monitor_stream_id,
+ sizeof(recovered_streamid)) == 0) {
+ listeners = 1;
+ AVB_LOG_DEBUG("added listener");
}
- break;
- case 'J':
- case 'N':
- AVB_LOGF_DEBUG("got a new/join indication substate %d", substate);
- mrp_attach_cb(recovered_streamid, substate);
- if (substate > MSRP_LISTENER_ASKFAILED) {
- if (memcmp
- (recovered_streamid,
- monitor_stream_id,
- sizeof(recovered_streamid)) == 0)
- listeners = 1;
- }
- break;
+ }
+ break;
+
+ case 'D':
+ i = offset + 4;
+
+ /* save the domain attribute */
+ sscanf(&(buf[i]), "%d", &id);
+ while (buf[i] != 'P')
+ i++;
+ i += 2; /* skip the ':' */
+ sscanf(&(buf[i]), "%d", &priority);
+ while (buf[i] != 'V')
+ i++;
+ i += 2; /* skip the ':' */
+ sscanf(&(buf[i]), "%x", &vid);
+ if (id == 6) {
+ domain_class_a_id = id;
+ domain_class_a_priority = priority;
+ domain_class_a_vid = vid;
+ domain_a_valid = 1;
+ } else {
+ domain_class_b_id = id;
+ domain_class_b_priority = priority;
+ domain_class_b_vid = vid;
+ domain_b_valid = 1;
}
break;
case 'T':
- i = k + 5;
+ i = offset;
while (buf[i] != 'S')
i++;
// skip S=
@@ -335,21 +228,127 @@ int process_mrp_msg(char *buf, int buflen)
i+= j*2 + 1;
sscanf(&(buf[i]), "V=%d,Z=%d,I=%d,P=%d,L=%d",
- &vid,
- &max_frame_size,
- &max_interval_frames,
- &priority_and_rank,
- &latency);
+ &vid,
+ &max_frame_size,
+ &max_interval_frames,
+ &priority_and_rank,
+ &latency);
+
+ mrp_register_cb(recovered_streamid, 0, dest_addr, max_frame_size, max_interval_frames, vid, latency);
+ break;
+
+ case 'S':
+
+ /* handle the leave/join events */
+ switch (buf[offset + 4]) {
+ case 'L':
+ i = offset + 5;
+ while (buf[i] != 'D')
+ i++;
+ i += 2; /* skip the ':' */
+ sscanf(&(buf[i]), "%d", &substate);
+ while (buf[i] != 'S')
+ i++;
+ i += 2; /* skip the ':' */
+ for (j = 0; j < 8; j++) {
+ sscanf(&(buf[i + 2 * j]), "%02x", &id);
+ recovered_streamid[j] = (unsigned char)id;
+ }
+ AVB_LOGF_DEBUG
+ ("EVENT on STREAM ID=%02x%02x%02x%02x%02x%02x%02x%02x ",
+ recovered_streamid[0], recovered_streamid[1],
+ recovered_streamid[2], recovered_streamid[3],
+ recovered_streamid[4], recovered_streamid[5],
+ recovered_streamid[6], recovered_streamid[7]);
+ switch (substate) {
+ case 0:
+ AVB_LOG_DEBUG("with state ignore");
+ break;
+ case 1:
+ AVB_LOG_DEBUG("with state askfailed");
+ break;
+ case 2:
+ AVB_LOG_DEBUG("with state ready");
+ break;
+ case 3:
+ AVB_LOG_DEBUG("with state readyfail");
+ break;
+ default:
+ AVB_LOGF_DEBUG("with state UNKNOWN (%d)", substate);
+ break;
+ }
+ switch (buf[offset + 1]) {
+ case 'L':
+ mrp_attach_cb(recovered_streamid, substate);
+ AVB_LOGF_DEBUG("got a leave indication substate %d", substate);
+ if (memcmp
+ (recovered_streamid, monitor_stream_id,
+ sizeof(recovered_streamid)) == 0) {
+ listeners = 0;
+ AVB_LOG_DEBUG("listener left");
+ }
+ break;
+ case 'J':
+ case 'N':
+ AVB_LOGF_DEBUG("got a new/join indication substate %d", substate);
+ mrp_attach_cb(recovered_streamid, substate);
+ if (substate > MSRP_LISTENER_ASKFAILED) {
+ if (memcmp
+ (recovered_streamid,
+ monitor_stream_id,
+ sizeof(recovered_streamid)) == 0)
+ listeners = 1;
+ }
+ break;
+ }
+ break;
+
+ case 'T':
+ i = offset + 5;
+ while (buf[i] != 'S')
+ i++;
+ // skip S=
+ i += 2;
+ for (j = 0; j < 8; j++) {
+ sscanf(&(buf[i + 2 * j]), "%02x", &id);
+ recovered_streamid[j] = (unsigned char)id;
+ }
+ while (buf[i] != 'A')
+ i++;
+ // skip A=
+ i += 2;
+ for (j = 0; j < 6; j++) {
+ sscanf(&(buf[i + 2 * j]), "%02x", &id);
+ dest_addr[j] = (unsigned char)id;
+ }
+ i+= j*2 + 1;
- mrp_register_cb(recovered_streamid, buf[k+1] == 'J', dest_addr, max_frame_size, max_interval_frames, vid, latency);
+ sscanf(&(buf[i]), "V=%d,Z=%d,I=%d,P=%d,L=%d",
+ &vid,
+ &max_frame_size,
+ &max_interval_frames,
+ &priority_and_rank,
+ &latency);
+
+ mrp_register_cb(recovered_streamid, buf[offset+1] == 'J' || buf[offset+1] == 'N', dest_addr, max_frame_size, max_interval_frames, vid, latency);
+ break;
+
+ default:
+ break;
+ }
break;
- default:
- return 0;
+
+ case '\0':
break;
}
- break;
- case '\0':
- break;
+
+ // Proceed to the next line.
+ while (offset < buflen && buf[offset] != '\n' && buf[offset] != '\0') {
+ offset++;
+ }
+ if (offset < buflen && buf[offset] == '\n') {
+ offset++;
+ }
}
return 0;
}
@@ -434,9 +433,10 @@ int mrp_disconnect(void)
msgbuf = malloc(1500);
if (NULL == msgbuf)
return -1;
- memset(msgbuf, 0, 64);
+ memset(msgbuf, 0, 1500);
sprintf(msgbuf, "BYE");
mrp_okay = 0;
+ AVB_LOGF_DEBUG("MRP Command (Disconnect): %s", msgbuf);
rc = send_mrp_msg(msgbuf, 1500);
free(msgbuf);
@@ -466,6 +466,7 @@ int mrp_register_domain(int *class_id, int *priority, u_int16_t * vid)
sprintf(msgbuf, "S+D:C=%d,P=%d,V=%04x", *class_id, *priority, *vid);
mrp_okay = 0;
+ AVB_LOGF_DEBUG("MRP Command (Register Domain): %s", msgbuf);
rc = send_mrp_msg(msgbuf, 1500);
free(msgbuf);
@@ -502,6 +503,7 @@ mrp_advertise_stream(uint8_t * streamid,
destaddr[3], destaddr[4], destaddr[5], vlan, pktsz,
interval, priority << 5, latency);
mrp_okay = 0;
+ AVB_LOGF_DEBUG("MRP Command (Advertise Stream): %s", msgbuf);
rc = send_mrp_msg(msgbuf, 1500);
free(msgbuf);
@@ -535,6 +537,7 @@ mrp_unadvertise_stream(uint8_t * streamid,
destaddr[3], destaddr[4], destaddr[5], vlan, pktsz,
interval, priority << 5, latency);
mrp_okay = 0;
+ AVB_LOGF_DEBUG("MRP Command (Unadvertise Stream): %s", msgbuf);
rc = send_mrp_msg(msgbuf, 1500);
free(msgbuf);
@@ -556,6 +559,7 @@ int mrp_await_listener(unsigned char *streamid)
return -1;
memset(msgbuf, 0, 1500);
sprintf(msgbuf, "S??");
+ AVB_LOGF_DEBUG("MRP Command (Await Listener): %s", msgbuf);
rc = send_mrp_msg(msgbuf, 1500);
free(msgbuf);
if (rc != 1500)
@@ -587,6 +591,7 @@ int mrp_get_domain(int *class_a_id, int *a_priority, u_int16_t * a_vid,
return -1;
memset(msgbuf, 0, 1500);
sprintf(msgbuf, "S??");
+ AVB_LOGF_DEBUG("MRP Command (Get Domain): %s", msgbuf);
ret = send_mrp_msg(msgbuf, 1500);
free(msgbuf);
if (ret != 1500)
@@ -623,6 +628,7 @@ int mrp_join_vlan()
return -1;
memset(msgbuf, 0, 1500);
sprintf(msgbuf, "V++:I=0002");
+ AVB_LOGF_DEBUG("MRP Command (Join VLAN): %s", msgbuf);
rc = send_mrp_msg(msgbuf, 1500);
free(msgbuf);
@@ -645,6 +651,7 @@ int mrp_join_listener(uint8_t * streamid)
",D=2", streamid[0], streamid[1], streamid[2], streamid[3],
streamid[4], streamid[5], streamid[6], streamid[7]);
mrp_okay = 0;
+ AVB_LOGF_DEBUG("MRP Command (Join Listener): %s", msgbuf);
rc = send_mrp_msg(msgbuf, 1500);
free(msgbuf);
@@ -676,6 +683,7 @@ int mrp_send_ready(uint8_t *stream_id)
stream_id[2], stream_id[3],
stream_id[4], stream_id[5],
stream_id[6], stream_id[7]);
+ AVB_LOGF_DEBUG("MRP Command (Send Ready): %s", databuf);
rc = send_mrp_msg(databuf, 1500);
free(databuf);
@@ -700,6 +708,7 @@ int mrp_send_leave(uint8_t *stream_id)
stream_id[4], stream_id[5],
stream_id[6], stream_id[7]);
+ AVB_LOGF_DEBUG("MRP Command (Send Leave): %s", databuf);
rc = send_mrp_msg(databuf, 1500);
free(databuf);
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 )
diff --git a/lib/avtp_pipeline/platform/generic/mcr/openavb_mcr_hal.c b/lib/avtp_pipeline/platform/generic/mcr/openavb_mcr_hal.c
index 6cdd873e..13236986 100644
--- a/lib/avtp_pipeline/platform/generic/mcr/openavb_mcr_hal.c
+++ b/lib/avtp_pipeline/platform/generic/mcr/openavb_mcr_hal.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/generic/mcr/openavb_mcr_hal.h b/lib/avtp_pipeline/platform/generic/mcr/openavb_mcr_hal.h
index 85579122..c6db6044 100644
--- a/lib/avtp_pipeline/platform/generic/mcr/openavb_mcr_hal.h
+++ b/lib/avtp_pipeline/platform/generic/mcr/openavb_mcr_hal.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/generic/openavb_hal.h b/lib/avtp_pipeline/platform/generic/openavb_hal.h
index e48711eb..1b748de7 100644
--- a/lib/avtp_pipeline/platform/generic/openavb_hal.h
+++ b/lib/avtp_pipeline/platform/generic/openavb_hal.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/platTCAL/GNU/openavb_mem_tcal.c b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.c
index 260c69f2..33cefb5c 100644
--- a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.c
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.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/platTCAL/GNU/openavb_mem_tcal.h b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.h
index 6060be93..95275438 100644
--- a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.h
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.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/platTCAL/GNU/openavb_mem_tcal_pub.h b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal_pub.h
index d1624e77..a0c772bf 100644
--- a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal_pub.h
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal_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
diff --git a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_tcal_pub.h b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_tcal_pub.h
index 2193e4b1..6a1ff93f 100644
--- a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_tcal_pub.h
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_tcal_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
diff --git a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_time_tcal_pub.h b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_time_tcal_pub.h
index 216adec0..acbc1809 100644
--- a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_time_tcal_pub.h
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_time_tcal_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
diff --git a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_types_base_tcal_pub.h b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_types_base_tcal_pub.h
index 64d7d6ba..ce39caa9 100644
--- a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_types_base_tcal_pub.h
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_types_base_tcal_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
diff --git a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_warnings_tcal.h b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_warnings_tcal.h
index 8da12fd1..99c24c91 100644
--- a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_warnings_tcal.h
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_warnings_tcal.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/platTCAL/GNU/rawsock/openavb_rawsock_tcal.h b/lib/avtp_pipeline/platform/platTCAL/GNU/rawsock/openavb_rawsock_tcal.h
index 72934112..51200551 100644
--- a/lib/avtp_pipeline/platform/platTCAL/GNU/rawsock/openavb_rawsock_tcal.h
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/rawsock/openavb_rawsock_tcal.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/x86_i210/mcr/openavb_mcr_hal.c b/lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.c
index 6cdd873e..13236986 100644
--- a/lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.c
+++ b/lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.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/x86_i210/mcr/openavb_mcr_hal.h b/lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.h
index 85579122..c6db6044 100644
--- a/lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.h
+++ b/lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.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/x86_i210/openavb_hal.h b/lib/avtp_pipeline/platform/x86_i210/openavb_hal.h
index a12e4dba..10114eb4 100644
--- a/lib/avtp_pipeline/platform/x86_i210/openavb_hal.h
+++ b/lib/avtp_pipeline/platform/x86_i210/openavb_hal.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/x86_i210/openavb_igb.c b/lib/avtp_pipeline/platform/x86_i210/openavb_igb.c
index 6bbbc8b4..f5c1acf0 100644
--- a/lib/avtp_pipeline/platform/x86_i210/openavb_igb.c
+++ b/lib/avtp_pipeline/platform/x86_i210/openavb_igb.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
@@ -107,7 +108,7 @@ device_t *igbAcquireDevice()
LOCK();
if (!igb_dev) {
- device_t *tmp_dev = malloc(sizeof(device_t));
+ device_t *tmp_dev = calloc(1, sizeof(device_t));
if (!tmp_dev) {
AVB_LOGF_ERROR("Cannot allocate memory for device: %s", strerror(errno));
goto unlock;
diff --git a/lib/avtp_pipeline/platform/x86_i210/openavb_igb.h b/lib/avtp_pipeline/platform/x86_i210/openavb_igb.h
index 20635e4b..2f160774 100644
--- a/lib/avtp_pipeline/platform/x86_i210/openavb_igb.h
+++ b/lib/avtp_pipeline/platform/x86_i210/openavb_igb.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/qmgr/openavb_qmgr.c b/lib/avtp_pipeline/qmgr/openavb_qmgr.c
index bf717157..5c054eb2 100644
--- a/lib/avtp_pipeline/qmgr/openavb_qmgr.c
+++ b/lib/avtp_pipeline/qmgr/openavb_qmgr.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
@@ -57,14 +58,19 @@ typedef struct {
#endif
int mode;
int ifindex;
- char ifname[IFNAMSIZ];
+ char ifname[IFNAMSIZ + 10]; // Include space for the socket type prefix (e.g. "simple:eth0")
U32 linkKbit;
U32 nsrKbit;
U32 linkMTU;
int ref;
} qdisc_data_t;
-static qdisc_data_t qdisc_data;
+static qdisc_data_t qdisc_data = {
+#if (AVB_FEATURE_IGB)
+ NULL,
+#endif
+ 0, 0, {0}, 0, 0, 0, 0
+};
// We do get accessed from multiple threads, so need a mutex
pthread_mutex_t qmgr_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
@@ -97,18 +103,20 @@ static qmgrStream_t qmgr_streams[MAX_AVB_STREAMS];
static bool setupHWQueue(int nClass, unsigned classBytesPerSec)
{
int err = 0;
+#if (AVB_FEATURE_IGB)
U32 class_a_bytes_per_sec, class_b_bytes_per_sec;
+#endif
AVB_TRACE_ENTRY(AVB_TRACE_QUEUE_MANAGER);
+#if (AVB_FEATURE_IGB)
if (nClass == SR_CLASS_A) {
class_a_bytes_per_sec = classBytesPerSec;
- class_b_bytes_per_sec = qmgr_classes[SR_CLASS_B].classBytesPerSec;
+ class_b_bytes_per_sec = qmgr_classes[SR_CLASS_B].classBytesPerSec;
} else {
- class_a_bytes_per_sec = qmgr_classes[SR_CLASS_A].classBytesPerSec;
+ class_a_bytes_per_sec = qmgr_classes[SR_CLASS_A].classBytesPerSec;
class_b_bytes_per_sec = classBytesPerSec;
}
-#if (AVB_FEATURE_IGB)
err = igb_set_class_bandwidth2(qdisc_data.igb_dev, class_a_bytes_per_sec, class_b_bytes_per_sec);
if (err)
AVB_LOGF_ERROR("Adding stream; igb_set_class_bandwidth failed: %s", strerror(err));
@@ -214,7 +222,7 @@ void openavbQmgrRemoveStream(U16 fwmark)
// update class
qmgr_classes[nClass].classBytesPerSec -= qmgr_streams[idx].streamBytesPerSec;
- AVB_LOGF_DEBUG("Removed strea; classBPS=%u, streamBPS=%u", qmgr_classes[nClass].classBytesPerSec, qmgr_streams[idx].streamBytesPerSec);
+ AVB_LOGF_DEBUG("Removed stream; classBPS=%u, streamBPS=%u", qmgr_classes[nClass].classBytesPerSec, qmgr_streams[idx].streamBytesPerSec);
// and stream
memset(&qmgr_streams[idx], 0, sizeof(qmgrStream_t));
}
@@ -267,7 +275,7 @@ bool openavbQmgrInitialize(int mode, int ifindex, const char* ifname, unsigned m
// Save the configuration
if (ifname)
- strncpy(qdisc_data.ifname, ifname, IFNAMSIZ - 1);
+ strncpy(qdisc_data.ifname, ifname, sizeof(qdisc_data.ifname) - 1);
qdisc_data.ifindex = ifindex;
qdisc_data.linkKbit = link_kbit;
qdisc_data.linkMTU = mtu;
diff --git a/lib/avtp_pipeline/qmgr/openavb_qmgr.h b/lib/avtp_pipeline/qmgr/openavb_qmgr.h
index 8e67257d..0a225d47 100644
--- a/lib/avtp_pipeline/qmgr/openavb_qmgr.h
+++ b/lib/avtp_pipeline/qmgr/openavb_qmgr.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/rawsock/CMakeLists.txt b/lib/avtp_pipeline/rawsock/CMakeLists.txt
index 561116ee..e3e0f49e 100644
--- a/lib/avtp_pipeline/rawsock/CMakeLists.txt
+++ b/lib/avtp_pipeline/rawsock/CMakeLists.txt
@@ -16,6 +16,7 @@ SET (SRC_FILES ${SRC_FILES}
${AVB_OSAL_DIR}/rawsock/openavb_rawsock.c
${AVB_OSAL_DIR}/rawsock/simple_rawsock.c
${AVB_OSAL_DIR}/rawsock/ring_rawsock.c
+ ${AVB_OSAL_DIR}/rawsock/sendmmsg_rawsock.c
${PCAP_FILES}
${IGB_FILES}
PARENT_SCOPE
diff --git a/lib/avtp_pipeline/rawsock/openavb_rawsock.h b/lib/avtp_pipeline/rawsock/openavb_rawsock.h
index 156e3711..11eb2b69 100644
--- a/lib/avtp_pipeline/rawsock/openavb_rawsock.h
+++ b/lib/avtp_pipeline/rawsock/openavb_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
@@ -61,6 +62,7 @@ typedef struct {
bool vlan; // Include VLAN header?
U8 vlan_pcp; // VLAN Priority Code Point
U16 vlan_vid; // VLAN ID
+ struct timespec ts; // RX timestamp
} hdr_info_t;
diff --git a/lib/avtp_pipeline/rawsock/rawsock_impl.c b/lib/avtp_pipeline/rawsock/rawsock_impl.c
index c9a4df53..8e4756be 100644
--- a/lib/avtp_pipeline/rawsock/rawsock_impl.c
+++ b/lib/avtp_pipeline/rawsock/rawsock_impl.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
@@ -35,16 +36,16 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_log.h"
void baseRawsockSetRxSignalMode(void *rawsock, bool rxSignalMode) {}
-int baseRawsockGetSocket(void *rawsock) { return -1; }
-U8 *baseRawsockGetRxFrame(void *rawsock, U32 usecTimeout, U32 *offset, U32 *len) { return NULL; }
+int baseRawsockGetSocket(void *rawsock) { AVB_LOG_ERROR("baseRawsockGetSocket called"); return -1; }
+U8 *baseRawsockGetRxFrame(void *rawsock, U32 usecTimeout, U32 *offset, U32 *len) { AVB_LOG_ERROR("baseRawsockGetRxFrame called"); return NULL; }
bool baseRawsockRelRxFrame(void *rawsock, U8 *pFrame) { return false; }
bool baseRawsockRxMulticast(void *rawsock, bool add_membership, const U8 buf[]) { return false; }
bool baseRawsockRxAVTPSubtype(void *rawsock, U8 subtype) { return false; }
bool baseRawsockTxSetMark(void *rawsock, int prio) { return false; }
-U8 *baseRawsockGetTxFrame(void *rawsock, bool blocking, U32 *size) { return NULL; }
+U8 *baseRawsockGetTxFrame(void *rawsock, bool blocking, U32 *size) { AVB_LOG_ERROR("baseRawsockGetTxFrame called"); return NULL; }
bool baseRawsockRelTxFrame(void *rawsock, U8 *pBuffer) { return false; }
-bool baseRawsockTxFrameReady(void *rawsock, U8 *pFrame, U32 len, U64 timeNsec) { return false; }
-int baseRawsockSend(void *rawsock) { return -1; }
+bool baseRawsockTxFrameReady(void *rawsock, U8 *pFrame, U32 len, U64 timeNsec) { AVB_LOG_ERROR("baseRawsockTxFrameReady called"); return false; }
+int baseRawsockSend(void *rawsock) { AVB_LOG_ERROR("baseRawsockSend called"); return -1; }
int baseRawsockTxBufLevel(void *rawsock) { return -1; }
int baseRawsockRxBufLevel(void *rawsock) { return -1; }
unsigned long baseRawsockGetTXOutOfBuffers(void *pvRawsock) { return 0; }
@@ -186,16 +187,24 @@ int baseRawsockRxParseHdr(void *pvRawsock, U8 *pBuffer, hdr_info_t *pInfo)
{
AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ memset(pInfo, 0, sizeof(hdr_info_t));
+
eth_hdr_t *eth_hdr = (eth_hdr_t*)pBuffer;
pInfo->dhost = eth_hdr->dhost;
pInfo->shost = eth_hdr->shost;
pInfo->ethertype = ntohs(eth_hdr->ethertype);
+ pInfo->ts.tv_sec = 0;
+ pInfo->ts.tv_nsec = 0;
int hdrLen = sizeof(eth_hdr_t);
if (pInfo->ethertype == ETHERTYPE_8021Q) {
+ U16 vlan_bits = ntohs(*(U16*)(pBuffer + hdrLen));
pInfo->vlan = TRUE;
- // TODO extract vlan_vid and vlan_pcp
- hdrLen += 4;
+ pInfo->vlan_vid = vlan_bits & 0x0FFF;
+ pInfo->vlan_pcp = (vlan_bits >> 13) & 0x0007;
+ hdrLen += 2;
+ pInfo->ethertype = ntohs(*(U16 *)(pBuffer + hdrLen));
+ hdrLen += 2;
}
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
diff --git a/lib/avtp_pipeline/rawsock/rawsock_impl.h b/lib/avtp_pipeline/rawsock/rawsock_impl.h
index 7269b9f0..050f32ab 100644
--- a/lib/avtp_pipeline/rawsock/rawsock_impl.h
+++ b/lib/avtp_pipeline/rawsock/rawsock_impl.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/shaper/openavb_shaper.h b/lib/avtp_pipeline/shaper/openavb_shaper.h
new file mode 100644
index 00000000..2639aab0
--- /dev/null
+++ b/lib/avtp_pipeline/shaper/openavb_shaper.h
@@ -0,0 +1,49 @@
+/*************************************************************************************************************
+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_SHAPER_H
+#define OPENAVB_SHAPER_H 1
+#include "openavb_types.h"
+
+// Shaper library lifecycle
+bool openavbShaperInitialize(const char *ifname, unsigned int shaperPort);
+void openavbShaperFinalize();
+
+bool openavbShaperDaemonAvailable(void);
+
+// Tell the Shaper to shape outgoing packets.
+// Use the returned value for the call to openavbShapingRelease().
+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);
+
+// Have the Shaper stop shaping outgoing packets.
+void openavbShaperRelease(void* handle);
+
+#endif // OPENAVB_SHAPER_H
diff --git a/lib/avtp_pipeline/srp/openavb_srp.h b/lib/avtp_pipeline/srp/openavb_srp.h
index e5d1471f..c0d05e93 100755
--- a/lib/avtp_pipeline/srp/openavb_srp.h
+++ b/lib/avtp_pipeline/srp/openavb_srp.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
@@ -33,7 +34,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*
* Implementation of IEEE 802.1Q
* Multiple Stream Reservation Protocol
-* (limited intial implementation for end stations)
+* (limited initial implementation for end stations)
*
* This file declares the "Private" portion - see also openavb_srp_api.h
*/
@@ -132,8 +133,8 @@ typedef struct SrClassParameters {
} SrClassParameters_t;
// Applicant State - IEEE 802.1Q Table 10-3
-// State here are simplified becasue:
-// - we are suppporting point-to-point only and
+// State here are simplified because:
+// - we are supporting point-to-point only and
// - initial declaration sends are immediate so there is no need for VP and VN
typedef enum openavbSrpAppState {
openavbSrp_ApSt_VO = 0x00, // no declarations - note that we initialize to 0
@@ -154,7 +155,7 @@ typedef enum openavbSrpRegState {
// Element for linked list of declared / registered streams.
// Since both a talker and a listener can exist for the same stream on the same
-// end-station, seperate talker and listener lists are kept.
+// end-station, separate talker and listener lists are kept.
// IMPORTANT NOTE: This implementation assumes that on a given end-station, no
// more than one talker and no more than one listener exist for each stream; if
// this is not the case, individual stream list elements could be corrupted
@@ -170,7 +171,7 @@ typedef enum openavbSrpRegState {
// - avtpHandle, streamId, DA, tSpec, SRClassId, Rank, and Latency
// are as received from AVTP via openavbSrpRegisterStream();
// - failInfo is populated only if this station has insufficient outbound
-// bandwidth for this stream, so must send Talker Failed delcaration;
+// bandwidth for this stream, so must send Talker Failed declaration;
// - kbpsReserved is the bandwidth currently reserved for the stream.
//
// On Listener:
@@ -184,9 +185,9 @@ typedef enum openavbSrpRegState {
// received for the stream, if anything; (openavbSrp_AtTyp_None indicates that
// the listener currently has no talker declaration for the stream);
// - regSubType is not used;
-// - avtpHandle is as recieved from AVTP via openavbSrpAttachStream();
-// - strmId is either as recieved from AVTP via openavbSrpAttachStream() or
-// as recieved via a talker declaration packet (MSRPDU), whichever occurs first;
+// - avtpHandle is as received from AVTP via openavbSrpAttachStream();
+// - strmId is either as received from AVTP via openavbSrpAttachStream() or
+// as received via a talker declaration packet (MSRPDU), whichever occurs first;
// - SRClassIdx is derived from priority received in talker declaration packet;
// - DA, tSpec, latency, and, if applicable, failInfo are
// as received in talker declaration packet
@@ -202,8 +203,8 @@ typedef struct openavbSrpStrm {
// (declType == openavbSrp_AtTyp_None is redundant to appState == openavbSrp_ApSt_VO).
openavbSrpLsnrDeclSubtype_t declSubType; // listener subtype this station is declaring for this stream, if any;
// not used on talker; valid only if declType == openavbSrp_AtTyp_Listener.
- openavbSrpAttribType_t regType; // attribute type this station has recieved (registered) for this stream, if any;
- openavbSrpLsnrDeclSubtype_t regSubType; // listener subtype this station has recieved (registered) for this stream, if any;
+ openavbSrpAttribType_t regType; // attribute type this station has received (registered) for this stream, if any;
+ openavbSrpLsnrDeclSubtype_t regSubType; // listener subtype this station has received (registered) for this stream, if any;
// not used on listener; valid only if regType == openavbSrp_AtTyp_Listener.
U8 DA[ETH_MAC_ADDR_LEN];
AVBTSpec_t tSpec;
diff --git a/lib/avtp_pipeline/srp/openavb_srp_api.h b/lib/avtp_pipeline/srp/openavb_srp_api.h
index 4c13b637..3f1d9bba 100755
--- a/lib/avtp_pipeline/srp/openavb_srp_api.h
+++ b/lib/avtp_pipeline/srp/openavb_srp_api.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
@@ -33,7 +34,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*
* Implementation of IEEE 802.1Q
* Multiple Stream Reservation Protocol
-* (limited intial implementation for end stations)
+* (limited initial implementation for end stations)
*
* This file declares the "Public" API.
*
@@ -48,7 +49,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_types.h"
// TBD - If queue manager can fail to configure a queue for a granted reservation, SRP
-// needs to know about the failure in order to correct reseved bandwidth totals.
+// needs to know about the failure in order to correct reserved bandwidth totals.
// (we are probably toast if queue manager fails when removing a stream)
// TBD - This implementation handles bandwidth in kilobits per second
@@ -82,7 +83,7 @@ enum openavbSrpFailureCode {
openavbSrp_FC_NoClassBandwidth = 3, // Insufficient bandwidth for Traffic Class,
// 4: StreamID in use by another Talker,
// 5: Stream destination address already in use,
- // 6: Stream pre-empted by higher rank,
+ // 6: Stream preempted by higher rank,
// 7: Reported latency has changed,
openavbSrp_FC_NotCapable = 8, // Egress port is not AVBCapable,
// 9: Use a different destination_address,
diff --git a/lib/avtp_pipeline/tl/CMakeLists.txt b/lib/avtp_pipeline/tl/CMakeLists.txt
index 99b0bce2..d3622cc9 100644
--- a/lib/avtp_pipeline/tl/CMakeLists.txt
+++ b/lib/avtp_pipeline/tl/CMakeLists.txt
@@ -3,6 +3,7 @@ SET (SRC_FILES_TL
${AVB_OSAL_DIR}/tl/openavb_tl_osal.c
${AVB_SRC_DIR}/tl/openavb_listener.c
${AVB_SRC_DIR}/tl/openavb_talker.c
+ ${AVB_SRC_DIR}/avdecc_msg/openavb_avdecc_msg_client.c
)
if(AVB_FEATURE_ENDPOINT)
diff --git a/lib/avtp_pipeline/tl/openavb_listener.c b/lib/avtp_pipeline/tl/openavb_listener.c
index 18333848..53cb3b2e 100644
--- a/lib/avtp_pipeline/tl/openavb_listener.c
+++ b/lib/avtp_pipeline/tl/openavb_listener.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.
*************************************************************************************************************/
@@ -40,6 +41,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_tl.h"
#include "openavb_avtp.h"
#include "openavb_listener.h"
+#include "openavb_avdecc_msg_client.h"
// DEBUG Uncomment to turn on logging for just this module.
//#define AVB_LOG_ON 1
@@ -83,6 +85,7 @@ bool listenerStartStream(tl_state_t *pTLState)
U64 nowNS;
CLOCK_GETTIME64(OPENAVB_TIMER_CLOCK, &nowNS);
pListenerData->nextReportNS = nowNS + (pCfg->report_seconds * NANOSECONDS_PER_SECOND);
+ pListenerData->lastReportFrames = 0;
pListenerData->nextSecondNS = nowNS + NANOSECONDS_PER_SECOND;
// Clear counters
@@ -121,7 +124,7 @@ void listenerStopStream(tl_state_t *pTLState)
openavbListenerAddStat(pTLState, TL_STAT_RX_LOST, openavbAvtpLost(pListenerData->avtpHandle));
openavbListenerAddStat(pTLState, TL_STAT_RX_BYTES, openavbAvtpBytes(pListenerData->avtpHandle));
- AVB_LOGF_INFO("RX "STREAMID_FORMAT", Totals: calls=%" PRIu64 "frames=%" PRIu64 "lost=%" PRIu64 "bytes=%" PRIu64,
+ AVB_LOGF_INFO("RX "STREAMID_FORMAT", Totals: calls=%" PRIu64 ", frames=%" PRIu64 ", lost=%" PRIu64 ", bytes=%" PRIu64,
STREAMID_ARGS(&pListenerData->streamID),
openavbListenerGetStat(pTLState, TL_STAT_RX_CALLS),
openavbListenerGetStat(pTLState, TL_STAT_RX_FRAMES),
@@ -129,13 +132,34 @@ void listenerStopStream(tl_state_t *pTLState)
openavbListenerGetStat(pTLState, TL_STAT_RX_BYTES));
if (pTLState->bStreaming) {
- openavbAvtpShutdown(pListenerData->avtpHandle);
+ openavbAvtpShutdownListener(pListenerData->avtpHandle);
pTLState->bStreaming = FALSE;
}
AVB_TRACE_EXIT(AVB_TRACE_TL);
}
+static inline void listenerShowStats(listener_data_t *pListenerData, tl_state_t *pTLState)
+{
+ U64 lost = openavbAvtpLost(pListenerData->avtpHandle);
+ U64 bytes = openavbAvtpBytes(pListenerData->avtpHandle);
+ U32 rxbuf = openavbAvtpRxBufferLevel(pListenerData->avtpHandle);
+ U32 mqbuf = openavbMediaQCountItems(pTLState->pMediaQ, TRUE);
+ U32 mqrdy = openavbMediaQCountItems(pTLState->pMediaQ, FALSE);
+
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "RX UID:%d, ", LOG_RT_DATATYPE_U16, &pListenerData->streamID.uniqueID);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "calls=%ld, ", LOG_RT_DATATYPE_U32, &pListenerData->nReportCalls);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "frames=%ld, ", LOG_RT_DATATYPE_U32, &pListenerData->nReportFrames);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "lost=%lld, ", LOG_RT_DATATYPE_U64, &lost);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "bytes=%lld, ", LOG_RT_DATATYPE_U64, &bytes);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "rxbuf=%d, ", LOG_RT_DATATYPE_U32, &rxbuf);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "mqbuf=%d, ", LOG_RT_DATATYPE_U32, &mqbuf);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "mqrdy=%d", LOG_RT_DATATYPE_U32, &mqrdy);
+
+ openavbListenerAddStat(pTLState, TL_STAT_RX_LOST, lost);
+ openavbListenerAddStat(pTLState, TL_STAT_RX_BYTES, bytes);
+}
+
static inline bool listenerDoStream(tl_state_t *pTLState)
{
AVB_TRACE_ENTRY(AVB_TRACE_TL);
@@ -164,30 +188,19 @@ static inline bool listenerDoStream(tl_state_t *pTLState)
if (pCfg->report_seconds > 0) {
if (nowNS > pListenerData->nextReportNS) {
-
- U64 lost = openavbAvtpLost(pListenerData->avtpHandle);
- U64 bytes = openavbAvtpBytes(pListenerData->avtpHandle);
- U32 rxbuf = openavbAvtpRxBufferLevel(pListenerData->avtpHandle);
- U32 mqbuf = openavbMediaQCountItems(pTLState->pMediaQ, TRUE);
- U32 mqrdy = openavbMediaQCountItems(pTLState->pMediaQ, FALSE);
-
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "RX UID:%d, ", LOG_RT_DATATYPE_U16, &pListenerData->streamID.uniqueID);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "calls=%ld, ", LOG_RT_DATATYPE_U32, &pListenerData->nReportCalls);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "frames=%ld, ", LOG_RT_DATATYPE_U32, &pListenerData->nReportFrames);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "lost=%lld, ", LOG_RT_DATATYPE_U64, &lost);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "bytes=%lld, ", LOG_RT_DATATYPE_U64, &bytes);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "rxbuf=%d, ", LOG_RT_DATATYPE_U32, &rxbuf);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "mqbuf=%d, ", LOG_RT_DATATYPE_U32, &mqbuf);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "mqrdy=%d", LOG_RT_DATATYPE_U32, &mqrdy);
+ listenerShowStats(pListenerData, pTLState);
openavbListenerAddStat(pTLState, TL_STAT_RX_CALLS, pListenerData->nReportCalls);
openavbListenerAddStat(pTLState, TL_STAT_RX_FRAMES, pListenerData->nReportFrames);
- openavbListenerAddStat(pTLState, TL_STAT_RX_LOST, lost);
- openavbListenerAddStat(pTLState, TL_STAT_RX_BYTES, bytes);
pListenerData->nReportCalls = 0;
pListenerData->nReportFrames = 0;
- pListenerData->nextReportNS += (pCfg->report_seconds * NANOSECONDS_PER_SECOND);
+ pListenerData->nextReportNS += (pCfg->report_seconds * NANOSECONDS_PER_SECOND);
+ }
+ } else if (pCfg->report_frames > 0 && pListenerData->nReportFrames != pListenerData->lastReportFrames) {
+ if (pListenerData->nReportFrames % pCfg->report_frames == 1) {
+ listenerShowStats(pListenerData, pTLState);
+ pListenerData->lastReportFrames = pListenerData->nReportFrames;
}
}
@@ -197,15 +210,15 @@ static inline bool listenerDoStream(tl_state_t *pTLState)
}
}
else {
- SLEEP(1);
- bRet = TRUE;
+ SLEEP_MSEC(1);
+ bRet = TRUE;
}
AVB_TRACE_EXIT(AVB_TRACE_TL);
return bRet;
}
-// Called from openavbTLThreadFn() which is started from openavbTLRun()
+// Called from openavbTLThreadFn() which is started from openavbTLRun()
void openavbTLRunListener(tl_state_t *pTLState)
{
AVB_TRACE_ENTRY(AVB_TRACE_TL);
@@ -225,6 +238,7 @@ void openavbTLRunListener(tl_state_t *pTLState)
}
AVBStreamID_t streamID;
+ memset(&streamID, 0, sizeof(streamID));
memcpy(streamID.addr, pCfg->stream_addr.mac, ETH_ALEN);
streamID.uniqueID = pCfg->stream_uid;
@@ -244,11 +258,14 @@ void openavbTLRunListener(tl_state_t *pTLState)
// Tell endpoint to listen for our stream.
// If there is a talker, we'll get callback (above.)
pTLState->bConnected = openavbTLRunListenerInit(pTLState->endpointHandle, &streamID);
-
+
if (pTLState->bConnected) {
bool bServiceIPC;
- // Do until we are stopped or loose connection to endpoint
+ // Notify AVDECC Msg of the state change.
+ openavbAvdeccMsgClntNotifyCurrentState(pTLState);
+
+ // Do until we are stopped or lose connection to endpoint
while (pTLState->bRunning && pTLState->bConnected) {
// Listen for an RX frame (or just sleep if not streaming)
@@ -276,6 +293,9 @@ void openavbTLRunListener(tl_state_t *pTLState)
// withdraw our listener attach
if (pTLState->bConnected)
openavbEptClntStopStream(pTLState->endpointHandle, &streamID);
+
+ // Notify AVDECC Msg of the state change.
+ openavbAvdeccMsgClntNotifyCurrentState(pTLState);
}
else {
AVB_LOGF_WARNING("Failed to connect to endpoint "STREAMID_FORMAT, STREAMID_ARGS(&streamID));
@@ -306,8 +326,12 @@ void openavbTLPauseListener(tl_state_t *pTLState, bool bPause)
return;
}
+ pTLState->bPaused = bPause;
openavbAvtpPause(pListenerData->avtpHandle, bPause);
+ // Notify AVDECC Msg of the state change.
+ openavbAvdeccMsgClntNotifyCurrentState(pTLState);
+
AVB_TRACE_EXIT(AVB_TRACE_TL);
}
diff --git a/lib/avtp_pipeline/tl/openavb_listener.h b/lib/avtp_pipeline/tl/openavb_listener.h
index f802d8cb..bbbeb806 100644
--- a/lib/avtp_pipeline/tl/openavb_listener.h
+++ b/lib/avtp_pipeline/tl/openavb_listener.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
@@ -46,7 +47,7 @@ typedef struct {
typedef struct {
// Data from callback
- char ifname[IFNAMSIZ];
+ char ifname[IFNAMSIZ + 10]; // Include space for the socket type prefix (e.g. "simple:eth0")
AVBStreamID_t streamID;
U8 destAddr[ETH_ALEN];
AVBTSpec_t tSpec;
@@ -58,6 +59,7 @@ typedef struct {
unsigned long nReportCalls;
U64 nextReportNS;
U64 nextSecondNS;
+ unsigned long lastReportFrames;
listener_stats_t stats;
} listener_data_t;
diff --git a/lib/avtp_pipeline/tl/openavb_listener_endpoint.c b/lib/avtp_pipeline/tl/openavb_listener_endpoint.c
index b1d4446e..6280266c 100644
--- a/lib/avtp_pipeline/tl/openavb_listener_endpoint.c
+++ b/lib/avtp_pipeline/tl/openavb_listener_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.
*************************************************************************************************************/
@@ -41,6 +42,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_endpoint.h"
#include "openavb_avtp.h"
#include "openavb_listener.h"
+#include "openavb_avdecc_msg.h"
// DEBUG Uncomment to turn on logging for just this module.
//#define AVB_LOG_ON 1
@@ -73,6 +75,12 @@ void openavbEptClntNotifyLstnrOfSrpCb(int endpointHandle,
return;
}
+ // If not a listener, ignore this callback.
+ if (pTLState->cfg.role != AVB_ROLE_LISTENER) {
+ AVB_LOG_DEBUG("Ignoring Listener callback");
+ return;
+ }
+
AVB_LOGF_DEBUG("%s streaming=%d, tlkrDecl=%d", __FUNCTION__, pTLState->bStreaming, tlkrDecl);
if (!pTLState->bStreaming
@@ -82,7 +90,11 @@ void openavbEptClntNotifyLstnrOfSrpCb(int endpointHandle,
bool rc = openavbEptClntAttachStream(pTLState->endpointHandle, streamID, openavbSrp_LDSt_Ready);
if (rc) {
// Save data provided by endpoint/SRP
- strncpy(pListenerData->ifname, ifname, IFNAMSIZ);
+ if (!pCfg->ifname[0]) {
+ strncpy(pListenerData->ifname, ifname, sizeof(pListenerData->ifname) - 1);
+ } else {
+ strncpy(pListenerData->ifname, pCfg->ifname, sizeof(pListenerData->ifname) - 1);
+ }
memcpy(&pListenerData->streamID, streamID, sizeof(AVBStreamID_t));
if (memcmp(destAddr, emptyMAC, ETH_ALEN) != 0) {
memcpy(&pListenerData->destAddr, destAddr, ETH_ALEN);
@@ -97,10 +109,8 @@ void openavbEptClntNotifyLstnrOfSrpCb(int endpointHandle,
}
else {
memcpy(&pListenerData->destAddr, &pCfg->dest_addr.mac->ether_addr_octet, ETH_ALEN);
- AVB_LOGF_INFO(" Listener configured dest_addr is %02x:%02x:%02x:%02x:%02x:%02x",
- pListenerData->destAddr[0], pListenerData->destAddr[1],
- pListenerData->destAddr[2], pListenerData->destAddr[3],
- pListenerData->destAddr[4], pListenerData->destAddr[5]);
+ AVB_LOGF_INFO(" Listener configured dest_addr is " ETH_FORMAT,
+ ETH_OCTETS(pListenerData->destAddr));
}
if ((!pCfg->max_interval_frames) || (!pCfg->max_frame_size)) {
AVB_LOG_ERROR(" Configuration Error - both max_interval_frames and max_frame_size required in listener config file");
@@ -128,6 +138,11 @@ void openavbEptClntNotifyLstnrOfSrpCb(int endpointHandle,
// We're still interested in the stream
openavbEptClntAttachStream(pTLState->endpointHandle, streamID, openavbSrp_LDSt_Interest);
+
+ // Notify AVDECC that fast connect is desired.
+ if (pTLState->bAvdeccMsgRunning) {
+ openavbAvdeccMsgClntChangeNotification(pTLState->avdeccMsgHandle, OPENAVB_AVDECC_MSG_STOPPED_UNEXPECTEDLY);
+ }
}
AVB_TRACE_EXIT(AVB_TRACE_TL);
diff --git a/lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c b/lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c
index d60de0cb..f7336f68 100644
--- a/lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c
+++ b/lib/avtp_pipeline/tl/openavb_listener_no_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.
*************************************************************************************************************/
@@ -51,7 +52,7 @@ bool openavbTLRunListenerInit(int hnd, AVBStreamID_t *streamID)
openavb_tl_cfg_t *pCfg = &pTLState->cfg;
listener_data_t *pListenerData = pTLState->pPvtListenerData;
- strncpy(pListenerData->ifname, pCfg->ifname, IFNAMSIZ);
+ strncpy(pListenerData->ifname, pCfg->ifname, sizeof(pListenerData->ifname) - 1);
memcpy(&pListenerData->streamID.addr, &pCfg->stream_addr.mac->ether_addr_octet, ETH_ALEN);
pListenerData->streamID.uniqueID = pCfg->stream_uid;
memcpy(&pListenerData->destAddr, &pCfg->dest_addr.mac->ether_addr_octet, ETH_ALEN);
@@ -61,7 +62,7 @@ bool openavbTLRunListenerInit(int hnd, AVBStreamID_t *streamID)
AVB_LOGF_INFO("Dest Addr: "ETH_FORMAT, ETH_OCTETS(pListenerData->destAddr));
AVB_LOGF_INFO("Starting stream: "STREAMID_FORMAT, STREAMID_ARGS(streamID));
listenerStartStream(pTLState);
-
+
return TRUE;
}
diff --git a/lib/avtp_pipeline/tl/openavb_talker.c b/lib/avtp_pipeline/tl/openavb_talker.c
index 81b69d4c..24fdacdd 100644
--- a/lib/avtp_pipeline/tl/openavb_talker.c
+++ b/lib/avtp_pipeline/tl/openavb_talker.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,7 +39,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_tl.h"
#include "openavb_avtp.h"
#include "openavb_talker.h"
-// #include "openavb_time.h"
+#include "openavb_avdecc_msg_client.h"
// DEBUG Uncomment to turn on logging for just this module.
//#define AVB_LOG_ON 1
@@ -126,7 +127,7 @@ bool talkerStartStream(tl_state_t *pTLState)
// setup the initial times
U64 nowNS;
- if (!pCfg->fixed_timestamp) {
+ if (!pCfg->spin_wait) {
CLOCK_GETTIME64(OPENAVB_TIMER_CLOCK, &nowNS);
} else {
CLOCK_GETTIME64(OPENAVB_CLOCK_WALLTIME, &nowNS);
@@ -136,6 +137,7 @@ bool talkerStartStream(tl_state_t *pTLState)
nowNS = ((nowNS + (pTalkerData->intervalNS)) / pTalkerData->intervalNS) * pTalkerData->intervalNS;
pTalkerData->nextReportNS = nowNS + (pCfg->report_seconds * NANOSECONDS_PER_SECOND);
+ pTalkerData->lastReportFrames = 0;
pTalkerData->nextSecondNS = nowNS + NANOSECONDS_PER_SECOND;
pTalkerData->nextCycleNS = nowNS + pTalkerData->intervalNS;
@@ -173,7 +175,7 @@ void talkerStopStream(tl_state_t *pTLState)
openavbTalkerAddStat(pTLState, TL_STAT_TX_CALLS, pTalkerData->cntWakes);
openavbTalkerAddStat(pTLState, TL_STAT_TX_FRAMES, pTalkerData->cntFrames);
-// openavbTalkerAddStat(pTLState, TL_STAT_TX_LATE, 0); // Can't calulate at this time
+// openavbTalkerAddStat(pTLState, TL_STAT_TX_LATE, 0); // Can't calculate at this time
openavbTalkerAddStat(pTLState, TL_STAT_TX_BYTES, openavbAvtpBytes(pTalkerData->avtpHandle));
AVB_LOGF_INFO("TX "STREAMID_FORMAT", Totals: calls=%" PRIu64 ", frames=%" PRIu64 ", late=%" PRIu64 ", bytes=%" PRIu64 ", TXOutOfBuffs=%ld",
@@ -186,13 +188,33 @@ void talkerStopStream(tl_state_t *pTLState)
);
if (pTLState->bStreaming) {
- openavbAvtpShutdown(pTalkerData->avtpHandle);
+ openavbAvtpShutdownTalker(pTalkerData->avtpHandle);
pTLState->bStreaming = FALSE;
}
AVB_TRACE_EXIT(AVB_TRACE_TL);
}
+static inline void talkerShowStats(talker_data_t *pTalkerData, tl_state_t *pTLState)
+{
+ S32 late = pTalkerData->wakesPerReport - pTalkerData->cntWakes;
+ U64 bytes = openavbAvtpBytes(pTalkerData->avtpHandle);
+ if (late < 0) late = 0;
+ U32 txbuf = openavbAvtpTxBufferLevel(pTalkerData->avtpHandle);
+ U32 mqbuf = openavbMediaQCountItems(pTLState->pMediaQ, TRUE);
+
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "TX UID:%d, ", LOG_RT_DATATYPE_U16, &pTalkerData->streamID.uniqueID);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "calls=%ld, ", LOG_RT_DATATYPE_U32, &pTalkerData->cntWakes);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "frames=%ld, ", LOG_RT_DATATYPE_U32, &pTalkerData->cntFrames);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "late=%d, ", LOG_RT_DATATYPE_U32, &late);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "bytes=%lld, ", LOG_RT_DATATYPE_U64, &bytes);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "txbuf=%d, ", LOG_RT_DATATYPE_U32, &txbuf);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "mqbuf=%d, ", LOG_RT_DATATYPE_U32, &mqbuf);
+
+ openavbTalkerAddStat(pTLState, TL_STAT_TX_LATE, late);
+ openavbTalkerAddStat(pTLState, TL_STAT_TX_BYTES, bytes);
+}
+
static inline bool talkerDoStream(tl_state_t *pTLState)
{
AVB_TRACE_ENTRY(AVB_TRACE_TL);
@@ -212,7 +234,7 @@ static inline bool talkerDoStream(tl_state_t *pTLState)
if (!pCfg->tx_blocking_in_intf) {
- if (!pCfg->fixed_timestamp) {
+ if (!pCfg->spin_wait) {
// sleep until the next interval
SLEEP_UNTIL_NSEC(pTalkerData->nextCycleNS);
} else {
@@ -238,47 +260,40 @@ static inline bool talkerDoStream(tl_state_t *pTLState)
pTalkerData->cntFrames++;
}
+ if (!pCfg->spin_wait) {
+ CLOCK_GETTIME64(OPENAVB_TIMER_CLOCK, &nowNS);
+ } else {
+ CLOCK_GETTIME64(OPENAVB_CLOCK_WALLTIME, &nowNS);
+ }
+
if (pTalkerData->cntWakes++ % pTalkerData->wakeRate == 0) {
// time to service the endpoint IPC
bRet = TRUE;
- }
- if (!pCfg->fixed_timestamp) {
- CLOCK_GETTIME64(OPENAVB_TIMER_CLOCK, &nowNS);
- } else {
- CLOCK_GETTIME64(OPENAVB_CLOCK_WALLTIME, &nowNS);
+ // Don't need to check again for another second.
+ pTalkerData->nextSecondNS = nowNS + NANOSECONDS_PER_SECOND;
}
if (pCfg->report_seconds > 0) {
if (nowNS > pTalkerData->nextReportNS) {
+ talkerShowStats(pTalkerData, pTLState);
- S32 late = pTalkerData->wakesPerReport - pTalkerData->cntWakes;
- U64 bytes = openavbAvtpBytes(pTalkerData->avtpHandle);
- if (late < 0) late = 0;
- U32 txbuf = openavbAvtpTxBufferLevel(pTalkerData->avtpHandle);
- U32 mqbuf = openavbMediaQCountItems(pTLState->pMediaQ, TRUE);
-
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "TX UID:%d, ", LOG_RT_DATATYPE_U16, &pTalkerData->streamID.uniqueID);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "calls=%ld, ", LOG_RT_DATATYPE_U32, &pTalkerData->cntWakes);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "frames=%ld, ", LOG_RT_DATATYPE_U32, &pTalkerData->cntFrames);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "late=%d, ", LOG_RT_DATATYPE_U32, &late);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "bytes=%lld, ", LOG_RT_DATATYPE_U64, &bytes);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "txbuf=%d, ", LOG_RT_DATATYPE_U32, &txbuf);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "mqbuf=%d, ", LOG_RT_DATATYPE_U32, &mqbuf);
-
openavbTalkerAddStat(pTLState, TL_STAT_TX_CALLS, pTalkerData->cntWakes);
openavbTalkerAddStat(pTLState, TL_STAT_TX_FRAMES, pTalkerData->cntFrames);
- openavbTalkerAddStat(pTLState, TL_STAT_TX_LATE, late);
- openavbTalkerAddStat(pTLState, TL_STAT_TX_BYTES, bytes);
pTalkerData->cntFrames = 0;
pTalkerData->cntWakes = 0;
- pTalkerData->nextReportNS = nowNS + (pCfg->report_seconds * NANOSECONDS_PER_SECOND);
+ pTalkerData->nextReportNS = nowNS + (pCfg->report_seconds * NANOSECONDS_PER_SECOND);
+ }
+ } else if (pCfg->report_frames > 0 && pTalkerData->cntFrames != pTalkerData->lastReportFrames) {
+ if (pTalkerData->cntFrames % pCfg->report_frames == 1) {
+ talkerShowStats(pTalkerData, pTLState);
+ pTalkerData->lastReportFrames = pTalkerData->cntFrames;
}
}
if (nowNS > pTalkerData->nextSecondNS) {
- pTalkerData->nextSecondNS += NANOSECONDS_PER_SECOND;
+ pTalkerData->nextSecondNS = nowNS + NANOSECONDS_PER_SECOND;
bRet = TRUE;
}
@@ -294,9 +309,10 @@ static inline bool talkerDoStream(tl_state_t *pTLState)
}
}
else {
- SLEEP(1);
- // time to service the endpoint IPC
- bRet = TRUE;
+ SLEEP_MSEC(10);
+
+ // time to service the endpoint IPC
+ bRet = TRUE;
}
AVB_TRACE_EXIT(AVB_TRACE_TL);
@@ -339,13 +355,16 @@ void openavbTLRunTalker(tl_state_t *pTLState)
if (pTLState->bConnected) {
bool bServiceIPC;
- // Do until we are stopped or loose connection to endpoint
+ // Notify AVDECC Msg of the state change.
+ openavbAvdeccMsgClntNotifyCurrentState(pTLState);
+
+ // Do until we are stopped or lose connection to endpoint
while (pTLState->bRunning && pTLState->bConnected) {
// Talk (or just sleep if not streaming.)
bServiceIPC = talkerDoStream(pTLState);
- // TalkerDoStream() returns TRUE once per second,
+ // TalkerDoStream() returns TRUE occasionally,
// so that we can service our IPC at that low rate.
if (bServiceIPC) {
// Look for messages from endpoint. Don't block (timeout=0)
@@ -371,6 +390,9 @@ void openavbTLRunTalker(tl_state_t *pTLState)
openavbEptClntStopStream(pTLState->endpointHandle, &(((talker_data_t *)pTLState->pPvtTalkerData)->streamID));
openavbTLRunTalkerFinish(pTLState);
+
+ // Notify AVDECC Msg of the state change.
+ openavbAvdeccMsgClntNotifyCurrentState(pTLState);
}
else {
AVB_LOGF_WARNING("Failed to connect to endpoint"STREAMID_FORMAT, STREAMID_ARGS(&(((talker_data_t *)pTLState->pPvtTalkerData)->streamID)));
@@ -401,8 +423,12 @@ void openavbTLPauseTalker(tl_state_t *pTLState, bool bPause)
return;
}
+ pTLState->bPaused = bPause;
openavbAvtpPause(pTalkerData->avtpHandle, bPause);
+ // Notify AVDECC Msg of the state change.
+ openavbAvdeccMsgClntNotifyCurrentState(pTLState);
+
AVB_TRACE_EXIT(AVB_TRACE_TL);
}
diff --git a/lib/avtp_pipeline/tl/openavb_talker.h b/lib/avtp_pipeline/tl/openavb_talker.h
index b180d12a..86bfc39e 100644
--- a/lib/avtp_pipeline/tl/openavb_talker.h
+++ b/lib/avtp_pipeline/tl/openavb_talker.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.
*************************************************************************************************************/
@@ -39,10 +40,11 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
typedef struct {
// Data from callback
- char ifname[IFNAMSIZ];
- AVBStreamID_t streamID;
+ char ifname[IFNAMSIZ + 10]; // Include space for the socket type prefix (e.g. "simple:eth0")
+ AVBStreamID_t streamID;
U8 destAddr[ETH_ALEN];
AVBTSpec_t tSpec;
+ U8 srClass;
U32 classRate;
U32 fwmark;
U16 vlanID;
@@ -60,6 +62,7 @@ typedef struct {
U64 intervalNS;
U64 nextReportNS;
U64 nextSecondNS;
+ unsigned long lastReportFrames;
talker_stats_t stats;
} talker_data_t;
diff --git a/lib/avtp_pipeline/tl/openavb_talker_endpoint.c b/lib/avtp_pipeline/tl/openavb_talker_endpoint.c
index 27511f96..c1a5eb4e 100644
--- a/lib/avtp_pipeline/tl/openavb_talker_endpoint.c
+++ b/lib/avtp_pipeline/tl/openavb_talker_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,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 : Talker implementation for use with endpoint
+* MODULE SUMMARY : Talker implementation for use with endpoint
*/
#include <stdlib.h>
@@ -41,6 +42,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_avtp.h"
#include "openavb_talker.h"
#include "openavb_time.h"
+#include "openavb_avdecc_msg.h"
// DEBUG Uncomment to turn on logging for just this module.
//#define AVB_LOG_ON 1
@@ -56,6 +58,7 @@ void openavbEptClntNotifyTlkrOfSrpCb(int endpointHandle,
char *ifname,
U8 destAddr[],
openavbSrpLsnrDeclSubtype_t lsnrDecl,
+ U8 srClass,
U32 classRate,
U16 vlanID,
U8 priority,
@@ -71,16 +74,29 @@ void openavbEptClntNotifyTlkrOfSrpCb(int endpointHandle,
return;
}
+ // If not a talker, ignore this callback.
+ if (pTLState->cfg.role != AVB_ROLE_TALKER) {
+ AVB_LOG_DEBUG("Ignoring Talker callback");
+ return;
+ }
+
AVB_LOGF_DEBUG("%s streaming=%d, lsnrDecl=%d", __FUNCTION__, pTLState->bStreaming, lsnrDecl);
+ openavb_tl_cfg_t *pCfg = &pTLState->cfg;
+
if (!pTLState->bStreaming) {
if (lsnrDecl == openavbSrp_LDSt_Ready
|| lsnrDecl == openavbSrp_LDSt_Ready_Failed) {
// Save the data provided by endpoint/SRP
- strncpy(pTalkerData->ifname, ifname, IFNAMSIZ);
+ if (!pCfg->ifname[0]) {
+ strncpy(pTalkerData->ifname, ifname, sizeof(pTalkerData->ifname) - 1);
+ } else {
+ strncpy(pTalkerData->ifname, pCfg->ifname, sizeof(pTalkerData->ifname) - 1);
+ }
memcpy(&pTalkerData->streamID, streamID, sizeof(AVBStreamID_t));
memcpy(&pTalkerData->destAddr, destAddr, ETH_ALEN);
+ pTalkerData->srClass = srClass;
pTalkerData->classRate = classRate;
pTalkerData->vlanID = vlanID;
pTalkerData->vlanPCP = priority;
@@ -92,9 +108,14 @@ void openavbEptClntNotifyTlkrOfSrpCb(int endpointHandle,
}
else if (lsnrDecl == openavbSrp_LDSt_Stream_Info) {
// Stream information is available does NOT mean listener is ready. Stream not started yet.
- strncpy(pTalkerData->ifname, ifname, IFNAMSIZ);
+ if (!pCfg->ifname[0]) {
+ strncpy(pTalkerData->ifname, ifname, sizeof(pTalkerData->ifname) - 1);
+ } else {
+ strncpy(pTalkerData->ifname, pCfg->ifname, sizeof(pTalkerData->ifname) - 1);
+ }
memcpy(&pTalkerData->streamID, streamID, sizeof(AVBStreamID_t));
memcpy(&pTalkerData->destAddr, destAddr, ETH_ALEN);
+ pTalkerData->srClass = srClass;
pTalkerData->classRate = classRate;
pTalkerData->vlanID = vlanID;
pTalkerData->vlanPCP = priority;
@@ -110,6 +131,14 @@ void openavbEptClntNotifyTlkrOfSrpCb(int endpointHandle,
}
}
+ // Let the AVDECC Msg server know our current stream ID, in case it was updated by MAAP.
+ if (pTLState->avdeccMsgHandle != AVB_AVDECC_MSG_HANDLE_INVALID) {
+ if (!openavbAvdeccMsgClntTalkerStreamID(pTLState->avdeccMsgHandle,
+ pTalkerData->srClass, pTalkerData->streamID.addr, pTalkerData->streamID.uniqueID,
+ pTalkerData->destAddr, pTalkerData->vlanID)) {
+ AVB_LOG_ERROR("openavbAvdeccMsgClntTalkerStreamID() failed");
+ }
+ }
AVB_TRACE_EXIT(AVB_TRACE_TL);
}
@@ -149,13 +178,20 @@ bool openavbTLRunTalkerInit(tl_state_t *pTLState)
// Tell endpoint to register our stream.
// SRP will send out talker declarations on the LAN.
// If there are listeners, we'll get callback (above.)
+ U32 transmitInterval = pTalkerData->classRate;
+ if (pCfg->map_cb.map_transmit_interval_cb(pTLState->pMediaQ)) {
+ // Override the class observation interval with the one provided by the mapping module.
+ transmitInterval = pCfg->map_cb.map_transmit_interval_cb(pTLState->pMediaQ);
+ }
return (openavbEptClntRegisterStream(pTLState->endpointHandle,
- &streamID,
- pCfg->dest_addr.mac->ether_addr_octet,
- &pTalkerData->tSpec,
- pCfg->sr_class,
- pCfg->sr_rank,
- pCfg->internal_latency));
+ &streamID,
+ pCfg->dest_addr.mac->ether_addr_octet,
+ pCfg->backup_dest_addr_valid, // If we have a backup dest_addr, then the current one was forced and MAAP should not be used.
+ &pTalkerData->tSpec,
+ pCfg->sr_class,
+ pCfg->sr_rank,
+ pCfg->internal_latency,
+ transmitInterval));
}
void openavbTLRunTalkerFinish(tl_state_t *pTLState)
diff --git a/lib/avtp_pipeline/tl/openavb_talker_no_endpoint.c b/lib/avtp_pipeline/tl/openavb_talker_no_endpoint.c
index 042801e3..90476031 100644
--- a/lib/avtp_pipeline/tl/openavb_talker_no_endpoint.c
+++ b/lib/avtp_pipeline/tl/openavb_talker_no_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,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 : Talker implementation for use without endpoint
+* MODULE SUMMARY : Talker implementation for use without endpoint
*/
#include <stdlib.h>
@@ -40,6 +41,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_talker.h"
#include "openavb_qmgr.h"
#include "openavb_endpoint.h"
+#include "openavb_avdecc_msg.h"
#define AVB_LOG_COMPONENT "Talker"
#include "openavb_log.h"
@@ -60,28 +62,28 @@ bool openavbTLRunTalkerInit(tl_state_t *pTLState)
talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
//avtp_stream_t *pStream = (avtp_stream_t *)(pTalkerData->avtpHandle);
- strncpy(pTalkerData->ifname, pCfg->ifname, IFNAMSIZ);
-
+ strncpy(pTalkerData->ifname, pCfg->ifname, sizeof(pTalkerData->ifname) - 1);
+
// CORE_TODO: It would be good to have some parts of endpoint moved into non-endpoint general code to handle some the stream
// configuration values.
- // strncpy(pTalkerData->ifname, pCfg->ifname, IFNAMSIZ);
if (pCfg->stream_addr.mac) {
memcpy(pTalkerData->streamID.addr, pCfg->stream_addr.mac, ETH_ALEN);
}else {
AVB_LOG_WARNING("Stream Address Not Set");
}
-
+
pTalkerData->streamID.uniqueID = pCfg->stream_uid;
+ pTalkerData->srClass = pCfg->sr_class;
if (pCfg->sr_class == SR_CLASS_A) {
pTalkerData->classRate = 8000;
- pTalkerData->vlanID = pCfg->vlan_id == VLAN_NULL ?
- SR_CLASS_A_DEFAULT_VID : pCfg->vlan_id;
+ pTalkerData->vlanID = (pCfg->vlan_id == 0 ?
+ SR_CLASS_A_DEFAULT_VID : pCfg->vlan_id);
pTalkerData->vlanPCP = SR_CLASS_A_DEFAULT_PRIORITY;
}
else if (pCfg->sr_class == SR_CLASS_B) {
pTalkerData->classRate = 4000;
- pTalkerData->vlanID = pCfg->vlan_id == VLAN_NULL ?
- SR_CLASS_B_DEFAULT_VID : pCfg->vlan_id;
+ pTalkerData->vlanID = (pCfg->vlan_id == 0 ?
+ SR_CLASS_B_DEFAULT_VID : pCfg->vlan_id);
pTalkerData->vlanPCP = SR_CLASS_B_DEFAULT_PRIORITY;
}
memcpy(&pTalkerData->destAddr, &pCfg->dest_addr.mac->ether_addr_octet, ETH_ALEN);
@@ -99,10 +101,10 @@ bool openavbTLRunTalkerInit(tl_state_t *pTLState)
unsigned int map_intv_frames = pCfg->map_cb.map_get_max_interval_frames_cb(pTLState->pMediaQ, pTLState->cfg.sr_class);
pCfg->max_interval_frames = map_intv_frames > 0 ? map_intv_frames : pCfg->max_interval_frames;
}
- }
+ }
pTalkerData->tSpec.maxIntervalFrames = pCfg->max_interval_frames;
pTalkerData->tSpec.maxFrameSize = pCfg->map_cb.map_max_data_size_cb(pTLState->pMediaQ);
-
+
// TODO_COREAVB : This wakeRate should also be set in the endpoint case and removed from the tasker.c start stream
if (!pCfg->map_cb.map_transmit_interval_cb(pTLState->pMediaQ)) {
pTalkerData->wakeRate = pTalkerData->classRate / pCfg->batch_factor;
@@ -122,11 +124,20 @@ bool openavbTLRunTalkerInit(tl_state_t *pTLState)
if (pTalkerData->fwmark == INVALID_FWMARK)
return FALSE;
-
+
AVB_LOGF_INFO("Dest Addr: "ETH_FORMAT, ETH_OCTETS(pTalkerData->destAddr));
AVB_LOGF_INFO("Starting stream: "STREAMID_FORMAT, STREAMID_ARGS(&pTalkerData->streamID));
talkerStartStream(pTLState);
-
+
+ // Let the AVDECC Msg server know our current stream ID, in case it is waiting for an update.
+ if (pTLState->avdeccMsgHandle != AVB_AVDECC_MSG_HANDLE_INVALID) {
+ if (!openavbAvdeccMsgClntTalkerStreamID(pTLState->avdeccMsgHandle,
+ pTalkerData->srClass, pTalkerData->streamID.addr, pTalkerData->streamID.uniqueID,
+ pTalkerData->destAddr, pTalkerData->vlanID)) {
+ AVB_LOG_ERROR("openavbAvdeccMsgClntTalkerStreamID() failed");
+ }
+ }
+
return TRUE;
}
@@ -142,6 +153,7 @@ AVBStreamID_t *streamID,
char *ifname,
U8 destAddr[],
openavbSrpLsnrDeclSubtype_t lsnrDecl,
+U8 srClass,
U32 classRate,
U16 vlanID,
U8 priority,
diff --git a/lib/avtp_pipeline/tl/openavb_tl.c b/lib/avtp_pipeline/tl/openavb_tl.c
index 0a534d44..4fc6eff5 100755
--- a/lib/avtp_pipeline/tl/openavb_tl.c
+++ b/lib/avtp_pipeline/tl/openavb_tl.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.
*************************************************************************************************************/
@@ -40,7 +41,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_mediaq.h"
#include "openavb_talker.h"
#include "openavb_listener.h"
-// #include "openavb_avtp.h"
+#include "openavb_avdecc_msg.h"
#include "openavb_platform.h"
#define AVB_LOG_COMPONENT "Talker / Listener"
@@ -64,6 +65,9 @@ void* openavbTLThreadFn(void *pv);
#define THREAD_CREATE_TALKER() THREAD_CREATE(talkerThread, pTLState->TLThread, NULL, openavbTLThreadFn, pTLState)
#define THREAD_CREATE_LISTENER() THREAD_CREATE(listenerThread, pTLState->TLThread, NULL, openavbTLThreadFn, pTLState)
+void* openavbAvdeccMsgThreadFn(void *pv);
+#define THREAD_CREATE_AVDECC_MSG() THREAD_CREATE(avdeccMsgThread, pTLState->avdeccMsgThread, NULL, openavbAvdeccMsgThreadFn, pTLState)
+
void timespec_add_usec(struct timespec *t, unsigned long us)
{
t->tv_nsec += us * NANOSECONDS_PER_USEC;
@@ -156,41 +160,35 @@ static bool checkIntfCallbacks(openavb_tl_cfg_t *pCfg)
bool validCfg = TRUE;
if (!pCfg->intf_cb.intf_cfg_cb) {
- AVB_LOG_WARNING("INI file doesn't specify inferface callback for '_cfg'.");
+ AVB_LOG_WARNING("INI file doesn't specify interface callback for '_cfg'.");
// validCfg = FALSE;
}
if ((pCfg->role == AVB_ROLE_TALKER) && !pCfg->intf_cb.intf_tx_init_cb) {
- AVB_LOG_WARNING("INI file doesn't specify inferface callback for '_tx_init'.");
+ AVB_LOG_WARNING("INI file doesn't specify interface callback for '_tx_init'.");
// validCfg = FALSE;
}
if ((pCfg->role == AVB_ROLE_TALKER) && !pCfg->intf_cb.intf_tx_cb) {
- AVB_LOG_ERROR("INI file doesn't specify inferface callback for '_tx'.");
+ AVB_LOG_ERROR("INI file doesn't specify interface callback for '_tx'.");
validCfg = FALSE;
}
if ((pCfg->role == AVB_ROLE_LISTENER) && !pCfg->intf_cb.intf_rx_init_cb) {
- AVB_LOG_WARNING("INI file doesn't specify inferface callback for '_rx_init'.");
+ AVB_LOG_WARNING("INI file doesn't specify interface callback for '_rx_init'.");
// validCfg = FALSE;
}
if ((pCfg->role == AVB_ROLE_LISTENER) && !pCfg->intf_cb.intf_rx_cb) {
- AVB_LOG_ERROR("INI file doesn't specify inferface callback for '_rx'.");
+ AVB_LOG_ERROR("INI file doesn't specify interface callback for '_rx'.");
validCfg = FALSE;
}
if (!pCfg->intf_cb.intf_end_cb) {
- AVB_LOG_WARNING("INI file doesn't specify inferface callback for '_end'.");
+ AVB_LOG_WARNING("INI file doesn't specify interface callback for '_end'.");
// validCfg = FALSE;
}
if (!pCfg->intf_cb.intf_gen_init_cb) {
- AVB_LOG_WARNING("INI file doesn't specify inferface callback for '_gen_init'.");
+ AVB_LOG_WARNING("INI file doesn't specify interface callback for '_gen_init'.");
// validCfg = FALSE;
}
if (!pCfg->intf_cb.intf_gen_end_cb) {
- AVB_LOG_WARNING("INI file doesn't specify inferface callback for '_gen_end'.");
- // validCfg = FALSE;
- }
- if (!pCfg->intf_cb.intf_avdecc_init_cb) {
- // Optional callback
- // CORE_TODO: AVDECC not formally supported yet.
- // AVB_LOG_WARNING("INI file doesn't specify inferface callback for '_avdecc_init'.");
+ AVB_LOG_WARNING("INI file doesn't specify interface callback for '_gen_end'.");
// validCfg = FALSE;
}
@@ -241,12 +239,6 @@ static bool checkMapCallbacks(openavb_tl_cfg_t *pCfg)
AVB_LOG_WARNING("INI doesn't specify mapping callback for '_gen_end'.");
// validCfg = FALSE;
}
- if (!pCfg->map_cb.map_avdecc_init_cb) {
- // Optional callback
- // CORE_TODO: AVDECC not formally supported yet.
- // AVB_LOG_WARNING("INI doesn't specify mapping callback for '_avdecc_init'.");
- // validCfg = FALSE;
- }
return validCfg;
}
@@ -348,6 +340,7 @@ EXTERN_DLL_EXPORT tl_handle_t openavbTLOpen(void)
AVB_TRACE_ENTRY(AVB_TRACE_TL);
tl_state_t *pTLState = calloc(1, sizeof(tl_state_t));
+ pTLState->avdeccMsgHandle = AVB_AVDECC_MSG_HANDLE_INVALID;
if (!pTLState) {
AVB_LOG_ERROR("Unable to allocate talker listener state data.");
@@ -372,12 +365,14 @@ EXTERN_DLL_EXPORT void openavbTLInitCfg(openavb_tl_cfg_t *pCfg)
memset(pCfg, 0, sizeof(openavb_tl_cfg_t));
// Set default values.
+ // (These values should match those set in openavbIniCfgInit().)
pCfg->role = AVB_ROLE_UNDEFINED;
+ pCfg->initial_state = TL_INIT_STATE_UNSPECIFIED;
//pCfg->map_cb;
//pCfg->intf_cb;
//pCfg->dest_addr;
//pCfg->stream_addr;
- pCfg->stream_uid = -1;
+ pCfg->stream_uid = 0xFFFF;
pCfg->max_interval_frames = 1;
pCfg->max_frame_size = 1500;
pCfg->max_transit_usec = 50000;
@@ -386,6 +381,7 @@ EXTERN_DLL_EXPORT void openavbTLInitCfg(openavb_tl_cfg_t *pCfg)
pCfg->max_stale = MICROSECONDS_PER_SECOND;
pCfg->batch_factor = 1;
pCfg->report_seconds = 0;
+ pCfg->report_frames = 0;
pCfg->start_paused = FALSE;
pCfg->sr_class = SR_CLASS_B;
pCfg->sr_rank = SR_RANK_REGULAR;
@@ -395,8 +391,9 @@ EXTERN_DLL_EXPORT void openavbTLInitCfg(openavb_tl_cfg_t *pCfg)
pCfg->rx_signal_mode = 1;
pCfg->pMapInitFn = NULL;
pCfg->pIntfInitFn = NULL;
- pCfg->vlan_id = VLAN_NULL;
+ pCfg->vlan_id = 0;
pCfg->fixed_timestamp = 0;
+ pCfg->spin_wait = FALSE;
pCfg->thread_rt_priority = 0;
pCfg->thread_affinity = 0xFFFFFFFF;
@@ -492,6 +489,10 @@ EXTERN_DLL_EXPORT bool openavbTLConfigure(tl_handle_t handle, openavb_tl_cfg_t *
pTLState->cfg.map_cb.map_gen_init_cb(pTLState->pMediaQ);
pTLState->cfg.intf_cb.intf_gen_init_cb(pTLState->pMediaQ);
+ // Initialize the AVDECC support for this Talker/Listener.
+ pTLState->bAvdeccMsgRunning = TRUE;
+ THREAD_CREATE_AVDECC_MSG();
+
return TRUE;
}
@@ -510,21 +511,25 @@ EXTERN_DLL_EXPORT bool openavbTLRun(tl_handle_t handle)
}
pTLState->bRunning = TRUE;
+ pTLState->bPaused = FALSE;
if (pTLState->cfg.role == AVB_ROLE_TALKER) {
THREAD_CREATE_TALKER();
- THREAD_SET_RT_PRIORITY(pTLState->TLThread, pTLState->cfg.thread_rt_priority);
- THREAD_PIN(pTLState->TLThread, pTLState->cfg.thread_affinity);
+ if (pTLState->cfg.thread_rt_priority != 0) { THREAD_SET_RT_PRIORITY(pTLState->TLThread, pTLState->cfg.thread_rt_priority); }
+ if (pTLState->cfg.thread_affinity != 0xFFFFFFFF) { THREAD_PIN(pTLState->TLThread, pTLState->cfg.thread_affinity); }
}
else if (pTLState->cfg.role == AVB_ROLE_LISTENER) {
THREAD_CREATE_LISTENER();
+
+ if (pTLState->cfg.thread_rt_priority != 0) { THREAD_SET_RT_PRIORITY(pTLState->TLThread, pTLState->cfg.thread_rt_priority); }
+ if (pTLState->cfg.thread_affinity != 0xFFFFFFFF) { THREAD_PIN(pTLState->TLThread, pTLState->cfg.thread_affinity); }
}
retVal = TRUE;
} while (0);
-
+
AVB_TRACE_EXIT(AVB_TRACE_TL);
return retVal;
@@ -542,6 +547,7 @@ extern DLL_EXPORT bool openavbTLStop(tl_handle_t handle)
return FALSE;
}
+ pTLState->bPaused = FALSE;
if (pTLState->bRunning) {
// don't set bStreaming to false here, that's needed to track
// that the streaming thread is running, so we can shut it down.
@@ -572,6 +578,12 @@ EXTERN_DLL_EXPORT bool openavbTLClose(tl_handle_t handle)
openavbTLStop(handle);
}
+ // Done with the AVDECC support.
+ if (pTLState->bAvdeccMsgRunning) {
+ pTLState->bAvdeccMsgRunning = FALSE;
+ THREAD_JOIN(pTLState->avdeccMsgThread, NULL);
+ }
+
pTLState->cfg.intf_cb.intf_gen_end_cb(pTLState->pMediaQ);
pTLState->cfg.map_cb.map_gen_end_cb(pTLState->pMediaQ);
@@ -689,6 +701,21 @@ EXTERN_DLL_EXPORT avb_role_t openavbTLGetRole(tl_handle_t handle)
return pTLState->cfg.role;
}
+EXTERN_DLL_EXPORT tl_init_state_t openavbTLGetInitialState(tl_handle_t handle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = (tl_state_t *)handle;
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid handle");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TL_INIT_STATE_UNSPECIFIED;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return pTLState->cfg.initial_state;
+}
EXTERN_DLL_EXPORT U64 openavbTLStat(tl_handle_t handle, tl_stat_t stat)
{
diff --git a/lib/avtp_pipeline/tl/openavb_tl.h b/lib/avtp_pipeline/tl/openavb_tl.h
index 82f38417..4b16da4b 100755
--- a/lib/avtp_pipeline/tl/openavb_tl.h
+++ b/lib/avtp_pipeline/tl/openavb_tl.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
@@ -55,11 +56,15 @@ typedef struct {
} talker_stats_t;
THREAD_TYPE(TLThread);
+THREAD_TYPE(avdeccMsgThread);
typedef struct {
// Running flag. (assumed atomic)
bool bRunning;
+ // Paused while Running flag. (assumed atomic)
+ bool bPaused;
+
// Connected to endpoint flag. (assumed atomic)
bool bConnected;
@@ -87,6 +92,15 @@ typedef struct {
// Thread for talker or listener
THREAD_DEFINITON(TLThread);
+ // AVDECC Msg Running flag. (assumed atomic)
+ bool bAvdeccMsgRunning;
+
+ // Thread for AVDECC Msg support
+ THREAD_DEFINITON(avdeccMsgThread);
+
+ // Handle to the AVDECC Msg support. (Value set by avdeccMsgThread)
+ int avdeccMsgHandle;
+
// Per stream Stats Mutex
MUTEX_HANDLE(statsMutex);
@@ -120,7 +134,7 @@ unsigned long timespec_usec_diff(struct timespec *t1, struct timespec *t2);
int timespec_cmp(struct timespec *a, struct timespec *b);
////////////////
-// TL Handle List functions. The TL handle list is created in the implemntation of openavbTLInitialize.
+// TL Handle List functions. The TL handle list is created in the implementation of openavbTLInitialize.
////////////////
// Get a tl_handle_t from the TLHandleList given an endpointHandle.
extern U32 gMaxTL;
@@ -135,21 +149,6 @@ bool TLHandleRemove(tl_handle_t handle);
////////////////
-// AVDECC Integration functions.
-////////////////
-// Run a single talker or listener. At this point data can be sent or recieved. Used in place of the public openavbTLRun
-bool openavbTLAVDECCRunListener(tl_handle_t handle, U16 configIdx, U16 descriptorType, U16 descriptorIdx, void *pVoidListenerStreamInfo);
-bool openavbTLAVDECCRunTalker(tl_handle_t handle, U16 configIdx, U16 descriptorType, U16 descriptorIdx, void *pVoidTalkerStreamInfo);
-
-// Stop a single talker or listener. At this point data will not be sent or recieved. Used in place of the public openavbTLStop.
-bool openavbTLAVDECCStopListener(tl_handle_t handle, U16 configIdx, void *pVoidListenerStreamInfo);
-bool openavbTLAVDECCStopTalker(tl_handle_t handle, U16 configIdx, void *pVoidTalkerStreamInfo);
-
-// Get talker stream details. Structure members in TalkerStrreamInfo will be filled.
-bool openavbTLAVDECCGetTalkerStreamInfo(tl_handle_t handle, U16 configIdx, void *pVoidTalkerStreamInfo);
-
-
-////////////////
// OSAL implementation functions
////////////////
bool openavbTLThreadFnOsal(tl_state_t *pTLState);
diff --git a/lib/avtp_pipeline/tl/openavb_tl_endpoint.c b/lib/avtp_pipeline/tl/openavb_tl_endpoint.c
index d6a4ad13..49c9420b 100644
--- a/lib/avtp_pipeline/tl/openavb_tl_endpoint.c
+++ b/lib/avtp_pipeline/tl/openavb_tl_endpoint.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,7 +118,7 @@ void* openavbTLThreadFn(void *pv)
}
if (pTLState->bRunning) {
- SLEEP(1);
+ SLEEP_MSEC(1);
}
}
@@ -153,126 +154,3 @@ tl_handle_t TLHandleListGet(int endpointHandle)
AVB_TRACE_EXIT(AVB_TRACE_TL);
return NULL;
}
-
-#ifdef AVTP_PIPELINE_AVDECC
-bool openavbTLAVDECCRunListener(tl_handle_t handle, U16 configIdx, U16 descriptorType, U16 descriptorIdx, void *pVoidListenerStreamInfo)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- if (!handle) {
- AVB_LOG_ERROR("Invalid handle.");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- if (!pVoidListenerStreamInfo) {
- AVB_LOG_ERROR("Invalid argument");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo = pVoidListenerStreamInfo;
- tl_state_t *pTLState = (tl_state_t *)handle;
-
- memcpy(pTLState->cfg.dest_addr.mac->ether_addr_octet, pListenerStreamInfo->stream_dest_mac, ETH_ALEN);
- memcpy(pTLState->cfg.stream_addr.mac->ether_addr_octet, pListenerStreamInfo->stream_id, ETH_ALEN);
- U8 *pStreamUID = pListenerStreamInfo->stream_id + 6;
-// pTLState->cfg.stream_uid = ntohs(*(U16 *)(pStreamUID));
- U16 align16;
- memcpy(&align16, (U16 *)(pStreamUID), sizeof(U16));
- pTLState->cfg.stream_uid = ntohs(align16);
-
- if (pTLState->cfg.intf_cb.intf_avdecc_init_cb) {
- pTLState->cfg.intf_cb.intf_avdecc_init_cb(pTLState->pMediaQ, configIdx, descriptorType, descriptorIdx);
- }
- if (pTLState->cfg.map_cb.map_avdecc_init_cb) {
- pTLState->cfg.map_cb.map_avdecc_init_cb(pTLState->pMediaQ, configIdx, descriptorType, descriptorIdx);
- }
-
- openavbTLRun(handle);
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return TRUE;
-}
-
-bool openavbTLAVDECCRunTalker(tl_handle_t handle, U16 configIdx, U16 descriptorType, U16 descriptorIdx, void *pVoidTalkerStreamInfo)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- if (!handle) {
- AVB_LOG_ERROR("Invalid handle.");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- tl_state_t *pTLState = (tl_state_t *)handle;
-
- if (pTLState->cfg.intf_cb.intf_avdecc_init_cb) {
- pTLState->cfg.intf_cb.intf_avdecc_init_cb(pTLState->pMediaQ, configIdx, descriptorType, descriptorIdx);
- }
- if (pTLState->cfg.map_cb.map_avdecc_init_cb) {
- pTLState->cfg.map_cb.map_avdecc_init_cb(pTLState->pMediaQ, configIdx, descriptorType, descriptorIdx);
- }
-
- if (!openavbTLIsRunning(handle)) {
- openavbTLRun(handle);
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return TRUE;
-}
-
-bool openavbTLAVDECCStopListener(tl_handle_t handle, U16 configIdx, void *pVoidListenerStreamInfo)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- openavbTLStop(handle);
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return TRUE;
-}
-
-bool openavbTLAVDECCStopTalker(tl_handle_t handle, U16 configIdx, void *pVoidTalkerStreamInfo)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- openavbTLStop(handle);
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return TRUE;
-}
-
-// CORE_TODO: Consider having this functionality live in openavb_talker.c and then talker_data_t can again be private to openavb_talker.c
-bool openavbTLAVDECCGetTalkerStreamInfo(tl_handle_t handle, U16 configIdx, void *pVoidTalkerStreamInfo)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- if (!handle) {
- AVB_LOG_ERROR("Invalid handle.");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- if (!pVoidTalkerStreamInfo) {
- AVB_LOG_ERROR("Invalid argument");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo = pVoidTalkerStreamInfo;
- tl_state_t *pTLState = (tl_state_t *)handle;
-
- talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
-
- // Get the destination mac address.
- memcpy(pTalkerStreamInfo->stream_dest_mac, pTalkerData->destAddr, ETH_ALEN);
-
- // Get the stream ID
- memcpy(pTalkerStreamInfo->stream_id, pTalkerData->streamID.addr, ETH_ALEN);
- U8 *pStreamUID = pTalkerStreamInfo->stream_id + 6;
- *(U16 *)(pStreamUID) = htons(pTLState->cfg.stream_uid);
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return TRUE;
-}
-
-#endif //AVTP_PIPELINE_AVDECC
diff --git a/lib/avtp_pipeline/tl/openavb_tl_no_endpoint.c b/lib/avtp_pipeline/tl/openavb_tl_no_endpoint.c
index c3940d87..5068fc0f 100644
--- a/lib/avtp_pipeline/tl/openavb_tl_no_endpoint.c
+++ b/lib/avtp_pipeline/tl/openavb_tl_no_endpoint.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
@@ -86,7 +87,7 @@ void* openavbTLThreadFn(void *pv)
}
if (pTLState->bRunning) {
- SLEEP(1);
+ SLEEP_MSEC(1);
}
}
diff --git a/lib/avtp_pipeline/tl/openavb_tl_pub.h b/lib/avtp_pipeline/tl/openavb_tl_pub.h
index 39a43b24..a5f3da69 100755
--- a/lib/avtp_pipeline/tl/openavb_tl_pub.h
+++ b/lib/avtp_pipeline/tl/openavb_tl_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.
*************************************************************************************************************/
@@ -73,25 +74,39 @@ typedef enum {
/// Maximum size of interface name
-#define IFNAMSIZE 16
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
-/// Indicatates that VLAN ID is not set in configuration
-#define VLAN_NULL UINT16_MAX
+/// Maximum size of the friendly name
+#define FRIENDLY_NAME_SIZE 64
+
+/// Initial talker/listener state
+typedef enum {
+ /// Unspecified
+ TL_INIT_STATE_UNSPECIFIED,
+ /// Stopped
+ TL_INIT_STATE_STOPPED,
+ /// Running
+ TL_INIT_STATE_RUNNING,
+} tl_init_state_t;
/// Structure containing configuration of the host
typedef struct {
/// Role of the host
avb_role_t role;
+ /// Initial Talker/Listener state
+ tl_init_state_t initial_state;
/// Structure with callbacks to mapping
openavb_map_cb_t map_cb;
- /// Structure with callbacks to inteface
+ /// Structure with callbacks to interface
openavb_intf_cb_t intf_cb;
/// MAC address of destination - multicast (talker only if SRP is enabled)
cfg_mac_t dest_addr;
/// MAC address of the source
cfg_mac_t stream_addr;
/// Stream UID (has to be unique)
- S32 stream_uid;
+ U16 stream_uid;
/// Maximum number of packets sent during one interval (talker only)
U32 max_interval_frames;
/// Maximum size of the frame
@@ -111,35 +126,57 @@ typedef struct {
U32 batch_factor;
/// Statistics reporting frequency
U32 report_seconds;
+ /// Statistics reporting frequency in frames
+ U32 report_frames;
/// Start paused
bool start_paused;
- /// Class in which host will operatea ::SRClassIdx_t (talker only)
+ /// Class in which host will operate ::SRClassIdx_t (talker only)
U8 sr_class;
/// Rank of the stream #SR_RANK_REGULAR or #SR_RANK_EMERGENCY (talker only)
U8 sr_rank;
/// Number of raw TX buffers that should be used (talker only)
U32 raw_tx_buffers;
- /// Number of raw rx buffers (listener only)
+ /// Number of raw RX buffers (listener only)
U32 raw_rx_buffers;
/// Is the interface module blocking in the TX CB.
bool tx_blocking_in_intf;
/// Network interface name. Not used on all platforms.
- char ifname[IFNAMSIZE];
+ char ifname[IFNAMSIZ + 10]; // Include space for the socket type prefix (e.g. "simple:eth0")
/// VLAN ID
U16 vlan_id;
/// When set incoming packets will trigger a signal to the stream task to wakeup.
bool rx_signal_mode;
/// Enable fixed timestamping in interface
U32 fixed_timestamp;
+ /// Wait for next observation interval by spinning rather than sleeping
+ bool spin_wait;
/// Bit mask used for CPU pinning
U32 thread_affinity;
/// Real time priority of thread.
U32 thread_rt_priority;
+ /// Friendly name for this configuration
+ char friendly_name[FRIENDLY_NAME_SIZE];
/// Initialization function in mapper
openavb_map_initialize_fn_t pMapInitFn;
/// Initialization function in interface
openavb_intf_initialize_fn_t pIntfInitFn;
+
+ /// TRUE if backup_stream_addr and backup_stream_uid are valid.
+ bool backup_stream_id_valid;
+ /// Saved original MAC address of the source
+ U8 backup_stream_addr[ETH_ALEN];
+ /// Stream UID (has to be unique)
+ U16 backup_stream_uid;
+ /// TRUE if backup_dest_addr_valid is valid.
+ bool backup_dest_addr_valid;
+ /// Saved original MAC address of destination - multicast (talker only if SRP is enabled)
+ U8 backup_dest_addr[ETH_ALEN];
+ /// TRUE if backup_vlan_id_valid is valid.
+ bool backup_vlan_id_valid;
+ /// Saved original VLAN ID
+ U16 backup_vlan_id;
+
} openavb_tl_cfg_t;
/// Structure holding configuration of mapping and interface modules
@@ -150,7 +187,7 @@ typedef struct openavb_tl_cfg_name_value_t {
char *libCfgValues[MAX_LIB_CFG_ITEMS];
/// Number of configuration parameters defined
U32 nLibCfgItems;
-} openavb_tl_cfg_name_value_t;
+} openavb_tl_cfg_name_value_t;
/** Initialize the talker listener library.
@@ -208,8 +245,8 @@ void openavbTLInitCfg(openavb_tl_cfg_t *pCfg);
* structure and name value pairs
*
* \param handle Handle of talker/listener
- * \param pCfg Pointer to configuration structure
- * \param pNVCfg Pointer to name value pair configuration
+ * \param pCfg Pointer to configuration structure
+ * \param pNVCfg Pointer to name value pair configuration
* structure
* \return TRUE on success or FALSE on failure
*/
@@ -320,6 +357,13 @@ bool openavbTLIsStreaming(tl_handle_t handle);
*/
avb_role_t openavbTLGetRole(tl_handle_t handle);
+/** Return the specified initial state of the talker or listener.
+ *
+ * \param handle The handle return from openavbTLOpen()
+ * \return The initial state requested
+ */
+tl_init_state_t openavbTLGetInitialState(tl_handle_t handle);
+
/** Allows pulling current stat counters for a running stream.
*
* The various stat counters for a stream can be retrieved with this function
@@ -330,15 +374,15 @@ avb_role_t openavbTLGetRole(tl_handle_t handle);
*/
U64 openavbTLStat(tl_handle_t handle, tl_stat_t stat);
-/** Read an ini file.
+/** Read an ini file.
*
* Parses an input configuration file tp populate configuration structures, and
* name value pairs. Only used in Operating Systems that have a file system
*
* \param TLhandle Pointer to handle of talker/listener
* \param fileName Pointer to configuration file name
- * \param pCfg Pointer to configuration structure
- * \param pNVCfg Pointer to name value pair configuration
+ * \param pCfg Pointer to configuration structure
+ * \param pNVCfg Pointer to name value pair configuration
* structure
* \return TRUE on success or FALSE on failure
*
diff --git a/lib/avtp_pipeline/util/openavb_array.c b/lib/avtp_pipeline/util/openavb_array.c
index ffebeba8..32ce1446 100644
--- a/lib/avtp_pipeline/util/openavb_array.c
+++ b/lib/avtp_pipeline/util/openavb_array.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/util/openavb_array.h b/lib/avtp_pipeline/util/openavb_array.h
index ba55a5b8..2a83dc8d 100644
--- a/lib/avtp_pipeline/util/openavb_array.h
+++ b/lib/avtp_pipeline/util/openavb_array.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/util/openavb_debug.c b/lib/avtp_pipeline/util/openavb_debug.c
index 42ebb977..cef411c1 100644
--- a/lib/avtp_pipeline/util/openavb_debug.c
+++ b/lib/avtp_pipeline/util/openavb_debug.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/util/openavb_debug.h b/lib/avtp_pipeline/util/openavb_debug.h
index b3c7b439..dba309c7 100644
--- a/lib/avtp_pipeline/util/openavb_debug.h
+++ b/lib/avtp_pipeline/util/openavb_debug.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/util/openavb_list.c b/lib/avtp_pipeline/util/openavb_list.c
index 9f36d819..7d045dba 100644
--- a/lib/avtp_pipeline/util/openavb_list.c
+++ b/lib/avtp_pipeline/util/openavb_list.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/util/openavb_list.h b/lib/avtp_pipeline/util/openavb_list.h
index 0d974abb..15826464 100644
--- a/lib/avtp_pipeline/util/openavb_list.h
+++ b/lib/avtp_pipeline/util/openavb_list.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
@@ -48,37 +49,37 @@ openavb_list_t openavbListNewList(void);
// Delete a link list.
void openavbListDeleteList(openavb_list_t list);
-// Add a data element as a node to a link list. Returns NULL on failure.
+// Add a data element as a node to the end (tail) of a link list. Returns NULL on failure.
openavb_list_node_t openavbListAdd(openavb_list_t list, void *data);
-// Allocate and manage data element and add as a node to a link list. Returns NULL on failure.
+// Allocate and manage data element and add as a node to the end (tail) of a link list. Returns NULL on failure.
openavb_list_node_t openavbListNew(openavb_list_t list, U32 size);
// Remove (delete) node. Returns NULL on failure otherwise next node.
openavb_list_node_t openavbListDelete(openavb_list_t list, openavb_list_node_t node);
-// Gets the next node. Returns FALSE on error or if already at the tail.
+// Gets the next node. Returns NULL on error or if already at the tail.
openavb_list_node_t openavbListNext(openavb_list_t list, openavb_list_node_t node);
-// Gets the previous node. Returns FALSE on error or if already at the head.
+// Gets the previous node. Returns NULL on error or if already at the head.
openavb_list_node_t openavbListPrev(openavb_list_t list, openavb_list_node_t node);
-// Gets the first (head) node. Returns FALSE on error or empty list.
+// Gets the first (head) node. Returns NULL on error or empty list.
openavb_list_node_t openavbListFirst(openavb_list_t list);
-// Gets the lastt (tail) node. Returns FALSE on error or empty list.
+// Gets the last (tail) node. Returns NULL on error or empty list.
openavb_list_node_t openavbListLast(openavb_list_t list);
-// Gets the first node and preps for iteration. Returns FALSE on error or empty list.
+// Gets the first node and preps for iteration. Returns NULL on error or empty list.
openavb_list_node_t openavbListIterFirst(openavb_list_t list);
-// Gets the last node and preps for iteration. Returns FALSE on error or empty list.
+// Gets the last node and preps for iteration. Returns NULL on error or empty list.
openavb_list_node_t openavbListIterLast(openavb_list_t list);
-// Gets the next node in the iteration. Returns FALSE on error or end of list.
+// Gets the next node in the iteration. Returns NULL on error or end of list.
openavb_list_node_t openavbListIterNext(openavb_list_t list);
-// Gets the prev node in the iteration. Returns FALSE on error or beginning of list.
+// Gets the previous node in the iteration. Returns NULL on error or beginning of list.
openavb_list_node_t openavbListIterPrev(openavb_list_t list);
// Get data element. Returns NULL on failure.
diff --git a/lib/avtp_pipeline/util/openavb_log.c b/lib/avtp_pipeline/util/openavb_log.c
index a0c937c4..5d32843f 100644
--- a/lib/avtp_pipeline/util/openavb_log.c
+++ b/lib/avtp_pipeline/util/openavb_log.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
@@ -61,6 +62,7 @@ typedef struct {
static openavb_queue_t logQueue;
static openavb_queue_t logRTQueue;
+static FILE *logOutputFd = NULL;
static char msg[LOG_MSG_LEN] = "";
static char time_msg[LOG_TIME_LEN] = "";
@@ -96,35 +98,35 @@ void avbLogRTRender(log_queue_item_t *pLogItem)
strcat((char *)pLogItem->msg, pLogRTItem->pFormat);
break;
case LOG_RT_DATATYPE_NOW_TS:
- sprintf(rt_msg, "[%lu:%09lu] ", pLogRTItem->data.nowTS.tv_sec, pLogRTItem->data.nowTS.tv_nsec);
+ snprintf(rt_msg, LOG_RT_MSG_LEN, "[%lu:%09lu] ", pLogRTItem->data.nowTS.tv_sec, pLogRTItem->data.nowTS.tv_nsec);
strcat((char *)pLogItem->msg, rt_msg);
break;
case LOG_RT_DATATYPE_U16:
- sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedShortVar);
+ snprintf(rt_msg, LOG_RT_MSG_LEN, pLogRTItem->pFormat, pLogRTItem->data.unsignedShortVar);
strcat((char *)pLogItem->msg, rt_msg);
break;
case LOG_RT_DATATYPE_S16:
- sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedShortVar);
+ snprintf(rt_msg, LOG_RT_MSG_LEN, pLogRTItem->pFormat, pLogRTItem->data.signedShortVar);
strcat((char *)pLogItem->msg, rt_msg);
break;
case LOG_RT_DATATYPE_U32:
- sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongVar);
+ snprintf(rt_msg, LOG_RT_MSG_LEN, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongVar);
strcat((char *)pLogItem->msg, rt_msg);
break;
case LOG_RT_DATATYPE_S32:
- sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedLongVar);
+ snprintf(rt_msg, LOG_RT_MSG_LEN, pLogRTItem->pFormat, pLogRTItem->data.signedLongVar);
strcat((char *)pLogItem->msg, rt_msg);
break;
case LOG_RT_DATATYPE_U64:
- sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongLongVar);
+ snprintf(rt_msg, LOG_RT_MSG_LEN, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongLongVar);
strcat((char *)pLogItem->msg, rt_msg);
break;
case LOG_RT_DATATYPE_S64:
- sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedLongLongVar);
+ snprintf(rt_msg, LOG_RT_MSG_LEN, pLogRTItem->pFormat, pLogRTItem->data.signedLongLongVar);
strcat((char *)pLogItem->msg, rt_msg);
break;
case LOG_RT_DATATYPE_FLOAT:
- sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.floatVar);
+ snprintf(rt_msg, LOG_RT_MSG_LEN, pLogRTItem->pFormat, pLogRTItem->data.floatVar);
strcat((char *)pLogItem->msg, rt_msg);
break;
default:
@@ -168,33 +170,42 @@ extern U32 DLL_EXPORT avbLogGetMsg(U8 *pBuf, U32 bufSize)
void *loggingThreadFn(void *pv)
{
- while (loggingThreadRunning) {
+ do {
SLEEP_MSEC(LOG_QUEUE_SLEEP_MSEC);
bool more = TRUE;
+ bool flush = FALSE;
while (more) {
more = FALSE;
openavb_queue_elem_t elem = openavbQueueTailLock(logQueue);
if (elem) {
log_queue_item_t *pLogItem = (log_queue_item_t *)openavbQueueData(elem);
-
+
if (pLogItem->bRT)
avbLogRTRender(pLogItem);
-
- fputs((const char *)pLogItem->msg, AVB_LOG_OUTPUT_FD);
+
+ fputs((const char *)pLogItem->msg, logOutputFd);
openavbQueueTailPull(logQueue);
more = TRUE;
+ flush = TRUE;
}
}
- }
+ if (flush)
+ fflush(logOutputFd);
+ } while (loggingThreadRunning);
return NULL;
}
-extern void DLL_EXPORT avbLogInit(void)
+extern void DLL_EXPORT avbLogInitEx(FILE* file)
{
MUTEX_CREATE_ALT(gLogMutex);
+
+ if (file != NULL)
+ logOutputFd = file;
+ else
+ logOutputFd = AVB_LOG_OUTPUT_FD;
logQueue = openavbQueueNewQueue(sizeof(log_queue_item_t), LOG_QUEUE_MSG_CNT);
if (!logQueue) {
@@ -216,12 +227,20 @@ extern void DLL_EXPORT avbLogInit(void)
}
}
+extern void DLL_EXPORT avbLogInit(void)
+{
+ avbLogInitEx(NULL);
+}
+
extern void DLL_EXPORT avbLogExit()
{
if (OPENAVB_LOG_FROM_THREAD) {
loggingThreadRunning = false;
THREAD_JOIN(loggingThread, NULL);
}
+
+ fflush(logOutputFd);
+ logOutputFd = NULL;
}
extern void DLL_EXPORT avbLogFn(
@@ -250,36 +269,37 @@ extern void DLL_EXPORT avbLogFn(
file += 1;
else
file = (char*)path;
- sprintf(file_msg, " %s:%d", file, line);
+ snprintf(file_msg, LOG_FILE_LEN, " %s:%d", file, line);
}
if (OPENAVB_LOG_PROC_INFO) {
- sprintf(proc_msg, " P:%5.5d", GET_PID());
+ snprintf(proc_msg, LOG_PROC_LEN, " P:%5.5d", GET_PID());
}
if (OPENAVB_LOG_THREAD_INFO) {
- sprintf(thread_msg, " T:%lu", THREAD_SELF());
+ snprintf(thread_msg, LOG_THREAD_LEN, " T:%lu", THREAD_SELF());
}
if (OPENAVB_LOG_TIME_INFO) {
time_t tNow = time(NULL);
struct tm tmNow;
localtime_r(&tNow, &tmNow);
- sprintf(time_msg, "%2.2d:%2.2d:%2.2d", tmNow.tm_hour, tmNow.tm_min, tmNow.tm_sec);
+ snprintf(time_msg, LOG_TIME_LEN, "%2.2d:%2.2d:%2.2d", tmNow.tm_hour, tmNow.tm_min, tmNow.tm_sec);
}
if (OPENAVB_LOG_TIMESTAMP_INFO) {
struct timespec nowTS;
CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &nowTS);
- sprintf(timestamp_msg, "%lu:%09lu", nowTS.tv_sec, nowTS.tv_nsec);
+ snprintf(timestamp_msg, LOG_TIMESTAMP_LEN, "%lu:%09lu", nowTS.tv_sec, nowTS.tv_nsec);
}
// using sprintf and puts allows using static buffers rather than heap.
if (OPENAVB_TCAL_LOG_EXTRA_NEWLINE)
- /* S32 full_msg_len = */ sprintf(full_msg, "[%s%s%s%s %s %s%s] %s: %s\n", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg);
+ /* S32 full_msg_len = */ snprintf(full_msg, LOG_FULL_MSG_LEN, "[%s%s%s%s %s %s%s] %s: %s\n", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg);
else
- /* S32 full_msg_len = */ sprintf(full_msg, "[%s%s%s%s %s %s%s] %s: %s", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg);
+ /* S32 full_msg_len = */ snprintf(full_msg, LOG_FULL_MSG_LEN, "[%s%s%s%s %s %s%s] %s: %s", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg);
if (!OPENAVB_LOG_FROM_THREAD && !OPENAVB_LOG_PULL_MODE) {
- fputs(full_msg, AVB_LOG_OUTPUT_FD);
+ fputs(full_msg, logOutputFd);
+ fflush(logOutputFd);
}
else {
if (logQueue) {
@@ -301,94 +321,139 @@ extern void DLL_EXPORT avbLogFn(
extern void DLL_EXPORT avbLogRT(int level, bool bBegin, bool bItem, bool bEnd, char *pFormat, log_rt_datatype_t dataType, void *pVar)
{
- if (level <= AVB_LOG_LEVEL) {
- if (logRTQueue) {
- if (bBegin) {
- LOG_LOCK();
+ if (logRTQueue) {
+ if (bBegin) {
+ LOG_LOCK();
- openavb_queue_elem_t elem = openavbQueueHeadLock(logRTQueue);
- if (elem) {
- log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)openavbQueueData(elem);
+ openavb_queue_elem_t elem = openavbQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)openavbQueueData(elem);
+ pLogRTItem->bEnd = FALSE;
+ pLogRTItem->pFormat = NULL;
+ pLogRTItem->dataType = LOG_RT_DATATYPE_NOW_TS;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pLogRTItem->data.nowTS);
+ openavbQueueHeadPush(logRTQueue);
+ }
+ }
+
+ if (bItem) {
+ openavb_queue_elem_t elem = openavbQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)openavbQueueData(elem);
+ if (bEnd)
+ pLogRTItem->bEnd = TRUE;
+ else
pLogRTItem->bEnd = FALSE;
- pLogRTItem->pFormat = NULL;
- pLogRTItem->dataType = LOG_RT_DATATYPE_NOW_TS;
- CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pLogRTItem->data.nowTS);
- openavbQueueHeadPush(logRTQueue);
+ pLogRTItem->pFormat = pFormat;
+ pLogRTItem->dataType = dataType;
+
+ switch (pLogRTItem->dataType) {
+ case LOG_RT_DATATYPE_CONST_STR:
+ break;
+ case LOG_RT_DATATYPE_U16:
+ pLogRTItem->data.unsignedLongVar = *(U16 *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S16:
+ pLogRTItem->data.signedLongVar = *(S16 *)pVar;
+ break;
+ case LOG_RT_DATATYPE_U32:
+ pLogRTItem->data.unsignedLongVar = *(U32 *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S32:
+ pLogRTItem->data.signedLongVar = *(S32 *)pVar;
+ break;
+ case LOG_RT_DATATYPE_U64:
+ pLogRTItem->data.unsignedLongLongVar = *(U64 *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S64:
+ pLogRTItem->data.signedLongLongVar = *(S64 *)pVar;
+ break;
+ case LOG_RT_DATATYPE_FLOAT:
+ pLogRTItem->data.floatVar = *(float *)pVar;
+ break;
+ default:
+ break;
}
+ openavbQueueHeadPush(logRTQueue);
}
+ }
- if (bItem) {
- openavb_queue_elem_t elem = openavbQueueHeadLock(logRTQueue);
- if (elem) {
- log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)openavbQueueData(elem);
- if (bEnd)
- pLogRTItem->bEnd = TRUE;
- else
- pLogRTItem->bEnd = FALSE;
- pLogRTItem->pFormat = pFormat;
- pLogRTItem->dataType = dataType;
-
- switch (pLogRTItem->dataType) {
- case LOG_RT_DATATYPE_CONST_STR:
- break;
- case LOG_RT_DATATYPE_U16:
- pLogRTItem->data.unsignedLongVar = *(U16 *)pVar;
- break;
- case LOG_RT_DATATYPE_S16:
- pLogRTItem->data.signedLongVar = *(S16 *)pVar;
- break;
- case LOG_RT_DATATYPE_U32:
- pLogRTItem->data.unsignedLongVar = *(U32 *)pVar;
- break;
- case LOG_RT_DATATYPE_S32:
- pLogRTItem->data.signedLongVar = *(S32 *)pVar;
- break;
- case LOG_RT_DATATYPE_U64:
- pLogRTItem->data.unsignedLongLongVar = *(U64 *)pVar;
- break;
- case LOG_RT_DATATYPE_S64:
- pLogRTItem->data.signedLongLongVar = *(S64 *)pVar;
- break;
- case LOG_RT_DATATYPE_FLOAT:
- pLogRTItem->data.floatVar = *(float *)pVar;
- break;
- default:
- break;
- }
- openavbQueueHeadPush(logRTQueue);
- }
+ if (!bItem && bEnd) {
+ openavb_queue_elem_t elem = openavbQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)openavbQueueData(elem);
+ pLogRTItem->bEnd = TRUE;
+ pLogRTItem->pFormat = NULL;
+ pLogRTItem->dataType = LOG_RT_DATATYPE_NONE;
+ openavbQueueHeadPush(logRTQueue);
}
-
- if (!bItem && bEnd) {
- openavb_queue_elem_t elem = openavbQueueHeadLock(logRTQueue);
+ }
+
+ if (bEnd) {
+ if (logQueue) {
+ openavb_queue_elem_t elem = openavbQueueHeadLock(logQueue);
if (elem) {
- log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)openavbQueueData(elem);
- pLogRTItem->bEnd = TRUE;
- pLogRTItem->pFormat = NULL;
- pLogRTItem->dataType = LOG_RT_DATATYPE_NONE;
- openavbQueueHeadPush(logRTQueue);
- }
- }
-
- if (bEnd) {
- if (logQueue) {
- openavb_queue_elem_t elem = openavbQueueHeadLock(logQueue);
- if (elem) {
- log_queue_item_t *pLogItem = (log_queue_item_t *)openavbQueueData(elem);
- pLogItem->bRT = TRUE;
- if (OPENAVB_LOG_FROM_THREAD) {
- openavbQueueHeadPush(logQueue);
- } else {
- avbLogRTRender(pLogItem);
- fputs((const char *)pLogItem->msg, AVB_LOG_OUTPUT_FD);
- openavbQueueHeadUnlock(logQueue);
- }
+ log_queue_item_t *pLogItem = (log_queue_item_t *)openavbQueueData(elem);
+ pLogItem->bRT = TRUE;
+ if (OPENAVB_LOG_FROM_THREAD) {
+ openavbQueueHeadPush(logQueue);
+ } else {
+ avbLogRTRender(pLogItem);
+ fputs((const char *)pLogItem->msg, logOutputFd);
+ fflush(logOutputFd);
+ openavbQueueHeadUnlock(logQueue);
}
}
-
- LOG_UNLOCK();
}
+
+ LOG_UNLOCK();
}
}
}
+extern void DLL_EXPORT avbLogBuffer(
+ int level,
+ const U8 *pData,
+ int dataLen,
+ int lineLen,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line)
+{
+ char szDataLine[ 400 ];
+ char *pszOut;
+ int i, j;
+
+ if (level > AVB_LOG_LEVEL) { return; }
+
+ for (i = 0; i < dataLen; i += lineLen) {
+ /* Create the hexadecimal output for the buffer. */
+ pszOut = szDataLine;
+ *pszOut++ = '\t';
+ for (j = i; j < i + lineLen; ++j) {
+ if (j < dataLen) {
+ sprintf(pszOut, "%02x ", pData[j]);
+ } else {
+ strcpy(pszOut, " ");
+ }
+ pszOut += 3;
+ }
+
+ *pszOut++ = ' ';
+ *pszOut++ = ' ';
+
+ /* Append the ASCII equivalent of each character. */
+ for (j = i; j < dataLen && j < i + lineLen; ++j) {
+ if (pData[j] >= 0x20 && pData[j] < 0x7f) {
+ *pszOut++ = (char) pData[j];
+ } else {
+ *pszOut++ = '.';
+ }
+ }
+
+ /* Display this line of text. */
+ *pszOut = '\0';
+ avbLogFn(level, "BUFFER", company, component, path, line, "%s", szDataLine);
+ }
+}
diff --git a/lib/avtp_pipeline/util/openavb_plugin.c b/lib/avtp_pipeline/util/openavb_plugin.c
index 1400cad4..2b9c3162 100644
--- a/lib/avtp_pipeline/util/openavb_plugin.c
+++ b/lib/avtp_pipeline/util/openavb_plugin.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/util/openavb_plugin.h b/lib/avtp_pipeline/util/openavb_plugin.h
index 9b0b2d59..5e2f4420 100644
--- a/lib/avtp_pipeline/util/openavb_plugin.h
+++ b/lib/avtp_pipeline/util/openavb_plugin.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/util/openavb_printbuf.c b/lib/avtp_pipeline/util/openavb_printbuf.c
index ba435b6c..981656fe 100644
--- a/lib/avtp_pipeline/util/openavb_printbuf.c
+++ b/lib/avtp_pipeline/util/openavb_printbuf.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/util/openavb_printbuf.h b/lib/avtp_pipeline/util/openavb_printbuf.h
index a3732a75..db36a364 100644
--- a/lib/avtp_pipeline/util/openavb_printbuf.h
+++ b/lib/avtp_pipeline/util/openavb_printbuf.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/util/openavb_queue.c b/lib/avtp_pipeline/util/openavb_queue.c
index cc7ea21d..ea48bf90 100644
--- a/lib/avtp_pipeline/util/openavb_queue.c
+++ b/lib/avtp_pipeline/util/openavb_queue.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/util/openavb_queue.h b/lib/avtp_pipeline/util/openavb_queue.h
index 69e22011..f2e62ff5 100644
--- a/lib/avtp_pipeline/util/openavb_queue.h
+++ b/lib/avtp_pipeline/util/openavb_queue.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/util/openavb_result_codes.c b/lib/avtp_pipeline/util/openavb_result_codes.c
index 61dd12b1..1e377b5b 100755
--- a/lib/avtp_pipeline/util/openavb_result_codes.c
+++ b/lib/avtp_pipeline/util/openavb_result_codes.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
@@ -163,6 +164,7 @@ char *openavbUtilRCCodeToString(openavbRC rc)
case OPENAVBAVDECC_RC_INVALID_CONFIG_IDX: return "Referenced an invalid configuration descriptor index";
case OPENAVBAVDECC_RC_PARSING_MAC_ADDRESS: return "Parsing Mac Address";
case OPENAVBAVDECC_RC_UNKNOWN_DESCRIPTOR: return "Unknown descriptor";
+ case OPENAVBAVDECC_RC_STALE_DATA: return "Stale data";
// No Default
}
diff --git a/lib/avtp_pipeline/util/openavb_result_codes.h b/lib/avtp_pipeline/util/openavb_result_codes.h
index 082828da..d2aadbc4 100644
--- a/lib/avtp_pipeline/util/openavb_result_codes.h
+++ b/lib/avtp_pipeline/util/openavb_result_codes.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
@@ -85,7 +86,7 @@ enum openavbCommonResultCodes {
OPENAVB_RC_FAILED_TO_OPEN = 0x1004, // Failed to open
};
-enum openavbPtpResultCodes {
+enum openavbPtpResultCodes {
OPENAVBPTP_RC_GENERIC = 0x0000,
OPENAVBPTP_RC_SHARED_MEMORY_OPEN = 0x0001, // Failed to open shared memory file
OPENAVBPTP_RC_SHARED_MEMORY_TRANC = 0x0002, // Failed to truncate shared memory file
@@ -115,7 +116,7 @@ enum openavbPtpResultCodes {
OPENAVBPTP_RC_TX_TIMESTAMP_FAIL = 0x0026, // Failed to get egress timestamp
};
-enum openavbSrpResultCodes {
+enum openavbSrpResultCodes {
OPENAVBSRP_RC_GENERIC = 0x0000,
OPENAVBSRP_RC_ALREADY_INIT = 0x0001, // Already initialized
OPENAVBSRP_RC_SOCK_OPEN = 0x0002, // Failed to open socket
@@ -140,7 +141,7 @@ enum openavbSrpResultCodes {
// limited to two bytes; max 0xffff
};
-enum openavbAVTPResultCodes {
+enum openavbAVTPResultCodes {
OPENAVBAVTP_RC_GENERIC = 0x0000,
OPENAVBAVTP_RC_TX_PACKET_NOT_READY = 0x0001, // Transmit packet not ready
OPENAVBAVTP_RC_MAPPING_CB_NOT_SET = 0x0002, // Mapping callback structure not set
@@ -152,7 +153,7 @@ enum openavbAVTPResultCodes {
OPENAVBAVTP_RC_PARSING_FRAME_HEADER = 0x0008, // Parsing frame header
};
-enum openavbAVTPTimeResultCodes {
+enum openavbAVTPTimeResultCodes {
OPENAVBAVTPTIME_RC_GENERIC = 0x0000,
OPENAVBAVTPTIME_RC_PTP_TIME_DESCRIPTOR = 0x0001, // PTP file descriptor not available
OPENAVBAVTPTIME_RC_OPEN_SRC_PTP_NOT_AVAIL = 0x0002, // Open source PTP configured but not available in this build
@@ -161,14 +162,15 @@ enum openavbAVTPTimeResultCodes {
OPENAVBAVTPTIME_RC_INVALID_PTP_TIME = 0x0005, // Invalid avtp_time_t
};
-enum openavbAVDECCResultCodes {
+enum openavbAvdeccResultCodes {
OPENAVBAVDECC_RC_GENERIC = 0x0000,
OPENAVBAVDECC_RC_BUFFER_TOO_SMALL = 0x0001, // Buffer size is too small
OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING = 0x0002, // The Entity Model has not been created
OPENAVBAVDECC_RC_INVALID_CONFIG_IDX = 0x0003, // Referenced an invalid configuration descriptor index
OPENAVBAVDECC_RC_PARSING_MAC_ADDRESS = 0x0004, // Parsing Mac Address
OPENAVBAVDECC_RC_UNKNOWN_DESCRIPTOR = 0x0005, // Unknown descriptor
-};
+ OPENAVBAVDECC_RC_STALE_DATA = 0x0006, // Stale data
+};
#define OPENAVB_PTP_SUCCESS (OPENAVB_SUCCESS | OPENAVB_MODULE_GPTP)
diff --git a/lib/avtp_pipeline/util/openavb_time.c b/lib/avtp_pipeline/util/openavb_time.c
index 7b624806..126afd26 100644
--- a/lib/avtp_pipeline/util/openavb_time.c
+++ b/lib/avtp_pipeline/util/openavb_time.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
@@ -61,9 +62,17 @@ void openavbTimeTimespecAddUsec(struct timespec *pTime, U32 us)
return; // Error case - undefined behavior
}
- pTime->tv_nsec += us * NANOSECONDS_PER_USEC;
- pTime->tv_sec += pTime->tv_nsec / NANOSECONDS_PER_SECOND;
- pTime->tv_nsec = pTime->tv_nsec % NANOSECONDS_PER_SECOND;
+ /* Handle the seconds provided (to prevent overflowing). */
+ pTime->tv_sec += us / MICROSECONDS_PER_SECOND;
+ us = us % MICROSECONDS_PER_SECOND;
+
+ /* Handle the remaining microseconds provided. */
+ if (us > 0) {
+ pTime->tv_nsec += us * NANOSECONDS_PER_USEC;
+
+ pTime->tv_sec += pTime->tv_nsec / NANOSECONDS_PER_SECOND;
+ pTime->tv_nsec = pTime->tv_nsec % NANOSECONDS_PER_SECOND;
+ }
}
void openavbTimeTimespecSubUsec(struct timespec *pTime, U32 us)
@@ -72,10 +81,19 @@ void openavbTimeTimespecSubUsec(struct timespec *pTime, U32 us)
return; // Error case - undefined behavior
}
- U64 nSec = ((U64)pTime->tv_sec * (U64)NANOSECONDS_PER_SECOND) + (U64)pTime->tv_nsec;
- nSec -= us * NANOSECONDS_PER_USEC;
- pTime->tv_sec = nSec / NANOSECONDS_PER_SECOND;
- pTime->tv_nsec = nSec % NANOSECONDS_PER_SECOND;
+ /* Handle the seconds provided (to prevent overflowing). */
+ pTime->tv_sec -= us / MICROSECONDS_PER_SECOND;
+ us = us % MICROSECONDS_PER_SECOND;
+
+ /* Handle the remaining microseconds provided. */
+ if (us > 0) {
+ pTime->tv_nsec -= us * NANOSECONDS_PER_USEC;
+
+ if (pTime->tv_nsec < 0) {
+ pTime->tv_nsec += NANOSECONDS_PER_SECOND;
+ pTime->tv_sec -= 1;
+ }
+ }
}
S64 openavbTimeTimespecUsecDiff(struct timespec *pTime1, struct timespec *pTime2)
diff --git a/lib/avtp_pipeline/util/openavb_time.h b/lib/avtp_pipeline/util/openavb_time.h
index 1a3e7d72..c52fa47f 100644
--- a/lib/avtp_pipeline/util/openavb_time.h
+++ b/lib/avtp_pipeline/util/openavb_time.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
@@ -56,10 +57,10 @@ S64 openavbTimeTimespecUsecDiff(struct timespec *pTime1, struct timespec *pTime2
// Compares 2 timespecs and returns -1, 0 or 1 depending on the compare.
S32 openavbTimeTimespecCmp(struct timespec *pTime1, struct timespec *pTime2);
-// Microseconds until Time2 reaches Time1. Returns 0 if Time2 is already past Time1
+// Microseconds until Time1 reaches Time2. Returns 0 if Time1 is already past Time2
U64 openavbTimeUntilUSec(struct timespec *pTime1, struct timespec *pTime2);
-// Milliseconds until Time2 reaches Time1. Returns 0 if Time2 is already past Time1
+// Milliseconds until Time1 reaches Time2. Returns 0 if Time1 is already past Time2
U32 openavbTimeUntilMSec(struct timespec *pTime1, struct timespec *pTime2);
#endif // OPENAVB_TIME_H
diff --git a/lib/avtp_pipeline/util/openavb_timestamp.c b/lib/avtp_pipeline/util/openavb_timestamp.c
index 442fa82c..82790ce3 100644
--- a/lib/avtp_pipeline/util/openavb_timestamp.c
+++ b/lib/avtp_pipeline/util/openavb_timestamp.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/util/openavb_timestamp.h b/lib/avtp_pipeline/util/openavb_timestamp.h
index 0b4d77b8..85745fac 100644
--- a/lib/avtp_pipeline/util/openavb_timestamp.h
+++ b/lib/avtp_pipeline/util/openavb_timestamp.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/igb/igb.c b/lib/igb/igb.c
index 497b0c8a..d59a0fcb 100644
--- a/lib/igb/igb.c
+++ b/lib/igb/igb.c
@@ -131,7 +131,7 @@ int igb_probe(device_t *dev)
int igb_attach(char *dev_path, device_t *pdev)
{
struct adapter *adapter;
- struct igb_bind_cmd bind;
+ struct igb_bind_cmd bind = {0};
int error = 0;
bool locked = false;
@@ -666,7 +666,7 @@ int igb_dma_malloc_page(device_t *dev, struct igb_dma_alloc *dma)
{
struct adapter *adapter;
int error = 0;
- struct igb_buf_cmd ubuf;
+ struct igb_buf_cmd ubuf = {0};
if (dev == NULL)
return -EINVAL;
@@ -749,7 +749,7 @@ err:
**********************************************************************/
static int igb_allocate_queues(struct adapter *adapter)
{
- struct igb_buf_cmd ubuf;
+ struct igb_buf_cmd ubuf = {0};
int dev = adapter->ldev;
int i, error = 0;
@@ -901,7 +901,7 @@ static void igb_initialize_transmit_units(struct adapter *adapter)
static void igb_free_transmit_structures(struct adapter *adapter)
{
int i;
- struct igb_buf_cmd ubuf;
+ struct igb_buf_cmd ubuf = {0};
for (i = 0; i < adapter->num_queues; i++) {
if (adapter->tx_rings[i].tx_base)
@@ -2017,7 +2017,7 @@ int igb_set_class_bandwidth(device_t *dev, u_int32_t class_a, u_int32_t class_b,
u_int32_t linkrate;
struct adapter *adapter;
struct e1000_hw *hw;
- struct igb_link_cmd link;
+ struct igb_link_cmd link = {0};
int err;
float class_a_percent, class_b_percent;
int error = 0;
@@ -2170,7 +2170,7 @@ int igb_set_class_bandwidth2(device_t *dev, u_int32_t class_a_bytes_per_second,
int temp;
struct adapter *adapter;
struct e1000_hw *hw;
- struct igb_link_cmd link;
+ struct igb_link_cmd link = {0};
int err;
float class_a_percent, class_b_percent;
int error = 0;
diff --git a/run_maap.sh b/run_maap.sh
new file mode 100755
index 00000000..740df758
--- /dev/null
+++ b/run_maap.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+# Simple script to run MAAP
+
+if [ "$#" -eq "0" ]; then
+ echo "please enter network interface name as parameter. For example:"
+ echo "sudo ./run_maap.sh eth1"
+ exit -1
+fi
+
+./daemons/maap/linux/build/maap_daemon -i $1
diff --git a/run_shaper.sh b/run_shaper.sh
new file mode 100755
index 00000000..2e7a5d69
--- /dev/null
+++ b/run_shaper.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+# Simple script to run the shaper daemon
+
+./daemons/shaper/shaper_daemon
diff --git a/run_srp.sh b/run_srp.sh
index f75c9c12..b45c5d4e 100755
--- a/run_srp.sh
+++ b/run_srp.sh
@@ -7,4 +7,4 @@ if [ "$#" -eq "0" ]; then
exit -1
fi
-daemons/mrpd/mrpd -s -i $1
+daemons/mrpd/mrpd -mvs -i $1
diff --git a/thirdparty/cpputest b/thirdparty/cpputest
-Subproject 69d1b24fa92fc8c3cf5542bf44293c3e05cfbf0
+Subproject 1d01e4900a6a63d89678a278f9fde4c5949f98e
diff --git a/travis.sh b/travis.sh
index 54a2b78a..b10cc42c 100755
--- a/travis.sh
+++ b/travis.sh
@@ -5,6 +5,7 @@ make lib
make daemons_all
make examples_all
make avtp_pipeline
+make avtp_avdecc
mkdir build
cd build
cmake .. -G "Unix Makefiles"