summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Cemin <david.cemin@coveloz.com>2015-11-05 09:18:44 -0500
committerDavid Cemin <david.cemin@coveloz.com>2015-11-05 09:18:44 -0500
commitec2202122bb9cf6deeb7624a3588f6440fc4dca1 (patch)
treeffea56ad09b51f95bfcfa6c312b3739d1b842567
parent0d0b41c0f1acf7a16d0e25fcd77a0c36c58de8e9 (diff)
parentefb699685e515b4b82d84c4fcd6b2b75a6cbbc37 (diff)
downloadOpen-AVB-ec2202122bb9cf6deeb7624a3588f6440fc4dca1.tar.gz
Merge branch 'open-avb-next' into task-gptpV2
Conflicts: daemons/gptp/common/ieee1588.hpp daemons/gptp/common/ieee1588port.cpp daemons/gptp/linux/src/linux_hal_generic.cpp
-rw-r--r--.travis.yml1
-rw-r--r--Makefile16
-rw-r--r--daemons/gptp/common/avbts_osnet.cpp40
-rw-r--r--daemons/gptp/common/avbts_osnet.hpp2
-rw-r--r--daemons/gptp/common/avbts_port.hpp5
-rw-r--r--daemons/gptp/common/ieee1588.hpp43
-rw-r--r--daemons/gptp/common/ieee1588port.cpp15
-rw-r--r--daemons/gptp/linux/src/daemon_cl.cpp107
-rw-r--r--daemons/gptp/linux/src/linux_hal_common.cpp103
-rw-r--r--daemons/gptp/linux/src/linux_hal_common.hpp46
-rw-r--r--daemons/gptp/linux/src/linux_hal_generic.cpp11
-rw-r--r--examples/common/listener_mrp_client.c261
-rw-r--r--examples/common/listener_mrp_client.h50
-rw-r--r--examples/common/talker_mrp_client.c229
-rw-r--r--examples/common/talker_mrp_client.h90
-rw-r--r--examples/jackd-listener/Makefile2
-rw-r--r--examples/jackd-listener/jack_listener.c113
-rw-r--r--examples/jackd-talker/Makefile3
-rw-r--r--examples/jackd-talker/jack.c29
-rw-r--r--examples/jackd-talker/jack.h3
-rw-r--r--[-rwxr-xr-x]examples/jackd-talker/jackd_talker.c116
-rw-r--r--examples/live_stream/listener.c54
-rw-r--r--examples/live_stream/talker.c73
-rw-r--r--examples/simple_listener/Makefile2
-rw-r--r--examples/simple_listener/simple_listener.c88
-rw-r--r--examples/simple_talker/simple_talker.c155
-rw-r--r--lib/avtp_pipeline/CMakeLists.txt40
-rw-r--r--lib/avtp_pipeline/LICENSE30
-rw-r--r--lib/avtp_pipeline/README.md140
-rw-r--r--lib/avtp_pipeline/avtp/CMakeLists.txt6
-rw-r--r--lib/avtp_pipeline/avtp/openavb_avtp.c701
-rw-r--r--lib/avtp_pipeline/avtp/openavb_avtp.h192
-rw-r--r--lib/avtp_pipeline/avtp/openavb_avtp_time.c438
-rw-r--r--lib/avtp_pipeline/avtp/openavb_avtp_time_pub.h275
-rw-r--r--lib/avtp_pipeline/avtp_pipeline.mk21
-rw-r--r--lib/avtp_pipeline/cmake/FindALSA.cmake36
-rw-r--r--lib/avtp_pipeline/cmake/FindPCAP.cmake121
-rw-r--r--lib/avtp_pipeline/cmake/LibFindMacros.cmake99
-rw-r--r--lib/avtp_pipeline/documents/CMakeLists.txt42
-rw-r--r--lib/avtp_pipeline/documents/Doxyfile.in341
-rw-r--r--lib/avtp_pipeline/documents/DoxygenLayout.xml194
-rw-r--r--lib/avtp_pipeline/documents/Release Notes.docxbin0 -> 312858 bytes
-rw-r--r--lib/avtp_pipeline/documents/images/AVTP_Data_Flow.pngbin0 -> 78191 bytes
-rw-r--r--lib/avtp_pipeline/documents/images/Core_AVB.pngbin0 -> 50777 bytes
-rw-r--r--lib/avtp_pipeline/documents/images/Listener_Stream_Data_Flow.pngbin0 -> 39573 bytes
-rw-r--r--lib/avtp_pipeline/documents/images/Stream_Initialize.pngbin0 -> 38142 bytes
-rw-r--r--lib/avtp_pipeline/documents/images/Talker_Stream_Data_Flow.pngbin0 -> 37146 bytes
-rw-r--r--lib/avtp_pipeline/documents/images/fig1.pngbin0 -> 18088 bytes
-rw-r--r--lib/avtp_pipeline/documents/images/fig2.pngbin0 -> 19598 bytes
-rw-r--r--lib/avtp_pipeline/documents/images/harman_logo.pngbin0 -> 3512 bytes
-rw-r--r--lib/avtp_pipeline/documents/index.md51
-rw-r--r--lib/avtp_pipeline/documents/sdk_avtp_interface_module_dev.md165
-rw-r--r--lib/avtp_pipeline/documents/sdk_avtp_stream_cfg.md343
-rw-r--r--lib/avtp_pipeline/documents/sdk_eavb_integration.md31
-rw-r--r--lib/avtp_pipeline/documents/sdk_notes.md7
-rw-r--r--lib/avtp_pipeline/documents/sdk_notes_media_queue_usage.md124
-rw-r--r--lib/avtp_pipeline/documents/sdk_overview.md233
-rw-r--r--lib/avtp_pipeline/endpoint/CMakeLists.txt7
-rw-r--r--lib/avtp_pipeline/endpoint/NOTES.TXT11
-rw-r--r--lib/avtp_pipeline/endpoint/endpoint.ini59
-rw-r--r--lib/avtp_pipeline/endpoint/gstreamer.txt98
-rw-r--r--lib/avtp_pipeline/endpoint/openavb_endpoint.c528
-rw-r--r--lib/avtp_pipeline/endpoint/openavb_endpoint.h279
-rw-r--r--lib/avtp_pipeline/endpoint/openavb_endpoint_client.c199
-rw-r--r--lib/avtp_pipeline/endpoint/openavb_endpoint_server.c394
-rw-r--r--lib/avtp_pipeline/endpoint/shutdown_openavb_endpoint.sh23
-rw-r--r--lib/avtp_pipeline/include/avb_sched.h126
-rw-r--r--lib/avtp_pipeline/include/openavb_audio_pub.h157
-rwxr-xr-xlib/avtp_pipeline/include/openavb_intf_pub.h230
-rw-r--r--lib/avtp_pipeline/include/openavb_log.h43
-rw-r--r--lib/avtp_pipeline/include/openavb_log_pub.h246
-rwxr-xr-xlib/avtp_pipeline/include/openavb_map_pub.h240
-rw-r--r--lib/avtp_pipeline/include/openavb_platform.h47
-rw-r--r--lib/avtp_pipeline/include/openavb_platform_pub.h42
-rw-r--r--lib/avtp_pipeline/include/openavb_pub.h87
-rw-r--r--lib/avtp_pipeline/include/openavb_trace.h78
-rw-r--r--lib/avtp_pipeline/include/openavb_trace_pub.h247
-rw-r--r--lib/avtp_pipeline/include/openavb_types.h45
-rw-r--r--lib/avtp_pipeline/include/openavb_types_base.h79
-rw-r--r--lib/avtp_pipeline/include/openavb_types_base_pub.h120
-rw-r--r--lib/avtp_pipeline/include/openavb_types_pub.h48
-rw-r--r--lib/avtp_pipeline/inih/CMakeLists.txt5
-rw-r--r--lib/avtp_pipeline/inih/LICENSE.txt27
-rw-r--r--lib/avtp_pipeline/inih/README.TXT15
-rw-r--r--lib/avtp_pipeline/inih/ini.c292
-rw-r--r--lib/avtp_pipeline/inih/ini.h72
-rw-r--r--lib/avtp_pipeline/inih/inih_r23.zipbin0 -> 13175 bytes
-rw-r--r--lib/avtp_pipeline/intf_ctrl/CMakeLists.txt6
-rw-r--r--lib/avtp_pipeline/intf_ctrl/ctrl_intf.md32
-rw-r--r--lib/avtp_pipeline/intf_ctrl/ctrl_listener.ini106
-rw-r--r--lib/avtp_pipeline/intf_ctrl/ctrl_mux_listener.ini106
-rw-r--r--lib/avtp_pipeline/intf_ctrl/ctrl_mux_talker.ini144
-rw-r--r--lib/avtp_pipeline/intf_ctrl/ctrl_talker.ini147
-rwxr-xr-xlib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl.c385
-rwxr-xr-xlib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl_pub.h66
-rw-r--r--lib/avtp_pipeline/intf_echo/CMakeLists.txt5
-rw-r--r--lib/avtp_pipeline/intf_echo/echo_host_intf.md29
-rw-r--r--lib/avtp_pipeline/intf_echo/echo_listener.ini110
-rw-r--r--lib/avtp_pipeline/intf_echo/echo_listener_auto.ini110
-rw-r--r--lib/avtp_pipeline/intf_echo/echo_talker.ini159
-rw-r--r--lib/avtp_pipeline/intf_echo/echo_talker_auto.ini159
-rwxr-xr-xlib/avtp_pipeline/intf_echo/openavb_intf_echo.c349
-rw-r--r--lib/avtp_pipeline/intf_logger/CMakeLists.txt5
-rw-r--r--lib/avtp_pipeline/intf_logger/openavb_intf_logger.c201
-rw-r--r--lib/avtp_pipeline/intf_logger/openavb_intf_logger.md24
-rw-r--r--lib/avtp_pipeline/intf_null/CMakeLists.txt5
-rw-r--r--lib/avtp_pipeline/intf_null/null_host_intf.md17
-rw-r--r--lib/avtp_pipeline/intf_null/null_listener.ini98
-rw-r--r--lib/avtp_pipeline/intf_null/null_talker.ini136
-rwxr-xr-xlib/avtp_pipeline/intf_null/openavb_intf_null.c208
-rw-r--r--lib/avtp_pipeline/intf_tonegen/CMakeLists.txt4
-rw-r--r--lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.c524
-rw-r--r--lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.md30
-rw-r--r--lib/avtp_pipeline/intf_tonegen/tonegen_talker.ini148
-rw-r--r--lib/avtp_pipeline/intf_viewer/CMakeLists.txt6
-rw-r--r--lib/avtp_pipeline/intf_viewer/latency_listener.ini126
-rw-r--r--lib/avtp_pipeline/intf_viewer/latency_talker.ini168
-rwxr-xr-xlib/avtp_pipeline/intf_viewer/openavb_intf_viewer.c520
-rw-r--r--lib/avtp_pipeline/intf_viewer/viewer_intf.md31
-rw-r--r--lib/avtp_pipeline/intf_viewer/viewer_listener.ini123
-rw-r--r--lib/avtp_pipeline/maap/openavb_maap.h61
-rw-r--r--lib/avtp_pipeline/map_aaf_audio/CMakeLists.txt5
-rw-r--r--lib/avtp_pipeline/map_aaf_audio/README.TXT42
-rw-r--r--lib/avtp_pipeline/map_aaf_audio/aaf_audio_map.md58
-rwxr-xr-xlib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c792
-rwxr-xr-xlib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio_pub.h52
-rw-r--r--lib/avtp_pipeline/map_ctrl/CMakeLists.txt5
-rw-r--r--lib/avtp_pipeline/map_ctrl/ctrl_map.md19
-rwxr-xr-xlib/avtp_pipeline/map_ctrl/openavb_map_ctrl.c484
-rwxr-xr-xlib/avtp_pipeline/map_ctrl/openavb_map_ctrl_pub.h44
-rw-r--r--lib/avtp_pipeline/map_h264/CMakeLists.txt5
-rwxr-xr-xlib/avtp_pipeline/map_h264/openavb_map_h264.c461
-rwxr-xr-xlib/avtp_pipeline/map_h264/openavb_map_h264_pub.h58
-rw-r--r--lib/avtp_pipeline/map_mjpeg/CMakeLists.txt5
-rw-r--r--lib/avtp_pipeline/map_mjpeg/mjpeg_map.md24
-rwxr-xr-xlib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg.c427
-rwxr-xr-xlib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg_pub.h77
-rw-r--r--lib/avtp_pipeline/map_mpeg2ts/CMakeLists.txt5
-rw-r--r--lib/avtp_pipeline/map_mpeg2ts/demo_listener.ini89
-rw-r--r--lib/avtp_pipeline/map_mpeg2ts/demo_talker.ini114
-rw-r--r--lib/avtp_pipeline/map_mpeg2ts/mpeg2ts_map.md38
-rwxr-xr-xlib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts.c734
-rwxr-xr-xlib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts_pub.h62
-rw-r--r--lib/avtp_pipeline/map_mpeg2ts/ts_packet_size.c117
-rw-r--r--lib/avtp_pipeline/map_null/CMakeLists.txt5
-rw-r--r--lib/avtp_pipeline/map_null/null_map.md17
-rwxr-xr-xlib/avtp_pipeline/map_null/openavb_map_null.c386
-rwxr-xr-xlib/avtp_pipeline/map_null/openavb_map_null_pub.h44
-rw-r--r--lib/avtp_pipeline/map_pipe/CMakeLists.txt5
-rwxr-xr-xlib/avtp_pipeline/map_pipe/openavb_map_pipe.c488
-rwxr-xr-xlib/avtp_pipeline/map_pipe/openavb_map_pipe_pub.h44
-rw-r--r--lib/avtp_pipeline/map_pipe/pipe_map.md24
-rw-r--r--lib/avtp_pipeline/map_uncmp_audio/CMakeLists.txt5
-rwxr-xr-xlib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio.c759
-rwxr-xr-xlib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio_pub.h132
-rw-r--r--lib/avtp_pipeline/map_uncmp_audio/uncmp_audio_map.md57
-rw-r--r--lib/avtp_pipeline/mcr/CMakeLists.txt1
-rw-r--r--lib/avtp_pipeline/mcr/openavb_mcr_hal_pub.h65
-rw-r--r--lib/avtp_pipeline/mediaq/CMakeLists.txt5
-rw-r--r--lib/avtp_pipeline/mediaq/openavb_mediaq.c1073
-rw-r--r--lib/avtp_pipeline/mediaq/openavb_mediaq.h60
-rw-r--r--lib/avtp_pipeline/mediaq/openavb_mediaq_pub.h365
-rw-r--r--lib/avtp_pipeline/openavb_common/README.TXT9
-rw-r--r--lib/avtp_pipeline/openavb_common/avb.c576
-rw-r--r--lib/avtp_pipeline/openavb_common/avb.h210
-rw-r--r--lib/avtp_pipeline/openavb_common/mrp_client.c710
-rw-r--r--lib/avtp_pipeline/openavb_common/mrp_client.h92
-rw-r--r--lib/avtp_pipeline/platform/Linux/CMakeLists.txt333
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_host/CMakeLists.txt86
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c543
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c290
-rw-r--r--lib/avtp_pipeline/platform/Linux/avtp/openavb_avtp_time_osal.c34
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/CMakeLists.txt2
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c224
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.h63
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_client_osal.c179
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.c577
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.h62
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_server_osal.c254
-rw-r--r--lib/avtp_pipeline/platform/Linux/generic.cmake17
-rw-r--r--lib/avtp_pipeline/platform/Linux/gst_al/gst_al.h161
-rw-r--r--lib/avtp_pipeline/platform/Linux/gst_al/gst_al_01.c123
-rw-r--r--lib/avtp_pipeline/platform/Linux/gst_al/gst_al_10.c211
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/CMakeLists.txt10
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_file_talker.ini120
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener.ini129
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener_auto.ini129
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_talker.ini155
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_intf.md50
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_listener.ini145
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_talker.ini148
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/openavb_intf_alsa.c1041
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_h264_gst/CMakeLists.txt23
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_intf.md18
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_listener.ini106
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_talker.ini127
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_h264_gst/openavb_intf_h264_gst.c619
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/CMakeLists.txt23
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_camera_intf.md18
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_listener.ini110
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_talker.ini136
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/openavb_intf_mjpeg_gst.c575
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/CMakeLists.txt4
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_intf.md50
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_listener.ini100
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_talker.ini142
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/openavb_intf_mpeg2ts_file.c706
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/CMakeLists.txt22
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_intf.md16
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_listener.ini119
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_talker.ini129
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/openavb_intf_mpeg2ts_gst.c605
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_wav_file/CMakeLists.txt9
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_wav_file/openavb_intf_wav_file.c698
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_intf.md45
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_listener.ini112
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_talker.ini128
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_ether_osal.c39
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_ether_osal.h40
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_os_services_osal.h169
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_os_services_osal_pub.h109
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal.c55
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal.h41
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c56
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h44
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_poll_osal.h77
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_tasks.h106
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_time_osal.c207
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_time_osal.h36
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_time_osal_pub.h69
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/avtp_rx.c227
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.c276
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.h67
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock.c215
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.c185
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.h55
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/rawsock_rx.c194
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/rawsock_tx.c219
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.c680
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.h115
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.c467
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.h85
-rw-r--r--lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c443
-rw-r--r--lib/avtp_pipeline/platform/Linux/x86_i210_linux.cmake33
-rw-r--r--lib/avtp_pipeline/platform/generic/include/linux/ptp_clock.h29
-rw-r--r--lib/avtp_pipeline/platform/generic/openavb_hal.h37
-rw-r--r--lib/avtp_pipeline/platform/platHAL/readme.txt1
-rw-r--r--lib/avtp_pipeline/platform/platOSAL/readme.txt1
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.c39
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.h37
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal_pub.h38
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_tcal_pub.h38
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_time_tcal_pub.h49
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_types_base_tcal_pub.h40
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_warnings_tcal.h37
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/rawsock/openavb_rawsock_tcal.h59
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.c62
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.h37
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/openavb_ether_hal.c283
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/openavb_ether_hal.h60
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/openavb_hal.h38
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/openavb_time_hal.c72
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/openavb_time_hal.h38
-rw-r--r--lib/avtp_pipeline/qmgr/CMakeLists.txt5
-rw-r--r--lib/avtp_pipeline/qmgr/openavb_qmgr.c303
-rw-r--r--lib/avtp_pipeline/qmgr/openavb_qmgr.h95
-rw-r--r--lib/avtp_pipeline/rawsock/CMakeLists.txt4
-rw-r--r--lib/avtp_pipeline/rawsock/openavb_rawsock.h164
-rw-r--r--lib/avtp_pipeline/rawsock/rawsock_impl.c374
-rw-r--r--lib/avtp_pipeline/rawsock/rawsock_impl.h122
-rw-r--r--lib/avtp_pipeline/sdk/CMakeLists.txt70
-rwxr-xr-xlib/avtp_pipeline/srp/openavb_srp.h320
-rwxr-xr-xlib/avtp_pipeline/srp/openavb_srp_api.h179
-rw-r--r--lib/avtp_pipeline/tl/CMakeLists.txt29
-rw-r--r--lib/avtp_pipeline/tl/NOTES.TXT28
-rw-r--r--lib/avtp_pipeline/tl/openavb_listener.c424
-rw-r--r--lib/avtp_pipeline/tl/openavb_listener.h73
-rw-r--r--lib/avtp_pipeline/tl/openavb_listener_endpoint.c139
-rw-r--r--lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c80
-rw-r--r--lib/avtp_pipeline/tl/openavb_talker.c495
-rw-r--r--lib/avtp_pipeline/tl/openavb_talker.h77
-rw-r--r--lib/avtp_pipeline/tl/openavb_talker_endpoint.c163
-rw-r--r--lib/avtp_pipeline/tl/openavb_talker_no_endpoint.c149
-rwxr-xr-xlib/avtp_pipeline/tl/openavb_tl.c733
-rwxr-xr-xlib/avtp_pipeline/tl/openavb_tl.h164
-rw-r--r--lib/avtp_pipeline/tl/openavb_tl_endpoint.c278
-rw-r--r--lib/avtp_pipeline/tl/openavb_tl_no_endpoint.c134
-rwxr-xr-xlib/avtp_pipeline/tl/openavb_tl_pub.h342
-rw-r--r--lib/avtp_pipeline/util/CMakeLists.txt14
-rw-r--r--lib/avtp_pipeline/util/openavb_array.c443
-rw-r--r--lib/avtp_pipeline/util/openavb_array.h122
-rw-r--r--lib/avtp_pipeline/util/openavb_debug.c90
-rw-r--r--lib/avtp_pipeline/util/openavb_debug.h57
-rw-r--r--lib/avtp_pipeline/util/openavb_list.c290
-rw-r--r--lib/avtp_pipeline/util/openavb_list.h99
-rw-r--r--lib/avtp_pipeline/util/openavb_log.c394
-rw-r--r--lib/avtp_pipeline/util/openavb_plugin.c75
-rw-r--r--lib/avtp_pipeline/util/openavb_plugin.h47
-rw-r--r--lib/avtp_pipeline/util/openavb_printbuf.c112
-rw-r--r--lib/avtp_pipeline/util/openavb_printbuf.h54
-rw-r--r--lib/avtp_pipeline/util/openavb_queue.c196
-rw-r--r--lib/avtp_pipeline/util/openavb_queue.h85
-rwxr-xr-xlib/avtp_pipeline/util/openavb_result_codes.c174
-rw-r--r--lib/avtp_pipeline/util/openavb_result_codes.h209
-rw-r--r--lib/avtp_pipeline/util/openavb_time.c134
-rw-r--r--lib/avtp_pipeline/util/openavb_time.h65
-rw-r--r--lib/avtp_pipeline/util/openavb_timestamp.c171
-rw-r--r--lib/avtp_pipeline/util/openavb_timestamp.h78
-rwxr-xr-xrun_echo_listener.sh11
-rwxr-xr-xrun_echo_talker.sh11
-rwxr-xr-xrun_gptp.sh11
-rwxr-xr-xrun_igb.sh16
-rwxr-xr-xrun_simple_talker.sh10
-rwxr-xr-xrun_srp.sh10
-rwxr-xr-xtravis.sh1
315 files changed, 44643 insertions, 638 deletions
diff --git a/.travis.yml b/.travis.yml
index 39437698..f06e4416 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,6 +14,7 @@ env: BUILD_KERNEL=3.13.0-36-generic
install:
- sudo apt-get update -qq
- sudo apt-get install -y libpcap-dev libpci-dev libsndfile1-dev libjack-dev linux-headers-3.13.0-36-generic cmake
+ - sudo apt-get install -y libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev libasound2-dev
- sudo cp /usr/src/linux-headers-3.13.0-36/include/uapi/linux/ethtool.h /usr/include/linux
- sudo cp /usr/src/linux-headers-3.13.0-36/include/uapi/linux/ptp_clock.h /usr/include/linux
script: ./travis.sh
diff --git a/Makefile b/Makefile
index e36cfff0..19cd87a9 100644
--- a/Makefile
+++ b/Makefile
@@ -14,6 +14,9 @@ help:
@echo ' gptp - gptp daemon for linux'
@echo ' maap - maap daemon'
@echo ''
+ @echo ' avtp_pipeline - AVTP pipeline'
+ @echo ' avtp_pipeline_doc - AVTP pipeline 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'
@echo ' simple_listener - simple_listener application'
@@ -104,14 +107,23 @@ live_stream:
live_stream_clean:
$(call descend,examples/live_stream/,clean)
+avtp_pipeline: lib
+ $(MAKE) -s -C lib/avtp_pipeline -f avtp_pipeline.mk
+
+avtp_pipeline_clean:
+ $(MAKE) -s -C lib/avtp_pipeline -f avtp_pipeline.mk clean
+
+avtp_pipeline_doc: lib
+ $(MAKE) -s -C lib/avtp_pipeline -f avtp_pipeline.mk doc
+
examples_all: simple_talker simple_listener mrp_client live_stream jackd-talker \
jackd-listener
examples_all_clean: simple_talker_clean simple_listener_clean mrp_client_clean \
jackd-talker_clean jackd-listener_clean live_stream_clean
-all: igb lib daemons_all examples_all
+all: igb lib daemons_all examples_all avtp_pipeline
-clean: igb_clean lib_clean daemons_all_clean examples_all_clean
+clean: igb_clean lib_clean daemons_all_clean examples_all_clean avtp_pipeline_clean
.PHONY: FORCE
diff --git a/daemons/gptp/common/avbts_osnet.cpp b/daemons/gptp/common/avbts_osnet.cpp
index 57c751e8..6c930d70 100644
--- a/daemons/gptp/common/avbts_osnet.cpp
+++ b/daemons/gptp/common/avbts_osnet.cpp
@@ -1,31 +1,31 @@
/******************************************************************************
- Copyright (c) 2009-2012, Intel Corporation
+ Copyright (c) 2009-2012, Intel Corporation
All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
+
+ 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,
+
+ 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
+
+ 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.
-
- 3. Neither the name of the Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived from
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 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)
+ 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 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/gptp/common/avbts_osnet.hpp b/daemons/gptp/common/avbts_osnet.hpp
index 2faf55f6..5d7f4da4 100644
--- a/daemons/gptp/common/avbts_osnet.hpp
+++ b/daemons/gptp/common/avbts_osnet.hpp
@@ -307,7 +307,7 @@ class OSNetworkInterface {
* @return net_result enumeration
*/
virtual net_result nrecv
- (LinkLayerAddress * addr, uint8_t * payload, size_t & length) = 0;
+ (LinkLayerAddress * addr, uint8_t * payload, size_t & length, struct phy_delay *delay) = 0;
/**
* @brief Get Link Layer address (mac address)
diff --git a/daemons/gptp/common/avbts_port.hpp b/daemons/gptp/common/avbts_port.hpp
index 904cae66..8454e74c 100644
--- a/daemons/gptp/common/avbts_port.hpp
+++ b/daemons/gptp/common/avbts_port.hpp
@@ -427,7 +427,7 @@ class IEEE1588Port {
* hardware timestamper and create OS locks conditions
* @return FALSE if error during building the interface. TRUE if success
*/
- bool init_port();
+ bool init_port(int delay[4]);
/**
* @brief Currently doesnt do anything. Just returns.
@@ -439,7 +439,7 @@ class IEEE1588Port {
* @brief Receives messages from the network interface
* @return Its an infinite loop. Returns NULL in case of error.
*/
- void *openPort(void);
+ void *openPort(IEEE1588Port *port);
/**
* @brief Get the payload offset inside a packet
@@ -960,4 +960,3 @@ class IEEE1588Port {
};
#endif
-
diff --git a/daemons/gptp/common/ieee1588.hpp b/daemons/gptp/common/ieee1588.hpp
index e81c09ab..921116f5 100644
--- a/daemons/gptp/common/ieee1588.hpp
+++ b/daemons/gptp/common/ieee1588.hpp
@@ -104,6 +104,14 @@ typedef struct {
Event event; //!< Event enumeration
} event_descriptor_t;
+struct phy_delay
+{
+ int mb_tx_phy_delay;
+ int mb_rx_phy_delay;
+ int gb_tx_phy_delay;
+ int gb_rx_phy_delay;
+};
+
/**
* Provides a generic InterfaceLabel class
*/
@@ -450,8 +458,10 @@ static inline void TIMESTAMP_ADD_NS( Timestamp &ts, uint64_t ns ) {
* Provides a generic interface for hardware timestamping
*/
class HWTimestamper {
+
protected:
uint8_t version; //!< HWTimestamper version
+ struct phy_delay delay;
public:
/**
* @brief Initializes the hardware timestamp unit
@@ -527,7 +537,6 @@ public:
* @param clock_value [out] Clock value
* @param last Signalizes that it is the last timestamp to get. When TRUE, releases the lock when its done.
* @return GPTP_EC_SUCCESS if no error, GPTP_EC_FAILURE if error and GPTP_EC_EAGAIN to try again.
-
*/
virtual int HWTimestamper_rxtimestamp(PortIdentity * identity,
uint16_t sequenceId,
@@ -580,6 +589,38 @@ public:
int getVersion() {
return version;
}
+ /**
+ * @brief Initializes the PHY delay for TX and RX
+ * @param [input] mb_tx_phy_delay, mb_rx_phy_delay, gb_tx_phy_delay, gb_rx_phy_delay
+ * @return 0
+ **/
+
+ int init_phy_delay(int phy_delay[4])
+ {
+ delay.gb_tx_phy_delay = phy_delay[0];
+ delay.gb_rx_phy_delay = phy_delay[1];
+ delay.mb_tx_phy_delay = phy_delay[2];
+ delay.mb_rx_phy_delay = phy_delay[3];
+
+
+ return 0;
+ }
+
+ /**
+ * @brief Returns the the PHY delay for TX and RX
+ * @param [input] struct phy_delay pointer
+ * @return 0
+ **/
+
+ int get_phy_delay (struct phy_delay *get_delay)
+ {
+ get_delay->mb_tx_phy_delay = delay.mb_tx_phy_delay;
+ get_delay->mb_rx_phy_delay = delay.mb_rx_phy_delay;
+ get_delay->gb_tx_phy_delay = delay.gb_tx_phy_delay;
+ get_delay->gb_rx_phy_delay = delay.gb_rx_phy_delay;
+
+ return 0;
+ }
/**
* Default constructor. Sets version to zero.
diff --git a/daemons/gptp/common/ieee1588port.cpp b/daemons/gptp/common/ieee1588port.cpp
index d076f215..eaadd0ae 100644
--- a/daemons/gptp/common/ieee1588port.cpp
+++ b/daemons/gptp/common/ieee1588port.cpp
@@ -55,7 +55,7 @@ OSThreadExitCode openPortWrapper(void *arg)
IEEE1588Port *port;
port = (IEEE1588Port *) arg;
- if (port->openPort() == NULL)
+ if (port->openPort(port) == NULL)
return osthread_ok;
else
return osthread_error;
@@ -129,7 +129,7 @@ IEEE1588Port::IEEE1588Port
sync_count = 0;
}
-bool IEEE1588Port::init_port()
+bool IEEE1588Port::init_port(int delay[4])
{
if (!OSNetworkInterfaceFactory::buildInterface
(&net_iface, factory_name_t("default"), net_label, _hw_timestamper))
@@ -147,6 +147,7 @@ bool IEEE1588Port::init_port()
_hw_timestamper = NULL;
}
}
+ _hw_timestamper->init_phy_delay(delay);
pdelay_rx_lock = lock_factory->createLock(oslock_recursive);
port_tx_lock = lock_factory->createLock(oslock_recursive);
@@ -289,9 +290,11 @@ bool IEEE1588Port::restoreSerializedState( void *buf, off_t *count ) {
return ret;
}
-void *IEEE1588Port::openPort(void)
+void *IEEE1588Port::openPort(IEEE1588Port *port)
{
port_ready_condition->signal();
+ struct phy_delay get_delay;
+ port->_hw_timestamper->get_phy_delay(&get_delay);
while (1) {
PTPMessageCommon *msg;
@@ -300,7 +303,7 @@ void *IEEE1588Port::openPort(void)
net_result rrecv;
size_t length = sizeof(buf);
- if ((rrecv = net_iface->nrecv(&remote, buf, length)) == net_succeed) {
+ if ((rrecv = net_iface->nrecv(&remote, buf, length,&get_delay)) == net_succeed) {
XPTPD_INFO("Processing network buffer");
msg = buildPTPMessage((char *)buf, (int)length, &remote,
this);
@@ -761,7 +764,11 @@ void IEEE1588Port::processEvent(Event e)
}
putTxLock();
+<<<<<<< HEAD
if (ts_good != GPTP_EC_SUCCESS) {
+=======
+ if (ts_good != 0) {
+>>>>>>> open-avb-next
char msg
[HWTIMESTAMPER_EXTENDED_MESSAGE_SIZE];
getExtendedError(msg);
diff --git a/daemons/gptp/linux/src/daemon_cl.cpp b/daemons/gptp/linux/src/daemon_cl.cpp
index e61d1c53..9e0e58f6 100644
--- a/daemons/gptp/linux/src/daemon_cl.cpp
+++ b/daemons/gptp/linux/src/daemon_cl.cpp
@@ -1,31 +1,31 @@
/******************************************************************************
- Copyright (c) 2012 Intel Corporation
+ Copyright (c) 2012 Intel Corporation
All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
+
+ 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,
+
+ 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
+
+ 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.
-
- 3. Neither the name of the Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived from
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 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)
+ 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 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.
@@ -48,11 +48,15 @@
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
+#define PHY_DELAY_GB_TX_I20 184 //1G delay
+#define PHY_DELAY_GB_RX_I20 382 //1G delay
+#define PHY_DELAY_MB_TX_I20 1044//100M delay
+#define PHY_DELAY_MB_RX_I20 2133//100M delay
void print_usage( char *arg0 ) {
fprintf( stderr,
"%s <network interface> [-S] [-P] [-M <filename>] "
- "[-A <count>] [-G <group>] [-R <priority 1>]\n",
+ "[-A <count>] [-G <group>] [-R <priority 1>] [-D <gb_tx_delay,gb_rx_delay,mb_tx_delay,mb_rx_delay>]\n",
arg0 );
fprintf
( stderr,
@@ -60,7 +64,7 @@ void print_usage( char *arg0 ) {
"\t-M <filename> save/restore state\n"
"\t-A <count> initial accelerated sync count\n"
"\t-G <group> group id for shared memory\n"
- "\t-R <priority 1> priority 1 value\n"
+ "\t-R <priority 1> priority 1 value\n"
"\t-T force master\n\t-L force slave\n" );
}
@@ -84,7 +88,7 @@ int main(int argc, char **argv)
off_t restoredatacount;
bool restorefailed = false;
LinuxIPCArg *ipc_arg = NULL;
-
+
int accelerated_sync_count = 0;
// Block SIGUSR1
@@ -97,7 +101,11 @@ int main(int argc, char **argv)
return -1;
}
}
-
+
+ int phy_delay[4]={0,0,0,0};
+ bool input_delay=false;
+
+
LinuxNetworkInterfaceFactory *default_factory =
new LinuxNetworkInterfaceFactory;
OSNetworkInterfaceFactory::registerFactory
@@ -114,7 +122,7 @@ int main(int argc, char **argv)
print_usage( argv[0] );
return -1;
}
- ifname = new InterfaceName( argv[1], strlen(argv[1]) );
+ ifname = new InterfaceName( argv[1], strlen(argv[1]) );
/* Process optional arguments */
for( i = 2; i < argc; ++i ) {
@@ -179,9 +187,40 @@ int main(int argc, char **argv)
}
}
}
+ else if(toupper(argv[i][1]) == 'D'){
+ input_delay=true;
+ int delay_count=0;
+ char *cli_inp_delay = strtok(argv[i+1],",");
+ while (cli_inp_delay != NULL)
+ {
+ if(delay_count>3)
+ {
+ printf("Too many values\n");
+ print_usage( argv[0] );
+ return 0;
+ }
+ phy_delay[delay_count]=atoi(cli_inp_delay);
+ delay_count++;
+ cli_inp_delay = strtok(NULL,",");
+ }
+ if (delay_count != 4)
+ {
+ printf("All four delay values must be specified\n");
+ print_usage( argv[0] );
+ return 0;
+ }
+ }
}
}
-
+
+ if (!input_delay)
+ {
+ phy_delay[0] = PHY_DELAY_GB_TX_I20;
+ phy_delay[1] = PHY_DELAY_GB_RX_I20;
+ phy_delay[2] = PHY_DELAY_MB_TX_I20;
+ phy_delay[3] = PHY_DELAY_MB_RX_I20;
+ }
+
if( !ipc->init( ipc_arg ) ) {
delete ipc;
ipc = NULL;
@@ -209,7 +248,7 @@ int main(int argc, char **argv)
}
}
}
-
+
if (argc < 2)
return -1;
ifname = new InterfaceName(argv[1], strlen(argv[1]));
@@ -231,11 +270,11 @@ int main(int argc, char **argv)
IEEE1588Clock *clock =
new IEEE1588Clock( false, syntonize, priority1, timestamper,
timerq_factory , ipc, lock_factory );
-
+
if( restoredataptr != NULL ) {
if( !restorefailed )
restorefailed =
- !clock->restoreSerializedState( restoredataptr,
+ !clock->restoreSerializedState( restoredataptr,
&restoredatacount );
restoredataptr = ((char *)restoredata) +
(restoredatalength - restoredatacount);
@@ -245,7 +284,7 @@ int main(int argc, char **argv)
new IEEE1588Port
( clock, 1, false, accelerated_sync_count, timestamper, 0, ifname,
condition_factory, thread_factory, timer_factory, lock_factory );
- if (!port->init_port()) {
+ if (!port->init_port(phy_delay)) {
printf("failed to initialize port \n");
return -1;
}
@@ -288,7 +327,7 @@ int main(int argc, char **argv)
restoredatacount += len;
port->serializeState( NULL, &len );
restoredatacount += len;
-
+
if( restoredatacount > restoredatalength ) {
ftruncate( restorefd, restoredatacount );
if( restoredata != ((void *) -1)) {
@@ -303,7 +342,7 @@ int main(int argc, char **argv)
if( restoredata == ((void *) -1 )) goto remap_failed;
restoredatalength = restoredatacount;
}
-
+
restoredataptr = (char *) restoredata;
clock->serializeState( restoredataptr, &restoredatacount );
restoredataptr = ((char *)restoredata) +
@@ -314,8 +353,8 @@ int main(int argc, char **argv)
remap_failed:
;;
}
-
-
+
+
if( restoredata != ((void *) -1 ))
munmap( restoredata, restoredatalength );
}
diff --git a/daemons/gptp/linux/src/linux_hal_common.cpp b/daemons/gptp/linux/src/linux_hal_common.cpp
index 6ae648da..0530da2b 100644
--- a/daemons/gptp/linux/src/linux_hal_common.cpp
+++ b/daemons/gptp/linux/src/linux_hal_common.cpp
@@ -1,31 +1,31 @@
/******************************************************************************
- Copyright (c) 2009-2012, Intel Corporation
+ Copyright (c) 2009-2012, Intel Corporation
All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
+
+ 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,
+
+ 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
+
+ 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.
-
- 3. Neither the name of the Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived from
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 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)
+ 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 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.
@@ -89,7 +89,7 @@ net_result LinuxNetworkInterface::send
addr->toOctetArray( remote->sll_addr );
if( timestamp ) {
-#ifndef ARCH_INTELCE
+#ifndef ARCH_INTELCE
net_lock.lock();
#endif
err = sendto
@@ -113,7 +113,7 @@ void LinuxNetworkInterface::disable_clear_rx_queue() {
struct packet_mreq mr_8021as;
int err;
char buf[256];
-
+
if( !net_lock.lock() ) {
fprintf( stderr, "D rx lock failed\n" );
_exit(0);
@@ -133,9 +133,9 @@ void LinuxNetworkInterface::disable_clear_rx_queue() {
ifindex );
return;
}
-
+
while( recvfrom( sd_event, buf, 256, MSG_DONTWAIT, NULL, 0 ) != -1 );
-
+
return;
}
@@ -193,9 +193,9 @@ void *LinuxTimerQueueHandler( void *arg ) {
sigset_t waitfor;
struct timespec timeout;
timeout.tv_sec = 0; timeout.tv_nsec = 100000000; /* 100 ms */
-
+
sigemptyset( &waitfor );
-
+
while( !timerq->stop ) {
siginfo_t info;
LinuxTimerQueueMap_t::iterator iter;
@@ -255,7 +255,7 @@ OSTimerQueue *LinuxTimerQueueFactory::createOSTimerQueue
return ret;
}
-
+
bool LinuxTimerQueue::addEvent
( unsigned long micros, int type, ostimerq_handler func,
@@ -275,7 +275,7 @@ bool LinuxTimerQueue::addEvent
while( timerQueueMap.find( key ) != timerQueueMap.end() ) {
++key;
}
-
+
{
struct itimerspec its;
memset(&(outer_arg->sevp), 0, sizeof(outer_arg->sevp));
@@ -296,7 +296,7 @@ bool LinuxTimerQueue::addEvent
err = timer_settime( outer_arg->timer_handle, 0, &its, NULL );
if( err < 0 ) {
fprintf
- ( stderr, "Failed to arm timer: %s\n",
+ ( stderr, "Failed to arm timer: %s\n",
strerror( errno ));
return false;
}
@@ -357,7 +357,7 @@ unsigned long LinuxTimer::sleep(unsigned long micros) {
struct TicketingLockPrivate {
pthread_cond_t condition;
- pthread_mutex_t cond_lock;
+ pthread_mutex_t cond_lock;
};
bool TicketingLock::lock( bool *got ) {
@@ -365,7 +365,7 @@ bool TicketingLock::lock( bool *got ) {
bool yield = false;
bool ret = true;
if( !init_flag ) return false;
-
+
if( pthread_mutex_lock( &_private->cond_lock ) != 0 ) {
ret = false;
goto done;
@@ -386,15 +386,15 @@ bool TicketingLock::lock( bool *got ) {
}
if( got != NULL ) *got = true;
-
+
unlock:
if( pthread_mutex_unlock( &_private->cond_lock ) != 0 ) {
ret = false;
goto done;
}
-
+
if( yield ) pthread_yield();
-
+
done:
return ret;
}
@@ -402,7 +402,7 @@ bool TicketingLock::lock( bool *got ) {
bool TicketingLock::unlock() {
bool ret = true;
if( !init_flag ) return false;
-
+
if( pthread_mutex_lock( &_private->cond_lock ) != 0 ) {
ret = false;
goto done;
@@ -437,7 +437,7 @@ bool TicketingLock::init() {
cond_ticket_issue = 0;
cond_ticket_serving = 0;
init_flag = true;
-
+
return true;
}
@@ -485,7 +485,7 @@ OSLockResult LinuxLock::lock() {
int lock_c;
lock_c = pthread_mutex_lock(&_private->mutex);
if(lock_c != 0) {
- fprintf( stderr, "LinuxLock: lock failed %d\n", lock_c );
+ fprintf( stderr, "LinuxLock: lock failed %d\n", lock_c );
return oslock_fail;
}
return oslock_ok;
@@ -502,7 +502,7 @@ OSLockResult LinuxLock::unlock() {
int lock_c;
lock_c = pthread_mutex_unlock(&_private->mutex);
if(lock_c != 0) {
- fprintf( stderr, "LinuxLock: unlock failed %d\n", lock_c );
+ fprintf( stderr, "LinuxLock: unlock failed %d\n", lock_c );
return oslock_fail;
}
return oslock_ok;
@@ -635,7 +635,7 @@ bool LinuxSharedMemoryIPC::init( OS_IPC_ARG *barg ) {
if( grp == NULL ) {
XPTPD_ERROR( "Group %s not found, will try root (0) instead", group_name );
}
-
+
shm_fd = shm_open( SHM_NAME, O_RDWR | O_CREAT, 0660 );
if( shm_fd == -1 ) {
XPTPD_ERROR( "shm_open(): %s", strerror(errno) );
@@ -675,7 +675,7 @@ bool LinuxSharedMemoryIPC::init( OS_IPC_ARG *barg ) {
}
return true;
exit_unlink:
- shm_unlink( SHM_NAME );
+ shm_unlink( SHM_NAME );
exit_error:
return false;
}
@@ -724,20 +724,20 @@ bool LinuxNetworkInterfaceFactory::createInterface
struct packet_mreq mr_8021as;
LinkLayerAddress addr;
int ifindex;
-
+
LinuxNetworkInterface *net_iface_l = new LinuxNetworkInterface();
-
+
if( !net_iface_l->net_lock.init()) {
XPTPD_ERROR( "Failed to initialize network lock");
return false;
}
-
+
InterfaceName *ifname = dynamic_cast<InterfaceName *>(label);
if( ifname == NULL ){
XPTPD_ERROR( "ifname == NULL");
return false;
}
-
+
net_iface_l->sd_general = socket( PF_PACKET, SOCK_DGRAM, 0 );
if( net_iface_l->sd_general == -1 ) {
XPTPD_ERROR( "failed to open general socket: %s", strerror(errno));
@@ -749,7 +749,7 @@ bool LinuxNetworkInterfaceFactory::createInterface
( "failed to open event socket: %s \n", strerror(errno));
return false;
}
-
+
memset( &device, 0, sizeof(device));
ifname->toString( device.ifr_name, IFNAMSIZ );
err = ioctl( net_iface_l->sd_event, SIOCGIFHWADDR, &device );
@@ -758,7 +758,7 @@ bool LinuxNetworkInterfaceFactory::createInterface
( "Failed to get interface address: %s", strerror( errno ));
return false;
}
-
+
addr = LinkLayerAddress( (uint8_t *)&device.ifr_hwaddr.sa_data );
net_iface_l->local_addr = addr;
err = ioctl( net_iface_l->sd_event, SIOCGIFINDEX, &device );
@@ -783,19 +783,19 @@ bool LinuxNetworkInterfaceFactory::createInterface
ifindex );
return false;
}
-
+
memset( &ifsock_addr, 0, sizeof( ifsock_addr ));
ifsock_addr.sll_family = AF_PACKET;
ifsock_addr.sll_ifindex = ifindex;
ifsock_addr.sll_protocol = PLAT_htons( PTP_ETHERTYPE );
err = bind
( net_iface_l->sd_event, (sockaddr *) &ifsock_addr,
- sizeof( ifsock_addr ));
- if( err == -1 ) {
+ sizeof( ifsock_addr ));
+ if( err == -1 ) {
XPTPD_ERROR( "Call to bind() failed: %s", strerror(errno) );
return false;
}
-
+
net_iface_l->timestamper =
dynamic_cast <LinuxTimestamper *>(timestamper);
if(net_iface_l->timestamper == NULL) {
@@ -808,7 +808,6 @@ bool LinuxNetworkInterfaceFactory::createInterface
return false;
}
*net_iface = net_iface_l;
-
+
return true;
}
-
diff --git a/daemons/gptp/linux/src/linux_hal_common.hpp b/daemons/gptp/linux/src/linux_hal_common.hpp
index 681929df..c37bdfaf 100644
--- a/daemons/gptp/linux/src/linux_hal_common.hpp
+++ b/daemons/gptp/linux/src/linux_hal_common.hpp
@@ -1,31 +1,31 @@
/******************************************************************************
- Copyright (c) 2012, Intel Corporation
+ Copyright (c) 2012, Intel Corporation
All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
+
+ 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,
+
+ 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
+
+ 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.
-
- 3. Neither the name of the Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived from
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 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)
+ 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 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.
@@ -68,7 +68,7 @@ struct TicketingLockPrivate;
* Provides the type for the TicketingLock private structure
*/
typedef struct TicketingLockPrivate * TicketingLockPrivate_t;
-
+
/**
* TicketingLock: Implements the ticket lock algorithm.
* A ticket lock consists of two counters, one containing the
@@ -176,7 +176,7 @@ public:
* an error on the transmit side, net_fatal if error on reception
*/
virtual net_result nrecv
- ( LinkLayerAddress *addr, uint8_t *payload, size_t &length );
+ ( LinkLayerAddress *addr, uint8_t *payload, size_t &length, struct phy_delay *delay );
/**
* @brief Disables rx socket descriptor and and clears the rx queue
@@ -448,7 +448,7 @@ public:
/**
* @brief Creates Linux timer queue
* @param clock [in] Pointer to IEEE15588Clock type
- * @return Pointer to OSTimerQueue
+ * @return Pointer to OSTimerQueue
*/
virtual OSTimerQueue *createOSTimerQueue( IEEE1588Clock *clock );
};
diff --git a/daemons/gptp/linux/src/linux_hal_generic.cpp b/daemons/gptp/linux/src/linux_hal_generic.cpp
index d8d978df..596d2ece 100644
--- a/daemons/gptp/linux/src/linux_hal_generic.cpp
+++ b/daemons/gptp/linux/src/linux_hal_generic.cpp
@@ -52,7 +52,7 @@
#define RX_PHY_TIME 382
net_result LinuxNetworkInterface::nrecv
-( LinkLayerAddress *addr, uint8_t *payload, size_t &length ) {
+( LinkLayerAddress *addr, uint8_t *payload, size_t &length,struct phy_delay *delay ) {
fd_set readfds;
int err;
struct msghdr msg;
@@ -136,7 +136,7 @@ net_result LinuxNetworkInterface::nrecv
if
( cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SO_TIMESTAMPING ) {
- Timestamp latency( RX_PHY_TIME, 0, 0 );
+ Timestamp latency( delay->gb_rx_phy_delay, 0, 0 );
struct timespec *ts_device, *ts_system;
Timestamp device, system;
ts_system = ((struct timespec *) CMSG_DATA(cmsg)) + 1;
@@ -270,9 +270,11 @@ int LinuxTimestamperGeneric::HWTimestamper_txtimestamp
struct cmsghdr cm;
char control[256];
} control;
- Timestamp latency( TX_PHY_TIME, 0, 0 );
+ struct phy_delay delay_val;
+ get_phy_delay (&delay_val);//gets the phy delay
- if( sd == -1 ) return GPTP_EC_FAILURE;
+ Timestamp latency( delay_val.gb_tx_phy_delay, 0, 0 );
+ if( sd == -1 ) return -1;
memset( &msg, 0, sizeof( msg ));
msg.msg_iov = &sgentry;
@@ -443,4 +445,3 @@ bool LinuxTimestamperGeneric::HWTimestamper_gettime
return false;
}
-
diff --git a/examples/common/listener_mrp_client.c b/examples/common/listener_mrp_client.c
index 1e5652c1..d087a866 100644
--- a/examples/common/listener_mrp_client.c
+++ b/examples/common/listener_mrp_client.c
@@ -26,19 +26,44 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/* global variables */
-int control_socket;
-volatile int talker = 0;
-unsigned char stream_id[8];
+//struct listener_context global_struct_listener;
+pthread_t monitor_thread;
+pthread_attr_t monitor_attr;
/*
* private
*/
-int send_msg(char *data, int data_len)
+int mrp_listener_client_init(struct mrp_listener_ctx *ctx)
+{
+ int i;
+ ctx->control_socket=-1;
+ ctx->talker = 0;
+ ctx->halt_tx = 0;
+ ctx->domain_a_valid = 0;
+ ctx->domain_class_a_id = 0;
+ ctx->domain_class_a_priority = 0;
+ ctx->domain_class_a_vid = 0;
+ ctx->domain_b_valid = 0;
+ ctx->domain_class_b_id = 0;
+ ctx->domain_class_b_priority = 0;
+ ctx->domain_class_b_vid = 0;
+ for (i=0;i<8;i++)
+ {
+ ctx->stream_id[i]=0;
+ }
+ for (i=0;i<6;i++)
+ {
+ ctx->dst_mac[i]=0;
+ }
+ return 0;
+}
+
+int send_msg(char *data, int data_len, struct mrp_listener_ctx *ctx)
{
struct sockaddr_in addr;
- if (control_socket == -1)
+ if (ctx->control_socket == -1)
return -1;
if (data == NULL)
return -1;
@@ -48,16 +73,19 @@ int send_msg(char *data, int data_len)
addr.sin_port = htons(MRPD_PORT_DEFAULT);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
inet_aton("127.0.0.1", &addr.sin_addr);
- return sendto(control_socket, data, data_len, 0,
+ return sendto(ctx->control_socket, data, data_len, 0,
(struct sockaddr*)&addr, (socklen_t)sizeof(addr));
}
-int msg_process(char *buf, int buflen)
+int msg_process(char *buf, int buflen, struct mrp_listener_ctx *ctx)
{
uint32_t id;
- int j, l;
+ int j, l=0;
+ unsigned int vid;
+ unsigned int priority;
fprintf(stderr, "Msg: %s\n", buf);
+
if (strncmp(buf, "SNE T:", 6) == 0 || strncmp(buf, "SJO T:", 6) == 0)
{
l = 6; /* skip "Sxx T:" */
@@ -68,67 +96,133 @@ int msg_process(char *buf, int buflen)
for(j = 0; j < 8 ; l+=2, j++)
{
sscanf(&buf[l],"%02x",&id);
- stream_id[j] = (unsigned char)id;
+ ctx->stream_id[j] = (unsigned char)id;
}
- talker = 1;
+ l+=3;
+ for(j = 0; j < 6 ; l+=2, j++)
+ {
+ sscanf(&buf[l],"%02x",&id);
+ ctx->dst_mac[j] = (unsigned char)id;
+ }
+ ctx->talker = 1;
}
- return 0;
-}
-
-int recv_msg()
-{
- char *databuf;
- int bytes = 0;
- int ret;
-
- databuf = (char *)malloc(1500);
- if (NULL == databuf)
- return -1;
- memset(databuf, 0, 1500);
- bytes = recv(control_socket, databuf, 1500, 0);
- if (bytes <= -1)
+ if (strncmp(buf, "SJO D:", 6) == 0)
{
- free(databuf);
- return -1;
- }
- ret = msg_process(databuf, bytes);
- free(databuf);
+ l=8;
+ sscanf(&(buf[l]), "%d", &id);
+ l=l+4;
+ sscanf(&(buf[l]), "%d", &priority);
+ l=l+4;
+ sscanf(&(buf[l]), "%x", &vid);
+
+ if (id == 6)
+ {
+ ctx->domain_class_a_id = id;
+ ctx->domain_class_a_priority = priority;
+ ctx->domain_class_a_vid = vid;
+ ctx->domain_a_valid = 1;
+ }
+ else
+ {
+ ctx->domain_class_b_id = id;
+ ctx->domain_class_b_priority = priority;
+ ctx->domain_class_b_vid = vid;
+ ctx->domain_b_valid = 1;
+ }
+ l+=4;
- return ret;
+ }
+ return 0;
}
/*
* public
*/
-int create_socket() // TODO FIX! =:-|
+int create_socket(struct mrp_listener_ctx *ctx) // TODO FIX! =:-|
{
struct sockaddr_in addr;
- control_socket = socket(AF_INET, SOCK_DGRAM, 0);
-
+ ctx->control_socket = socket(AF_INET, SOCK_DGRAM, 0);
+
/** in POSIX fd 0,1,2 are reserved */
- if (2 > control_socket)
+ if (2 > ctx->control_socket)
{
- if (-1 > control_socket)
- close(control_socket);
+ if (-1 > ctx->control_socket)
+ close(ctx->control_socket);
return -1;
}
-
+
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(0);
-
- if(0 > (bind(control_socket, (struct sockaddr*)&addr, sizeof(addr))))
+
+ if(0 > (bind(ctx->control_socket, (struct sockaddr*)&addr, sizeof(addr))))
{
fprintf(stderr, "Could not bind socket.\n");
- close(control_socket);
+ close(ctx->control_socket);
return -1;
}
return 0;
}
-int report_domain_status()
+void *mrp_monitor_thread(void *arg)
+{
+ char *msgbuf;
+ struct sockaddr_in client_addr;
+ struct msghdr msg;
+ struct iovec iov;
+ int bytes = 0;
+ struct pollfd fds;
+ int rc;
+ struct mrp_listener_ctx *ctx = (struct mrp_listener_ctx*) arg;
+
+ msgbuf = (char *)malloc(MAX_MRPD_CMDSZ);
+ if (NULL == msgbuf)
+ return NULL;
+ while (!ctx->halt_tx) {
+ fds.fd = ctx->control_socket;
+ fds.events = POLLIN;
+ fds.revents = 0;
+ rc = poll(&fds, 1, 100);
+ if (rc < 0) {
+ free(msgbuf);
+ pthread_exit(NULL);
+ }
+ if (rc == 0)
+ continue;
+ if ((fds.revents & POLLIN) == 0) {
+ free(msgbuf);
+ pthread_exit(NULL);
+ }
+ memset(&msg, 0, sizeof(msg));
+ memset(&client_addr, 0, sizeof(client_addr));
+ memset(msgbuf, 0, MAX_MRPD_CMDSZ);
+ iov.iov_len = MAX_MRPD_CMDSZ;
+ iov.iov_base = msgbuf;
+ msg.msg_name = &client_addr;
+ msg.msg_namelen = sizeof(client_addr);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ bytes = recvmsg(ctx->control_socket, &msg, 0);
+ if (bytes < 0)
+ continue;
+ msg_process(msgbuf, bytes, ctx);
+ }
+ free(msgbuf);
+ pthread_exit(NULL);
+}
+
+
+int mrp_monitor(struct mrp_listener_ctx *ctx)
+{
+ int rc;
+ rc = pthread_attr_init(&monitor_attr);
+ rc |= pthread_create(&monitor_thread, NULL, mrp_monitor_thread, ctx);
+ return rc;
+}
+
+int report_domain_status(struct mrp_domain_attr *class_a, struct mrp_listener_ctx *ctx)
{
char* msgbuf;
int rc;
@@ -137,8 +231,8 @@ int report_domain_status()
if (NULL == msgbuf)
return -1;
memset(msgbuf, 0, 1500);
- sprintf(msgbuf, "S+D:C=6,P=3,V=0002");
- rc = send_msg(msgbuf, 1500);
+ sprintf(msgbuf, "S+D:C=%d,P=%d,V=%04x", class_a->id, class_a->priority, class_a->vid);
+ rc = send_msg(msgbuf, 1500, ctx);
free(msgbuf);
if (rc != 1500)
@@ -147,7 +241,45 @@ int report_domain_status()
return 0;
}
-int join_vlan()
+int mrp_get_domain(struct mrp_listener_ctx *ctx, struct mrp_domain_attr *class_a, struct mrp_domain_attr *class_b)
+{
+ char *msgbuf;
+ int ret;
+
+ /* we may not get a notification if we are joining late,
+ * so query for what is already there ...
+ */
+ msgbuf = malloc(1500);
+ if (NULL == msgbuf)
+ return -1;
+ memset(msgbuf, 0, 1500);
+ sprintf(msgbuf, "S??");
+ ret = send_msg(msgbuf, 1500, ctx);
+ free(msgbuf);
+ if (ret != 1500)
+ return -1;
+ while (!ctx->halt_tx && (ctx->domain_a_valid == 0) && (ctx->domain_b_valid == 0))
+ usleep(20000);
+ class_a->id = 0;
+ class_a->priority = 0;
+ class_a->vid = 0;
+ class_b->id = 0;
+ class_b->priority = 0;
+ class_b->vid = 0;
+ if (ctx->domain_a_valid) {
+ class_a->id = ctx->domain_class_a_id;
+ class_a->priority = ctx->domain_class_a_priority;
+ class_a->vid = ctx->domain_class_a_vid;
+ }
+ if (ctx->domain_b_valid) {
+ class_b->id = ctx->domain_class_b_id;
+ class_b->priority = ctx->domain_class_b_priority;
+ class_b->vid = ctx->domain_class_b_vid;
+ }
+ return 0;
+}
+
+int join_vlan(struct mrp_domain_attr *class_a, struct mrp_listener_ctx *ctx)
{
char *msgbuf;
int rc;
@@ -156,8 +288,9 @@ int join_vlan()
if (NULL == msgbuf)
return -1;
memset(msgbuf, 0, 1500);
- sprintf(msgbuf, "V++:I=0002");
- rc = send_msg(msgbuf, 1500);
+ sprintf(msgbuf, "V++:I=%04x\n",class_a->vid);
+ printf("Joing VLAN %s\n",msgbuf);
+ rc = send_msg(msgbuf, 1500, ctx);
free(msgbuf);
if (rc != 1500)
@@ -166,14 +299,14 @@ int join_vlan()
return 0;
}
-int await_talker()
+int await_talker(struct mrp_listener_ctx *ctx)
{
- while (0 == talker)
- recv_msg();
+ while (0 == ctx->talker)
+ ;
return 0;
}
-int send_ready()
+int send_ready(struct mrp_listener_ctx *ctx)
{
char *databuf;
int rc;
@@ -183,11 +316,11 @@ int send_ready()
return -1;
memset(databuf, 0, 1500);
sprintf(databuf, "S+L:L=%02x%02x%02x%02x%02x%02x%02x%02x, D=2",
- stream_id[0], stream_id[1],
- stream_id[2], stream_id[3],
- stream_id[4], stream_id[5],
- stream_id[6], stream_id[7]);
- rc = send_msg(databuf, 1500);
+ ctx->stream_id[0], ctx->stream_id[1],
+ ctx->stream_id[2], ctx->stream_id[3],
+ ctx->stream_id[4], ctx->stream_id[5],
+ ctx->stream_id[6], ctx->stream_id[7]);
+ rc = send_msg(databuf, 1500, ctx);
free(databuf);
if (rc != 1500)
@@ -196,7 +329,7 @@ int send_ready()
return 0;
}
-int send_leave()
+int send_leave(struct mrp_listener_ctx *ctx)
{
char *databuf;
int rc;
@@ -206,11 +339,11 @@ int send_leave()
return -1;
memset(databuf, 0, 1500);
sprintf(databuf, "S-L:L=%02x%02x%02x%02x%02x%02x%02x%02x, D=3",
- stream_id[0], stream_id[1],
- stream_id[2], stream_id[3],
- stream_id[4], stream_id[5],
- stream_id[6], stream_id[7]);
- rc = send_msg(databuf, 1500);
+ ctx->stream_id[0], ctx->stream_id[1],
+ ctx->stream_id[2], ctx->stream_id[3],
+ ctx->stream_id[4], ctx->stream_id[5],
+ ctx->stream_id[6], ctx->stream_id[7]);
+ rc = send_msg(databuf, 1500, ctx);
free(databuf);
if (rc != 1500)
@@ -219,7 +352,7 @@ int send_leave()
return 0;
}
-int mrp_disconnect()
+int mrp_disconnect(struct mrp_listener_ctx *ctx)
{
int rc;
char *msgbuf = malloc(1500);
@@ -229,7 +362,7 @@ int mrp_disconnect()
memset(msgbuf, 0, 1500);
sprintf(msgbuf, "BYE");
- rc = send_msg(msgbuf, 1500);
+ rc = send_msg(msgbuf, 1500, ctx);
free(msgbuf);
if (rc != 1500)
diff --git a/examples/common/listener_mrp_client.h b/examples/common/listener_mrp_client.h
index 142d8f39..3646b3c9 100644
--- a/examples/common/listener_mrp_client.h
+++ b/examples/common/listener_mrp_client.h
@@ -34,25 +34,53 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <string.h>
#include <stdio.h> // TODO fprintf, to be removed
#include <unistd.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <poll.h>
#include "mrpd.h"
+#include "mrp.h"
+#include "msrp.h"
/* global variables */
-// TODO move these in a talker_context struct + init func
+struct mrp_listener_ctx
+{
+ int control_socket;
+ volatile int talker;
+ unsigned char stream_id[8];
+ unsigned char dst_mac[6];
+ volatile int halt_tx;
+ volatile int domain_a_valid;
+ int domain_class_a_id;
+ int domain_class_a_priority;
+ u_int16_t domain_class_a_vid;
+ volatile int domain_b_valid;
+ int domain_class_b_id;
+ int domain_class_b_priority;
+ u_int16_t domain_class_b_vid;
+};
+
+struct mrp_domain_attr
+{
+ int id;
+ int priority;
+ u_int16_t vid;
+};
+
-extern int control_socket;
-extern volatile int talker;
-extern unsigned char stream_id[8];
/* functions */
-int create_socket();
-int report_domain_status();
-int join_vlan();
-int await_talker();
-int send_ready();
-int send_leave();
-int mrp_disconnect();
+int create_socket(struct mrp_listener_ctx *ctx);
+int mrp_monitor(struct mrp_listener_ctx *ctx);
+int report_domain_status(struct mrp_domain_attr *class_a, struct mrp_listener_ctx *ctx);
+int join_vlan(struct mrp_domain_attr *class_a, struct mrp_listener_ctx *ctx);
+int await_talker(struct mrp_listener_ctx *ctx);
+int send_ready(struct mrp_listener_ctx *ctx);
+int send_leave(struct mrp_listener_ctx *ctx);
+int mrp_disconnect(struct mrp_listener_ctx *ctx);
+int mrp_get_domain(struct mrp_listener_ctx *ctx, struct mrp_domain_attr *class_a, struct mrp_domain_attr *class_b);
+int mrp_listener_client_init(struct mrp_listener_ctx *ctx);
#endif /* _LISTENER_MRP_CLIENT_H_ */
diff --git a/examples/common/talker_mrp_client.c b/examples/common/talker_mrp_client.c
index 1b42fabb..6959e220 100644
--- a/examples/common/talker_mrp_client.c
+++ b/examples/common/talker_mrp_client.c
@@ -3,30 +3,30 @@
Copyright (c) 2012, Intel Corporation
Copyright (c) 2014, Parrot SA
All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
+
+ 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,
+
+ 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
+
+ 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.
-
- 3. Neither the name of the Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived from
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 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)
+ 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 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.
@@ -36,37 +36,43 @@
/* global variables */
-int control_socket = -1;
-
-volatile int halt_tx = 0;
-volatile int listeners = 0;
volatile int mrp_okay;
volatile int mrp_error = 0;;
-
-volatile int domain_a_valid = 0;
-int domain_class_a_id = 0;
-int domain_class_a_priority = 0;
-u_int16_t domain_class_a_vid = 0;
-
-volatile int domain_b_valid = 0;
-int domain_class_b_id = 0;
-int domain_class_b_priority = 0;
-u_int16_t domain_class_b_vid = 0;
-
pthread_t monitor_thread;
pthread_attr_t monitor_attr;
-unsigned char monitor_stream_id[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
/*
* private
*/
-int send_mrp_msg(char *notify_data, int notify_len)
+int mrp_talker_client_init(struct mrp_talker_ctx *ctx)
+{
+ int i;
+ ctx->control_socket = -1;
+ ctx->halt_tx = 0;
+ ctx->listeners = 0;
+ ctx->domain_a_valid = 0;
+ ctx->domain_class_a_id = 0;
+ ctx->domain_class_a_priority = 0;
+ ctx->domain_class_a_vid = 0;
+ ctx->domain_b_valid = 0;
+ ctx->domain_class_b_id = 0;
+ ctx->domain_class_b_priority = 0;
+ ctx->domain_class_b_vid = 0;
+ for (i=0;i<8;i++)
+ {
+ ctx->monitor_stream_id[i] = 0;
+ }
+ return 0;
+}
+
+int send_mrp_msg(char *notify_data, int notify_len, struct mrp_talker_ctx *ctx)
{
struct sockaddr_in addr;
socklen_t addr_len;
- if (control_socket == -1)
+ if (ctx->control_socket == -1)
return -1;
if (notify_data == NULL)
return -1;
@@ -76,11 +82,11 @@ int send_mrp_msg(char *notify_data, int notify_len)
addr.sin_port = htons(MRPD_PORT_DEFAULT);
inet_aton("127.0.0.1", &addr.sin_addr);
addr_len = sizeof(addr);
- return sendto(control_socket, notify_data, notify_len, 0,
+ return sendto(ctx->control_socket, notify_data, notify_len, 0,
(struct sockaddr *)&addr, addr_len);
}
-int process_mrp_msg(char *buf, int buflen)
+int process_mrp_msg(char *buf, int buflen, struct mrp_talker_ctx *ctx)
{
/*
@@ -151,9 +157,9 @@ int process_mrp_msg(char *buf, int buflen)
}
if (substate > MSRP_LISTENER_ASKFAILED) {
if (memcmp
- (recovered_streamid, monitor_stream_id,
+ (recovered_streamid, ctx->monitor_stream_id,
sizeof(recovered_streamid)) == 0) {
- listeners = 1;
+ ctx->listeners = 1;
printf("added listener\n");
}
}
@@ -184,15 +190,15 @@ int process_mrp_msg(char *buf, int buflen)
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;
+ ctx->domain_class_a_id = id;
+ ctx->domain_class_a_priority = priority;
+ ctx->domain_class_a_vid = vid;
+ ctx->domain_a_valid = 1;
} else {
- domain_class_b_id = id;
- domain_class_b_priority = priority;
- domain_class_b_vid = vid;
- domain_b_valid = 1;
+ ctx->domain_class_b_id = id;
+ ctx->domain_class_b_priority = priority;
+ ctx->domain_class_b_vid = vid;
+ ctx->domain_b_valid = 1;
}
while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0'))
i++;
@@ -259,9 +265,9 @@ int process_mrp_msg(char *buf, int buflen)
case 'L':
printf("got a leave indication\n");
if (memcmp
- (recovered_streamid, monitor_stream_id,
+ (recovered_streamid, ctx->monitor_stream_id,
sizeof(recovered_streamid)) == 0) {
- listeners = 0;
+ ctx->listeners = 0;
printf("listener left\n");
}
break;
@@ -271,9 +277,9 @@ int process_mrp_msg(char *buf, int buflen)
if (substate > MSRP_LISTENER_ASKFAILED) {
if (memcmp
(recovered_streamid,
- monitor_stream_id,
+ ctx->monitor_stream_id,
sizeof(recovered_streamid)) == 0)
- listeners = 1;
+ ctx->listeners = 1;
}
break;
}
@@ -299,13 +305,13 @@ void *mrp_monitor_thread(void *arg)
int bytes = 0;
struct pollfd fds;
int rc;
- (void) arg; /* unused */
+ struct mrp_talker_ctx *ctx = (struct mrp_talker_ctx*) arg;
msgbuf = (char *)malloc(MAX_MRPD_CMDSZ);
if (NULL == msgbuf)
return NULL;
- while (!halt_tx) {
- fds.fd = control_socket;
+ while (!ctx->halt_tx) {
+ fds.fd = ctx->control_socket;
fds.events = POLLIN;
fds.revents = 0;
rc = poll(&fds, 1, 100);
@@ -328,10 +334,10 @@ void *mrp_monitor_thread(void *arg)
msg.msg_namelen = sizeof(client_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
- bytes = recvmsg(control_socket, &msg, 0);
+ bytes = recvmsg(ctx->control_socket, &msg, 0);
if (bytes < 0)
continue;
- process_mrp_msg(msgbuf, bytes);
+ process_mrp_msg(msgbuf, bytes, ctx);
}
free(msgbuf);
pthread_exit(NULL);
@@ -341,10 +347,11 @@ void *mrp_monitor_thread(void *arg)
* public
*/
-int mrp_connect(void)
+int mrp_connect(struct mrp_talker_ctx *ctx)
{
struct sockaddr_in addr;
int sock_fd = -1;
+ int rc;
sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock_fd < 0)
goto out;
@@ -353,7 +360,10 @@ int mrp_connect(void)
addr.sin_port = htons(MRPD_PORT_DEFAULT);
inet_aton("127.0.0.1", &addr.sin_addr);
memset(&addr, 0, sizeof(addr));
- control_socket = sock_fd;
+ ctx->control_socket = sock_fd;
+ rc = pthread_attr_init(&monitor_attr);
+ rc |= pthread_create(&monitor_thread, NULL, mrp_monitor_thread, ctx);
+ return rc;
return 0;
out: if (sock_fd != -1)
close(sock_fd);
@@ -361,7 +371,7 @@ int mrp_connect(void)
return -1;
}
-int mrp_disconnect(void)
+int mrp_disconnect(struct mrp_talker_ctx *ctx)
{
char *msgbuf;
int rc;
@@ -372,7 +382,7 @@ int mrp_disconnect(void)
memset(msgbuf, 0, 64);
sprintf(msgbuf, "BYE");
mrp_okay = 0;
- rc = send_mrp_msg(msgbuf, 1500);
+ rc = send_mrp_msg(msgbuf, 1500, ctx);
free(msgbuf);
if (rc != 1500)
@@ -389,7 +399,7 @@ int mrp_monitor(void)
return rc;
}
-int mrp_register_domain(int *class_id, int *priority, u_int16_t * vid)
+int mrp_register_domain(struct mrp_domain_attr *reg_class, struct mrp_talker_ctx *ctx)
{
char *msgbuf;
int rc;
@@ -399,9 +409,9 @@ int mrp_register_domain(int *class_id, int *priority, u_int16_t * vid)
return -1;
memset(msgbuf, 0, 1500);
- sprintf(msgbuf, "S+D:C=%d,P=%d,V=%04x", *class_id, *priority, *vid);
+ sprintf(msgbuf, "S+D:C=%d,P=%d,V=%04x", reg_class->id, reg_class->priority, reg_class->vid);
mrp_okay = 0;
- rc = send_mrp_msg(msgbuf, 1500);
+ rc = send_mrp_msg(msgbuf, 1500, ctx);
free(msgbuf);
if (rc != 1500)
@@ -414,8 +424,7 @@ int mrp_register_domain(int *class_id, int *priority, u_int16_t * vid)
int
mrp_advertise_stream(uint8_t * streamid,
uint8_t * destaddr,
- u_int16_t vlan,
- int pktsz, int interval, int priority, int latency)
+ int pktsz, int interval, int latency, struct mrp_talker_ctx *ctx)
{
char *msgbuf;
int rc;
@@ -434,10 +443,10 @@ mrp_advertise_stream(uint8_t * streamid,
",L=%d", streamid[0], streamid[1], streamid[2],
streamid[3], streamid[4], streamid[5], streamid[6],
streamid[7], destaddr[0], destaddr[1], destaddr[2],
- destaddr[3], destaddr[4], destaddr[5], vlan, pktsz,
- interval, priority << 5, latency);
+ destaddr[3], destaddr[4], destaddr[5], ctx->domain_class_a_vid, pktsz,
+ interval, ctx->domain_class_a_priority << 5, latency);
mrp_okay = 0;
- rc = send_mrp_msg(msgbuf, 1500);
+ rc = send_mrp_msg(msgbuf, 1500, ctx);
free(msgbuf);
if (rc != 1500)
@@ -449,8 +458,7 @@ mrp_advertise_stream(uint8_t * streamid,
int
mrp_unadvertise_stream(uint8_t * streamid,
uint8_t * destaddr,
- u_int16_t vlan,
- int pktsz, int interval, int priority, int latency)
+ int pktsz, int interval, int latency, struct mrp_talker_ctx *ctx)
{
char *msgbuf;
int rc;
@@ -467,10 +475,10 @@ mrp_unadvertise_stream(uint8_t * streamid,
",L=%d", streamid[0], streamid[1], streamid[2],
streamid[3], streamid[4], streamid[5], streamid[6],
streamid[7], destaddr[0], destaddr[1], destaddr[2],
- destaddr[3], destaddr[4], destaddr[5], vlan, pktsz,
- interval, priority << 5, latency);
+ destaddr[3], destaddr[4], destaddr[5], ctx->domain_class_a_vid, pktsz,
+ interval, ctx->domain_class_a_priority << 5, latency);
mrp_okay = 0;
- rc = send_mrp_msg(msgbuf, 1500);
+ rc = send_mrp_msg(msgbuf, 1500, ctx);
free(msgbuf);
if (rc != 1500)
@@ -480,24 +488,24 @@ mrp_unadvertise_stream(uint8_t * streamid,
}
-int mrp_await_listener(unsigned char *streamid)
+int mrp_await_listener(unsigned char *streamid, struct mrp_talker_ctx *ctx)
{
char *msgbuf;
int rc;
- memcpy(monitor_stream_id, streamid, sizeof(monitor_stream_id));
+ memcpy(ctx->monitor_stream_id, streamid, sizeof(ctx->monitor_stream_id));
msgbuf = malloc(1500);
if (NULL == msgbuf)
return -1;
memset(msgbuf, 0, 1500);
sprintf(msgbuf, "S??");
- rc = send_mrp_msg(msgbuf, 1500);
+ rc = send_mrp_msg(msgbuf, 1500, ctx);
free(msgbuf);
if (rc != 1500)
return -1;
/* either already there ... or need to wait ... */
- while (!halt_tx && (listeners == 0))
+ while (!ctx->halt_tx && (ctx->listeners == 0))
usleep(20000);
return 0;
@@ -507,8 +515,7 @@ int mrp_await_listener(unsigned char *streamid)
* actually not used
*/
-int mrp_get_domain(int *class_a_id, int *a_priority, u_int16_t * a_vid,
- int *class_b_id, int *b_priority, u_int16_t * b_vid)
+int mrp_get_domain(struct mrp_talker_ctx *ctx,struct mrp_domain_attr *class_a,struct mrp_domain_attr *class_b)
{
char *msgbuf;
int ret;
@@ -521,32 +528,32 @@ 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??");
- ret = send_mrp_msg(msgbuf, 1500);
+ ret = send_mrp_msg(msgbuf, 1500, ctx);
free(msgbuf);
if (ret != 1500)
return -1;
- while (!halt_tx && (domain_a_valid == 0) && (domain_b_valid == 0))
+ while (!ctx->halt_tx && (ctx->domain_a_valid == 0) && (ctx->domain_b_valid == 0))
usleep(20000);
- *class_a_id = 0;
- *a_priority = 0;
- *a_vid = 0;
- *class_b_id = 0;
- *b_priority = 0;
- *b_vid = 0;
- if (domain_a_valid) {
- *class_a_id = domain_class_a_id;
- *a_priority = domain_class_a_priority;
- *a_vid = domain_class_a_vid;
+ class_a->id = 0;
+ class_a->priority = 0;
+ class_a->vid = 0;
+ class_b->id = 0;
+ class_b->priority = 0;
+ class_b->vid = 0;
+ if (ctx->domain_a_valid) {
+ class_a->id = ctx->domain_class_a_id;
+ class_a->priority = ctx->domain_class_a_priority;
+ class_a->vid = ctx->domain_class_a_vid;
}
- if (domain_b_valid) {
- *class_b_id = domain_class_b_id;
- *b_priority = domain_class_b_priority;
- *b_vid = domain_class_b_vid;
+ if (ctx->domain_b_valid) {
+ class_b->id = ctx->domain_class_b_id;
+ class_b->priority = ctx->domain_class_b_priority;
+ class_b->vid = ctx->domain_class_b_vid;
}
return 0;
}
-int mrp_join_vlan()
+int mrp_join_vlan(struct mrp_domain_attr *reg_class, struct mrp_talker_ctx *ctx)
{
char *msgbuf;
int rc;
@@ -555,8 +562,8 @@ int mrp_join_vlan()
if (NULL == msgbuf)
return -1;
memset(msgbuf, 0, 1500);
- sprintf(msgbuf, "V++:I=0002");
- rc = send_mrp_msg(msgbuf, 1500);
+ sprintf(msgbuf, "V++:I=%04x\n",reg_class->vid);
+ rc = send_mrp_msg(msgbuf, 1500, ctx);
free(msgbuf);
if (rc != 1500)
@@ -565,27 +572,6 @@ int mrp_join_vlan()
return 0;
}
-int mrp_join_listener(uint8_t * streamid)
-{
- char *msgbuf;
- int rc;
-
- msgbuf = malloc(1500);
- if (NULL == msgbuf)
- return -1;
- memset(msgbuf, 0, 1500);
- sprintf(msgbuf, "S+L:S=%02X%02X%02X%02X%02X%02X%02X%02X"
- ",D=2", streamid[0], streamid[1], streamid[2], streamid[3],
- streamid[4], streamid[5], streamid[6], streamid[7]);
- mrp_okay = 0;
- rc = send_mrp_msg(msgbuf, 1500);
- free(msgbuf);
-
- if (rc != 1500)
- return -1;
- else
- return 0;
-}
// TODO remove
int recv_mrp_okay()
@@ -594,4 +580,3 @@ int recv_mrp_okay()
usleep(20000);
return 0;
}
-
diff --git a/examples/common/talker_mrp_client.h b/examples/common/talker_mrp_client.h
index 60ced4cd..cea4f227 100644
--- a/examples/common/talker_mrp_client.h
+++ b/examples/common/talker_mrp_client.h
@@ -3,30 +3,30 @@
Copyright (c) 2012, Intel Corporation
Copyright (c) 2014, Parrot SA
All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
+
+ 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,
+
+ 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
+
+ 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.
-
- 3. Neither the name of the Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived from
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 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)
+ 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 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.
@@ -52,31 +52,41 @@
/* global variables */
-// TODO move these in a talker_context struct + init func
+struct mrp_talker_ctx
+{
+ int control_socket;
+ volatile int halt_tx;
+ volatile int domain_a_valid;
+ int domain_class_a_id;
+ int domain_class_a_priority;
+ u_int16_t domain_class_a_vid;
+ volatile int domain_b_valid;
+ int domain_class_b_id;
+ int domain_class_b_priority;
+ u_int16_t domain_class_b_vid;
+ unsigned char monitor_stream_id[8];
+ volatile int listeners;
+};
-extern volatile int halt_tx;
-extern volatile int listeners;
-extern volatile int mrp_error;
+struct mrp_domain_attr
+{
+ int id;
+ int priority;
+ u_int16_t vid;
+};
-extern volatile int domain_a_valid;
-extern int domain_class_a_id;
-extern int domain_class_a_priority;
-extern u_int16_t domain_class_a_vid;
-extern volatile int domain_b_valid;
-extern int domain_class_b_id;
-extern int domain_class_b_priority;
-extern u_int16_t domain_class_b_vid;
+extern volatile int mrp_error;
/* functions */
-int mrp_connect(void);
-int mrp_disconnect(void);
-int mrp_monitor(void);
-int mrp_register_domain(int *class_id, int *priority, u_int16_t *vid);
-int mrp_join_vlan(void);
-int mrp_advertise_stream(uint8_t * streamid, uint8_t * destaddr, u_int16_t vlan, int pktsz, int interval, int priority, int latency);
-int mrp_unadvertise_stream(uint8_t * streamid, uint8_t * destaddr, u_int16_t vlan, int pktsz, int interval, int priority, int latency);
-int mrp_await_listener(unsigned char *streamid);
-
+int mrp_connect(struct mrp_talker_ctx *ctx);
+int mrp_disconnect(struct mrp_talker_ctx *ctx);
+int mrp_register_domain(struct mrp_domain_attr *reg_class, struct mrp_talker_ctx *ctx);
+int mrp_join_vlan(struct mrp_domain_attr *reg_class, struct mrp_talker_ctx *ctx);
+int mrp_advertise_stream(uint8_t * streamid, uint8_t * destaddr, int pktsz, int interval, int latency, struct mrp_talker_ctx *ctx);
+int mrp_unadvertise_stream(uint8_t * streamid, uint8_t * destaddr, int pktsz, int interval, int latency, struct mrp_talker_ctx *ctx);
+int mrp_await_listener(unsigned char *streamid, struct mrp_talker_ctx *ctx);
+int mrp_get_domain(struct mrp_talker_ctx *ctx, struct mrp_domain_attr *class_a, struct mrp_domain_attr *class_b);
+int mrp_talker_client_init(struct mrp_talker_ctx *ctx);
#endif /* _TALKER_MRP_CLIENT_H_ */
diff --git a/examples/jackd-listener/Makefile b/examples/jackd-listener/Makefile
index a9004923..b0208530 100644
--- a/examples/jackd-listener/Makefile
+++ b/examples/jackd-listener/Makefile
@@ -2,7 +2,7 @@ CC ?= gcc
OPT = -O2 -g
CFLAGS = $(OPT) -Wall -Wextra -Wno-parentheses -std=gnu99
INCFLAGS = -I../../daemons/mrpd -I../common -I../../daemons/common
-LDLIBS = -lpcap -lsndfile -ljack
+LDLIBS = -lpcap -lsndfile -ljack -lpthread
all: jack_listener
diff --git a/examples/jackd-listener/jack_listener.c b/examples/jackd-listener/jack_listener.c
index 1b0b51c7..103a52b8 100644
--- a/examples/jackd-listener/jack_listener.c
+++ b/examples/jackd-listener/jack_listener.c
@@ -54,6 +54,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define DEFAULT_RINGBUFFER_SIZE (32768)
#define MAX_SAMPLE_VALUE ((1U << ((sizeof(int32_t) * 8) -1)) -1)
+struct mrp_listener_ctx *ctx_sig;//Context pointer for signal handler
+
struct ethernet_header{
u_char dst[6];
u_char src[6];
@@ -95,17 +97,17 @@ void shutdown_and_exit(int sig)
fprintf(stdout,"Received signal %d:", sig);
fprintf(stdout,"Leaving...\n");
- if (0 != talker) {
- ret = send_leave();
+ if (0 != ctx_sig->talker) {
+ ret = send_leave(ctx_sig);
if (ret)
printf("send_leave failed\n");
}
- ret = mrp_disconnect();
+ ret = mrp_disconnect(ctx_sig);
if (ret)
printf("mrp_disconnect failed\n");
- close(control_socket);
+ close(ctx_sig->control_socket);
if (NULL != handle) {
pcap_breakloop(handle);
@@ -140,7 +142,7 @@ void pcap_callback(u_char* args, const struct pcap_pkthdr* packet_header, const
jack_default_audio_sample_t jackframe[CHANNELS];
int cnt;
static int total;
- (void) args; /* unused */
+ struct mrp_listener_ctx *ctx = (struct mrp_listener_ctx*) args;
(void) packet_header; /* unused */
eth_header = (struct ethernet_header*)(packet);
@@ -150,34 +152,34 @@ void pcap_callback(u_char* args, const struct pcap_pkthdr* packet_header, const
}
test_stream_id = (unsigned char*)(packet + ETHERNET_HEADER_SIZE + SEVENTEEN22_HEADER_PART1_SIZE);
- if (0 != memcmp(test_stream_id, stream_id, STREAM_ID_SIZE)) {
+ if (0 != memcmp(test_stream_id, ctx->stream_id, STREAM_ID_SIZE)) {
return;
}
-
+
mybuf = (uint32_t*) (packet + HEADER_SIZE);
-
- for(int i = 0; i < SAMPLES_PER_FRAME * CHANNELS; i+=CHANNELS) {
+
+ for(int i = 0; i < SAMPLES_PER_FRAME * CHANNELS; i+=CHANNELS) {
memcpy(&frame[0], &mybuf[i], sizeof(frame));
for(int j = 0; j < CHANNELS; j++) {
-
+
frame[j] = ntohl(frame[j]); /* convert to host-byte order */
frame[j] &= 0x00ffffff; /* ignore leading label */
frame[j] <<= 8; /* left-align remaining PCM-24 sample */
-
+
jackframe[j] = ((int32_t)frame[j])/(float)(MAX_SAMPLE_VALUE);
}
if ((cnt = jack_ringbuffer_write_space(ringbuffer)) >= SAMPLE_SIZE * CHANNELS) {
jack_ringbuffer_write(ringbuffer, (void*)&jackframe[0], SAMPLE_SIZE * CHANNELS);
-
+
} else {
fprintf(stdout, "Only %i bytes available after %i samples.\n", cnt, total);
}
if (jack_ringbuffer_write_space(ringbuffer) <= SAMPLE_SIZE * CHANNELS * DEFAULT_RINGBUFFER_SIZE / 4) {
- /** Ringbuffer has only 25% or less write space available, it's time to tell jackd
+ /** Ringbuffer has only 25% or less write space available, it's time to tell jackd
to read some data. */
ready = 1;
}
@@ -201,7 +203,7 @@ static int process_jack(jack_nframes_t nframes, void* arg)
}
for(size_t i = 0; i < nframes; i++) {
-
+
if (jack_ringbuffer_read_space(ringbuffer) >= SAMPLE_SIZE * CHANNELS) {
for(int j = 0; j < CHANNELS; j++){
@@ -221,13 +223,13 @@ static int process_jack(jack_nframes_t nframes, void* arg)
void jack_shutdown(void* arg)
{
- (void) arg; /* unused*/
+ (void)arg; /* unused*/
printf("JACK shutdown\n");
shutdown_and_exit(0);
}
-jack_client_t* init_jack(void)
+jack_client_t* init_jack(struct mrp_listener_ctx *ctx)
{
const char* client_name = "simple_listener";
const char* server_name = NULL;
@@ -250,8 +252,8 @@ jack_client_t* init_jack(void)
fprintf (stderr, "unique name `%s' assigned\n", client_name);
}
- jack_set_process_callback(client, process_jack, 0);
- jack_on_shutdown(client, jack_shutdown, 0);
+ jack_set_process_callback(client, process_jack, (void *)ctx);
+ jack_on_shutdown(client, jack_shutdown, (void *)ctx);
outputports = (jack_port_t**) malloc (CHANNELS * sizeof (jack_port_t*));
out = (jack_default_audio_sample_t**) malloc (CHANNELS * sizeof (jack_default_audio_sample_t*));
@@ -262,13 +264,13 @@ jack_client_t* init_jack(void)
memset(ringbuffer->buf, 0, ringbuffer->size);
for(int i = 0; i < CHANNELS; i++) {
-
+
char* portName;
if (asprintf(&portName, "output%d", i) < 0) {
fprintf(stderr, "could not create portname for port %d\n", i);
shutdown_and_exit(0);
- }
-
+ }
+
outputports[i] = jack_port_register (client, portName, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
if (NULL == outputports[i]) {
fprintf (stderr, "cannot register output port \"%d\"!\n", i);
@@ -278,13 +280,13 @@ jack_client_t* init_jack(void)
const char** ports;
if (jack_activate (client)) {
- fprintf (stderr, "cannot activate client\n");
+ fprintf (stderr, "cannot activate client\n");
shutdown_and_exit(0);
}
ports = jack_get_ports(client, NULL, NULL, JackPortIsPhysical|JackPortIsInput);
- if(NULL == ports) {
- fprintf (stderr, "no physical playback ports\n");
+ if(NULL == ports) {
+ fprintf (stderr, "no physical playback ports\n");
shutdown_and_exit(0);
}
@@ -306,17 +308,20 @@ int main(int argc, char *argv[])
char* dev = NULL;
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program comp_filter_exp; /** The compiled filter expression */
- char filter_exp[] = "ether dst 91:E0:F0:00:0e:80"; /** The filter expression */
+ char filter_exp[100]; /** The filter expression */
int rc;
-
+ struct mrp_listener_ctx *ctx = malloc(sizeof(struct mrp_listener_ctx));
+ struct mrp_domain_attr *class_a = malloc(sizeof(struct mrp_domain_attr));
+ struct mrp_domain_attr *class_b = malloc(sizeof(struct mrp_domain_attr));
+ ctx_sig = ctx;
signal(SIGINT, shutdown_and_exit);
-
+
int c;
- while((c = getopt(argc, argv, "hi:")) > 0)
+ while((c = getopt(argc, argv, "hi:")) > 0)
{
- switch (c)
+ switch (c)
{
- case 'h':
+ case 'h':
help();
break;
case 'i':
@@ -331,23 +336,51 @@ int main(int argc, char *argv[])
help();
}
- if (create_socket()) {
+ rc = mrp_listener_client_init(ctx);
+ if (rc)
+ {
+ printf("failed to initialize global variables\n");
+ return EXIT_FAILURE;
+ }
+
+ if (create_socket(ctx)) {
fprintf(stderr, "Socket creation failed.\n");
return errno;
}
- rc = report_domain_status();
+ rc = mrp_monitor(ctx);
+ if (rc)
+ {
+ printf("failed creating MRP monitor thread\n");
+ return EXIT_FAILURE;
+ }
+ rc=mrp_get_domain(ctx, class_a, class_b);
+ if (rc)
+ {
+ printf("failed calling mrp_get_domain()\n");
+ return EXIT_FAILURE;
+ }
+
+ printf("detected domain Class A PRIO=%d VID=%04x...\n",class_a->priority,class_a->vid);
+
+ rc = report_domain_status(class_a,ctx);
if (rc) {
printf("report_domain_status failed\n");
return EXIT_FAILURE;
}
- init_jack();
-
+ rc = join_vlan(class_a, ctx);
+ if (rc) {
+ printf("join_vlan failed\n");
+ return EXIT_FAILURE;
+ }
+
+ init_jack(ctx);
+
fprintf(stdout,"Waiting for talker...\n");
- await_talker();
+ await_talker(ctx);
- rc = send_ready();
+ rc = send_ready(ctx);
if (rc) {
printf("send_ready failed\n");
return EXIT_FAILURE;
@@ -382,6 +415,7 @@ int main(int argc, char *argv[])
}
/** compile and apply filter */
+ sprintf(filter_exp,"ether dst %02x:%02x:%02x:%02x:%02x:%02x",ctx->dst_mac[0],ctx->dst_mac[1],ctx->dst_mac[2],ctx->dst_mac[3],ctx->dst_mac[4],ctx->dst_mac[5]);
if (-1 == pcap_compile(handle, &comp_filter_exp, filter_exp, 0, PCAP_NETMASK_UNKNOWN)) {
fprintf(stderr, "Could not parse filter %s: %s.\n", filter_exp, pcap_geterr(handle));
shutdown_and_exit(0);
@@ -391,11 +425,14 @@ int main(int argc, char *argv[])
fprintf(stderr, "Could not install filter %s: %s.\n", filter_exp, pcap_geterr(handle));
shutdown_and_exit(0);
}
-
+
/** loop forever and call callback-function for every received packet */
- pcap_loop(handle, -1, pcap_callback, NULL);
+ pcap_loop(handle, -1, pcap_callback, (u_char*)ctx);
usleep(-1);
+ free(ctx);
+ free(class_a);
+ free(class_b);
return EXIT_SUCCESS;
}
diff --git a/examples/jackd-talker/Makefile b/examples/jackd-talker/Makefile
index 815235f0..1d4a84ba 100644
--- a/examples/jackd-talker/Makefile
+++ b/examples/jackd-talker/Makefile
@@ -1,6 +1,6 @@
CC ?= gcc
OPT = -O2 -g
-CFLAGS = $(OPT) -Wall -Wextra -Wno-parentheses -std=gnu99
+CFLAGS = $(OPT) $(INCFLAGS) -Wall -Wextra -Wno-parentheses -std=gnu99
INCFLAGS = -I../../lib/igb -I../../daemons/mrpd -I../common -I../../daemons/common
LDLIBS = -ligb -lpci -lrt -pthread -ljack
LDFLAGS = -L../../lib/igb
@@ -24,4 +24,3 @@ jackd_talker.o: jackd_talker.c defines.h jack.h
clean:
$(RM) jackd_talker
$(RM) `find . -name "*~" -o -name "*.[oa]" -o -name "\#*\#" -o -name TAGS -o -name core -o -name "*.orig"`
-
diff --git a/examples/jackd-talker/jack.c b/examples/jackd-talker/jack.c
index 214d3d11..dc0d621b 100644
--- a/examples/jackd-talker/jack.c
+++ b/examples/jackd-talker/jack.c
@@ -8,9 +8,8 @@
#include <jack/ringbuffer.h>
#include "jack.h"
#include "defines.h"
+#include "talker_mrp_client.h"
-extern volatile int halt_tx;
-extern volatile int listeners;
extern volatile int glob_unleash_jack;
static jack_port_t** inputports;
@@ -30,18 +29,18 @@ static int process(jack_nframes_t nframes, void* arg)
{
int cnt;
static int total;
- (void) arg; /* unused */
+ struct mrp_talker_ctx *ctx = (struct mrp_talker_ctx *) arg;
/* Do nothing until we're ready to begin. */
if (!glob_unleash_jack) {
printf ("nothing to do\n");
return 0;
}
-
+
for(int i = 0; i < CHANNELS; i++) {
in[i] = jack_port_get_buffer(inputports[i], nframes);
}
-
+
for (size_t i = 0; i < nframes; i++) {
for(int j = 0; j < CHANNELS; j++) {
total++;
@@ -54,7 +53,7 @@ static int process(jack_nframes_t nframes, void* arg)
} else {
printf ("Only %i bytes available after %i samples\n",
cnt, total);
- halt_tx = 1;
+ ctx->halt_tx = 1;
}
}
}
@@ -70,13 +69,13 @@ static int process(jack_nframes_t nframes, void* arg)
void jack_shutdown(void* arg)
{
- (void) arg; /* unused */
+ struct mrp_talker_ctx *ctx = (struct mrp_talker_ctx *) arg;
printf("JACK shutdown\n");
- halt_tx = 1;
+ ctx->halt_tx = 1;
}
-jack_client_t* init_jack(void)
+jack_client_t* init_jack(struct mrp_talker_ctx *ctx)
{
jack_client_t *client;
const char *client_name = "simple_talker";
@@ -98,8 +97,8 @@ jack_client_t* init_jack(void)
fprintf (stderr, "unique name `%s' assigned\n", client_name);
}
- jack_set_process_callback(client, process, 0);
- jack_on_shutdown(client, jack_shutdown, 0);
+ jack_set_process_callback(client, process, (void *)ctx);
+ jack_on_shutdown(client, jack_shutdown, (void *)ctx);
if (jack_activate (client))
fprintf (stderr, "cannot activate client");
@@ -115,15 +114,15 @@ jack_client_t* init_jack(void)
for(int i = 0; i < CHANNELS; i++)
{
char* portName;
- if (asprintf(&portName, "input%d", i) < 0)
+ if (asprintf(&portName, "input%d", i) < 0)
{
fprintf(stderr, "Could not create portname for port %d", i);
exit(EXIT_FAILURE);
- }
-
+ }
+
inputports[i] = jack_port_register (client, portName,
JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
- if (NULL == inputports[i])
+ if (NULL == inputports[i])
{
fprintf (stderr, "cannot register input port \"%d\"!\n", i);
jack_client_close (client);
diff --git a/examples/jackd-talker/jack.h b/examples/jackd-talker/jack.h
index c78dc1ab..1e96bfb0 100644
--- a/examples/jackd-talker/jack.h
+++ b/examples/jackd-talker/jack.h
@@ -2,9 +2,10 @@
#define _AVB_JACK_H
#define DEFAULT_RINGBUFFER_SIZE 32768
+extern struct mrp_talker_ctx *ctx;
/* Prototypes */
-jack_client_t* init_jack(void);
+jack_client_t* init_jack(struct mrp_talker_ctx *ctx);
void stop_jack(jack_client_t* client);
#endif /* _AVB_JACK_H */
diff --git a/examples/jackd-talker/jackd_talker.c b/examples/jackd-talker/jackd_talker.c
index 11005fc7..b3ddac07 100755..100644
--- a/examples/jackd-talker/jackd_talker.c
+++ b/examples/jackd-talker/jackd_talker.c
@@ -1,31 +1,31 @@
/******************************************************************************
- Copyright (c) 2012, Intel Corporation
+ Copyright (c) 2012, Intel Corporation
All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
+
+ 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,
+
+ 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
+
+ 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.
-
- 3. Neither the name of the Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived from
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 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)
+ 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 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.
@@ -64,6 +64,7 @@
#define RENDER_DELAY (XMIT_DELAY+2000000) /* us */
#define PACKET_IPG (125000) /* (1) packet every 125 usec */
#define PKT_SZ (100)
+volatile int *halt_tx_sig;//Global variable for signal handler
typedef long double FrequencyRatio;
@@ -208,7 +209,7 @@ int gptpscaling(char *igb_mmap, gPtpTimeData *td)
void sigint_handler(int signum)
{
printf("got SIGINT\n");
- halt_tx = signum;
+ *halt_tx_sig = signum;
glob_unleash_jack = 0;
}
@@ -291,6 +292,7 @@ static void usage(void)
static void* packetizer_thread(void *arg) {
struct igb_packet *cleaned_packets;
+ struct mrp_talker_ctx *ctx = (struct mrp_talker_ctx *)arg;
six1883_sample *sample;
unsigned total_samples = 0;
int err;
@@ -307,7 +309,7 @@ static void* packetizer_thread(void *arg) {
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_mutex_lock(&threadLock);
- while (listeners && !halt_tx) {
+ while (ctx->listeners && !ctx->halt_tx) {
pthread_cond_wait(&dataReady, &threadLock);
while ((jack_ringbuffer_read_space(ringbuffer) >= bytes_to_read)) {
@@ -405,6 +407,9 @@ int main(int argc, char *argv[])
uint64_t update_8021as;
unsigned delta_8021as, delta_local;
jack_client_t* _jackclient;
+ struct mrp_talker_ctx *ctx = malloc(sizeof(struct mrp_talker_ctx));
+ struct mrp_domain_attr *class_a = malloc(sizeof(struct mrp_domain_attr));
+ struct mrp_domain_attr *class_b = malloc(sizeof(struct mrp_domain_attr));
for (;;) {
c = getopt(argc, argv, "hi:");
@@ -429,7 +434,14 @@ int main(int argc, char *argv[])
if (NULL == interface) {
usage();
}
- rc = mrp_connect();
+ rc = mrp_talker_client_init(ctx);
+ if (rc) {
+ printf("MRP talker client initialization failed\n");
+ return errno;
+ }
+ halt_tx_sig = &ctx->halt_tx;
+
+ rc = mrp_connect(ctx);
if (rc) {
printf("socket creation failed\n");
return errno;
@@ -459,28 +471,24 @@ int main(int argc, char *argv[])
usage();
}
- rc = mrp_monitor();
+ rc = mrp_get_domain(ctx, class_a, class_b);
if (rc) {
- printf("failed creating MRP monitor thread\n");
+ printf("failed calling msp_get_domain()\n");
return EXIT_FAILURE;
}
+ printf("detected domain Class A PRIO=%d VID=%04x...\n",class_a->priority,
+ class_a->vid);
- /*
- * should use mrp_get_domain() above but this is a simplification
- */
-
- domain_a_valid = 1;
- domain_class_a_id = MSRP_SR_CLASS_A;
- domain_class_a_priority = MSRP_SR_CLASS_A_PRIO;
- domain_class_a_vid = 2;
- printf("detected domain Class A PRIO=%d VID=%04x...\n", domain_class_a_priority,
- domain_class_a_vid);
-
- rc = mrp_register_domain(&domain_class_a_id, &domain_class_a_priority, &domain_class_a_vid);
+ rc = mrp_register_domain(class_a, ctx);
if (rc) {
printf("mrp_register_domain failed\n");
return EXIT_FAILURE;
}
+ rc = mrp_join_vlan(class_a, ctx);
+ if (rc) {
+ printf("mrp_join_vlan failed\n");
+ return EXIT_FAILURE;
+ }
igb_set_class_bandwidth(&glob_igb_dev, PACKET_IPG / 125000, 0, PKT_SZ - 22,
0);
@@ -517,9 +525,9 @@ int main(int argc, char *argv[])
((char *)glob_tmp_packet->vaddr)[12] = 0x81;
((char *)glob_tmp_packet->vaddr)[13] = 0x00;
((char *)glob_tmp_packet->vaddr)[14] =
- ((domain_class_a_priority << 13 | domain_class_a_vid)) >> 8;
+ ((ctx->domain_class_a_priority << 13 | ctx->domain_class_a_vid)) >> 8;
((char *)glob_tmp_packet->vaddr)[15] =
- ((domain_class_a_priority << 13 | domain_class_a_vid)) & 0xFF;
+ ((ctx->domain_class_a_priority << 13 | ctx->domain_class_a_vid)) & 0xFF;
((char *)glob_tmp_packet->vaddr)[16] = 0x22; /* 1722 eth type */
((char *)glob_tmp_packet->vaddr)[17] = 0xF0;
@@ -561,31 +569,32 @@ int main(int argc, char *argv[])
glob_free_packets = glob_tmp_packet;
}
- /*
- * subtract 16 bytes for the MAC header/Q-tag - pktsz is limited to the
+ /*
+ * subtract 16 bytes for the MAC header/Q-tag - pktsz is limited to the
* data payload of the ethernet frame .
*
* IPG is scaled to the Class (A) observation interval of packets per 125 usec
*/
- _jackclient = init_jack();
+ _jackclient = init_jack(ctx);
fprintf(stderr, "advertising stream ...\n");
- rc = mrp_advertise_stream(glob_stream_id, glob_dest_addr, domain_class_a_vid, PKT_SZ - 16,
- PACKET_IPG / 125000, domain_class_a_priority, 3900);
+ rc = mrp_advertise_stream(glob_stream_id, glob_dest_addr, PKT_SZ - 16,
+ PACKET_IPG / 125000, 3900, ctx);
if (rc) {
printf("mrp_advertise_stream failed\n");
return EXIT_FAILURE;
}
fprintf(stderr, "awaiting a listener ...\n");
- rc = mrp_await_listener(glob_stream_id);
+ rc = mrp_await_listener(glob_stream_id,ctx);
if (rc) {
printf("mrp_await_listener failed\n");
return EXIT_FAILURE;
}
+ ctx->listeners = 1;
printf("got a listener ...\n");
- halt_tx = 0;
+ ctx->halt_tx = 0;
if(-1 == gptpinit(&igb_shm_fd, &igb_mmap)) {
return EXIT_FAILURE;
@@ -609,28 +618,31 @@ int main(int argc, char *argv[])
rc = nice(-20);
- pthread_create (&glob_packetizer_id, NULL, packetizer_thread, NULL);
+ pthread_create (&glob_packetizer_id, NULL, packetizer_thread, (void *)ctx);
run_packetizer();
rc = nice(0);
stop_jack(_jackclient);
- if (halt_tx == 0)
+ if (ctx->halt_tx == 0)
printf("listener left ...\n");
- halt_tx = 1;
+ ctx->halt_tx = 1;
- rc = mrp_unadvertise_stream(glob_stream_id, glob_dest_addr, domain_class_a_vid, PKT_SZ - 16,
- PACKET_IPG / 125000, domain_class_a_priority, 3900);
+ rc = mrp_unadvertise_stream(glob_stream_id, glob_dest_addr, PKT_SZ - 16,
+ PACKET_IPG / 125000, 3900, ctx);
if (rc)
printf("mrp_unadvertise_stream failed\n");
igb_set_class_bandwidth(&glob_igb_dev, 0, 0, 0, 0); /* disable Qav */
- rc = mrp_disconnect();
+ rc = mrp_disconnect(ctx);
if (rc)
printf("mrp_disconnect failed\n");
+ free(ctx);
+ free(class_a);
+ free(class_b);
igb_dma_free_page(&glob_igb_dev, &a_page);
rc = gptpdeinit(&igb_shm_fd, &igb_mmap);
err = igb_detach(&glob_igb_dev);
diff --git a/examples/live_stream/listener.c b/examples/live_stream/listener.c
index a7ae7dd0..7ce12000 100644
--- a/examples/live_stream/listener.c
+++ b/examples/live_stream/listener.c
@@ -34,6 +34,7 @@
/* globals */
unsigned char glob_dest_addr[] = { 0x91, 0xE0, 0xF0, 0x00, 0x0E, 0x80 };
+struct mrp_listener_ctx *ctx_sig;//Context pointer for signal handler
void sigint_handler(int signum)
{
@@ -41,15 +42,18 @@ void sigint_handler(int signum)
fprintf(stderr, "Received signal %d:leaving...\n", signum);
#if USE_MRPD
- if (0 != talker) {
- ret = send_leave();
+ if (0 != ctx_sig->talker) {
+ ret = send_leave(ctx_sig);
if (ret)
printf("send_leave failed\n");
}
#endif /* USE_MRPD */
- if (2 > control_socket)
+ if (2 > ctx_sig->control_socket)
{
- close(control_socket);
+ close(ctx_sig->control_socket);
+ ret = mrp_disconnect(ctx_sig);
+ if (ret)
+ printf("mrp_disconnect failed\n");
}
exit(EXIT_SUCCESS);
}
@@ -69,6 +73,10 @@ int main(int argc, char *argv[ ])
unsigned char frame[MAX_FRAME_SIZE];
int size, length;
struct sched_param sched;
+ struct mrp_listener_ctx *ctx = malloc(sizeof(struct mrp_listener_ctx));
+ struct mrp_domain_attr *class_a = malloc(sizeof(struct mrp_domain_attr));
+ struct mrp_domain_attr *class_b = malloc(sizeof(struct mrp_domain_attr));
+ ctx_sig = ctx;
int rc;
if (argc < 2) {
@@ -78,20 +86,45 @@ int main(int argc, char *argv[ ])
signal(SIGINT, sigint_handler);
#if USE_MRPD
- if (create_socket()) {
+ rc = mrp_listener_client_init(ctx);
+ if (rc)
+ {
+ printf("failed to initialize global variables\n");
+ return EXIT_FAILURE;
+ }
+ if (create_socket(ctx)) {
fprintf(stderr, "Socket creation failed.\n");
return errno;
}
+ rc = mrp_monitor(ctx);
+ if (rc)
+ {
+ printf("failed creating MRP monitor thread\n");
+ return EXIT_FAILURE;
+ }
+ rc=mrp_get_domain(ctx, class_a, class_b);
+ if (rc)
+ {
+ printf("failed calling mrp_get_domain()\n");
+ return EXIT_FAILURE;
+ }
- rc = report_domain_status();
+ printf("detected domain Class A PRIO=%d VID=%04x...\n",class_a->priority,class_a->vid);
+
+ rc = report_domain_status(class_a,ctx);
if (rc) {
printf("report_domain_status failed\n");
return EXIT_FAILURE;
}
+ rc = join_vlan(class_a, ctx);
+ if (rc) {
+ printf("join_vlan failed\n");
+ return EXIT_FAILURE;
+ }
fprintf(stdout,"Waiting for talker...\n");
- await_talker();
- rc = send_ready();
+ await_talker(ctx);
+ rc = send_ready(ctx);
if (rc) {
printf("send_ready failed\n");
return EXIT_FAILURE;
@@ -174,8 +207,9 @@ int main(int argc, char *argv[ ])
usleep(100);
close(socket_descriptor);
+ free(ctx);
+ free(class_a);
+ free(class_b);
return EXIT_SUCCESS;
}
-
-
diff --git a/examples/live_stream/talker.c b/examples/live_stream/talker.c
index 320d347a..fb787c5d 100644
--- a/examples/live_stream/talker.c
+++ b/examples/live_stream/talker.c
@@ -39,6 +39,7 @@ unsigned char glob_station_addr[] = { 0, 0, 0, 0, 0, 0 };
unsigned char glob_stream_id[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
/* IEEE 1722 reserved address */
unsigned char glob_dest_addr[] = { 0x91, 0xE0, 0xF0, 0x00, 0x0E, 0x80 };
+volatile int *halt_tx_sig;//Global variable for signal handler
uint64_t reverse_64(uint64_t val)
{
@@ -59,7 +60,7 @@ uint64_t reverse_64(uint64_t val)
void sigint_handler(int signum)
{
fprintf(stderr, "got SIGINT\n");
- halt_tx = signum;
+ *halt_tx_sig = signum;
}
int get_mac_addr(int8_t *iface)
@@ -94,6 +95,7 @@ int main(int argc, char *argv[])
struct igb_packet *tmp_packet;
struct igb_packet *cleaned_packets;
struct igb_packet *free_packets;
+ struct mrp_talker_ctx *ctx = malloc(sizeof(struct mrp_talker_ctx));
six1883_header *h61883;
seventeen22_header *h1722;
unsigned i;
@@ -106,6 +108,8 @@ int main(int argc, char *argv[])
void *stream_packet;
long long int frame_sequence = 0;
struct sched_param sched;
+ struct mrp_domain_attr *class_a = malloc(sizeof(struct mrp_domain_attr));
+ struct mrp_domain_attr *class_b = malloc(sizeof(struct mrp_domain_attr));
if (argc < 2) {
fprintf(stderr,"%s <if_name> <payload>\n", argv[0]);
@@ -116,9 +120,14 @@ int main(int argc, char *argv[])
packet_size = atoi(argv[2]);;
glob_payload_length = atoi(argv[2]);;
packet_size += sizeof(six1883_header) + sizeof(seventeen22_header) + sizeof(eth_header);
-
+ err = mrp_talker_client_init(ctx);
+ if (err) {
+ printf("MRP talker client initialization failed\n");
+ return errno;
+ }
+ halt_tx_sig = &ctx->halt_tx;
#ifdef USE_MRPD
- err = mrp_connect();
+ err = mrp_connect(ctx);
if (err) {
fprintf(stderr, "socket creation failed\n");
return errno;
@@ -152,28 +161,24 @@ int main(int argc, char *argv[])
}
#ifdef USE_MRPD
- err = mrp_monitor();
+ err = mrp_get_domain(ctx, class_a, class_b);
if (err) {
- printf("failed creating MRP monitor thread\n");
+ printf("failed calling msp_get_domain()\n");
return EXIT_FAILURE;
}
+ fprintf(stderr, "detected domain Class A PRIO=%d VID=%04x...\n", class_a->priority,
+ class_a->vid);
- domain_a_valid = 1;
- domain_class_a_id = MSRP_SR_CLASS_A;
- domain_class_a_priority = MSRP_SR_CLASS_A_PRIO;
- domain_class_a_vid = 2;
- fprintf(stderr, "detected domain Class A PRIO=%d VID=%04x...\n", domain_class_a_priority,
- domain_class_a_vid);
-
- err = mrp_register_domain(&domain_class_a_id, &domain_class_a_priority, &domain_class_a_vid);
+ err = mrp_register_domain(class_a, ctx);
if (err) {
printf("mrp_register_domain failed\n");
return EXIT_FAILURE;
}
-
- domain_a_valid = 1;
- domain_class_a_vid = 2;
- fprintf(stderr, "detected domain Class A PRIO=%d VID=%04x...\n", domain_class_a_priority, domain_class_a_vid);
+ err = mrp_join_vlan(class_a, ctx);
+ if (err) {
+ printf("mrp_join_vlan failed\n");
+ return EXIT_FAILURE;
+ }
#endif
igb_set_class_bandwidth(&igb_dev, PACKET_IPG / 125000, 0, packet_size - 22, 0);
@@ -205,7 +210,7 @@ int main(int argc, char *argv[])
avb_set_1722_stream_id(h1722,reverse_64(STREAMID));
avb_set_1722_sid_valid(h1722, 0x1);
-
+
/*initalize h61883 header */
avb_initialize_61883_to_defaults(h61883);
avb_set_61883_format_tag(h61883, 0x1);
@@ -242,26 +247,29 @@ int main(int argc, char *argv[])
}
#ifdef USE_MRPD
- /*
- * subtract 16 bytes for the MAC header/Q-tag - pktsz is limited to the
+ /*
+ * subtract 16 bytes for the MAC header/Q-tag - pktsz is limited to the
* data payload of the ethernet frame .
*
* IPG is scaled to the Class (A) observation interval of packets per 125 usec
*/
fprintf(stderr, "advertising stream ...\n");
- err = mrp_advertise_stream(glob_stream_id, glob_dest_addr, domain_class_a_vid, packet_size - 16,
- PACKET_IPG / 125000, domain_class_a_priority, 3900);
+ err = mrp_advertise_stream(glob_stream_id, glob_dest_addr, packet_size - 16,
+ PACKET_IPG / 125000, 3900, ctx);
if (err) {
printf("mrp_advertise_stream failed\n");
return EXIT_FAILURE;
}
fprintf(stderr, "awaiting a listener ...\n");
- err = mrp_await_listener(glob_stream_id);
+ err = mrp_await_listener(glob_stream_id,ctx);
if (err) {
printf("mrp_await_listener failed\n");
return EXIT_FAILURE;
}
+ ctx->listeners = 1;
+ printf("got a listener ...\n");
+ ctx->halt_tx = 0;
#endif
@@ -269,7 +277,7 @@ int main(int argc, char *argv[])
sched.sched_priority = 1;
sched_setscheduler(0, SCHED_RR, &sched);
- while (listeners && !halt_tx)
+ while (ctx->listeners && !ctx->halt_tx)
{
tmp_packet = free_packets;
if (NULL == tmp_packet)
@@ -289,9 +297,9 @@ int main(int argc, char *argv[])
else
avb_set_1722_timestamp_valid(h1722, 1);
- data_ptr = (uint8_t *)((uint8_t*)stream_packet + sizeof(eth_header) + sizeof(seventeen22_header)
+ data_ptr = (uint8_t *)((uint8_t*)stream_packet + sizeof(eth_header) + sizeof(seventeen22_header)
+ sizeof(six1883_header));
-
+
read_bytes = read(0, (void *)data_ptr, glob_payload_length);
/* Error case while reading the input file */
if (read_bytes < 0) {
@@ -325,24 +333,27 @@ cleanup:
}
}
- if (halt_tx == 0)
+ if (ctx->halt_tx == 0)
fprintf(stderr, "listener left ...\n");
- halt_tx = 1;
+ ctx->halt_tx = 1;
sleep(1);
#ifdef USE_MRPD
- err = mrp_unadvertise_stream(glob_stream_id, glob_dest_addr, domain_class_a_vid, packet_size - 16,
- PACKET_IPG / 125000, domain_class_a_priority, 3900);
+ err = mrp_unadvertise_stream(glob_stream_id, glob_dest_addr, packet_size - 16,
+ PACKET_IPG / 125000, 3900, ctx);
if (err)
printf("mrp_unadvertise_stream failed\n");
#endif
/* disable Qav */
igb_set_class_bandwidth(&igb_dev, 0, 0, 0, 0);
#ifdef USE_MRPD
- err = mrp_disconnect();
+ err = mrp_disconnect(ctx);
if (err)
printf("mrp_disconnect failed\n");
#endif
+ free(ctx);
+ free(class_a);
+ free(class_b);
igb_dma_free_page(&igb_dev, &a_page);
err = igb_detach(&igb_dev);
diff --git a/examples/simple_listener/Makefile b/examples/simple_listener/Makefile
index cb863045..9a4b33a6 100644
--- a/examples/simple_listener/Makefile
+++ b/examples/simple_listener/Makefile
@@ -2,7 +2,7 @@ CC ?= gcc
OPT = -O2 -g
CFLAGS = $(OPT) -Wall -Wextra -Wno-parentheses
INCFLAGS = -I../../daemons/mrpd -I../common -I../../daemons/common
-LDLIBS = -lpcap -lsndfile
+LDLIBS = -lpcap -lsndfile -pthread
all: simple_listener
diff --git a/examples/simple_listener/simple_listener.c b/examples/simple_listener/simple_listener.c
index 85f322e8..bd1c1cab 100644
--- a/examples/simple_listener/simple_listener.c
+++ b/examples/simple_listener/simple_listener.c
@@ -49,6 +49,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SAMPLES_PER_FRAME (6)
#define CHANNELS (2)
+struct mrp_listener_ctx *ctx_sig;//Context pointer for signal handler
+
struct ethernet_header{
u_char dst[6];
u_char src[6];
@@ -73,7 +75,7 @@ static void help()
"Options:\n"
" -h show this message\n"
" -i specify interface for AVB connection\n"
- " -f set the name of the output wav-file\n"
+ " -f set the name of the output wav-file\n"
"\n" "%s" "\n", version_str);
exit(EXIT_FAILURE);
}
@@ -85,7 +87,7 @@ void pcap_callback(u_char* args, const struct pcap_pkthdr* packet_header, const
uint32_t *buf;
uint32_t frame[2] = { 0 , 0 };
int i;
- (void) args; /* unused */
+ struct mrp_listener_ctx *ctx = (struct mrp_listener_ctx*) args;
(void) packet_header; /* unused */
#if DEBUG
@@ -99,7 +101,7 @@ void pcap_callback(u_char* args, const struct pcap_pkthdr* packet_header, const
#endif /* DEBUG*/
if (0 == memcmp(glob_ether_type,eth_header->type,sizeof(eth_header->type)))
- {
+ {
test_stream_id = (unsigned char*)(packet + ETHERNET_HEADER_SIZE + SEVENTEEN22_HEADER_PART1_SIZE);
#if DEBUG
@@ -110,7 +112,7 @@ void pcap_callback(u_char* args, const struct pcap_pkthdr* packet_header, const
test_stream_id[6], test_stream_id[7]);
#endif /* DEBUG*/
- if (0 == memcmp(test_stream_id, stream_id, sizeof(STREAM_ID_SIZE)))
+ if (0 == memcmp(test_stream_id, ctx->stream_id, sizeof(STREAM_ID_SIZE)))
{
#if DEBUG
@@ -118,7 +120,7 @@ void pcap_callback(u_char* args, const struct pcap_pkthdr* packet_header, const
#endif /* DEBUG*/
buf = (uint32_t*) (packet + HEADER_SIZE);
for(i = 0; i < SAMPLES_PER_FRAME * CHANNELS; i += 2)
- {
+ {
memcpy(&frame[0], &buf[i], sizeof(frame));
frame[0] = ntohl(frame[0]); /* convert to host-byte order */
@@ -130,7 +132,7 @@ void pcap_callback(u_char* args, const struct pcap_pkthdr* packet_header, const
sf_writef_int(glob_snd_file, (const int *)frame, 1);
}
- }
+ }
}
}
@@ -140,16 +142,16 @@ void sigint_handler(int signum)
fprintf(stdout,"Received signal %d:leaving...\n", signum);
- if (0 != talker) {
- ret = send_leave();
+ if (0 != ctx_sig->talker) {
+ ret = send_leave(ctx_sig);
if (ret)
printf("send_leave failed\n");
}
- if (2 > control_socket)
+ if (2 > ctx_sig->control_socket)
{
- close(control_socket);
- ret = mrp_disconnect();
+ close(ctx_sig->control_socket);
+ ret = mrp_disconnect(ctx_sig);
if (ret)
printf("mrp_disconnect failed\n");
}
@@ -161,7 +163,7 @@ void sigint_handler(int signum)
pcap_close(glob_pcap_handle);
}
#endif /* PCAP */
-
+
#if LIBSND
sf_write_sync(glob_snd_file);
sf_close(glob_snd_file);
@@ -174,17 +176,19 @@ int main(int argc, char *argv[])
char* dev = NULL;
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program comp_filter_exp; /* The compiled filter expression */
- char filter_exp[] = "ether dst 91:E0:F0:00:0e:80"; /* The filter expression */
- int rc;
-
+ char filter_exp[100]; /* The filter expression */
+ struct mrp_listener_ctx *ctx = malloc(sizeof(struct mrp_listener_ctx));
+ struct mrp_domain_attr *class_a = malloc(sizeof(struct mrp_domain_attr));
+ struct mrp_domain_attr *class_b = malloc(sizeof(struct mrp_domain_attr));
+ ctx_sig = ctx;
signal(SIGINT, sigint_handler);
- int c;
- while((c = getopt(argc, argv, "hi:f:")) > 0)
+ int c,rc;
+ while((c = getopt(argc, argv, "hi:f:")) > 0)
{
- switch (c)
+ switch (c)
{
- case 'h':
+ case 'h':
help();
break;
case 'i':
@@ -201,41 +205,63 @@ int main(int argc, char *argv[])
if ((NULL == dev) || (NULL == file_name))
help();
- if (create_socket())
+ rc = mrp_listener_client_init(ctx);
+ if (rc)
+ {
+ printf("failed to initialize global variables\n");
+ return EXIT_FAILURE;
+ }
+
+ if (create_socket(ctx))
{
fprintf(stderr, "Socket creation failed.\n");
return errno;
}
- rc = report_domain_status();
+ rc = mrp_monitor(ctx);
+ if (rc)
+ {
+ printf("failed creating MRP monitor thread\n");
+ return EXIT_FAILURE;
+ }
+ rc=mrp_get_domain(ctx, class_a, class_b);
+ if (rc)
+ {
+ printf("failed calling mrp_get_domain()\n");
+ return EXIT_FAILURE;
+ }
+
+ printf("detected domain Class A PRIO=%d VID=%04x...\n",class_a->priority,class_a->vid);
+
+ rc = report_domain_status(class_a,ctx);
if (rc) {
printf("report_domain_status failed\n");
return EXIT_FAILURE;
}
- rc = join_vlan();
+ rc = join_vlan(class_a, ctx);
if (rc) {
printf("join_vlan failed\n");
return EXIT_FAILURE;
}
fprintf(stdout,"Waiting for talker...\n");
- await_talker();
+ await_talker(ctx);
#if DEBUG
fprintf(stdout,"Send ready-msg...\n");
#endif /* DEBUG */
- rc = send_ready();
+ rc = send_ready(ctx);
if (rc) {
printf("send_ready failed\n");
return EXIT_FAILURE;
}
-
+
#if LIBSND
SF_INFO* sf_info = (SF_INFO*)malloc(sizeof(SF_INFO));
memset(sf_info, 0, sizeof(SF_INFO));
-
+
sf_info->samplerate = SAMPLES_PER_SECOND;
sf_info->channels = CHANNELS;
sf_info->format = SF_FORMAT_WAV | SF_FORMAT_PCM_24;
@@ -245,13 +271,13 @@ int main(int argc, char *argv[])
fprintf(stderr, "Wrong format.");
return EXIT_FAILURE;
}
-
+
if (NULL == (glob_snd_file = sf_open(file_name, SFM_WRITE, sf_info)))
{
fprintf(stderr, "Could not create file.");
return EXIT_FAILURE;
}
- fprintf(stdout,"Created file called %s\n", file_name);
+ fprintf(stdout,"Created file called %s\n", file_name);
#endif /* LIBSND */
#if PCAP
@@ -268,6 +294,7 @@ int main(int argc, char *argv[])
fprintf(stdout,"Got session pcap handler.\n");
#endif /* DEBUG */
/* compile and apply filter */
+ sprintf(filter_exp,"ether dst %02x:%02x:%02x:%02x:%02x:%02x",ctx->dst_mac[0],ctx->dst_mac[1],ctx->dst_mac[2],ctx->dst_mac[3],ctx->dst_mac[4],ctx->dst_mac[5]);
if (-1 == pcap_compile(glob_pcap_handle, &comp_filter_exp, filter_exp, 0, PCAP_NETMASK_UNKNOWN))
{
fprintf(stderr, "Could not parse filter %s: %s\n", filter_exp, pcap_geterr(glob_pcap_handle));
@@ -285,8 +312,11 @@ int main(int argc, char *argv[])
#endif /* DEBUG */
/** loop forever and call callback-function for every received packet */
- pcap_loop(glob_pcap_handle, -1, pcap_callback, NULL);
+ pcap_loop(glob_pcap_handle, -1, pcap_callback, (u_char*)ctx);
#endif /* PCAP */
+ free(ctx);
+ free(class_a);
+ free(class_b);
return EXIT_SUCCESS;
}
diff --git a/examples/simple_talker/simple_talker.c b/examples/simple_talker/simple_talker.c
index e66e8c52..38636b90 100644
--- a/examples/simple_talker/simple_talker.c
+++ b/examples/simple_talker/simple_talker.c
@@ -1,31 +1,31 @@
/******************************************************************************
- Copyright (c) 2012, Intel Corporation
+ Copyright (c) 2012, Intel Corporation
All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
+
+ 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,
+
+ 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
+
+ 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.
-
- 3. Neither the name of the Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived from
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 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)
+ 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 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.
@@ -73,6 +73,7 @@
#define PKT_SZ (100)
typedef long double FrequencyRatio;
+volatile int *halt_tx_sig;//Global variable for signal handler
typedef struct {
int64_t ml_phoffset;
@@ -147,7 +148,7 @@ typedef struct __attribute__ ((packed)) {
uint16_t sequence;
uint32_t timestamp;
uint32_t ssrc;
-
+
uint8_t tag[2];
uint16_t total_length;
uint8_t tag_length;
@@ -183,13 +184,13 @@ uint16_t inet_checksum(uint8_t *ip, int len){
sum = (sum & 0xFFFF) + (sum >> 16);
len -= 2;
}
-
+
if(len) /* take care of left over byte */
sum += (uint16_t) *(uint8_t *)ip;
-
+
while(sum>>16)
sum = (sum & 0xFFFF) + (sum >> 16);
-
+
return ~sum;
}
@@ -241,7 +242,7 @@ uint16_t inet_checksum_sg( struct iovec *buf_iov, size_t buf_iovlen ){
while(sum>>16)
sum = (sum & 0xFFFF) + (sum >> 16);
-
+
return ~sum;
}
@@ -352,7 +353,7 @@ int get_samples(unsigned count, int32_t * buffer)
void sigint_handler(int signum)
{
printf("got SIGINT\n");
- halt_tx = signum;
+ *halt_tx_sig = signum;
}
int pci_connect(device_t *igb_dev)
@@ -452,6 +453,7 @@ int main(int argc, char *argv[])
struct igb_packet *tmp_packet;
struct igb_packet *cleaned_packets;
struct igb_packet *free_packets;
+ struct mrp_talker_ctx *ctx = malloc(sizeof(struct mrp_talker_ctx));
int c;
u_int64_t last_time;
int rc = 0;
@@ -480,6 +482,8 @@ int main(int argc, char *argv[])
unsigned delta_8021as, delta_local;
uint8_t dest_addr[6];
size_t packet_size;
+ struct mrp_domain_attr *class_a = malloc(sizeof(struct mrp_domain_attr));
+ struct mrp_domain_attr *class_b = malloc(sizeof(struct mrp_domain_attr));
for (;;) {
c = getopt(argc, argv, "hi:t:");
@@ -491,8 +495,7 @@ int main(int argc, char *argv[])
break;
case 'i':
if (interface) {
- printf
- ("only one interface per daemon is supported\n");
+ printf("only one interface per daemon is supported\n");
usage();
}
interface = strdup(optarg);
@@ -510,7 +513,16 @@ int main(int argc, char *argv[])
fprintf( stderr, "Must specify valid transport\n" );
usage();
}
- rc = mrp_connect();
+
+ rc = mrp_talker_client_init(ctx);
+ if (rc) {
+ printf("MRP talker client initialization failed\n");
+ return errno;
+ }
+
+ halt_tx_sig = &ctx->halt_tx;
+
+ rc = mrp_connect(ctx);
if (rc) {
printf("socket creation failed\n");
return errno;
@@ -568,32 +580,24 @@ int main(int argc, char *argv[])
( &l4_local_address,
&(( struct sockaddr_in *)&if_request.ifr_addr)->sin_addr,
sizeof( l4_local_address ));
-
+
}
- rc = mrp_monitor();
+ rc = mrp_get_domain(ctx, class_a, class_b);
if (rc) {
- printf("failed creating MRP monitor thread\n");
+ printf("failed calling msp_get_domain()\n");
return EXIT_FAILURE;
}
+ printf("detected domain Class A PRIO=%d VID=%04x...\n",class_a->priority,
+ class_a->vid);
- /*
- * should use mrp_get_domain() but this is a simplification
- */
- domain_a_valid = 1;
- domain_class_a_id = MSRP_SR_CLASS_A;
- domain_class_a_priority = MSRP_SR_CLASS_A_PRIO;
- domain_class_a_vid = 2;
- printf("detected domain Class A PRIO=%d VID=%04x...\n", domain_class_a_priority,
- domain_class_a_vid);
-
- rc = mrp_register_domain(&domain_class_a_id, &domain_class_a_priority, &domain_class_a_vid);
+ rc = mrp_register_domain(class_a, ctx);
if (rc) {
printf("mrp_register_domain failed\n");
return EXIT_FAILURE;
}
- rc = mrp_join_vlan();
+ rc = mrp_join_vlan(class_a, ctx);
if (rc) {
printf("mrp_join_vlan failed\n");
return EXIT_FAILURE;
@@ -649,9 +653,9 @@ int main(int argc, char *argv[])
((char *)tmp_packet->vaddr)[12] = 0x81;
((char *)tmp_packet->vaddr)[13] = 0x00;
((char *)tmp_packet->vaddr)[14] =
- ((domain_class_a_priority << 13 | domain_class_a_vid)) >> 8;
+ ((ctx->domain_class_a_priority << 13 | ctx->domain_class_a_vid)) >> 8;
((char *)tmp_packet->vaddr)[15] =
- ((domain_class_a_priority << 13 | domain_class_a_vid)) & 0xFF;
+ ((ctx->domain_class_a_priority << 13 | ctx->domain_class_a_vid)) & 0xFF;
if( transport == 2 ) {
((char *)tmp_packet->vaddr)[16] = 0x22; /* 1722 eth type */
((char *)tmp_packet->vaddr)[17] = 0xF0;
@@ -703,7 +707,7 @@ int main(int argc, char *argv[])
pseudo_hdr.zero = 0;
pseudo_hdr.protocol = 0x11;
pseudo_hdr.length = htons(packet_size-18-20);
-
+
l4_headers =
(IP_RTP_Header *) (((char *)tmp_packet->vaddr) + 18);
l4_headers->version_length = 0x45;
@@ -734,7 +738,7 @@ int main(int argc, char *argv[])
l4_headers->sequence = 0;
l4_headers->timestamp = 0;
l4_headers->ssrc = 0;
-
+
l4_headers->tag[0] = 0xBE;
l4_headers->tag[1] = 0xDE;
l4_headers->total_length = htons(2);
@@ -748,7 +752,7 @@ int main(int argc, char *argv[])
free_packets = tmp_packet;
}
- /*
+ /*
* subtract 16 bytes for the MAC header/Q-tag - pktsz is limited to the
* data payload of the ethernet frame.
*
@@ -757,9 +761,9 @@ int main(int argc, char *argv[])
fprintf(stderr, "advertising stream ...\n");
if( transport == 2 ) {
rc = mrp_advertise_stream(glob_stream_id, dest_addr,
- domain_class_a_vid, PKT_SZ - 16,
+ PKT_SZ - 16,
L2_PACKET_IPG / 125000,
- domain_class_a_priority, 3900);
+ 3900,ctx);
} else {
/*
* 1 is the wrong number for frame rate, but fractional values
@@ -767,10 +771,9 @@ int main(int argc, char *argv[])
* using it consistently
*/
rc = mrp_advertise_stream(glob_stream_id, dest_addr,
- domain_class_a_vid,
sizeof(*l4_headers) + L4_SAMPLES_PER_FRAME * CHANNELS * 2 + 6,
1,
- domain_class_a_priority, 3900);
+ 3900, ctx);
}
if (rc) {
printf("mrp_advertise_stream failed\n");
@@ -778,14 +781,14 @@ int main(int argc, char *argv[])
}
fprintf(stderr, "awaiting a listener ...\n");
- rc = mrp_await_listener(glob_stream_id);
+ rc = mrp_await_listener(glob_stream_id, ctx);
if (rc) {
printf("mrp_await_listener failed\n");
return EXIT_FAILURE;
}
- listeners = 1;
+ ctx->listeners = 1;
printf("got a listener ...\n");
- halt_tx = 0;
+ ctx->halt_tx = 0;
if(-1 == gptpinit(&igb_shm_fd, &igb_mmap)) {
fprintf(stderr, "GPTP init failed.\n");
@@ -811,13 +814,13 @@ int main(int argc, char *argv[])
rc = nice(-20);
- while (listeners && !halt_tx) {
+ while (ctx->listeners && !ctx->halt_tx) {
tmp_packet = free_packets;
if (NULL == tmp_packet)
goto cleanup;
-
+
free_packets = tmp_packet->next;
-
+
if( transport == 2 ) {
uint32_t timestamp_l;
get_samples( L2_SAMPLES_PER_FRAME, sample_buffer );
@@ -911,13 +914,13 @@ int main(int argc, char *argv[])
}
if (ENOSPC == err) {
-
+
/* put back for now */
tmp_packet->next = free_packets;
free_packets = tmp_packet;
}
-
- cleanup:
+
+ cleanup:
igb_clean(&igb_dev, &cleaned_packets);
i = 0;
while (cleaned_packets) {
@@ -929,35 +932,35 @@ int main(int argc, char *argv[])
}
}
rc = nice(0);
-
- if (halt_tx == 0)
+ if (ctx->halt_tx == 0)
printf("listener left ...\n");
- halt_tx = 1;
-
+ ctx->halt_tx = 1;
if( transport == 2 ) {
rc = mrp_unadvertise_stream
- (glob_stream_id, dest_addr, domain_class_a_vid, PKT_SZ - 16, L2_PACKET_IPG / 125000,
- domain_class_a_priority, 3900);
+ (glob_stream_id, dest_addr, PKT_SZ - 16, L2_PACKET_IPG / 125000,
+ 3900, ctx);
} else {
rc = mrp_unadvertise_stream
- (glob_stream_id, dest_addr, domain_class_a_vid,
+ (glob_stream_id, dest_addr,
sizeof(*l4_headers)+L4_SAMPLES_PER_FRAME*CHANNELS*2 + 6, 1,
- domain_class_a_priority, 3900);
+ 3900, ctx);
}
if (rc)
printf("mrp_unadvertise_stream failed\n");
-
+
igb_set_class_bandwidth(&igb_dev, 0, 0, 0, 0); /* disable Qav */
-
- rc = mrp_disconnect();
+
+ rc = mrp_disconnect(ctx);
if (rc)
printf("mrp_disconnect failed\n");
-
+ free(ctx);
+ free(class_a);
+ free(class_b);
igb_dma_free_page(&igb_dev, &a_page);
rc = gptpdeinit(&igb_shm_fd, &igb_mmap);
err = igb_detach(&igb_dev);
-
+
pthread_exit(NULL);
-
+
return EXIT_SUCCESS;
}
diff --git a/lib/avtp_pipeline/CMakeLists.txt b/lib/avtp_pipeline/CMakeLists.txt
new file mode 100644
index 00000000..c558ffbf
--- /dev/null
+++ b/lib/avtp_pipeline/CMakeLists.txt
@@ -0,0 +1,40 @@
+cmake_minimum_required ( VERSION 2.6 )
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
+project ( AVB )
+
+# point to AVB SRC directory
+set ( AVB_SRC_DIR ${CMAKE_SOURCE_DIR} )
+
+# point to HAL directory
+set ( AVB_HAL_DIR ${AVB_SRC_DIR}/platform/${OPENAVB_HAL} )
+
+# point to OSAL directory
+set ( AVB_OSAL_DIR ${AVB_SRC_DIR}/platform/${OPENAVB_OSAL} )
+
+# point to TCAL directory
+set ( AVB_TCAL_DIR ${AVB_SRC_DIR}/platform/platTCAL/${OPENAVB_TCAL} )
+
+# Directory to install binaries to
+set ( AVB_INSTALL_DIR ${CMAKE_BINARY_DIR}/bin )
+
+# CORE_TODO: There may be additional common CMakeLists.txt functionality that can be migrated out of the platform specific area.
+
+# CMake is happier when the CMakeLists.txt is in a top level directory working down. Therefore the platform specific CMakeLists.txt
+# is included here. The common CMake command uage will take this form below when run from a build directory that is at the same
+# directory level as the repo:
+# cmake -DCMAKE_TOOLCHAIN_FILE=../<avb_repo>/platform/<platform name>/<target>.cmake -DCMAKE_BUILD_TYPE=Release ../<avb_repo>
+# for example:
+# cmake -DCMAKE_TOOLCHAIN_FILE=../avbrepo/platform/Linux/x86_i210_linux.cmake -DCMAKE_BUILD_TYPE=Release ../avbrepo
+
+# Used to hold lists of source files from common code subdirectories
+SET (SRC_FILES "")
+
+# Suppress the policy warning when including a CMakeLists.txt file
+if(POLICY CMP0011)
+ cmake_policy(SET CMP0011 OLD)
+endif(POLICY CMP0011)
+
+include(${AVB_OSAL_DIR}/CMakeLists.txt)
+
+
+
diff --git a/lib/avtp_pipeline/LICENSE b/lib/avtp_pipeline/LICENSE
new file mode 100644
index 00000000..71e4e44e
--- /dev/null
+++ b/lib/avtp_pipeline/LICENSE
@@ -0,0 +1,30 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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.
+*************************************************************************************************************/
+
diff --git a/lib/avtp_pipeline/README.md b/lib/avtp_pipeline/README.md
new file mode 100644
index 00000000..315f8825
--- /dev/null
+++ b/lib/avtp_pipeline/README.md
@@ -0,0 +1,140 @@
+# STC AVTP Pipeline Contribution Notes
+
+## General Status
+- Consider the AVTP Pipeline a work in progress.
+- Integrated with OpenAVB:
+ - gPTP
+ - 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
+### Tool chain and libraries
+- Ubuntu 14.04
+- Install dependencies for OpenAVB ($ sudo apt-get install ...)
+ - $ sudo apt-get install build-essential
+ - $ sudo apt-get install libpcap-dev
+ - $ sudo apt-get install libpci-dev
+ - $ sudo apt-get install libsndfile1-dev
+ - $ sudo apt-get install libjack-dev
+ - $ sudo apt-get install linux-headers-generic
+ - linux-headers (same version as the kernel you're building for)
+
+- Install dependencies for AVTP pipeline
+ - $ sudo apt-get install libglib2.0-dev
+ - $ sudo apt-get install libgstreamer0.10-dev
+ - $ sudo apt-get install libgstreamer-plugins-base0.10-dev
+ - $ sudo apt-get install libasound2-dev
+
+### Building everything
+- Building from the repo root
+- $ ARCH=I210 make all
+
+### Building just AVTP pipeline.
+- $ make avtp_pipeline
+
+Binaries will be installed in lib/avtp_pipeline/build/bin.
+
+### Building AVTP pipeline without SRP.
+- $ 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
+- Helper scripts in the repo root.
+- `$ sudo ./run_igb.sh eth1`
+ - Load the igb driver. Supply the interface name (ethx) as parameter.
+- `$ sudo ./run_gptp.sh eth1`
+ - 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.
+
+## Running OpenAVB simple talker example
+- `$ sudo ./run_simple_talker.sh eth1`
+ - Run the current OpenAVB simple talker example. Supply the interface name (ethx) as parameter.
+
+## Running STC 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
+- `$ sudo ./run_echo_listener.sh eth1`
+ - Run the AVTP Echo talker test stream. Supply the interface name (ethx) as parameter.
+
+
+## Benchmark results
+
+All test done on DELL Optiplex 755 with Intel Core 2 Duo CPU E8400 @ 3.00GHz
+
+| Type | Comment | Class | Streams | CPU Talker | CPU Listener |
+|:-------:| -------------|:-----:| -------:| ----------:| ------------:|
+| 61883-6 | 48kHz stereo | A | 1 | 3.2%| 4.9%|
+| | | | 2 | 22.8%| 9.3%|
+| | | | 4 | 28.2%| 20.3%|
+| | | | 8 | 39.7%| 35.0%|
+| | | | 16 | 60.8%| 73.1%|
+| aaf | 48kHz stereo | A | 1 | 3.4%| 4.8%|
+| | | | 2 | 22.7%| 8.9%|
+| | | | 4 | 28.7%| 19.4%|
+| | | | 8 | 40.5%| 35.7%|
+| | | | 16 | 63.0%| 74.8%|
+| h264 | 4675 Kbps vbr| A | 1 | 3.2%| 27.0%|
+| | | | 2 | 6.4%| 59.8%|
+| | | | 4 | 10.5%| 108.1%|
+| | | | 6 | 15.6%| 149.9%|
+| mpeg2ts | 1405 Kbps vbr| A | 1 | 2.5%| 14.7%|
+| | | | 2 | 5.0%| 40.9%|
+| | | | 4 | 7.6%| 86.3%|
+| | | | 6 | 10.7%| 123.5%|
+| mjpeg | live camera | A | 1 | 11.5%| 10.2%|
+| mjpeg | videotestsrc | A | 1 | 10.0%| 6.4%|
+| | | | 2 | 21.4%| 13.0%|
+| | | | 4 | 40.5%| 26.9%|
+| | | | 6 | 57.7%| 42.0%|
+| | | B | 12 | 113.0%| 79.0%|
+
+## More examples
+
+Below are examples of AVTP pipeline usage with various stream types (mappings). These commands were used for generating benchmark results above. AVTP pipeline was compiled without SRP support (`AVB_FEATURE_ENDPOINT=0 make avtp_pipeline`).
+
+ IFNAME=eth0
+ STREAMS=7
+ CLASS=A
+ RATE=8000
+ TRANSIT_USEC=2000
+ REPORT=0 # statistics display interval in seconds (0 turns off statistics)
+
+ # AAF talker
+ sudo ./openavb_harness -I $IFNAME -s $STREAMS -d 0 -a a0:36:9f:2d:01:ad aaf_file_talker.ini,sr_class=$CLASS,map_nv_tx_rate=$RATE,max_transit_usec=$TRANSIT_USEC,map_nv_sparse_mode=0,intf_nv_file_name=test01.wav,report_seconds=$REPORT
+ # AAF listener
+ sudo ./openavb_harness -I $IFNAME -s $STREAMS -d 0 -a a0:36:9f:2d:01:ad aaf_listener_auto.ini,sr_class=$CLASS,map_nv_tx_rate=$RATE,max_transit_usec=$TRANSIT_USEC,map_nv_sparse_mode=0,intf_nv_audio_endian=big,report_seconds=$REPORT
+
+ # 61883-6 talker
+ sudo ./openavb_harness -I $IFNAME -s $STREAMS -d 0 -a a0:36:9f:2d:01:ad wav_file_talker.ini,sr_class=$CLASS,map_nv_tx_rate=$RATE,max_transit_usec=$TRANSIT_USEC,intf_nv_file_name=test01.wav,report_seconds=$REPORT
+ # 61883-6 listener
+ sudo ./openavb_harness -I $IFNAME -s $STREAMS -d 0 -a a0:36:9f:2d:01:ad alsa_listener.ini,sr_class=$CLASS,map_nv_tx_rate=$RATE,max_transit_usec=$TRANSIT_USEC,report_seconds=$REPORT
+
+ # H264 talker
+ sudo ./openavb_harness -I $IFNAME -s $STREAMS -d 0 -a a0:36:9f:2d:01:ad h264_gst_talker.ini,sr_class=$CLASS,map_nv_tx_rate=$RATE,max_transit_usec=$TRANSIT_USEC,report_seconds=$REPORT
+ # H264 listener
+ sudo ./openavb_harness -I $IFNAME -s $STREAMS -d 0 -a a0:36:9f:2d:01:ad h264_gst_listener.ini,sr_class=$CLASS,map_nv_tx_rate=$RATE,max_transit_usec=$TRANSIT_USEC,report_seconds=$REPORT
+
+ # MJPEG talker
+ sudo ./openavb_harness -I $IFNAME -s $STREAMS -d 0 -a a0:36:9f:2d:01:ad mjpeg_gst_talker.ini,sr_class=$CLASS,map_nv_tx_rate=$RATE,max_transit_usec=$TRANSIT_USEC,report_seconds=$REPORT
+ # MJPEG listener
+ sudo ./openavb_harness -I $IFNAME -s $STREAMS -d 0 -a a0:36:9f:2d:01:ad mjpeg_gst_listener.ini,sr_class=$CLASS,map_nv_tx_rate=$RATE,max_transit_usec=$TRANSIT_USEC,report_seconds=$REPORT
+
+ # MPEG2TS talker
+ sudo ./openavb_harness -I $IFNAME -s $STREAMS -d 0 -a a0:36:9f:2d:01:ad mpeg2ts_file_talker.ini,sr_class=$CLASS,map_nv_tx_rate=$RATE,max_transit_usec=$TRANSIT_USEC,report_seconds=$REPORT
+ # MPEG2TS listener
+ sudo ./openavb_harness -I $IFNAME -s $STREAMS -d 0 -a a0:36:9f:2d:01:ad mpeg2ts_gst_listener.ini,sr_class=$CLASS,map_nv_tx_rate=$RATE,max_transit_usec=$TRANSIT_USEC,report_seconds=$REPORT
diff --git a/lib/avtp_pipeline/avtp/CMakeLists.txt b/lib/avtp_pipeline/avtp/CMakeLists.txt
new file mode 100644
index 00000000..7f43c471
--- /dev/null
+++ b/lib/avtp_pipeline/avtp/CMakeLists.txt
@@ -0,0 +1,6 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/avtp/openavb_avtp.c
+ ${AVB_SRC_DIR}/avtp/openavb_avtp_time.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/avtp/openavb_avtp.c b/lib/avtp_pipeline/avtp/openavb_avtp.c
new file mode 100644
index 00000000..0fd4addb
--- /dev/null
+++ b/lib/avtp_pipeline/avtp/openavb_avtp.c
@@ -0,0 +1,701 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Implements main functions for AVTP. Includes
+* functions to create/destroy and AVTP stream, and to send or receive
+* data from that AVTP stream.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdint.h>
+#include <errno.h>
+#include "openavb_platform.h"
+#include "openavb_types.h"
+#include "openavb_trace.h"
+#include "openavb_avtp.h"
+#include "openavb_rawsock.h"
+#include "openavb_mediaq.h"
+
+#define AVB_LOG_COMPONENT "AVTP"
+#include "openavb_log.h"
+
+// Maximum time that AVTP RX/TX calls should block before returning
+#define AVTP_MAX_BLOCK_USEC (1 * MICROSECONDS_PER_SECOND)
+
+/*
+ * This is broken out into a function, so that we can close and reopen
+ * the socket if we detect a problem receiving frames.
+ */
+static openavbRC openAvtpSock(avtp_stream_t *pStream)
+{
+ if (pStream->tx) {
+ pStream->rawsock = openavbRawsockOpen(pStream->ifname, FALSE, TRUE, ETHERTYPE_AVTP, pStream->frameLen, pStream->nbuffers);
+ }
+ else {
+#ifndef UBUNTU
+ // This is the normal case for most of our supported platforms
+ pStream->rawsock = openavbRawsockOpen(pStream->ifname, TRUE, FALSE, ETHERTYPE_8021Q, pStream->frameLen, pStream->nbuffers);
+#else
+ pStream->rawsock = openavbRawsockOpen(pStream->ifname, TRUE, FALSE, ETHERTYPE_AVTP, pStream->frameLen, pStream->nbuffers);
+#endif
+ }
+
+ 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);
+ }
+ AVB_RC_RET(OPENAVB_AVTP_SUCCESS);
+ }
+
+ AVB_RC_LOG_RET(AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVB_RC_RAWSOCK_OPEN));
+}
+
+
+// Evaluate the AVTP timestamp. Only valid for common AVTP stream subtypes
+#define HIDX_AVTP_HIDE7_TV1 1
+#define HIDX_AVTP_HIDE7_TU1 3
+#define HIDX_AVTP_TIMESPAMP32 12
+static void processTimestampEval(avtp_stream_t *pStream, U8 *pHdr)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVTP_DETAIL);
+
+ if (pStream->tsEval) {
+ bool tsValid = (pHdr[HIDX_AVTP_HIDE7_TV1] & 0x01) ? TRUE : FALSE;
+ bool tsUncertain = (pHdr[HIDX_AVTP_HIDE7_TU1] & 0x01) ? TRUE : FALSE;
+
+ if (tsValid && !tsUncertain) {
+ U32 ts = ntohl(*(U32 *)(&pHdr[HIDX_AVTP_TIMESPAMP32]));
+ U32 tsSmoothed = openavbTimestampEvalTimestamp(pStream->tsEval, ts);
+ if (tsSmoothed != ts) {
+ *(U32 *)(&pHdr[HIDX_AVTP_TIMESPAMP32]) = htonl(tsSmoothed);
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVTP_DETAIL);
+}
+
+
+/* Initialize AVTP for talking
+ */
+openavbRC openavbAvtpTxInit(
+ media_q_t *pMediaQ,
+ openavb_map_cb_t *pMapCB,
+ openavb_intf_cb_t *pIntfCB,
+ char *ifname,
+ AVBStreamID_t *streamID,
+ U8 *destAddr,
+ U32 max_transit_usec,
+ U32 fwmark,
+ U16 vlanID,
+ U8 vlanPCP,
+ U16 nbuffers,
+ void **pStream_out)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVTP);
+ AVB_LOG_DEBUG("Initialize");
+
+ *pStream_out = NULL;
+
+ // Malloc the structure to hold state information
+ avtp_stream_t *pStream = calloc(1, sizeof(avtp_stream_t));
+ if (!pStream) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVB_RC_OUT_OF_MEMORY), AVB_TRACE_AVTP);
+ }
+ pStream->tx = TRUE;
+
+ pStream->pMediaQ = pMediaQ;
+ pStream->pMapCB = pMapCB;
+ pStream->pIntfCB = pIntfCB;
+
+ pStream->pMapCB->map_tx_init_cb(pStream->pMediaQ);
+ pStream->pIntfCB->intf_tx_init_cb(pStream->pMediaQ);
+
+ // Set the frame length
+ pStream->frameLen = pStream->pMapCB->map_max_data_size_cb(pStream->pMediaQ) + ETH_HDR_LEN_VLAN;
+
+ // and the latency
+ pStream->max_transit_usec = max_transit_usec;
+
+ // and save other stuff needed to (re)open the socket
+ pStream->ifname = strdup(ifname);
+ pStream->nbuffers = nbuffers;
+
+ // Open a raw socket
+ openavbRC rc = openAvtpSock(pStream);
+ if (IS_OPENAVB_FAILURE(rc)) {
+ free(pStream);
+ AVB_RC_LOG_TRACE_RET(rc, AVB_TRACE_AVTP);
+ }
+
+ // Create the AVTP frame header for the frames we'll send
+ hdr_info_t hdrInfo;
+
+ U8 srcAddr[ETH_ALEN];
+ if (openavbRawsockGetAddr(pStream->rawsock, srcAddr)) {
+ hdrInfo.shost = srcAddr;
+ }
+ else {
+ openavbRawsockClose(pStream->rawsock);
+ free(pStream);
+ AVB_LOG_ERROR("Failed to get source MAC address");
+ AVB_RC_TRACE_RET(OPENAVB_AVTP_FAILURE, AVB_TRACE_AVTP);
+ }
+
+ hdrInfo.dhost = destAddr;
+ if (vlanPCP != 0 || vlanID != 0) {
+ hdrInfo.vlan = TRUE;
+ hdrInfo.vlan_pcp = vlanPCP;
+ hdrInfo.vlan_vid = vlanID;
+ AVB_LOGF_DEBUG("VLAN pcp=%d vid=%d", hdrInfo.vlan_pcp, hdrInfo.vlan_vid);
+ }
+ else {
+ hdrInfo.vlan = FALSE;
+ }
+ openavbRawsockTxSetHdr(pStream->rawsock, &hdrInfo);
+
+ // Remember the AVTP subtype and streamID
+ pStream->subtype = pStream->pMapCB->map_subtype_cb();
+
+ memcpy(pStream->streamIDnet, streamID->addr, ETH_ALEN);
+ U16 *pStreamUID = (U16 *)((U8 *)(pStream->streamIDnet) + ETH_ALEN);
+ *pStreamUID = htons(streamID->uniqueID);
+
+ // Set the fwmark - used to steer packets into the right traffic control queue
+ openavbRawsockTxSetMark(pStream->rawsock, fwmark);
+
+ *pStream_out = (void *)pStream;
+ AVB_RC_TRACE_RET(OPENAVB_AVTP_SUCCESS, AVB_TRACE_AVTP);
+}
+
+#ifdef OPENAVB_AVTP_REPORT_RX_STATS
+static void inline rxDeliveryStats(avtp_rx_info_t *rxInfo,
+ struct timespec *tmNow,
+ U32 early, U32 late)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVTP);
+
+ rxInfo->rxCnt++;
+
+ if (late > 0) {
+ rxInfo->lateCnt++;
+ if (late > rxInfo->maxLate)
+ rxInfo->maxLate = late;
+ }
+ if (early > 0) {
+ rxInfo->earlyCnt++;
+ if (early > rxInfo->maxEarly)
+ rxInfo->maxEarly = early;
+ }
+
+ if (rxInfo->lastTime.tv_sec == 0) {
+ rxInfo->lastTime.tv_sec = tmNow->tv_sec;
+ rxInfo->lastTime.tv_nsec = tmNow->tv_nsec;
+ }
+ else if ((tmNow->tv_sec > (rxInfo->lastTime.tv_sec + OPENAVB_AVTP_REPORT_INTERVAL))
+ || ((tmNow->tv_sec == (rxInfo->lastTime.tv_sec + OPENAVB_AVTP_REPORT_INTERVAL))
+ && (tmNow->tv_nsec > rxInfo->lastTime.tv_nsec))) {
+ AVB_LOGF_INFO("Stream %d seconds, %lu samples: %lu late, max=%lums, %lu early, max=%lums",
+ OPENAVB_AVTP_REPORT_INTERVAL, (unsigned long)rxInfo->rxCnt,
+ (unsigned long)rxInfo->lateCnt, (unsigned long)rxInfo->maxLate / NANOSECONDS_PER_MSEC,
+ (unsigned long)rxInfo->earlyCnt, (unsigned long)rxInfo->maxEarly / NANOSECONDS_PER_MSEC);
+ rxInfo->maxLate = 0;
+ rxInfo->lateCnt = 0;
+ rxInfo->maxEarly = 0;
+ rxInfo->earlyCnt = 0;
+ rxInfo->rxCnt = 0;
+ rxInfo->lastTime.tv_sec = tmNow->tv_sec;
+ rxInfo->lastTime.tv_nsec = tmNow->tv_nsec;
+ }
+
+#if 0
+ if (++txCnt >= 1000) {}
+#endif
+ AVB_TRACE_EXIT(AVB_TRACE_AVTP);
+}
+#endif
+
+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));
+ case 0:
+ //
+ // - 1 bit cd (control/data indicator) = 0 (stream data)
+ // - 7 bits subtype = as configured
+ *pFill++ = pStream->subtype & 0x7F;
+ // - 1 bit sv (stream valid) = 1
+ // - 3 bits AVTP version = binary 000
+ // - 1 bit mr (media restart) = toggled when clock changes
+ // - 1 bit r (reserved) = 0
+ // - 1 bit gv (gateway valid) = 0
+ // - 1 bit tv (timestamp valid) = 1
+ // TODO: set mr correctly
+ *pFill++ = 0x81;
+ // - 8 bits sequence num = increments with each frame
+ *pFill++ = pStream->avtp_sequence_num;
+ // - 7 bits reserved = 0;
+ // - 1 bit tu (timestamp uncertain) = 1 when no PTP sync
+ // TODO: set tu correctly
+ *pFill++ = 0;
+ // - 8 bytes stream_id
+ memcpy(pFill, (U8 *)&pStream->streamIDnet, 8);
+ break;
+ }
+ AVB_RC_TRACE_RET(OPENAVB_AVTP_SUCCESS, AVB_TRACE_AVTP_DETAIL);
+}
+
+/* Send a frame
+ */
+openavbRC openavbAvtpTx(void *pv, bool bSend, bool txBlockingInIntf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVTP_DETAIL);
+
+ avtp_stream_t *pStream = (avtp_stream_t *)pv;
+ if (!pStream) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AVTP_DETAIL);
+ }
+
+ U8 * pAvtpFrame,*pFill;
+ U32 avtpFrameLen, frameLen;
+ tx_cb_ret_t txCBResult = TX_CB_RET_PACKET_NOT_READY;
+
+ // Get a TX buf if we don't already have one.
+ // (We keep the TX buf in our stream data, so that if we don't
+ // get data from the mapping module, we can use the buf next time.)
+ if (!pStream->pBuf) {
+
+ pStream->pBuf = (U8 *)openavbRawsockGetTxFrame(pStream->rawsock, TRUE, &frameLen);
+ if (!pStream->pBuf) {
+ txCBResult = TX_CB_RET_PACKET_NOT_READY;
+ }
+ else {
+ assert(frameLen >= pStream->frameLen);
+ // Fill in the Ethernet header
+ openavbRawsockTxFillHdr(pStream->rawsock, pStream->pBuf, &pStream->ethHdrLen);
+ }
+ }
+
+ if (pStream->pBuf) {
+ // AVTP frame starts right after the Ethernet header
+ pAvtpFrame = pFill = pStream->pBuf + pStream->ethHdrLen;
+ avtpFrameLen = pStream->frameLen - pStream->ethHdrLen;
+
+ // Fill the AVTP Header. This must be done before calling the interface and mapping modules.
+ openavbRC rc = fillAvtpHdr(pStream, pFill);
+ if (IS_OPENAVB_FAILURE(rc)) {
+ AVB_RC_LOG_TRACE_RET(rc, AVB_TRACE_AVTP_DETAIL);
+ }
+
+ if (!txBlockingInIntf) {
+ // Call interface module to read data
+ pStream->pIntfCB->intf_tx_cb(pStream->pMediaQ);
+ // Call mapping module to move data into AVTP frame
+ txCBResult = pStream->pMapCB->map_tx_cb(pStream->pMediaQ, pAvtpFrame, &avtpFrameLen);
+
+ pStream->bytes += avtpFrameLen;
+ }
+ else {
+ // Blocking in interface mode. Pull from media queue for tx first
+ if ((txCBResult = pStream->pMapCB->map_tx_cb(pStream->pMediaQ, pAvtpFrame, &avtpFrameLen)) == TX_CB_RET_PACKET_NOT_READY) {
+ // Call interface module to read data
+ pStream->pIntfCB->intf_tx_cb(pStream->pMediaQ);
+ }
+ else {
+ pStream->bytes += avtpFrameLen;
+ }
+ }
+
+ // If we got data from the mapping module, notifiy the raw sockets.
+ if (txCBResult != TX_CB_RET_PACKET_NOT_READY) {
+
+ if (pStream->tsEval) {
+ processTimestampEval(pStream, pAvtpFrame);
+ }
+
+ // Increment the sequence number now that we are sure this is a good packet.
+ pStream->avtp_sequence_num++;
+ // Mark the frame "ready to send".
+ openavbRawsockTxFrameReady(pStream->rawsock, pStream->pBuf, avtpFrameLen + pStream->ethHdrLen);
+ // Send if requested
+ if (bSend)
+ openavbRawsockSend(pStream->rawsock);
+ // Drop our reference to it
+ pStream->pBuf = NULL;
+ }
+ else {
+ AVB_RC_TRACE_RET(OPENAVB_AVTP_FAILURE, AVB_TRACE_AVTP_DETAIL);
+ }
+ }
+ else {
+ AVB_RC_TRACE_RET(OPENAVB_AVTP_FAILURE, AVB_TRACE_AVTP_DETAIL);
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVTP_SUCCESS, AVB_TRACE_AVTP_DETAIL);
+}
+
+openavbRC openavbAvtpRxInit(
+ media_q_t *pMediaQ,
+ openavb_map_cb_t *pMapCB,
+ openavb_intf_cb_t *pIntfCB,
+ char *ifname,
+ AVBStreamID_t *streamID,
+ U8 *daddr,
+ U16 nbuffers,
+ bool rxSignalMode,
+ void **pStream_out)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVTP);
+ AVB_LOG_DEBUG("Initialize");
+
+ *pStream_out = NULL;
+
+ if (!pMapCB) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVBAVTP_RC_MAPPING_CB_NOT_SET), AVB_TRACE_AVTP);
+ }
+ if (!pIntfCB) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVBAVTP_RC_INTERFACE_CB_NOT_SET), AVB_TRACE_AVTP);
+ }
+ if (!daddr) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AVTP);
+ }
+
+ avtp_stream_t *pStream = calloc(1, sizeof(avtp_stream_t));
+ if (!pStream) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVB_RC_OUT_OF_MEMORY), AVB_TRACE_AVTP);
+ }
+ pStream->tx = FALSE;
+ pStream->nLost = -1;
+
+ pStream->pMediaQ = pMediaQ;
+ pStream->pMapCB = pMapCB;
+ pStream->pIntfCB = pIntfCB;
+
+ pStream->pMapCB->map_rx_init_cb(pStream->pMediaQ);
+ pStream->pIntfCB->intf_rx_init_cb(pStream->pMediaQ);
+
+ // Set the frame length
+ pStream->frameLen = pStream->pMapCB->map_max_data_size_cb(pStream->pMediaQ) + ETH_HDR_LEN_VLAN;
+
+ // Save the streamID
+ memcpy(pStream->streamIDnet, streamID->addr, ETH_ALEN);
+ U16 *pStreamUID = (U16 *)((U8 *)(pStream->streamIDnet) + ETH_ALEN);
+ *pStreamUID = htons(streamID->uniqueID);
+
+ // and the destination MAC address
+ memcpy(pStream->dest_addr.ether_addr_octet, daddr, ETH_ALEN);
+
+ // and other stuff needed to (re)open the socket
+ pStream->ifname = strdup(ifname);
+ pStream->nbuffers = nbuffers;
+ pStream->bRxSignalMode = rxSignalMode;
+
+ openavbRC rc = openAvtpSock(pStream);
+ if (IS_OPENAVB_FAILURE(rc)) {
+ free(pStream);
+ AVB_RC_LOG_TRACE_RET(rc, AVB_TRACE_AVTP);
+ }
+
+ // Save the AVTP subtype
+ pStream->subtype = pStream->pMapCB->map_subtype_cb();
+
+ *pStream_out = (void *)pStream;
+ AVB_RC_TRACE_RET(OPENAVB_AVTP_SUCCESS, AVB_TRACE_AVTP);
+}
+
+static void x_avtpRxFrame(avtp_stream_t *pStream, U8 *pFrame, U32 frameLen)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVTP_DETAIL);
+ AVB_LOGF_DEBUG("pFrame=%8.8p, len=%u", pFrame, frameLen);
+ U8 subtype, flags, flags2, rxSeq, nLost, avtpVersion;
+ U8 *pRead = pFrame;
+
+ // AVTP Header
+ //
+ // Check control/data bit. We only expect data packets.
+ if (0 == (*pRead & 0x80)) {
+ // - 7 bits subtype
+ subtype = *pRead++ & 0x7F;
+ flags = *pRead++;
+ avtpVersion = (flags >> 4) & 0x07;
+
+ // Check AVTPDU version, BZ 106
+ if (0 == avtpVersion) {
+
+ rxSeq = *pRead++;
+
+ if (pStream->nLost == -1) {
+ // first frame received, don't check for mismatch
+ pStream->nLost = 0;
+ }
+ 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",
+ pStream->avtp_sequence_num, rxSeq, nLost);
+ pStream->nLost += nLost;
+ }
+ pStream->avtp_sequence_num = rxSeq + 1;
+
+ pStream->bytes += frameLen;
+
+ flags2 = *pRead++;
+
+ 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);
+
+ pRead += 8;
+
+ if (pStream->tsEval) {
+ processTimestampEval(pStream, pFrame);
+ }
+
+ 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);
+
+ pStream->info.rx.bComplete = TRUE;
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVBAVTP_RC_INVALID_AVTP_VERSION));
+ }
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVBAVTP_RC_IGNORING_CONTROL_PACKET));
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVTP_DETAIL);
+}
+
+/*
+ * Try to receive some data.
+ *
+ * Keeps state information in pStream.
+ * Look at pStream->info for the received data.
+ */
+static void avtpTryRx(avtp_stream_t *pStream)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVTP_DETAIL);
+
+ U8 *pBuf = NULL; // pointer to buffer containing rcvd frame, if any
+ U8 *pAvtpPdu; // pointer to AVTP PDU within Ethernet frame
+ U32 offsetToFrame; // offset into pBuf where Ethernet frame begins (bytes)
+ U32 frameLen; // length of the Ethernet frame (bytes)
+ int hdrLen; // length of the Ethernet frame header (bytes)
+ U32 avtpPduLen; // length of the AVTP PDU (bytes)
+ hdr_info_t hdrInfo; // Ethernet header contents
+ U32 timeout;
+
+ while (!pBuf) {
+ if (!openavbMediaQUsecTillTail(pStream->pMediaQ, &timeout)) {
+ // No mediaQ item available therefore wait for a new packet
+ timeout = AVTP_MAX_BLOCK_USEC;
+ pBuf = (U8 *)openavbRawsockGetRxFrame(pStream->rawsock, timeout, &offsetToFrame, &frameLen);
+ if (!pBuf) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVTP_DETAIL);
+ return;
+ }
+ }
+ else if (timeout == 0) {
+ // Process the pending media queue item and after check for available incoming packets
+ pStream->pIntfCB->intf_rx_cb(pStream->pMediaQ);
+
+ // Previously would check for new packets but disabled to favor presentation times.
+ // pBuf = (U8 *)openavbRawsockGetRxFrame(pStream->rawsock, OPENAVB_RAWSOCK_NONBLOCK, &offsetToFrame, &frameLen);
+ }
+ else {
+ if (timeout > AVTP_MAX_BLOCK_USEC)
+ 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);
+ }
+ }
+
+ hdrLen = openavbRawsockRxParseHdr(pStream->rawsock, pBuf, &hdrInfo);
+ if (hdrLen < 0) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVBAVTP_RC_PARSING_FRAME_HEADER));
+ }
+ else {
+ pAvtpPdu = pBuf + offsetToFrame + hdrLen;
+ avtpPduLen = frameLen - hdrLen;
+ x_avtpRxFrame(pStream, pAvtpPdu, avtpPduLen);
+ }
+ openavbRawsockRelRxFrame(pStream->rawsock, pBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVTP_DETAIL);
+}
+
+int openavbAvtpTxBufferLevel(void *pv)
+{
+ avtp_stream_t *pStream = (avtp_stream_t *)pv;
+ if (!pStream) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ return 0;
+ }
+ return openavbRawsockTxBufLevel(pStream->rawsock);
+}
+
+int openavbAvtpRxBufferLevel(void *pv)
+{
+ avtp_stream_t *pStream = (avtp_stream_t *)pv;
+ if (!pStream) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ return 0;
+ }
+ return openavbRawsockRxBufLevel(pStream->rawsock);
+}
+
+int openavbAvtpLost(void *pv)
+{
+ avtp_stream_t *pStream = (avtp_stream_t *)pv;
+ if (!pStream) {
+ // Quietly return. Since this can be called before a stream is available.
+ return 0;
+ }
+ int count = pStream->nLost;
+ pStream->nLost = 0;
+ return count;
+}
+
+U64 openavbAvtpBytes(void *pv)
+{
+ avtp_stream_t *pStream = (avtp_stream_t *)pv;
+ if (!pStream) {
+ // Quietly return. Since this can be called before a stream is available.
+ return 0;
+ }
+
+ U64 bytes = pStream->bytes;
+ pStream->bytes = 0;
+ return bytes;
+}
+
+openavbRC openavbAvtpRx(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVTP_DETAIL);
+
+ avtp_stream_t *pStream = (avtp_stream_t *)pv;
+ if (!pStream) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AVTP_DETAIL);
+ }
+
+ // Check our socket, and potentially receive some data.
+ avtpTryRx(pStream);
+
+ // See if there's a complete (re-assembled) data sample.
+ if (pStream->info.rx.bComplete) {
+ pStream->info.rx.bComplete = FALSE;
+ AVB_RC_TRACE_RET(OPENAVB_AVTP_SUCCESS, AVB_TRACE_AVTP_DETAIL);
+ }
+
+ AVB_RC_TRACE_RET(AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVBAVTP_RC_NO_FRAMES_PROCESSED), AVB_TRACE_AVTP_DETAIL);
+}
+
+void openavbAvtpConfigTimsstampEval(void *handle, U32 tsInterval, U32 reportInterval, bool smoothing, U32 tsMaxJitter, U32 tsMaxDrift)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVTP);
+
+ avtp_stream_t *pStream = (avtp_stream_t *)handle;
+ if (!pStream) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AVTP);
+ return;
+ }
+
+ pStream->tsEval = openavbTimestampEvalNew();
+ openavbTimestampEvalInitialize(pStream->tsEval, tsInterval);
+ openavbTimestampEvalSetReport(pStream->tsEval, reportInterval);
+ if (smoothing) {
+ openavbTimestampEvalSetSmoothing(pStream->tsEval, tsMaxJitter, tsMaxDrift);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVTP);
+}
+
+void openavbAvtpPause(void *handle, bool bPause)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVTP);
+
+ avtp_stream_t *pStream = (avtp_stream_t *)handle;
+ if (!pStream) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AVTP);
+ return;
+ }
+
+ pStream->bPause = bPause;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVTP);
+}
+
+void openavbAvtpShutdown(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVTP);
+ AVB_LOG_DEBUG("Shutdown");
+
+ avtp_stream_t *pStream = (avtp_stream_t *)pv;
+ if (pStream) {
+ pStream->pIntfCB->intf_end_cb(pStream->pMediaQ);
+ pStream->pMapCB->map_end_cb(pStream->pMediaQ);
+
+ // close the rawsock
+ if (pStream->rawsock) {
+ openavbRawsockClose(pStream->rawsock);
+ pStream->rawsock = NULL;
+ }
+
+ 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
new file mode 100644
index 00000000..b7d56b89
--- /dev/null
+++ b/lib/avtp_pipeline/avtp/openavb_avtp.h
@@ -0,0 +1,192 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Declare the main functions for AVTP. Includes
+* functions to create/destroy and AVTP stream, and to send or receive
+* data from that AVTP stream.
+*/
+
+#ifndef AVB_AVTP_H
+#define AVB_AVTP_H 1
+
+#include "openavb_platform.h"
+#include "openavb_intf_pub.h"
+#include "openavb_map_pub.h"
+#include "openavb_rawsock.h"
+#include "openavb_timestamp.h"
+
+#define ETHERTYPE_AVTP 0x22F0
+#define ETHERTYPE_8021Q 0x8100
+#define ETHERNET_8021Q_OCTETS 4
+#define TS_PACKET_LEN 188
+#define SRC_PACKET_LEN 192
+#define CIP_HEADER_LEN 8
+
+// Length of Ethernet frame header, with and without 802.1Q tag
+#define ETH_HDR_LEN 14
+#define ETH_HDR_LEN_VLAN 18
+
+// AVTP Headers
+#define AVTP_COMMON_STREAM_DATA_HDR_LEN 24
+
+//#define OPENAVB_AVTP_REPORT_RX_STATS 1
+#define OPENAVB_AVTP_REPORT_INTERVAL 100
+
+typedef struct {
+ // These are significant only for RX data
+ U32 timestamp; // delivery timestamp
+ bool bComplete; // not waiting for more data
+#ifdef OPENAVB_AVTP_REPORT_RX_STATS
+ U32 rxCnt, lateCnt, earlyCnt;
+ U32 maxLate, maxEarly;
+ struct timespec lastTime;
+#endif
+} avtp_rx_info_t;
+
+typedef struct {
+ U8 *data; // pointer to data
+ avtp_rx_info_t rx; // re-assembly info
+} avtp_info_t;
+
+typedef struct {
+ media_q_t mediaq;
+} avtp_state_t;
+
+
+/* Info associated with an AVTP stream (RX or TX).
+ *
+ * The void* handle that is returned to the client
+ * really is a pointer to an avtp_stream_t.
+ *
+ * TODO: This passed around as void * handle can be typed since the avtp_stream_t is
+ * now seen by the talker / listern module.
+ *
+ */
+typedef struct
+{
+ // TX socket?
+ bool tx;
+ // Interface name
+ char* ifname;
+ // Number of rawsock buffers
+ 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
+ struct ether_addr dest_addr;
+ // The AVTP subtype; it determines the encapsulation
+ U8 subtype;
+ // Max Transit - value added to current time to get play time
+ U64 max_transit_usec;
+ // Max frame size
+ U16 frameLen;
+ // AVTP sequence number
+ U8 avtp_sequence_num;
+ // Paused state of the stream
+ bool bPause;
+ // Encapsulation-specific state information
+ avtp_state_t state;
+ // RX info for data sample currently being received
+ avtp_info_t info;
+ // Mapping callbacks
+ openavb_map_cb_t *pMapCB;
+ // Interface callbacks
+ openavb_intf_cb_t *pIntfCB;
+ // MediaQ
+ media_q_t *pMediaQ;
+ bool bRxSignalMode;
+
+ // TX frame buffer
+ U8* pBuf;
+ // Ethernet header length
+ U32 ethHdrLen;
+
+ // Timestamp evaluation related
+ openavb_timestamp_eval_t tsEval;
+
+ // Stat related
+ // RX frames lost
+ int nLost;
+ // Bytes sent or recieved
+ U64 bytes;
+
+} avtp_stream_t;
+
+
+typedef void (*avtp_listener_callback_fn)(void *pv, avtp_info_t *data);
+
+// tx/rx
+openavbRC openavbAvtpTxInit(media_q_t *pMediaQ,
+ openavb_map_cb_t *pMapCB,
+ openavb_intf_cb_t *pIntfCB,
+ char* ifname,
+ AVBStreamID_t *streamID,
+ U8* destAddr,
+ U32 max_transit_usec,
+ U32 fwmark,
+ U16 vlanID,
+ U8 vlanPCP,
+ U16 nbuffers,
+ void **pStream_out);
+
+openavbRC openavbAvtpTx(void *pv, bool bSend, bool txBlockingInIntf);
+
+openavbRC openavbAvtpRxInit(media_q_t *pMediaQ,
+ openavb_map_cb_t *pMapCB,
+ openavb_intf_cb_t *pIntfCB,
+ char* ifname,
+ AVBStreamID_t *streamID,
+ U8* destAddr,
+ U16 nbuffers,
+ bool rxSignalMode,
+ void **pStream_out);
+
+openavbRC openavbAvtpRx(void *handle);
+
+void openavbAvtpConfigTimsstampEval(void *handle, U32 tsInterval, U32 reportInterval, bool smoothing, U32 tsMaxJitter, U32 tsMaxDrift);
+
+void openavbAvtpPause(void *handle, bool bPause);
+
+void openavbAvtpShutdown(void *handle);
+
+int openavbAvtpTxBufferLevel(void *handle);
+
+int openavbAvtpRxBufferLevel(void *handle);
+
+int openavbAvtpLost(void *handle);
+
+U64 openavbAvtpBytes(void *handle);
+
+#endif //AVB_AVTP_H
diff --git a/lib/avtp_pipeline/avtp/openavb_avtp_time.c b/lib/avtp_pipeline/avtp/openavb_avtp_time.c
new file mode 100644
index 00000000..345d0204
--- /dev/null
+++ b/lib/avtp_pipeline/avtp/openavb_avtp_time.c
@@ -0,0 +1,438 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Avtp Time implementation
+*/
+
+#include "openavb_platform.h"
+#include <stdlib.h>
+
+#include "openavb_types.h"
+#include "openavb_trace.h"
+#include "openavb_avtp_time_pub.h"
+
+#define AVB_LOG_COMPONENT "AVTP"
+#include "openavb_log.h"
+
+#define OPENAVB_AVTP_TIME_MAX_TS_DIFF (0x7FFFFFFF)
+
+#include "openavb_avtp_time_osal.c"
+
+static U64 x_getNsTime(timespec_t *tmTime)
+{
+ return ((U64)tmTime->tv_sec * (U64)NANOSECONDS_PER_SECOND) + (U64)tmTime->tv_nsec;
+}
+
+static U32 x_getTimestamp(U64 timeNsec)
+{
+ return (U32)(timeNsec & 0x00000000FFFFFFFFL);
+}
+
+avtp_time_t* openavbAvtpTimeCreate(U32 maxLatencyUsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVTP_TIME);
+
+ avtp_time_t *pAvtpTime = calloc(1, sizeof(avtp_time_t));
+
+ if (pAvtpTime) {
+ pAvtpTime->maxLatencyNsec = maxLatencyUsec * NANOSECONDS_PER_USEC;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVTP_TIME);
+ return pAvtpTime;
+}
+
+void openavbAvtpTimeDelete(avtp_time_t *pAvtpTime)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVTP_TIME);
+
+ if (pAvtpTime) {
+ free(pAvtpTime);
+ pAvtpTime = NULL;
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVTP_TIME);
+}
+
+void openavbAvtpTimeAddUSec(avtp_time_t *pAvtpTime, long uSec)
+{
+ if (pAvtpTime) {
+ pAvtpTime->timeNsec += uSec * NANOSECONDS_PER_USEC;
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ }
+}
+
+void openavbAvtpTimeAddNSec(avtp_time_t *pAvtpTime, long nSec)
+{
+ if (pAvtpTime) {
+ pAvtpTime->timeNsec += nSec;
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ }
+}
+
+void openavbAvtpTimeSubUSec(avtp_time_t *pAvtpTime, long uSec)
+{
+ if (pAvtpTime) {
+ pAvtpTime->timeNsec -= uSec * NANOSECONDS_PER_USEC;
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ }
+}
+
+void openavbAvtpTimeSubNSec(avtp_time_t *pAvtpTime, long nSec)
+{
+ if (pAvtpTime) {
+ pAvtpTime->timeNsec -= nSec;
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ }
+}
+
+
+void openavbAvtpTimeSetToWallTime(avtp_time_t *pAvtpTime)
+{
+ if (pAvtpTime) {
+ timespec_t tmNow;
+ if (CLOCK_GETTIME(OPENAVB_CLOCK_WALLTIME, &tmNow)) {
+ pAvtpTime->timeNsec = x_getNsTime(&tmNow);
+ pAvtpTime->bTimestampValid = TRUE;
+ pAvtpTime->bTimestampUncertain = FALSE;
+ }
+ else {
+ pAvtpTime->bTimestampValid = FALSE;
+ pAvtpTime->bTimestampUncertain = FALSE;
+ }
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ }
+}
+
+void openavbAvtpTimeSetToSystemTime(avtp_time_t *pAvtpTime)
+{
+ if (pAvtpTime) {
+ timespec_t tmNow = {0, 0};
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &tmNow);
+ pAvtpTime->timeNsec = x_getNsTime(&tmNow);
+ pAvtpTime->bTimestampValid = tmNow.tv_sec || tmNow.tv_nsec;
+ pAvtpTime->bTimestampUncertain = FALSE;
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ }
+}
+
+// This function will take a AVTP timestamp and set the local AvtpTime values for it.
+// Commonly this is used in the RX mapping callbacks, to take the AVTP timestamp received
+// on the listener and place it into the AvtpTime so that the media queue and determine
+// the correct time to release the media queue item for presentation.
+void openavbAvtpTimeSetToTimestamp(avtp_time_t *pAvtpTime, U32 timestamp)
+{
+ if (pAvtpTime) {
+ timespec_t tmNow;
+ if (CLOCK_GETTIME(OPENAVB_CLOCK_WALLTIME, &tmNow)) {
+ U64 nsNow = x_getNsTime(&tmNow);
+ U32 tsNow = x_getTimestamp(nsNow);
+
+ U32 delta;
+ if (tsNow < timestamp) {
+ delta = timestamp - tsNow;
+ }
+ else if (tsNow > timestamp) {
+ delta = timestamp + (0x100000000ULL - tsNow);
+ }
+ else {
+ delta = 0;
+ }
+
+ if (delta < OPENAVB_AVTP_TIME_MAX_TS_DIFF) {
+ // Normal case, timestamp is upcoming
+ pAvtpTime->timeNsec = nsNow + delta;
+ }
+ else {
+ // Timestamp is past
+ pAvtpTime->timeNsec = nsNow - (0x100000000ULL - delta);
+ }
+
+ pAvtpTime->bTimestampValid = TRUE;
+ pAvtpTime->bTimestampUncertain = FALSE;
+ }
+ else {
+ pAvtpTime->bTimestampValid = FALSE;
+ pAvtpTime->bTimestampUncertain = TRUE;
+ }
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ }
+}
+
+void openavbAvtpTimeSetToTimestampNS(avtp_time_t *pAvtpTime, U64 timeNS)
+{
+ if (pAvtpTime) {
+ pAvtpTime->timeNsec = timeNS;
+ pAvtpTime->bTimestampValid = TRUE;
+ pAvtpTime->bTimestampUncertain = FALSE;
+ }
+}
+
+void openavbAvtpTimeSetToTimespec(avtp_time_t *pAvtpTime, timespec_t* timestamp)
+{
+ if (pAvtpTime)
+ {
+ if ((timestamp->tv_sec == 0) && (timestamp->tv_nsec == 0))
+ {
+ pAvtpTime->bTimestampValid = FALSE;
+ pAvtpTime->bTimestampUncertain = TRUE;
+ }
+ else
+ {
+ U64 nsec = x_getNsTime(timestamp);
+ pAvtpTime->timeNsec = nsec;
+ pAvtpTime->bTimestampValid = TRUE;
+ pAvtpTime->bTimestampUncertain = FALSE;
+ }
+ }
+ else
+ {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ }
+}
+
+void openavbAvtpTimePushMCR(avtp_time_t *pAvtpTime, U32 timestamp)
+{
+ if (pAvtpTime)
+ {
+ if ( HAL_PUSH_MCR(&timestamp) == FALSE) {
+ AVB_LOG_ERROR("Pushing MCR timestamp");
+ }
+ }
+}
+
+
+void openavbAvtpTimeSetTimestampValid(avtp_time_t *pAvtpTime, bool validFlag)
+{
+ if (pAvtpTime) {
+ pAvtpTime->bTimestampValid = validFlag;
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ }
+}
+
+void openavbAvtpTimeSetTimestampUncertain(avtp_time_t *pAvtpTime, bool uncertainFlag)
+{
+ if (pAvtpTime) {
+ pAvtpTime->bTimestampUncertain = uncertainFlag;
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ }
+}
+
+U32 openavbAvtpTimeGetAvtpTimestamp(avtp_time_t *pAvtpTime)
+{
+ if (pAvtpTime) {
+ return x_getTimestamp(pAvtpTime->timeNsec);
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ return 0;
+ }
+}
+
+U64 openavbAvtpTimeGetAvtpTimeNS(avtp_time_t *pAvtpTime)
+{
+ if (pAvtpTime) {
+ return pAvtpTime->timeNsec;
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ return 0;
+ }
+}
+
+bool openavbAvtpTimeTimestampIsValid(avtp_time_t *pAvtpTime)
+{
+ if (pAvtpTime) {
+ return pAvtpTime->bTimestampValid;
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ return FALSE;
+ }
+}
+
+bool openavbAvtpTimeTimestampIsUncertain(avtp_time_t *pAvtpTime)
+{
+ if (pAvtpTime) {
+ return pAvtpTime->bTimestampUncertain;
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ return TRUE;
+ }
+}
+
+// Check if the AvtpTime is past now. If something goes wrong return true to allow
+// data to continue to flow.
+bool openavbAvtpTimeIsPast(avtp_time_t *pAvtpTime)
+{
+ if (pAvtpTime) {
+ timespec_t tmNow;
+
+ if (!pAvtpTime->bTimestampValid || pAvtpTime->bTimestampUncertain) {
+ return TRUE; // If timestamp can't be trusted assume time is past.
+ }
+
+ if (CLOCK_GETTIME(OPENAVB_CLOCK_WALLTIME, &tmNow)) {
+ U64 nsNow = x_getNsTime(&tmNow);
+
+ if (nsNow >= pAvtpTime->timeNsec) {
+ return TRUE; // Normal timestamp time reached.
+ }
+
+ if (nsNow + pAvtpTime->maxLatencyNsec < pAvtpTime->timeNsec) {
+ IF_LOG_INTERVAL(100) {
+ AVB_LOGF_INFO("Timestamp out of range: Now:%llu TSTime%llu MaxLatency:%lluns Delta:%lluns", nsNow, pAvtpTime->timeNsec, pAvtpTime->maxLatencyNsec, pAvtpTime->timeNsec - nsNow);
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+ else {
+ return TRUE; // If timestamp can't be retrieved assume time is past to keep data flowing.
+ }
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ return TRUE;
+ }
+}
+
+bool openavbAvtpTimeIsPastTime(avtp_time_t *pAvtpTime, U64 nSecTime)
+{
+ if (pAvtpTime) {
+
+ if (!pAvtpTime->bTimestampValid || pAvtpTime->bTimestampUncertain) {
+ return TRUE; // If timestamp can't be trusted assume time is past.
+ }
+
+ if (nSecTime >= pAvtpTime->timeNsec) {
+ return TRUE; // Normal timestamp time reached.
+ }
+
+ if (nSecTime + pAvtpTime->maxLatencyNsec < pAvtpTime->timeNsec) {
+ IF_LOG_INTERVAL(100) {
+ AVB_LOGF_INFO("Timestamp out of range: Now:%llu TSTime%llu MaxLatency:%lluns Delta:%lluns", nSecTime, pAvtpTime->timeNsec, pAvtpTime->maxLatencyNsec, pAvtpTime->timeNsec - nSecTime);
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ return TRUE;
+ }
+}
+
+
+
+bool openavbAvtpTimeUsecTill(avtp_time_t *pAvtpTime, U32 *pUsecTill)
+{
+ if (pAvtpTime) {
+ if (pAvtpTime->bTimestampValid && !pAvtpTime->bTimestampUncertain) {
+
+ timespec_t tmNow;
+
+ if (CLOCK_GETTIME(OPENAVB_CLOCK_WALLTIME, &tmNow)) {
+ U64 nsNow = x_getNsTime(&tmNow);
+
+ if (pAvtpTime->timeNsec >= nsNow) {
+ U32 usecTill = (pAvtpTime->timeNsec - nsNow) / NANOSECONDS_PER_USEC;
+
+ if (usecTill <= MICROSECONDS_PER_SECOND * 5) {
+ *pUsecTill = usecTill;
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+ }
+ else {
+ *pUsecTill = 0;
+ return TRUE;
+ }
+ }
+ }
+
+ // When the timestamp is invalid or uncertain assume timestamp is now.
+ *pUsecTill = 0;
+ return TRUE;
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ return FALSE;
+ }
+}
+
+S32 openavbAvtpTimeUsecDelta(avtp_time_t *pAvtpTime)
+{
+ S32 delta = 0;
+ if (pAvtpTime) {
+ if (pAvtpTime->bTimestampValid && !pAvtpTime->bTimestampUncertain) {
+ timespec_t tmNow;
+
+ if (CLOCK_GETTIME(OPENAVB_CLOCK_WALLTIME, &tmNow)) {
+ U64 nsNow = x_getNsTime(&tmNow);
+
+ delta = (S64)(pAvtpTime->timeNsec - nsNow) / NANOSECONDS_PER_USEC;
+ }
+ }
+ }
+ else {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVTP_TIME_FAILURE | OPENAVBAVTPTIME_RC_INVALID_PTP_TIME));
+ }
+ return delta;
+}
+
+
diff --git a/lib/avtp_pipeline/avtp/openavb_avtp_time_pub.h b/lib/avtp_pipeline/avtp/openavb_avtp_time_pub.h
new file mode 100644
index 00000000..e2ab0c2e
--- /dev/null
+++ b/lib/avtp_pipeline/avtp/openavb_avtp_time_pub.h
@@ -0,0 +1,275 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : AVTP Time public interface
+*/
+
+#ifndef OPENAVB_AVTP_TIME_PUB_H
+#define OPENAVB_AVTP_TIME_PUB_H 1
+
+#include "openavb_platform_pub.h"
+#include "openavb_types_pub.h"
+
+/** \file
+ * AVTP Time public interface.
+ */
+
+/// standard timespec type.
+typedef struct timespec timespec_t;
+
+/** AVTP time structure.
+ */
+typedef struct {
+ /// Time in nanoseconds.
+ U64 timeNsec;
+
+ /// Maximum latency. Timestamps greater than now + max latency will be considered uncertain.
+ U64 maxLatencyNsec;
+
+ /// Timestamp valid.
+ bool bTimestampValid;
+
+ /// Timestamp uncertain.
+ bool bTimestampUncertain;
+} avtp_time_t;
+
+
+/** Create a avtp_time_t structure.
+ *
+ * Allocate storage for a avtp_time_t structure. When a media queue items are
+ * created an avtp_time_t structure is allocated for each item. Interface
+ * modules do not need to be concerned with doing this.
+ *
+ * \param maxLatencyUsec Maximum Latency (in usec) for the avtp_time_t
+ * structure. Timestamps greater than now + maximum latency are
+ * considered uncertain.
+ * \return A pointer to the avtp_time_t structure. Returns NULL if the memory
+ * could not be allocated.
+ */
+avtp_time_t * openavbAvtpTimeCreate(U32 maxLatencyUsec);
+
+/** Delete the time struct.
+ *
+ * Delete the avtp_time_t structure and any additional allocations it owns.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ */
+void openavbAvtpTimeDelete(avtp_time_t *pAvtpTime);
+
+/** Set to wall time (gPTP time).
+ *
+ * Set the time in the avtp_time_t structure to that of the synchronized PTP
+ * time. An interface module will normally use this function to set the time
+ * that media data was placed into the media queue.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ */
+void openavbAvtpTimeSetToWallTime(avtp_time_t *pAvtpTime);
+
+/** Set to system time.
+ *
+ * Set the time in the avtp_time_t structure to that of the system time on the
+ * device.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ */
+void openavbAvtpTimeSetToSystemTime(avtp_time_t *pAvtpTime);
+
+/** Set to timestamp.
+ *
+ * Set the time in the avtp_time_t structure to the value of the timestamp
+ * parameter which is in the same format as an AVTP timestamp.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ * \param timestamp A timestamp in the same format as the 1722 AVTP timestamp.
+ */
+void openavbAvtpTimeSetToTimestamp(avtp_time_t *pAvtpTime, U32 timestamp);
+
+/** Set to timestamp.
+ *
+ * Set the time in the avtp_time_t structure to the value of timespec_t
+ * *timestamp.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ * \param timestamp A timestamp in the timespec_t format.
+ */
+void openavbAvtpTimeSetToTimespec(avtp_time_t *pAvtpTime, timespec_t* timestamp);
+
+/** Push a timestamp, for use in Media Clock Recovery (MCR).
+ * \note Not available in all platforms.
+ *
+ * Push a timestamp, for use in Media Clock Recover (MCR). *pAvtpTime is not
+ * modified.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ * \param timestamp A timestamp in the same format as the 1722 AVTP timestamp.
+ */
+void openavbAvtpTimePushMCR(avtp_time_t *pAvtpTime, U32 timestamp);
+
+/** Set the AVTP timestamp valid indicator.
+ *
+ * Sets the indicator for AVTP timestamp is valid or not.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ * \param validFlag Flag indicating is timestamp is valid.
+ */
+void openavbAvtpTimeSetTimestampValid(avtp_time_t *pAvtpTime, bool validFlag);
+
+/** Set the AVTP timestamp uncertain indicator.
+ *
+ * Sets the indicator for AVTP timestamp is uncertain or not.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ * \param uncertainFlag Flag indicating is timestamp is uncertain.
+ */
+void openavbAvtpTimeSetTimestampUncertain(avtp_time_t *pAvtpTime, bool uncertainFlag);
+
+/** Add microseconds to the time.
+ *
+ * Add the number of microseconds passed in to the time stored in avtp_time_t.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ * \param uSec Number of microseconds to add to the stored time.
+ */
+void openavbAvtpTimeAddUSec(avtp_time_t *pAvtpTime, long uSec);
+
+/** Add nanoseconds to the time.
+ *
+ * Add the number of nanoseconds passed in to the time stored in avtp_time_t.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ * \param nSec Number of nanoseconds to add to the stored time.
+ */
+void openavbAvtpTimeAddNSec(avtp_time_t *pAvtpTime, long nSec);
+
+/** Subtract microseconds from the time
+ *
+ * Subtract the number of microseconds passed in from the time
+ * stored in avtp_time_t.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ * \param uSec Number of microseconds to subtract from the
+ * stored time.
+ */
+void openavbAvtpTimeSubUSec(avtp_time_t *pAvtpTime, long uSec);
+
+/** Subtract nanoseconds from the time
+ *
+ * Subtract the number of nanoseconds passed in from the time
+ * stored in avtp_time_t.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ * \param nSec Number of nanoseconds to subtract from the stored
+ * time.
+ */
+void openavbAvtpTimeSubNSec(avtp_time_t *pAvtpTime, long nSec);
+
+/** Get AVTP timestamp
+ *
+ * Get the time stored in avtp_time_t and return it in an AVTP timestamp format
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ * \return Returns an integer (U32) in the same format as a 1722 AVTP Timestamp.
+ */
+U32 openavbAvtpTimeGetAvtpTimestamp(avtp_time_t *pAvtpTime);
+
+/** Get AVTP timestamp in nanoseconds
+ *
+ * Get the time stored in avtp_time_t and return it as a full time value in nanoseconds
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ * \return Returns an integer (U64) of the full walltime in
+ * nanoseconds.
+ */
+U64 openavbAvtpTimeGetAvtpTimeNS(avtp_time_t *pAvtpTime);
+
+/** Get the AVTP timestamp valid indicator.
+ *
+ * Gets the indicator for AVTP timestamp is valid or not.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ * \return Returns TRUE if the AVTP timestamp valid indicator is set otherwise
+ * FALSE.
+ */
+bool openavbAvtpTimeTimestampIsValid(avtp_time_t *pAvtpTime);
+
+/** Get the AVTP timestamp uncertain indicator.
+ *
+ * Gets the indicator for AVTP timestamp is uncertain or not.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ * \return Returns TRUE if the AVTP timestamp uncertain indicator is set
+ * otherwise FALSE.
+ */
+bool openavbAvtpTimeTimestampIsUncertain(avtp_time_t *pAvtpTime);
+
+/** Check if time is in the past.
+ *
+ * Checks if the time stored in avtp_time_t is past the PTP wall time.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ * \return Returns TRUE if time is in the past otherwise FALSE.
+ */
+bool openavbAvtpTimeIsPast(avtp_time_t *pAvtpTime);
+
+/** Check if time is in the past a specific time (PTP time)
+ *
+ * Checks if the time stored in avtp_time_t is past the time
+ * passed in.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ * \param nSecTime Time in nanoseconds to compare against.
+ * \return Returns TRUE if time is in the past otherwise FALSE.
+ */
+bool openavbAvtpTimeIsPastTime(avtp_time_t *pAvtpTime, U64 nSecTime);
+
+/** Determines microseconds until PTP time.
+ *
+ * Returns the number of microseconds until the time stored in avtp_time_t
+ * reaches the PTP time.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ * \param pUsecTill An output parameter that is set with the number of
+ * microseconds until the time is reached.
+ * \return Return FALSE if greater than 5 second otherwise TRUE.
+ */
+bool openavbAvtpTimeUsecTill(avtp_time_t *pAvtpTime, U32 *pUsecTill);
+
+/** Returns delta from timestamp and now.
+ *
+ * Returns difference between timestamp and current time.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ * \return Difference in microseconds between timestamp and now.
+ */
+S32 openavbAvtpTimeUsecDelta(avtp_time_t *pAvtpTime);
+
+#endif // OPENAVB_AVTP_TIME_PUB_H
diff --git a/lib/avtp_pipeline/avtp_pipeline.mk b/lib/avtp_pipeline/avtp_pipeline.mk
new file mode 100644
index 00000000..b0f4ede0
--- /dev/null
+++ b/lib/avtp_pipeline/avtp_pipeline.mk
@@ -0,0 +1,21 @@
+AVB_FEATURE_ENDPOINT ?= 1
+
+.PHONY: all clean
+
+all: build/Makefile
+ $(MAKE) -s -C build install
+
+doc: build/Makefile
+ $(MAKE) -s -C build doc
+ @echo "\n\nTo display documentation use:\n\n" \
+ "\txdg-open $(abspath build/documents/api_docs/index.html)\n"
+
+clean:
+ $(RM) -r build
+
+build/Makefile:
+ mkdir -p build && \
+ cd build && \
+ cmake -DCMAKE_TOOLCHAIN_FILE=../platform/Linux/x86_i210_linux.cmake \
+ -DAVB_FEATURE_ENDPOINT=$(AVB_FEATURE_ENDPOINT) \
+ ..
diff --git a/lib/avtp_pipeline/cmake/FindALSA.cmake b/lib/avtp_pipeline/cmake/FindALSA.cmake
new file mode 100644
index 00000000..8bdf01aa
--- /dev/null
+++ b/lib/avtp_pipeline/cmake/FindALSA.cmake
@@ -0,0 +1,36 @@
+# - Try to find ALSA
+# Once done, this will define
+#
+# ALSA_FOUND - system has ALSA (GL and GLU)
+# ALSA_INCLUDE_DIRS - the ALSA include directories
+# ALSA_LIBRARIES - link these to use ALSA
+# ALSA_GL_LIBRARY - only GL
+# ALSA_GLU_LIBRARY - only GLU
+#
+# See documentation on how to write CMake scripts at
+# http://www.cmake.org/Wiki/CMake:How_To_Find_Libraries
+
+include(LibFindMacros)
+
+libfind_pkg_check_modules(ALSA alsa)
+
+find_path(ALSA_INCLUDE_DIR
+ NAMES alsa/version.h
+ PATHS ${ALSA_INCLUDE_DIRS}
+)
+
+find_library(ALSA_LIBRARY
+ NAMES asound
+ PATHS ${ALSA_LIBRARY_DIRS}
+)
+
+# Extract the version number
+IF(ALSA_INCLUDE_DIR)
+file(READ "${ALSA_INCLUDE_DIR}/alsa/version.h" _ALSA_VERSION_H_CONTENTS)
+string(REGEX REPLACE ".*#define SND_LIB_VERSION_STR[ \t]*\"([^\n]*)\".*" "\\1" ALSA_VERSION "${_ALSA_VERSION_H_CONTENTS}")
+ENDIF(ALSA_INCLUDE_DIR)
+
+set(ALSA_PROCESS_INCLUDES ALSA_INCLUDE_DIR)
+set(ALSA_PROCESS_LIBS ALSA_LIBRARY)
+libfind_process(ALSA)
+
diff --git a/lib/avtp_pipeline/cmake/FindPCAP.cmake b/lib/avtp_pipeline/cmake/FindPCAP.cmake
new file mode 100644
index 00000000..2be3fe3b
--- /dev/null
+++ b/lib/avtp_pipeline/cmake/FindPCAP.cmake
@@ -0,0 +1,121 @@
+###################################################################
+#
+# Copyright (c) 2006 Frederic Heem, <frederic.heem@telsey.it>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * 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.
+#
+# * Neither the name of the Telsey nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "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 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.
+#
+###################################################################
+# - Find pcap
+# Find the PCAP includes and library
+# http://www.tcpdump.org/
+#
+# The environment variable PCAPDIR allows to specficy where to find
+# libpcap in non standard location.
+#
+# PCAP_INCLUDE_DIRS - where to find pcap.h, etc.
+# PCAP_LIBRARIES - List of libraries when using pcap.
+# PCAP_FOUND - True if pcap found.
+
+
+IF(EXISTS $ENV{PCAPDIR})
+ FIND_PATH(PCAP_INCLUDE_DIR
+ NAMES
+ pcap/pcap.h
+ pcap.h
+ PATHS
+ $ENV{PCAPDIR}
+ NO_DEFAULT_PATH
+ )
+
+ FIND_LIBRARY(PCAP_LIBRARY
+ NAMES
+ pcap
+ PATHS
+ $ENV{PCAPDIR}
+ NO_DEFAULT_PATH
+ )
+
+
+ELSE(EXISTS $ENV{PCAPDIR})
+ FIND_PATH(PCAP_INCLUDE_DIR
+ NAMES
+ pcap/pcap.h
+ pcap.h
+ )
+
+ FIND_LIBRARY(PCAP_LIBRARY
+ NAMES
+ pcap
+ )
+
+ENDIF(EXISTS $ENV{PCAPDIR})
+
+SET(PCAP_INCLUDE_DIRS ${PCAP_INCLUDE_DIR})
+SET(PCAP_LIBRARIES ${PCAP_LIBRARY})
+
+IF(PCAP_INCLUDE_DIRS)
+ MESSAGE(STATUS "Pcap include dirs set to ${PCAP_INCLUDE_DIRS}")
+ELSE(PCAP_INCLUDE_DIRS)
+ MESSAGE(FATAL " Pcap include dirs cannot be found")
+ENDIF(PCAP_INCLUDE_DIRS)
+
+IF(PCAP_LIBRARIES)
+ MESSAGE(STATUS "Pcap library set to ${PCAP_LIBRARIES}")
+ELSE(PCAP_LIBRARIES)
+ MESSAGE(FATAL "Pcap library cannot be found")
+ENDIF(PCAP_LIBRARIES)
+
+#Functions
+INCLUDE(CheckFunctionExists)
+SET(CMAKE_REQUIRED_INCLUDES ${PCAP_INCLUDE_DIRS})
+SET(CMAKE_REQUIRED_LIBRARIES ${PCAP_LIBRARIES})
+CHECK_FUNCTION_EXISTS("pcap_breakloop" HAVE_PCAP_BREAKLOOP)
+CHECK_FUNCTION_EXISTS("pcap_datalink_name_to_val" HAVE_PCAP_DATALINK_NAME_TO_VAL)
+CHECK_FUNCTION_EXISTS("pcap_datalink_val_to_name" HAVE_PCAP_DATALINK_VAL_TO_NAME)
+CHECK_FUNCTION_EXISTS("pcap_findalldevs" HAVE_PCAP_FINDALLDEVS)
+CHECK_FUNCTION_EXISTS("pcap_freecode" HAVE_PCAP_FREECODE)
+CHECK_FUNCTION_EXISTS("pcap_get_selectable_fd" HAVE_PCAP_GET_SELECTABLE_FD)
+CHECK_FUNCTION_EXISTS("pcap_lib_version" HAVE_PCAP_LIB_VERSION)
+CHECK_FUNCTION_EXISTS("pcap_list_datalinks" HAVE_PCAP_LIST_DATALINKS)
+CHECK_FUNCTION_EXISTS("pcap_open_dead" HAVE_PCAP_OPEN_DEAD)
+CHECK_FUNCTION_EXISTS("pcap_set_datalink" HAVE_PCAP_SET_DATALINK)
+
+
+#Is pcap found ?
+IF(PCAP_INCLUDE_DIRS AND PCAP_LIBRARIES)
+ SET( PCAP_FOUND "YES" )
+ENDIF(PCAP_INCLUDE_DIRS AND PCAP_LIBRARIES)
+
+
+MARK_AS_ADVANCED(
+ PCAP_LIBRARIES
+ PCAP_INCLUDE_DIRS
+)
diff --git a/lib/avtp_pipeline/cmake/LibFindMacros.cmake b/lib/avtp_pipeline/cmake/LibFindMacros.cmake
new file mode 100644
index 00000000..69975c51
--- /dev/null
+++ b/lib/avtp_pipeline/cmake/LibFindMacros.cmake
@@ -0,0 +1,99 @@
+# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments
+# used for the current package. For this to work, the first parameter must be the
+# prefix of the current package, then the prefix of the new package etc, which are
+# passed to find_package.
+macro (libfind_package PREFIX)
+ set (LIBFIND_PACKAGE_ARGS ${ARGN})
+ if (${PREFIX}_FIND_QUIETLY)
+ set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} QUIET)
+ endif (${PREFIX}_FIND_QUIETLY)
+ if (${PREFIX}_FIND_REQUIRED)
+ set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED)
+ endif (${PREFIX}_FIND_REQUIRED)
+ find_package(${LIBFIND_PACKAGE_ARGS})
+endmacro (libfind_package)
+
+# CMake developers made the UsePkgConfig system deprecated in the same release (2.6)
+# where they added pkg_check_modules. Consequently I need to support both in my scripts
+# to avoid those deprecated warnings. Here's a helper that does just that.
+# Works identically to pkg_check_modules, except that no checks are needed prior to use.
+macro (libfind_pkg_check_modules PREFIX PKGNAME)
+ if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
+ include(UsePkgConfig)
+ pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS)
+ else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
+ find_package(PkgConfig)
+ if (PKG_CONFIG_FOUND)
+ pkg_check_modules(${PREFIX} ${PKGNAME})
+ endif (PKG_CONFIG_FOUND)
+ endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
+endmacro (libfind_pkg_check_modules)
+
+# Do the final processing once the paths have been detected.
+# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain
+# all the variables, each of which contain one include directory.
+# Ditto for ${PREFIX}_PROCESS_LIBS and library files.
+# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES.
+# Also handles errors in case library detection was required, etc.
+macro (libfind_process PREFIX)
+ # Skip processing if already processed during this run
+ if (NOT ${PREFIX}_FOUND)
+ # Start with the assumption that the library was found
+ set (${PREFIX}_FOUND TRUE)
+
+ # Process all includes and set _FOUND to false if any are missing
+ foreach (i ${${PREFIX}_PROCESS_INCLUDES})
+ if (${i})
+ set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}})
+ mark_as_advanced(${i})
+ else (${i})
+ set (${PREFIX}_FOUND FALSE)
+ endif (${i})
+ endforeach (i)
+
+ # Process all libraries and set _FOUND to false if any are missing
+ foreach (i ${${PREFIX}_PROCESS_LIBS})
+ if (${i})
+ set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}})
+ mark_as_advanced(${i})
+ else (${i})
+ set (${PREFIX}_FOUND FALSE)
+ endif (${i})
+ endforeach (i)
+
+ # Print message and/or exit on fatal error
+ if (${PREFIX}_FOUND)
+ if (NOT ${PREFIX}_FIND_QUIETLY)
+ message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}")
+ endif (NOT ${PREFIX}_FIND_QUIETLY)
+ else (${PREFIX}_FOUND)
+ if (${PREFIX}_FIND_REQUIRED)
+ foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS})
+ message("${i}=${${i}}")
+ endforeach (i)
+ message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.")
+ endif (${PREFIX}_FIND_REQUIRED)
+ endif (${PREFIX}_FOUND)
+ endif (NOT ${PREFIX}_FOUND)
+endmacro (libfind_process)
+
+macro(libfind_library PREFIX basename)
+ set(TMP "")
+ if(MSVC80)
+ set(TMP -vc80)
+ endif(MSVC80)
+ if(MSVC90)
+ set(TMP -vc90)
+ endif(MSVC90)
+ set(${PREFIX}_LIBNAMES ${basename}${TMP})
+ if(${ARGC} GREATER 2)
+ set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2})
+ string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES})
+ set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP})
+ endif(${ARGC} GREATER 2)
+ find_library(${PREFIX}_LIBRARY
+ NAMES ${${PREFIX}_LIBNAMES}
+ PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS}
+ )
+endmacro(libfind_library)
+
diff --git a/lib/avtp_pipeline/documents/CMakeLists.txt b/lib/avtp_pipeline/documents/CMakeLists.txt
new file mode 100644
index 00000000..464532cc
--- /dev/null
+++ b/lib/avtp_pipeline/documents/CMakeLists.txt
@@ -0,0 +1,42 @@
+# add a target to generate API documentation with Doxygen
+find_package(Doxygen)
+
+if(DOXYGEN_FOUND)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/DoxygenLayout.xml
+ ${CMAKE_CURRENT_BINARY_DIR}/DoxygenLayout.xml @ONLY)
+
+add_custom_target(doc
+ ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Generating API documentation with Doxygen" VERBATIM
+)
+
+add_custom_target(pdfdoc
+ make 1>/dev/null 2>/dev/null
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/latex
+ DEPENDS doc
+ COMMENT "Generating PDF document"
+)
+
+install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/api_docs
+ DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR} OPTIONAL)
+
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/latex/refman.pdf
+ DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR}
+ RENAME "OPENAVB EAVB SDK.pdf"
+ OPTIONAL)
+
+install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/api_docs
+ DESTINATION ${SDK_INSTALL_SDK_EAVB_DIR} OPTIONAL)
+
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/latex/refman.pdf
+ DESTINATION ${SDK_INSTALL_SDK_EAVB_DIR}
+ RENAME "OPENAVB EAVB SDK.pdf"
+ OPTIONAL)
+
+
+endif(DOXYGEN_FOUND)
diff --git a/lib/avtp_pipeline/documents/Doxyfile.in b/lib/avtp_pipeline/documents/Doxyfile.in
new file mode 100644
index 00000000..9df638df
--- /dev/null
+++ b/lib/avtp_pipeline/documents/Doxyfile.in
@@ -0,0 +1,341 @@
+# Doxyfile 1.8.6
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+DOXYFILE_ENCODING = UTF-8
+PROJECT_NAME = "Open-AVB AVTP Pipeline SDK"
+PROJECT_NUMBER = 1.4
+PROJECT_BRIEF =
+PROJECT_LOGO = @CMAKE_CURRENT_SOURCE_DIR@/images/harman_logo.png
+OUTPUT_DIRECTORY =
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF =
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = YES
+QT_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+INHERIT_DOCS = YES
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 4
+ALIASES =
+TCL_SUBST =
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+OPTIMIZE_FOR_FORTRAN = NO
+OPTIMIZE_OUTPUT_VHDL = NO
+EXTENSION_MAPPING =
+MARKDOWN_SUPPORT = YES
+AUTOLINK_SUPPORT = YES
+BUILTIN_STL_SUPPORT = NO
+CPP_CLI_SUPPORT = NO
+SIP_SUPPORT = NO
+IDL_PROPERTY_SUPPORT = YES
+DISTRIBUTE_GROUP_DOC = NO
+SUBGROUPING = YES
+INLINE_GROUPED_CLASSES = NO
+INLINE_SIMPLE_STRUCTS = NO
+TYPEDEF_HIDES_STRUCT = YES
+LOOKUP_CACHE_SIZE = 0
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = YES
+EXTRACT_PACKAGE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+EXTRACT_ANON_NSPACES = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+SHOW_GROUPED_MEMB_INC = NO
+FORCE_LOCAL_INCLUDES = NO
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = NO
+SORT_BRIEF_DOCS = NO
+SORT_MEMBERS_CTORS_1ST = NO
+SORT_GROUP_NAMES = NO
+SORT_BY_SCOPE_NAME = NO
+STRICT_PROTO_MATCHING = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_FILES = YES
+SHOW_NAMESPACES = YES
+FILE_VERSION_FILTER =
+LAYOUT_FILE =
+CITE_BIB_FILES =
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = YES
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = @CMAKE_CURRENT_SOURCE_DIR@/index.md \
+ @CMAKE_CURRENT_SOURCE_DIR@/../README.md \
+ @CMAKE_CURRENT_SOURCE_DIR@/sdk_overview.md \
+ @CMAKE_CURRENT_SOURCE_DIR@/sdk_eavb_integration.md \
+ @CMAKE_CURRENT_SOURCE_DIR@/sdk_avtp_stream_cfg.md \
+ @CMAKE_CURRENT_SOURCE_DIR@/sdk_avtp_interface_module_dev.md \
+ @CMAKE_CURRENT_SOURCE_DIR@/sdk_notes.md \
+ @CMAKE_CURRENT_SOURCE_DIR@/sdk_notes_media_queue_usage.md \
+ @CMAKE_CURRENT_SOURCE_DIR@/../map_aaf_audio \
+ @CMAKE_CURRENT_SOURCE_DIR@/../map_ctrl \
+ @CMAKE_CURRENT_SOURCE_DIR@/../map_mjpeg \
+ @CMAKE_CURRENT_SOURCE_DIR@/../map_mpeg2ts \
+ @CMAKE_CURRENT_SOURCE_DIR@/../map_null \
+ @CMAKE_CURRENT_SOURCE_DIR@/../map_pipe \
+ @CMAKE_CURRENT_SOURCE_DIR@/../map_uncmp_audio \
+ @CMAKE_CURRENT_SOURCE_DIR@/../platform/Linux/intf_alsa \
+ @CMAKE_CURRENT_SOURCE_DIR@/../intf_ctrl \
+ @CMAKE_CURRENT_SOURCE_DIR@/../intf_echo \
+ @CMAKE_CURRENT_SOURCE_DIR@/../intf_logger \
+ @CMAKE_CURRENT_SOURCE_DIR@/../intf_null \
+ @CMAKE_CURRENT_SOURCE_DIR@/../intf_tonegen \
+ @CMAKE_CURRENT_SOURCE_DIR@/../intf_viewer \
+ @CMAKE_CURRENT_SOURCE_DIR@/../platform/Linux/intf_mjpeg_gst \
+ @CMAKE_CURRENT_SOURCE_DIR@/../platform/Linux/intf_mpeg2ts_file \
+ @CMAKE_CURRENT_SOURCE_DIR@/../platform/Linux/intf_mpeg2ts_gst \
+ @CMAKE_CURRENT_SOURCE_DIR@/../platform/Linux/intf_wav_file \
+ @CMAKE_CURRENT_SOURCE_DIR@/../include \
+ @CMAKE_CURRENT_SOURCE_DIR@/../avtp \
+ @CMAKE_CURRENT_SOURCE_DIR@/../mediaq \
+ @CMAKE_CURRENT_SOURCE_DIR@/../tl \
+
+INPUT_ENCODING = UTF-8
+FILE_PATTERNS = *_pub.h *.md
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXCLUDE_SYMBOLS =
+EXAMPLE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/../intf_echo \
+ @CMAKE_CURRENT_SOURCE_DIR@/../platform/Linux/avb_host \
+
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/images
+INPUT_FILTER =
+# In markdown files join lines ended with '\'
+FILTER_PATTERNS = "*.md=\"perl -p -e 's/\\\n//'\""
+FILTER_SOURCE_FILES = NO
+FILTER_SOURCE_PATTERNS =
+USE_MDFILE_AS_MAINPAGE =
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+REFERENCES_LINK_SOURCE = YES
+SOURCE_TOOLTIPS = YES
+USE_HTAGS = NO
+VERBATIM_HEADERS = YES
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = api_docs
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_EXTRA_STYLESHEET =
+HTML_EXTRA_FILES =
+HTML_COLORSTYLE_HUE = 220
+HTML_COLORSTYLE_SAT = 100
+HTML_COLORSTYLE_GAMMA = 80
+HTML_TIMESTAMP = YES
+HTML_DYNAMIC_SECTIONS = NO
+HTML_INDEX_NUM_ENTRIES = 100
+GENERATE_DOCSET = NO
+DOCSET_FEEDNAME = "Doxygen generated docs"
+DOCSET_BUNDLE_ID = org.doxygen.Project
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+DOCSET_PUBLISHER_NAME = Publisher
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+CHM_INDEX_ENCODING =
+BINARY_TOC = NO
+TOC_EXPAND = NO
+GENERATE_QHP = NO
+QCH_FILE =
+QHP_NAMESPACE = org.doxygen.Project
+QHP_VIRTUAL_FOLDER = doc
+QHP_CUST_FILTER_NAME =
+QHP_CUST_FILTER_ATTRS =
+QHP_SECT_FILTER_ATTRS =
+QHG_LOCATION =
+GENERATE_ECLIPSEHELP = NO
+ECLIPSE_DOC_ID = org.doxygen.Project
+DISABLE_INDEX = NO
+GENERATE_TREEVIEW = NO
+ENUM_VALUES_PER_LINE = 4
+TREEVIEW_WIDTH = 250
+EXT_LINKS_IN_WINDOW = NO
+FORMULA_FONTSIZE = 10
+FORMULA_TRANSPARENT = YES
+USE_MATHJAX = NO
+MATHJAX_FORMAT = HTML-CSS
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+MATHJAX_EXTENSIONS =
+MATHJAX_CODEFILE =
+SEARCHENGINE = YES
+SERVER_BASED_SEARCH = NO
+EXTERNAL_SEARCH = NO
+SEARCHENGINE_URL =
+SEARCHDATA_FILE = searchdata.xml
+EXTERNAL_SEARCH_ID =
+EXTRA_SEARCH_MAPPINGS =
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = YES
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = YES
+PAPER_TYPE = a4
+EXTRA_PACKAGES =
+LATEX_HEADER =
+LATEX_FOOTER =
+LATEX_EXTRA_FILES =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = YES
+LATEX_SOURCE_CODE = NO
+LATEX_BIB_STYLE = plain
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = YES
+RTF_OUTPUT = rtf
+COMPACT_RTF = YES
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+GENERATE_DOCBOOK = NO
+DOCBOOK_OUTPUT = docbook
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED = __GNUC__=4
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+EXTERNAL_PAGES = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = YES
+MSCGEN_PATH =
+DIA_PATH =
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = NO
+DOT_NUM_THREADS = 0
+DOT_FONTNAME = Helvetica
+DOT_FONTSIZE = 10
+DOT_FONTPATH =
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+UML_LIMIT_NUM_FIELDS = 10
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+CALLER_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = YES
+DOT_IMAGE_FORMAT = png
+INTERACTIVE_SVG = NO
+DOT_PATH =
+DOTFILE_DIRS =
+MSCFILE_DIRS =
+DIAFILE_DIRS =
+DOT_GRAPH_MAX_NODES = 50
+MAX_DOT_GRAPH_DEPTH = 0
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = YES
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
diff --git a/lib/avtp_pipeline/documents/DoxygenLayout.xml b/lib/avtp_pipeline/documents/DoxygenLayout.xml
new file mode 100644
index 00000000..5b5f92b7
--- /dev/null
+++ b/lib/avtp_pipeline/documents/DoxygenLayout.xml
@@ -0,0 +1,194 @@
+<doxygenlayout version="1.0">
+ <!-- Generated by doxygen 1.8.6 -->
+ <!-- Navigation index tabs for HTML output -->
+ <navindex>
+ <tab type="mainpage" visible="yes" title="Table of Contents"/>
+ <tab type="pages" visible="yes" title="Topics" intro=""/>
+ <tab type="modules" visible="yes" title="" intro=""/>
+ <tab type="namespaces" visible="yes" title="">
+ <tab type="namespacelist" visible="yes" title="" intro=""/>
+ <tab type="namespacemembers" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="classes" visible="yes" title="">
+ <tab type="classlist" visible="yes" title="" intro=""/>
+ <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
+ <tab type="hierarchy" visible="yes" title="" intro=""/>
+ <tab type="classmembers" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="files" visible="yes" title="">
+ <tab type="filelist" visible="yes" title="" intro=""/>
+ <tab type="globals" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="examples" visible="yes" title="" intro=""/>
+ </navindex>
+
+ <!-- Layout definition for a class page -->
+ <class>
+ <briefdescription visible="yes"/>
+ <includes visible="$SHOW_INCLUDE_FILES"/>
+ <inheritancegraph visible="$CLASS_GRAPH"/>
+ <collaborationgraph visible="$COLLABORATION_GRAPH"/>
+ <memberdecl>
+ <nestedclasses visible="yes" title=""/>
+ <publictypes title=""/>
+ <services title=""/>
+ <interfaces title=""/>
+ <publicslots title=""/>
+ <signals title=""/>
+ <publicmethods title=""/>
+ <publicstaticmethods title=""/>
+ <publicattributes title=""/>
+ <publicstaticattributes title=""/>
+ <protectedtypes title=""/>
+ <protectedslots title=""/>
+ <protectedmethods title=""/>
+ <protectedstaticmethods title=""/>
+ <protectedattributes title=""/>
+ <protectedstaticattributes title=""/>
+ <packagetypes title=""/>
+ <packagemethods title=""/>
+ <packagestaticmethods title=""/>
+ <packageattributes title=""/>
+ <packagestaticattributes title=""/>
+ <properties title=""/>
+ <events title=""/>
+ <privatetypes title=""/>
+ <privateslots title=""/>
+ <privatemethods title=""/>
+ <privatestaticmethods title=""/>
+ <privateattributes title=""/>
+ <privatestaticattributes title=""/>
+ <friends title=""/>
+ <related title="" subtitle=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ <memberdef>
+ <inlineclasses title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <services title=""/>
+ <interfaces title=""/>
+ <constructors title=""/>
+ <functions title=""/>
+ <related title=""/>
+ <variables title=""/>
+ <properties title=""/>
+ <events title=""/>
+ </memberdef>
+ <allmemberslink visible="yes"/>
+ <usedfiles visible="$SHOW_USED_FILES"/>
+ <authorsection visible="yes"/>
+ </class>
+
+ <!-- Layout definition for a namespace page -->
+ <namespace>
+ <briefdescription visible="yes"/>
+ <memberdecl>
+ <nestednamespaces visible="yes" title=""/>
+ <constantgroups visible="yes" title=""/>
+ <classes visible="yes" title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ <memberdef>
+ <inlineclasses title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ </memberdef>
+ <authorsection visible="yes"/>
+ </namespace>
+
+ <!-- Layout definition for a file page -->
+ <file>
+ <briefdescription visible="yes"/>
+ <includes visible="$SHOW_INCLUDE_FILES"/>
+ <includegraph visible="$INCLUDE_GRAPH"/>
+ <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
+ <sourcelink visible="yes"/>
+ <memberdecl>
+ <classes visible="yes" title=""/>
+ <namespaces visible="yes" title=""/>
+ <constantgroups visible="yes" title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ <memberdef>
+ <inlineclasses title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ </memberdef>
+ <authorsection/>
+ </file>
+
+ <!-- Layout definition for a group page -->
+ <group>
+ <briefdescription visible="yes"/>
+ <groupgraph visible="$GROUP_GRAPHS"/>
+ <memberdecl>
+ <nestedgroups visible="yes" title=""/>
+ <dirs visible="yes" title=""/>
+ <files visible="yes" title=""/>
+ <namespaces visible="yes" title=""/>
+ <classes visible="yes" title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <enumvalues title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <signals title=""/>
+ <publicslots title=""/>
+ <protectedslots title=""/>
+ <privateslots title=""/>
+ <events title=""/>
+ <properties title=""/>
+ <friends title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ <memberdef>
+ <pagedocs/>
+ <inlineclasses title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <enumvalues title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <signals title=""/>
+ <publicslots title=""/>
+ <protectedslots title=""/>
+ <privateslots title=""/>
+ <events title=""/>
+ <properties title=""/>
+ <friends title=""/>
+ </memberdef>
+ <authorsection visible="yes"/>
+ </group>
+
+ <!-- Layout definition for a directory page -->
+ <directory>
+ <briefdescription visible="yes"/>
+ <directorygraph visible="yes"/>
+ <memberdecl>
+ <dirs visible="yes"/>
+ <files visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ </directory>
+</doxygenlayout>
diff --git a/lib/avtp_pipeline/documents/Release Notes.docx b/lib/avtp_pipeline/documents/Release Notes.docx
new file mode 100644
index 00000000..0edfb800
--- /dev/null
+++ b/lib/avtp_pipeline/documents/Release Notes.docx
Binary files differ
diff --git a/lib/avtp_pipeline/documents/images/AVTP_Data_Flow.png b/lib/avtp_pipeline/documents/images/AVTP_Data_Flow.png
new file mode 100644
index 00000000..2b19d9e0
--- /dev/null
+++ b/lib/avtp_pipeline/documents/images/AVTP_Data_Flow.png
Binary files differ
diff --git a/lib/avtp_pipeline/documents/images/Core_AVB.png b/lib/avtp_pipeline/documents/images/Core_AVB.png
new file mode 100644
index 00000000..cfb6f96c
--- /dev/null
+++ b/lib/avtp_pipeline/documents/images/Core_AVB.png
Binary files differ
diff --git a/lib/avtp_pipeline/documents/images/Listener_Stream_Data_Flow.png b/lib/avtp_pipeline/documents/images/Listener_Stream_Data_Flow.png
new file mode 100644
index 00000000..7594107b
--- /dev/null
+++ b/lib/avtp_pipeline/documents/images/Listener_Stream_Data_Flow.png
Binary files differ
diff --git a/lib/avtp_pipeline/documents/images/Stream_Initialize.png b/lib/avtp_pipeline/documents/images/Stream_Initialize.png
new file mode 100644
index 00000000..3b6c80f8
--- /dev/null
+++ b/lib/avtp_pipeline/documents/images/Stream_Initialize.png
Binary files differ
diff --git a/lib/avtp_pipeline/documents/images/Talker_Stream_Data_Flow.png b/lib/avtp_pipeline/documents/images/Talker_Stream_Data_Flow.png
new file mode 100644
index 00000000..e1a9cc5c
--- /dev/null
+++ b/lib/avtp_pipeline/documents/images/Talker_Stream_Data_Flow.png
Binary files differ
diff --git a/lib/avtp_pipeline/documents/images/fig1.png b/lib/avtp_pipeline/documents/images/fig1.png
new file mode 100644
index 00000000..33ae6d37
--- /dev/null
+++ b/lib/avtp_pipeline/documents/images/fig1.png
Binary files differ
diff --git a/lib/avtp_pipeline/documents/images/fig2.png b/lib/avtp_pipeline/documents/images/fig2.png
new file mode 100644
index 00000000..1aecb34d
--- /dev/null
+++ b/lib/avtp_pipeline/documents/images/fig2.png
Binary files differ
diff --git a/lib/avtp_pipeline/documents/images/harman_logo.png b/lib/avtp_pipeline/documents/images/harman_logo.png
new file mode 100644
index 00000000..6c4f4105
--- /dev/null
+++ b/lib/avtp_pipeline/documents/images/harman_logo.png
Binary files differ
diff --git a/lib/avtp_pipeline/documents/index.md b/lib/avtp_pipeline/documents/index.md
new file mode 100644
index 00000000..57757484
--- /dev/null
+++ b/lib/avtp_pipeline/documents/index.md
@@ -0,0 +1,51 @@
+Contents {#mainpage}
+========
+
+- [EAVB SDK Overview](@ref sdk_overview)
+ - [Introduction](@ref sdk_overview_introduction)
+ - [Glossary](@ref sdk_overview_glossary)
+ - [Architecture](@ref sdk_overview_architecture)
+ - [Integration, Extension and Configuration](@ref sdk_overview_integration)
+ - [Platform Specific Considerations](@ref sdk_overview_platform)
+- [EAVB Integration](@ref sdk_integration)
+ - [Introduction] (@ref sdk_integration_introduction)
+ - [AVTP Control] (@ref sdk_integration_avtp_control)
+ - [Host Application Integration] (@ref sdk_integration_host_app)
+- [AVTP Interface Module Development](@ref sdk_avtp_interface_module_dev)
+ - [Introduction] (@ref sdk_avtp_intf_module_introduction)
+ - [The Plug-in Architecture] (@ref sdk_avtp_intf_module_plugin)
+ - [Task / Thread Model] (@ref sdk_avtp_intf_module_task)
+ - [Building an Interface Module] (@ref sdk_avtp_intf_module_building)
+ - [Interface Module in a Talker] (@ref sdk_avtp_intf_module_talker)
+ - [Interface Module in a Listener] (@ref sdk_avtp_intf_module_listener)
+ - [Working With the Media Queue] (@ref working_with_mediaq)
+ - [Timestamps] (@ref sdk_avtp_intf_module_timestamps)
+- [AVTP Stream (Talker/Listener) Configuration](@ref sdk_avtp_stream_cfg)
+ - [Overview](@ref sdk_avtp_stream_cfg_overview)
+ - [Example Interface Mapping Combinations](@ref sdk_avtp_stream_cfg_combinations)
+ - [Common Stream Configuration](@ref sdk_avtp_stream_cfg_common)
+ - [Interface and Mapping Module Configuration] (@ref sdk_avtp_stream_cfg_intf_map)
+ - Reference: AVTP Mapping Modules
+ - [1722 AAF (aaf_audio)](@ref aaf_audio_map)
+ - [Control (ctrl)](@ref ctrl_map)
+ - [Motion JPEG (mjpeg)](@ref mjpeg_map)
+ - [MPEG2 TS (mpeg2ts)](@ref mpeg2ts_map)
+ - [NULL (null)](@ref null_map)
+ - [PIPE (pipe)](@ref pipe_map)
+ - [61883-6 (uncmp_audio)](@ref uncmp_audio_map)
+ - Reference: AVTP Interface Module
+ - [Control (ctrl)](@ref ctrl_intf)
+ - [Echo (echo)](@ref echo_host_intf)
+ - [Logger (logger)](@ref logger_intf)
+ - [Null (null)](@ref null_host_intf)
+ - [Tone Generator (tonegen)](@ref tonegen_intf)
+ - [Viewer (viewer)](@ref viewer_intf)
+ - Reference: AVTP Interface Module Linux Specific
+ - [ALSA (alsa)](@ref alsa_intf)
+ - [MJPEG GST (mjpeg_gstreamer)](@ref mjpeg_gst_intf)
+ - [MPEG2 TS File (mpeg2ts_file)](@ref mpeg2ts_file_intf)
+ - [MPEG2 TS GST (mpeg2ts_gstreamer)](@ref mpeg2ts_gst_intf)
+ - [WAV File (wav_file)](@ref wav_file_intf)
+- [Developer Notes](@ref sdk_notes)
+
+
diff --git a/lib/avtp_pipeline/documents/sdk_avtp_interface_module_dev.md b/lib/avtp_pipeline/documents/sdk_avtp_interface_module_dev.md
new file mode 100644
index 00000000..4e6fb69f
--- /dev/null
+++ b/lib/avtp_pipeline/documents/sdk_avtp_interface_module_dev.md
@@ -0,0 +1,165 @@
+AVTP Interface Module Development {#sdk_avtp_interface_module_dev}
+=================================
+
+Introduction {#sdk_avtp_intf_module_introduction}
+============
+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
+form of interface modules. This allows for easily hooking into the AVB stack to
+extend it for interfacing to media specific hardware.
+
+Mapping modules, which are mentioned through-out these guides, are also
+plug-ins. These implement the various AVTP encapsulations and require a deep
+understanding of AVTP and therefore are developed internally by OPENAVB.
+
+Interface modules are discovered at runtime using configuration information
+that is passed to the openavbTLOpen() function. Below is an example of a section of
+the configuration information with interface module values.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+// pIntfInitFn : Interface module initialization function.
+// openavb_intf_initialize_fn_t)
+cfg->osalCfg.pIntfInitFn = openavbIntfJ6Video;
+
+///////////////////
+// Interface module
+///////////////////
+
+// intf_nv_blocking_tx_callback : A talker only option. When set packet pacing
+// is expected to be handled in the interface module.
+// Commonly the TL configuration option tx_blocking_in_intf needs to be set
+// to match this.
+// cfg->libCfgNames[cfgIdx] = "intf_nv_blocking_tx_callback";
+// cfg->libCfgValues[cfgIdx++] = "1";
+
+// intf_nv_ignore_timestamp : If set the listener will ignore the timestamp
+// on media queue items.
+cfg->libCfgNames[cfgIdx] = "intf_nv_ignore_timestamp";
+cfg->libCfgValues[cfgIdx++] = "0";
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The function pointer variable `pIntfInitFn` points to the interface module
+initialization function.
+
+When the talker/listener module calls the interface module initialization
+function it passes in a callback structure as a parameter that must get filled
+with the required callback function addresses by the interface module.
+
+After initialization the talker/listener module will call directly into the
+interface module via these callbacks. See the API reference section for details
+and examples of these callbacks.
+
+The callback functions in an interface module, aside from the initialization
+call, receives a pointer to a media queue structure. This structure is
+self-contained, similar to an object in C++, in that it includes a function
+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
+for interface modules is very simple. All callbacks will occur on the same task
+and therefore there are no synchronization concerns. However, access to media
+sources and media sinks can have demanding timing and processing requirements
+and it may be necessary for an interface module to have complete control over an
+execution task to ensure timely pulling or pushing data into the media hardware
+or driver. In those cases the interface module may find it a benefit to create
+its own task or tasks.
+
+When an interface module has its own task the point of synchronization between
+the callback thread and the interface module private thread would be the
+sharing of a media queue item pointer. When a head or tail item is locked a
+pointer to that media queue item is returned. At that point the data area for
+that item remains locked and can be used by another task beyond the scope of
+the callback into the interface module. The media queue item will remain locked
+until unlocked (or pushed or pulled). The media queue itself can't be locked,
+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
+interface module can be built as a static library and include all the required
+callbacks as defined in the reference section of this document.
+
+Access to all functionality in the AVB stack from an interface module is also
+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
+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.
+The media queue is the only entry point for interface modules to call into the
+AVB stack and allows for pushing or pulling media data though it as well as
+access to time functionality in the AVTP time structure.
+
+The media queue is internally implemented as a circular FIFO container. The
+format of the data for items in the media queue is defined by the mapping
+module being used in the talker/listener. For some mapping modules the data
+format of an item will match the defined AVB encapsulation. For example the
+MPEG2-TS (61883-4) mapping module data format of media queue items are simple
+192 byte MPEG2-TS source packets. Each media queue item contains one or more
+MPEG2-TS source packet. The actual MPEG2-TS mapping may combine multiple source
+packets into one AVTP packet but that is hidden from the interface module.
+
+The media queue functions are accessed as API calls.
+
+For example, the openavbMediaQHeadLock() function is called as:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ openavbMediaQHeadLock(pMediaQ);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The pMediaQ pointer is passed to all of the interface module callbacks.
+
+Access to the queue items is accomplished with the Head functions for pushing
+data into the media queue. These are used by interface modules running in a
+talker. To read items from the media queue the Tail functions are used by
+interface modules running in a listener.
+
+At any one time only 2 items are accessible in the media queue. These are the
+head item and tail item. Care must be taken to always match up the
+openavbMediaQHeadLock() with a openavbMediaQHeadUnlock() or openavbMediaQHeadPush()
+functions. The same applies that the openavbMediaQTailLock() must be paired with
+either a openavbMediaQTailPull() or openavbMediaQTailUnlock() functions. This means
+a new item can not be added to the media queue until a openavbMediaQHeadPush()
+is called and a new item can not be pulled from the media queue until
+openavbMediaQTailPull() is called.
+
+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
+PTP time to the items added to the media queue when running as a talker. For
+example:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In most cases the mapping modules and media queue take care of the rest of the
+requirements for AVTP.
+
+[Source code](@ref openavb_intf_echo.c)
diff --git a/lib/avtp_pipeline/documents/sdk_avtp_stream_cfg.md b/lib/avtp_pipeline/documents/sdk_avtp_stream_cfg.md
new file mode 100644
index 00000000..f96d0a0e
--- /dev/null
+++ b/lib/avtp_pipeline/documents/sdk_avtp_stream_cfg.md
@@ -0,0 +1,343 @@
+AVTP Stream (Talker/Listener) Configuration {#sdk_avtp_stream_cfg}
+===========================================
+
+Overview {#sdk_avtp_stream_cfg_overview}
+========
+
+The configuration of streams (talkers and listeners) is controlled via the
+structure @ref openavb_tl_cfg_t that is passed to the @ref openavbTLConfigure function.
+There are 3 major sections within the configuration structure. The general
+talker / listener (AVTP stream) section, the mapping module section and the
+interface module section. The general section has settings used by the
+talker/listener module directly. The mapping module section has settings
+specific to the mapping module being used for the stream and the interface
+module section has settings specific to the interface module being used for the
+stream.
+
+How the @ref openavb_tl_cfg_t structure gets set is platform dependent. For the
+Linux reference implementation reading from .ini files is supported which in
+turn fills this structure. For RTOSes the stream configuration structure is
+usually set directly via code in the AVB host application module. Therefore the
+use of .ini files is a layer above the what the core AVB stack uses. The Release
+Notes for the AVB port should be referenced with regards to where the
+configuration values can be set.
+
+
+Here is a sample configuration structure initialization for a H.264 listener.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+void h264_SampleListenerCfg(openavb_tl_cfg_t *cfg)
+{
+ // Clear our the configuration structure to ensure defaults (0)
+ memset(cfg, 0, sizeof(openavb_tl_cfg_t));
+
+ // This must be set to the multicast address that is used
+ U8 multicastStrmAddr[] = { 0x91, 0xE0, 0xF0, 0x00, 0xFE, 0x00 };
+
+ ///////////////////
+ // TL (Talker / Listener) Configuration
+ ///////////////////
+
+ // Identify the role of the stream (talker or listener)
+ // must be set to AVB_ROLE_LISTENER or AVB_ROLE_TALKER
+ cfg->role = AVB_ROLE_LISTENER;
+
+ memcpy(cfg->stream_addr.buffer.ether_addr_octet, multicastStrmAddr, ETH_ALEN);
+ cfg->stream_addr.mac = &cfg->stream_addr.buffer;
+
+ // max_interval_frames: The maximum number of packets that will be sent during
+ // an observation interval. This is only used on the talker.
+ // cfg->max_interval_frames = 1;
+
+ // max_transit_usec: Allows manually specifying a maximum transit time.
+ // 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
+ // max transit time.
+ cfg->max_transit_usec = 2000;
+
+ // max_transmit_deficit_usec: Allows setting the maximum packet transmit rate deficit that will
+ // be recovered when a talker falls behind. This is only used on a talker side. 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. Typically this value can be set to the expected buffer size (in usec) that listeners are
+ // expected to be buffering. 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.
+ // cfg->max_transmit_deficit_usec = 2000;
+
+ // internal_latency: Allows mannually specifying an internal latency time. This is used
+ // only on the talker.
+ // cfg->internal_latency = 0;
+
+ // The number of microseconds a media queue items can be passed the presentation time at which
+ // point it will be purged.
+ cfg->max_stale = 500;
+
+ // number of intervals to handle at once (talker)
+ // cfg->batch_factor = 1;
+
+ // report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+ cfg->report_seconds = 0;
+
+ // sr_class: A talker only setting. Values are either SR_CLASS_A or SR_CLASS_B.
+ // cfg->sr_class = SR_CLASS_A;
+
+ // raw_tx_buffers: The number of raw socket transmit buffers.
+ // cfg->raw_tx_buffers = 40;
+
+ // raw_rx_buffers: The number of raw socket receive buffers.
+ cfg->raw_rx_buffers = 40;
+
+ // tx_blocking_in_intf : A talker only option. When set packet pacing is expected to be handled in the interface module.
+ // Commonly there will be a matching interface module configuration item that needs to be set.
+ // cfg->tx_blocking_in_intf = FALSE;
+
+ ///////////////////
+ // The remaining configuration items vary depending on the mapping module and interface module being used.
+ // These configuration values are populated as name value pairs.
+ ///////////////////
+
+ // Configuration index counter.
+ int cfgIdx = 0;
+
+ ///////////////////
+ // Mapping module
+ ///////////////////
+ // map_nv_item_count: The number of media queue elements to hold.
+ cfg->libCfgNames[cfgIdx] = "map_nv_item_count";
+ cfg->libCfgValues[cfgIdx++] = "10";
+
+ // map_nv_tx_rate: Transmit rate. Typically this is set to match the SR Class. 8000 for A and 4000 for B
+ // 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
+ cfg->libCfgNames[cfgIdx] = "map_nv_max_payload_size";
+ cfg->libCfgValues[cfgIdx++] = "1412";
+
+ ///////////////////
+ // Interface module
+ ///////////////////
+
+ // intf_nv_blocking_tx_callback : A talker only option. When set packet pacing is expected to be handled in the interface module.
+ // Commonly the TL configuration option tx_blocking_in_intf needs to be set to match this.
+ // cfg->libCfgNames[cfgIdx] = "intf_nv_blocking_tx_callback";
+ // cfg->libCfgValues[cfgIdx++] = "1";
+
+ // intf_nv_ignore_timestamp : If set the listener will ignore the timestamp on media queue items.
+ cfg->libCfgNames[cfgIdx] = "intf_nv_ignore_timestamp";
+ cfg->libCfgValues[cfgIdx++] = "0";
+
+ cfg->nLibCfgItems = cfgIdx;
+
+ ///////////////////
+ // Mapping and interface modules main initialization entry points
+ ///////////////////
+
+ // pMapInitFn : Mapping module initialization function. (openavb_map_initialize_fn_t)
+ cfg->osalCfg.pMapInitFn = openavbMapH264Initialize;
+
+ // pIntfInitFn : Interface module initialization function. (openavb_intf_initialize_fn_t)
+ cfg->osalCfg.pIntfInitFn = openavbIntfJ6Video;
+}
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+<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.
+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.
+
+
+<br>
+# Platform Specific Stream Configuration Values
+Some platform ports have unique configuration values.
+
+## Linux
+
+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_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_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
+interface module may work with mutliple mapping modules. Additionally some
+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
+
+
+<br>
+Interface and Mapping Module Configuration {#sdk_avtp_stream_cfg_intf_map}
+==========================================
+
+Each interface module and mapping module has unique configuration values.
+Details of these configuration values can be found in the reference pages for
+each module.
+
+- Reference: AVTP Mapping Modules
+ - [1722 AAF (aaf_audio)](@ref aaf_audio_map)
+ - [Control (ctrl)](@ref ctrl_map)
+ - [Motion JPEG (mjpeg)](@ref mjpeg_map)
+ - [MPEG2 TS (mpeg2ts)](@ref mpeg2ts_map)
+ - [NULL (null)](@ref null_map)
+ - [PIPE (pipe)](@ref pipe_map)
+ - [61883-6 (uncmp_audio)](@ref uncmp_audio_map)
+- Reference: AVTP Interface Module
+ - [Control (ctrl)](@ref ctrl_intf)
+ - [Echo (echo)](@ref echo_host_intf)
+ - [Null (null)](@ref null_host_intf)
+ - [Viewer (viewer)](@ref viewer_intf)
+- Reference: AVTP Interface Module Linux Specific
+ - [ALSA (alsa)](@ref alsa_intf)
+ - [MJPEG GST (mjpeg_gstreamer)](@ref mjpeg_gst_intf)
+ - [MPEG2 TS File (mpeg2ts_file)](@ref mpeg2ts_file_intf)
+ - [MPEG2 TS GST (mpeg2ts_gstreamer)](@ref mpeg2ts_gst_intf)
+ - [WAV File (wav_file)](@ref wav_file_intf)
+
+
diff --git a/lib/avtp_pipeline/documents/sdk_eavb_integration.md b/lib/avtp_pipeline/documents/sdk_eavb_integration.md
new file mode 100644
index 00000000..c1200834
--- /dev/null
+++ b/lib/avtp_pipeline/documents/sdk_eavb_integration.md
@@ -0,0 +1,31 @@
+EAVB Integration Guide {#sdk_integration}
+======================
+
+Introduction {#sdk_integration_introduction}
+============
+Integrating the OPENAVB AVB stack into a larger solution can be conceptually divided
+into 2 parts. The first is the configuration and start up of the AVB components
+such as gPTP and AVTP. The second part is the configuration of the streams that
+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
+done indirectly when opening, running and closing talkers and listeners. The
+general flow is:
+1. openavbTLInitialize() is called to initialize the openavb_tl module.
+2. openavbTLOpen() is called one or more times to load talkers and listeners.
+3. openavbTLConfigure() is called for each talker or listener.
+4. openavbTLRun() is called for each talker and listener to start their stream.
+5. openavbTLClose() is called for each talker and listener to stop the stream and
+ close.
+
+<br>
+Host Application Integration {#sdk_integration_host_app}
+============================
+Controlling the non-AVTP components of the AVB stack are platform dependent.
+Release notes for the specific port should be referenced for those details.
+
+
diff --git a/lib/avtp_pipeline/documents/sdk_notes.md b/lib/avtp_pipeline/documents/sdk_notes.md
new file mode 100644
index 00000000..f1c9a300
--- /dev/null
+++ b/lib/avtp_pipeline/documents/sdk_notes.md
@@ -0,0 +1,7 @@
+Developer Notes {#sdk_notes}
+===============
+
+These are additional topics from the trenches but the details have not yet been incorporated into the formal SDK documentation sections.
+
+- [Media Queue Usage](@ref sdk_notes_media_queue_usage)
+
diff --git a/lib/avtp_pipeline/documents/sdk_notes_media_queue_usage.md b/lib/avtp_pipeline/documents/sdk_notes_media_queue_usage.md
new file mode 100644
index 00000000..aaa4cda8
--- /dev/null
+++ b/lib/avtp_pipeline/documents/sdk_notes_media_queue_usage.md
@@ -0,0 +1,124 @@
+Media Queue Usage {#sdk_notes_media_queue_usage}
+=================
+
+# Description
+
+This section presents the work flow required for working with the Media Queue.
+Please note that most of the described steps are performed inside the AVB stack
+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.
+* [Starting](@ref media_queue_usage_start) - Initialization common for talker
+and listener streams
+* [Talker specific](@ref media_queue_usage_talker) - Talker specific usage
+* [Listener specific](@ref media_queue_usage_listener) - Listener specific usage
+* [Stopping](@ref media_queue_usage_stop) - Stopping procedure common for talker
+and listener streams
+* [Rules](@ref media_queue_usage_rules) - general rules to follow while using
+the Media Queue
+
+<br>
+Starting {#media_queue_usage_start}
+========
+
+First the Media Queue has to be created and initialized with correct data. Below
+are the function calls needed for proper creation and initialization. Note:
+these calls are initiated from the AVTP module.
+
+* @ref openavbMediaQCreate - data is allocated, queue is initialized, internal data
+structures are prepared
+* @ref openavbMediaQSetMaxStaleTail - sets maximum stale in microseconds before data
+is being purged
+* The Interface module initialization function for this media queue is called
+with media queue as a parameter, those functions
+ * Set internal interface module parameters
+ * Initialize Media Queue
+ * Creates Media Queue Interface Module Private Data
+ * Fills the private data structure with information needed by interface
+ module
+* Stream configuration values are processed. This actually configuration data
+may come from .ini files or internally set within the AVB host application.
+* Mapping module init function openavb_map_cb_t::map_gen_init_cb is being called
+during which several steps (media queue parameters **have to** be set)
+ * Media Queue Items count is set
+ * Media Queue Items are allocated
+* Interface module init function openavb_intf_cb_t::intf_gen_init_cb function is
+called
+
+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}
+====================
+
+As a talker, an interface module is responsible for writing data to Media Queue,
+so important steps are:
+
+* @ref openavbMediaQHeadLock function for getting the head of the media queue and
+marking it as locked
+* @ref openavbMediaQHeadUnlock function which releases head. Any subsequent calls to
+@ref openavbMediaQHeadLock will return the same MediaQueueItem
+* @ref openavbMediaQHeadPush function unlocks head previously taken by the Lock
+function and informs that work on the current Item is finished so that next call
+to @ref openavbMediaQHeadLock will return next Media Queue Item. Call of this
+function makes the item accessible via the @ref openavbMediaQTailLock function. This
+function additionally unlocks the head so the @ref openavbMediaQHeadUnlock call is
+not needed
+
+<br>
+Listener specific flow {#media_queue_usage_listener}
+======================
+
+As a listener, an interface module works on Media Queue tail elements. Data in
+those items is being written by the mapping module. These are the key Media
+Queue functions for the listener functionality in an interface module:
+
+* @ref openavbMediaQTailLock gets an item from the tail and allows working on
+the current tail item of the Media Queue
+* @ref openavbMediaQTailUnlock unlocks the tail element in MediaQueue which means
+that interface module has stopped working on it for now but processing of
+current tail element will be continued later
+* @ref openavbMediaQTailPull unlocks the tail element and removes it from the Media
+Queue. This means that the interface module has finished processing of current
+tail element and it can be rewritten again by new data. This function
+additionally unlocks tail, so it is not necessary to call @ref
+openavbMediaQTailUnlock.
+
+<br>
+Stopping {#media_queue_usage_stop}
+========
+
+During the stopping process following action are taken
+
+* openavb_intf_cb_t::intf_gen_end_cb is called
+* openavb_map_cb_t::map_gen_end_cb is called
+* Media Queue is deleted using the @ref openavbMediaQDelete function which frees
+the memory taken by all internal structures of Media Queue
+
+<br>
+Guidelines {#media_queue_usage_rules}
+==========
+
+* Calls to **Lock** functions must always be paired with their **Unlock**
+counterparts to avoid problems while working with MediaQueue. Push and Pull
+functions additional result in an unlock.
+* The current implementation Media Queue allows accessing two elements at the
+same time - one is head and second the tail
+* The number of Media Queue items and their sizes depends on configuration for
+the stream. The main driving factor is to make the data accessible for the next
+element that follows interface module. The size of the Media Queue item is a
+factor of the According to this Media Queue number of size of AVTP stream
+encapsulation payload multiplied by the packing factor. The number of Media
+Queue items required if different for a talker and listener. The talker usually
+needs minimal Media Queue items. However, the listener must have enough Media
+Queue items to buffer data until the AVTP presentation time. This is based on
+the maximum transit time for the SR Class in use. ring decoding
+* If there are not enough Media Queue items warnings will be logged to the
+implemented logging system for the port for debugging purposes.
+
+More implementation details might be find in @ref openavb_mediaq_pub.h
diff --git a/lib/avtp_pipeline/documents/sdk_overview.md b/lib/avtp_pipeline/documents/sdk_overview.md
new file mode 100644
index 00000000..75d6f926
--- /dev/null
+++ b/lib/avtp_pipeline/documents/sdk_overview.md
@@ -0,0 +1,233 @@
+EAVB SDK Overview {#sdk_overview}
+=================
+
+
+Introduction {#sdk_overview_introduction}
+============
+Symphony Teleca Corporation (OPENAVB) 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
+specific platforms. The complete OPENAVB EAVB implementation, and its role within an
+overall EAVB system are discussed in OPENAVB?s Ethernet Audio Video Bridging (AVB)
+High Level Specification (OPENAVB13-01059).
+
+The OPENAVB AVB stack is designed to work on both General Purpose OSes (GPOS), such
+as Linux, as well as Real-Time OSes (RTOS). There are some difference in
+concepts and terms between a GPOS and RTOS, for example threads vs tasks, or the
+concept of multiple processes. For the purposes of the SDK guides the terms
+thread and task are used interchangeably.
+
+The guides in this SDK focus on integrating the OPENAVB AVB stack in an application,
+developing interface module components and configuration AVB streams. These
+guides are separated into four sections:
+
+- [EAVB SDK Overview](@ref sdk_overview)
+- [EAVB Integration](@ref sdk_integration)
+- [AVTP Interface Module Development](@ref sdk_avtp_interface_module_dev)
+- [AVTP Stream Configuration](@ref sdk_avtp_stream_cfg)
+
+This overview section will cover general architecture.
+
+<br>
+Glossary {#sdk_overview_glossary}
+========
+**AAF:** AVTP Audio Format
+
+**AVB:** Audio Video Bridging (used interchangeably with EAVB)
+
+**AVB Stack:** The primary functionality that implements the various AVB
+protocols
+
+**AVTP:** Audio Video Transport Protocol
+
+**EAVB:** Ethernet Audio Video Bridging (used interchangeably with AVB)
+
+**EMAC:** Ethernet Media Access Control
+
+**FQTSS:** Forwarding and Queuing enhancements for Time Sensitive Streams
+
+**GPOS:** General purpose OS
+
+**gPTP:** generalized Precision Time Protocol
+
+**HAL:** Hardware Abstraction Layer
+
+**Listener:** Receives an AVTP stream, unpacks it and pushes it to a media sink
+for playback. It consists of a dedicated task and uses functionality in the AVTP
+module, one mapping module and one interface module.
+
+**IEEE:** Institute of Electrical and Electronics Engineers
+
+**Interface Module:** An AVTP component that when called from the talker pulls
+data from a media source and pushes it onto the media queue in the format
+expected by the mapping module running on the talker. When called from a
+listener it pulls data from the media queue and pushes it to the media sink for
+playback.
+
+**ISR:** Interrupt Service Routine
+
+**MAAP:** Multicast Address Allocation Protocol
+
+**MAC:** Media Access Control
+
+**Mapping Module:** An AVTP component that when called from the talker pulls
+data from the media queue and packages it into the AVTP data payload according
+to a specific AVB encapsulation. When called from a listener it unpacks the AVTP
+data payload according to the specific AVB encapsulation and pushes it on to the
+media queue.
+
+**Media Queue:** A circular FIFO container used to opaquely pass media data
+blocks between interface modules and mapping modules. This is the only way
+interface modules and mapping modules communicate.
+
+**MJPEG:** Motion Joint Photographic Expert Group
+
+**MPEG2-TS:** Motion Picture Expert Group (version 2) Transport Stream
+
+**OS:** Operating System
+
+**OSAL:** Operating System Abstraction Layer
+
+**SDK:** Software Development Kit
+
+**SR:** Stream Reservation
+
+**RTOS:** Real-time OS
+
+**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
+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}
+============
+
+The complete OPENAVB EAVB implementation and its role within an overall EAVB system
+are discussed in OPENAVB?s Ethernet Audio Video Bridging (AVB) High Level
+Specification (OPENAVB13-01059).
+
+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
+interfaces the host application will use (TL APIs).
+
+@image html Core_AVB.png "Core AVB"
+@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
+Linux reference implementation.
+
+@image html fig1.png "AVB Components"
+@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
+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.
+
+@image html fig2.png "AVB Audio Stream Flow"
+@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.
+
+@image html Stream_Initialize.png "Stream Initialization"
+@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.
+
+**Integration:** This refers to the integration of the OPENAVB AVB stack into an
+existing or new application. This is also sometimes referred to as the hosting
+application. For details related to this see [EAVB Integration](@ref
+sdk_integration)
+
+**AVTP Interface Module Development:** In order for the AVB stack to be used it
+must have interaction with media data sources and sinks on the platform. This is
+accomplished with Interface modules. The AVB stack ported to a platform may
+include some interface modules already but typically new interface modules are
+needed for the specific hardware and drivers being targeted. See [AVTP Interface
+Module Development](@ref sdk_avtp_interface_module_dev) for more details.
+
+**Configuration:** Configuration can be split into 2 distinct area. Hosting
+application configuration and stream configuration. Hosting application
+configuration is port specifici and therefore not covered in detail in this SDK.
+However, in the configuration guide section of the SDK some host application
+configuration example are provided as a point of reference. The other primary
+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
+and real-time OSes. The base public APIs of the SDK do not change depending on
+the port. However, some elements of working with the SDK do change depending on
+the port of the OPENAVB stack. See the release notes for the specific port for
+details that may be beyond the common SDK usage.
+
+## Threads / Tasks
+Within the SDK guides the terms threads and tasks are used interchangeability
+and for the purposes of the SDK they can be considered the same.
+
+## Processes
+Some platform OSes support multiple processes. The OPENAVB stack for a particular
+port may make use of multiple processes. For example in the Linux reference
+implementation gPTP resided in a separate process. Additionally in this
+reference implementation the talk / listener end-station functionality for each
+stream can be in a single process or split across multiple processes. Whereas in
+a RTOS there isn't typically the concept of multile processes.
+
+## Configuration Overview
+Configuration of both the host application as well as the streams can vary based
+on platform capabilities. For example on configuration information may come from
+.ini files on the device and in other platforms there may not be a file system
+in which case configuration may be set at build time.
+
+## Startup
+See the port specific Release Notes for the details on AVB start up.
+
+## Libraries
+The AVB core stack commonly is build as a static library and linked with a
+hosting application. Interface modules may be built differently depending on the
+platform. In some cases they my be dynamic libraries and other cases they may be
+static libraries. It is also possible that the interface modules will be built
+with the host application or as part of the AVB core library.
+
diff --git a/lib/avtp_pipeline/endpoint/CMakeLists.txt b/lib/avtp_pipeline/endpoint/CMakeLists.txt
new file mode 100644
index 00000000..5960d371
--- /dev/null
+++ b/lib/avtp_pipeline/endpoint/CMakeLists.txt
@@ -0,0 +1,7 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/endpoint/openavb_endpoint.c
+ ${AVB_OSAL_DIR}/endpoint/openavb_endpoint_osal.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/NOTES.TXT b/lib/avtp_pipeline/endpoint/NOTES.TXT
new file mode 100644
index 00000000..a4b912da
--- /dev/null
+++ b/lib/avtp_pipeline/endpoint/NOTES.TXT
@@ -0,0 +1,11 @@
+The endpoint process hosts the per-node functionality that's used by
+all the talkers/listeners on the node. This includesthe SRP and FQTSS
+logic, which is provided by the SRP and FQTSS libraries.
+
+The actual AVTP talkers/listeners are implemented as seperate
+processes. Those processes communicate with the endpoint through IPC
+(currently we're using a local socket on Linux.) The IPC
+communication is handled by openavb_resv_server.c (server-side IPC,
+linked into the endpoint process) and openavb_resv_client.c
+(client-side of the IPC, linked into the talker and listener
+processes.)
diff --git a/lib/avtp_pipeline/endpoint/endpoint.ini b/lib/avtp_pipeline/endpoint/endpoint.ini
new file mode 100644
index 00000000..5138c661
--- /dev/null
+++ b/lib/avtp_pipeline/endpoint/endpoint.ini
@@ -0,0 +1,59 @@
+[network]
+
+# interface name on which to talk/listen
+ifname=eth0
+
+# information rate (wire speed) for the link specified in kilobits/sec
+# (fast ethernet = 100000, gigabit ethernet = 1000000)
+link_kbit = 1000000
+
+# Bandwidth reserved for non-SR traffic
+# specified in kilobits/sec
+nsr_kbit = 250000
+
+[ptp]
+
+# Endpoint will always start openavb_gptp on the interface specified by ifname (above)
+# (unless gptp_asCapable_not_required = 1 is set - see warning below)
+# Additional openavb_gptp command line options may be provided here, if desired
+start_options = -u 60
+
+[fqtss]
+
+# FQTSS mode - how talker traffic will be shaped.
+#
+# Modes are:
+# 0 = AVB_SHAPER_DISABLED - Disable FQTSS (no shaping)
+# 1 = AVB_SHAPER_DROP_ALL - Drop all frames
+# 2 = AVB_SHAPER_ALL_NONSR - Treat everything as non-SR traffic
+# 3 = AVB_SHAPER_DROP_SR - Drop all AVTP frames
+# 4 = AVB_SHAPER_SW - Credit-based shaping per-class (in software)
+# 5 = AVB_SHAPER_HWQ_PER_CLASS - shaping in HW per AVB class
+#
+# By default on platforms which support HW shaping, the default mode
+# will be AVB_SHAPER_HWQ_PER_CLASS, on other platforms the default
+# mode is AVB_SHAPER_SW.
+#mode = 4
+
+[srp]
+
+# To disable dynamic SRP operation in the case of manually preconfigured streams
+# (e.g. in an AVB network using Broadcom Polar Switches) set:
+#preconfigured = 1
+# CAUTION: All streams registered by talker or listener are assumed to be valid.
+# WARNING: Preconfigured streams require COMPLETE manual stream configuration
+# on EVERY device in the network, without exception.
+# ANY NETWORK WHICH IS NOT EITHER
+# - USING DYNAMIC SRP ON **EVERY** NETWORK DEVICE, OR
+# - HAS COMPLETE MANUAL STREAM CONFIGURATION ON **EVERY** NETWORK DEVICE
+# IS NOT AN ETHERNET AVB NETWORK AND WILL NOT FUNCTION PROPERLY.
+
+# IEEE 802.1ba section 6.4 requires that SRP grant stream reservations on a link
+# only if that link is "asCapable" with gPTP (IEEE 802.1AS) operating. To bypass
+# that requirement, set:
+# gptp_asCapable_not_required = 1
+# WARNING: This non-standards complaint option is intended ONLY to allow for the
+# use of PTPv2 on older AVB netowrks where gPTP may not be supported.
+# ANY NETWORK WHICH IS NOT USING PTP TO KEEP ALL DEVICE CLOCKS IN SYNC
+# IS NOT AN ETHERNET AVB NETWORK AND WILL NOT FUNCTION PROPERLY.
+
diff --git a/lib/avtp_pipeline/endpoint/gstreamer.txt b/lib/avtp_pipeline/endpoint/gstreamer.txt
new file mode 100644
index 00000000..14f164df
--- /dev/null
+++ b/lib/avtp_pipeline/endpoint/gstreamer.txt
@@ -0,0 +1,98 @@
+Notes on creating GSgtreamer audio/video pipelines, and the
+talker/listener.ini entries for those streams.
+
+First, need figure out the GStreamer pipelines using gst-inspect and
+gst-launch. gst-inspect shows info about the plugins
+(src/sink/filter). Gst-launch creates a pipeline in the same way that
+our talker/listener (openavb-gst-talk and openavb-gst-listen) do - but all the
+parts obviously run on the same node.
+
+To use a pipeline with AVTP, we need a capability filter (a format
+specification) in the middle of the pipeline. This is where we'll
+break the pipe between talker and listener. The caps filter specifies
+the format of the gstreamer data samples that are sent across the
+network using AVTP.
+
+Start with a simple "gst-launch src ! sink" pipeline, and use
+the verbose option (-v) to make gst-launch show the caps negotiated
+between the source and sink.
+
+Next, use filters to transform the stream to/from the format that you
+want to transport over AVTP.
+
+Audio example:
+
+For audio, "aplay -l" and "arecord -l" list the ALSA sinks and
+sources. On my boards, device 1 was the USB microphone, and device
+0 was the HDMI audio output.
+
+Next I ran this to verify that the pipeline works:
+
+ gst-launch -v alsasrc device=hw:1 ! audio/x-raw-int,rate=48000 ! audioconvert ! alsasink device=hw:0
+
+The audioconvert filter was needed because the microphone is mono,
+and HDMI is stereo. Without that, gst-launch complains that the
+"capabilities couldn't be negotiated".
+
+The "audio/x-raw-int,rate-48000" was needed to get alsasrc to use the
+USB audio. Without that, gstreamer complained of an internal error. (Ugh!)
+
+When I ran the simple pipeline, it reported:
+
+ $ gst-launch -v alsasrc device=hw:1 ! audio/x-raw-int,rate=48000 ! audioconvert ! alsasink device=hw:0
+ Setting pipeline to PAUSED ...
+ /GstPipeline:pipeline0/GstAlsaSrc:alsasrc0: actual-buffer-time = 200000
+ /GstPipeline:pipeline0/GstAlsaSrc:alsasrc0: actual-latency-time = 10000
+ /GstPipeline:pipeline0/GstAlsaSrc:alsasrc0.GstPad:src: caps = audio/x-raw-int, width=(int)16, depth=(int)16, rate=(int)44100, channels=(int)1, endianness=(int)1234, signed=(boolean)true
+ Pipeline is live and does not need PREROLL ...
+ Setting pipeline to PLAYING ...
+ New clock: GstAudioSrcClock
+ /GstPipeline:pipeline0/GstAudioConvert:audioconvert0.GstPad:src: caps = audio/x-raw-int, endianness=(int)1234, signed=(boolean)true, width=(int)16, depth=(int)16, rate=(int)48000, channels=(int)2
+ /GstPipeline:pipeline0/GstAudioConvert:audioconvert0.GstPad:sink: caps = audio/x-raw-int, width=(int)16, depth=(int)16, rate=(int)48000, channels=(int)1, endianness=(int)1234, signed=(boolean)true
+ /GstPipeline:pipeline0/GstAlsaSink:alsasink0.GstPad:sink: caps = audio/x-raw-int, endianness=(int)1234, signed=(boolean)true, width=(int)16, depth=(int)16, rate=(int)48000, channels=(int)2
+
+The caps lines show the format of the data at each plugin in the
+pipeline. I wanted a lower sample rate to send across the network,
+and since the microphone is mono, it makes sense to only send 1 sound
+channel.
+
+That gives me the desired caps for the middle of the pipeline (where
+we'll split it.) I moved the audioconvert (which does the mono ->
+stereo conversion) after the split point.
+
+gst-launch -v alsasrc device=hw:1
+ ! audio/x-raw-int,rate=48000
+ ! audioresample
+ ! audio/x-raw-int,width=16,depth=16,rate=44100,channels=1,endianness=1234,signed=true
+ ! audioconvert
+ ! alsasink device=hw:0
+
+I then retested, and verified that the longer pipeline still works.
+
+Next, we split the pipeline, and add our AVTP appsrc and appsink:
+
+For the talker, this gives us:
+
+alsasrc device=hw:1
+ ! audio/x-raw-int,rate=48000
+ ! audioresample
+ ! audio/x-raw-int,width=16,depth=16,rate=44100,channels=1,endianness=1234,signed=true
+ ! appsink name=avbsink
+
+And for the listener:
+
+appsrc name=avbsrc
+ ! audio/x-raw-int,width=16,depth=16,rate=44100,channels=1,endianness=1234,signed=true
+ ! audioconvert
+ ! alsasink device=hw:0
+
+Those lines become the values for "pipeline" in talker.ini and
+listner.ini.
+
+The final step is to find the tx_size and tx_samples for talker.ini.
+GStreamer decides how and when to deliver data to our appsink, so we
+need to run an experiment. Add the pipelines to the
+talker/listener.ini files, and run the talker and listener. Watch for
+the "INFO: TX Sample=N" log lines. That line shows tx_size, which
+goes directly into talker.ini, and tx_samples, which is used to
+calculate tx_rate. (tx_rate = pipeline rate / tx_samples).
diff --git a/lib/avtp_pipeline/endpoint/openavb_endpoint.c b/lib/avtp_pipeline/endpoint/openavb_endpoint.c
new file mode 100644
index 00000000..5a4dfe17
--- /dev/null
+++ b/lib/avtp_pipeline/endpoint/openavb_endpoint.c
@@ -0,0 +1,528 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : The AVB endpoint is the "master process".
+* 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 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.
+*
+* Streamer processes contact the endpoint process through an IPC to
+* declare their streams. Currently, the IPC uses unix sockets. The
+* IPC methods are implemented in openavb_endpoint_client.c and
+* openavb_endpoint_server.c. The streamers (talkers and listeners)
+* are referred to as our"clients", and the endpoint process is their
+* "server".
+*
+* When SRP establishes a reservation (or when a reservation goes
+* away), the endpoint communicates the event back to the streamer
+* process through a callback (which also uses the IPC mechanism.)
+*/
+
+#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_avtp.h"
+#include "openavb_qmgr.h"
+#include "openavb_maap.h"
+
+#define AVB_LOG_COMPONENT "Endpoint"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+/* Information that we need to remember about each stream
+ */
+
+
+// list of streams that we're managing
+clientStream_t* x_streamList;
+// true until we are signalled to stop
+bool endpointRunning = TRUE;
+// data from our configuation file
+openavb_endpoint_cfg_t x_cfg;
+
+/*************************************************************
+ * Functions to manage our list of streams.
+ */
+
+/* Log information on all statically configured streams.
+ * (Dynamically configured streams are logged by SRP.)
+*/
+void openavbEndPtLogAllStaticStreams(void)
+{
+ bool hdrDone = FALSE;
+
+ if(x_cfg.noSrp) {
+ clientStream_t **lpp;
+ for(lpp = &x_streamList; *lpp != NULL; lpp = &(*lpp)->next) {
+ if ((*lpp)->clientHandle != AVB_ENDPOINT_HANDLE_INVALID) {
+ if (!hdrDone) {
+ AVB_LOG_INFO("Statically Configured Streams:");
+ AVB_LOG_INFO(" | SR | Destination | ----Max Frame(s)--- |");
+ AVB_LOG_INFO(" Role | Stream Id | Class | Address | Size | Per Interval |");
+ hdrDone = TRUE;
+ }
+ if ((*lpp)->role == clientTalker) {
+ AVB_LOGF_INFO(" Talker | %02x:%02x:%02x:%02x:%02x:%02x - %4d | %c | %02x:%02x:%02x:%02x:%02x:%02x | %4u | %2u |",
+ (*lpp)->streamID.addr[0], (*lpp)->streamID.addr[1], (*lpp)->streamID.addr[2],
+ (*lpp)->streamID.addr[3], (*lpp)->streamID.addr[4], (*lpp)->streamID.addr[5],
+ (*lpp)->streamID.uniqueID,
+ AVB_CLASS_LABEL((*lpp)->srClass),
+ (*lpp)->destAddr[0], (*lpp)->destAddr[1], (*lpp)->destAddr[2],
+ (*lpp)->destAddr[3], (*lpp)->destAddr[4], (*lpp)->destAddr[5],
+ (*lpp)->tSpec.maxFrameSize, (*lpp)->tSpec.maxIntervalFrames );
+ } else if ((*lpp)->role == clientListener) {
+ AVB_LOGF_INFO(" Listener | %02x:%02x:%02x:%02x:%02x:%02x - %4d | - | --:--:--:--:--:-- | -- | -- |",
+ (*lpp)->streamID.addr[0], (*lpp)->streamID.addr[1], (*lpp)->streamID.addr[2],
+ (*lpp)->streamID.addr[3], (*lpp)->streamID.addr[4], (*lpp)->streamID.addr[5],
+ (*lpp)->streamID.uniqueID );
+
+ }
+ }
+ }
+ }
+}
+
+/* Called for each talker or listener stream declared by clients
+ */
+clientStream_t* addStream(int h, AVBStreamID_t *streamID)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+ clientStream_t *newClientStream = NULL, **lpp;
+
+ do {
+ newClientStream = (clientStream_t *)calloc(1, sizeof(clientStream_t));
+ if(newClientStream == NULL) {
+ AVB_LOG_ERROR("addStream: Failed to malloc stream");
+ break;
+ }
+
+ memcpy(newClientStream->streamID.addr, streamID->addr, ETH_ALEN);
+ newClientStream->streamID.uniqueID = streamID->uniqueID;
+ newClientStream->clientHandle = h;
+ newClientStream->fwmark = INVALID_FWMARK;
+
+ if(x_streamList == NULL) {
+ x_streamList = newClientStream;
+ }else {
+ // insert at end
+ for(lpp = &x_streamList; *lpp != NULL; lpp = &(*lpp)->next) {
+ if ((*lpp)->next == NULL) {
+ (*lpp)->next = newClientStream;
+ break;
+ }
+ }
+ }
+ } while (0);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return newClientStream;
+}
+
+void delStream(clientStream_t* ps)
+{
+ clientStream_t **lpp;
+ for(lpp = &x_streamList; *lpp != NULL; lpp = &(*lpp)->next) {
+ if((*lpp) == ps) {
+ *lpp = (*lpp)->next;
+ free(ps);
+ break;
+ }
+ }
+}
+
+/* Find a stream in the list of streams we're handling
+ */
+clientStream_t* findStream(AVBStreamID_t *streamID)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+ clientStream_t* ps = NULL;
+
+ // Check for default stream MAC address, and fill it in with
+ // interface MAC so that if the talker didn't fill in
+ // the stream MAC, we use the one that the endpoint is
+ // configured to use.
+ //
+ // Listener should never pass a default MAC in,
+ // because the config code forces the listener to specify MAC in
+ // its configuration. Talker may send a default (empty) MAC in
+ // the stream ID, in which case we fill it in.
+ //
+ // TODO: This is sketchy - it would probably be better to force every
+ // client to send fully populated stream IDs. I think the reason
+ // I didn't do that is that it would cause duplicate configuration
+ // (in the talker and in the endpoint.) Perhaps the filling in of
+ // the MAC could happen in the endpoint function which calls
+ // findstream for the talker.
+ //
+ static const U8 emptyMAC[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+ if (memcmp(streamID->addr, emptyMAC, ETH_ALEN) == 0) {
+ memcpy(streamID->addr, x_cfg.ifmac, ETH_ALEN);
+ AVB_LOGF_DEBUG("Replaced default streamID MAC with interface MAC "ETH_FORMAT, ETH_OCTETS(streamID->addr));
+ }
+
+ clientStream_t **lpp;
+ for(lpp = &x_streamList; *lpp != NULL; lpp = &(*lpp)->next) {
+ if (memcmp(streamID->addr, (*lpp)->streamID.addr, ETH_ALEN) == 0
+ && streamID->uniqueID == (*lpp)->streamID.uniqueID)
+ {
+ ps = *lpp;
+ break;
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return ps;
+}
+
+/* Find a stream by MAAP handle
+ */
+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)
+ {
+ ps = *lpp;
+ break;
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return ps;
+}
+
+/*************************************************************
+ *
+ * Internal function to cleanup streams
+ *
+ */
+bool x_talkerDeregister(clientStream_t *ps)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ openavbRC rc = OPENAVB_SUCCESS;
+
+ if(!x_cfg.noSrp) {
+ // Pass to SRP
+ rc = openavbSrpDeregisterStream(&ps->streamID);
+ }
+
+ // Remove QMgr entry for stream
+ if (ps->fwmark != INVALID_FWMARK) {
+ openavbQmgrRemoveStream(ps->fwmark);
+ ps->fwmark = INVALID_FWMARK;
+ }
+
+ // Release MAAP address allocation
+ if (ps->hndMaap) {
+ openavbMaapRelease(ps->hndMaap);
+ ps->hndMaap = NULL;
+ }
+
+ // remove record
+ delStream(ps);
+
+ openavbEndPtLogAllStaticStreams();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return IS_OPENAVB_SUCCESS(rc);
+}
+
+bool x_listenerDetach(clientStream_t *ps)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ openavbRC rc = OPENAVB_SUCCESS;
+
+ if(!x_cfg.noSrp) {
+ // Pass to SRP
+ rc = openavbSrpDetachStream(&ps->streamID);
+ }
+
+ // remove record
+ delStream(ps);
+
+ openavbEndPtLogAllStaticStreams();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return IS_OPENAVB_SUCCESS(rc);
+}
+
+
+/*************************************************
+ * SRP CALLBACKS
+ */
+
+/* SRP tells us about a listener peer (Listener Ready or Failed)
+ */
+openavbRC strmAttachCb(void* pv,
+ openavbSrpLsnrDeclSubtype_t lsnrDecl)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ openavbRC rc = OPENAVB_FAILURE;
+ clientStream_t *ps = (clientStream_t*)pv;
+
+ AVB_LOGF_INFO("SRP talker callback uid=%d: lsnrDecl=%x", ps->streamID.uniqueID, lsnrDecl);
+
+ if (lsnrDecl == openavbSrp_LDSt_Ready
+ || 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;
+ }
+ else {
+ AVB_LOG_DEBUG("Attach callback: setting up queues for streaming");
+
+ rc = openavbSrpGetClassParams(ps->srClass, &ps->priority, &ps->vlanID, &ps->classRate);
+ if (IS_OPENAVB_SUCCESS(rc)) {
+ ps->fwmark = openavbQmgrAddStream(ps->srClass, ps->classRate, ps->tSpec.maxIntervalFrames, ps->tSpec.maxFrameSize);
+ if (ps->fwmark == INVALID_FWMARK) {
+ AVB_LOG_ERROR("Error in attach callback: unable to setup stream queues");
+ rc = OPENAVB_FAILURE;
+ }
+ else {
+ rc = OPENAVB_SUCCESS;
+ }
+ }
+ else {
+ AVB_LOG_ERROR("Error in attach callback: unable to get class params");
+ rc = OPENAVB_FAILURE;
+ }
+ }
+ }
+ else {
+ // Nobody listening
+ if (ps->fwmark != INVALID_FWMARK) {
+ AVB_LOG_DEBUG("Attach callback: tearing down queues");
+ openavbQmgrRemoveStream(ps->fwmark);
+ ps->fwmark = INVALID_FWMARK;
+ }
+ rc = OPENAVB_SUCCESS;
+ }
+
+ if (IS_OPENAVB_SUCCESS(rc)) {
+
+ openavbEptSrvrNotifyTlkrOfSrpCb(ps->clientHandle,
+ &ps->streamID,
+ x_cfg.ifname,
+ ps->destAddr,
+ lsnrDecl,
+ ps->classRate,
+ ps->vlanID,
+ ps->priority,
+ ps->fwmark);
+ rc = OPENAVB_SUCCESS;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return rc;
+}
+
+/* SRP tells us about talker peer (Talker Registration or De-registration)
+ */
+openavbRC strmRegCb(void *pv,
+ openavbSrpAttribType_t tlkrDecl,
+ U8 destAddr[],
+ AVBTSpec_t *tSpec,
+ SRClassIdx_t srClass,
+ U32 accumLatency,
+ openavbSrpFailInfo_t *failInfo)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ clientStream_t *ps = (clientStream_t*)pv;
+ AVB_LOGF_INFO("SRP listener callback uid=%d: tlkrDecl=%x", ps->streamID.uniqueID, tlkrDecl);
+
+ openavbEptSrvrNotifyLstnrOfSrpCb(ps->clientHandle,
+ &ps->streamID,
+ x_cfg.ifname,
+ destAddr,
+ tlkrDecl,
+ tSpec,
+ srClass,
+ accumLatency,
+ failInfo);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return OPENAVB_SUCCESS;
+}
+
+
+/*************************************************************
+ * MAAP Restart - our destination MAC has been changed.
+ *
+ * This is a clunky way to handle it - but it works, and this code
+ * won't be called often. (MAAP sends probes before settling on an
+ * address, so only a buggy or malicious peer should send us down this
+ * path.)
+ *
+ * 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
+ * destination address changes.
+ */
+static void maapRestartCallback(void* handle, struct ether_addr *addr)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ static clientStream_t* ps;
+ openavbRC rc;
+
+ ps = findStreamMaap(handle);
+ AVB_LOGF_STATUS("MAAP restart callback: handle=%p, stream=%p", handle, ps);
+
+ if (ps) {
+ memcpy(ps->destAddr, addr->ether_addr_octet, ETH_ALEN);
+
+ // Pretend that our listeners went away
+ strmAttachCb(ps, (openavbSrpLsnrDeclSubtype_t)0);
+
+ if(!x_cfg.noSrp) {
+ // Remove the old registration with SRP
+ openavbSrpDeregisterStream(&ps->streamID);
+
+ // Re-register with the new address
+ rc = openavbSrpRegisterStream((void*)ps,
+ &ps->streamID,
+ ps->destAddr,
+ &ps->tSpec,
+ ps->srClass,
+ ps->srRank,
+ ps->latency);
+ } else {
+ rc = OPENAVB_SUCCESS;
+ }
+
+ if (!IS_OPENAVB_SUCCESS(rc)) {
+ AVB_LOG_ERROR("MAAP restart: failed to re-register talker stream");
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+}
+
+
+int avbEndpointLoop(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ int retVal = -1;
+ openavbRC rc = OPENAVB_SUCCESS;
+ do {
+
+ if (!x_cfg.bypassAsCapableCheck && (startPTP() < 0)) {
+ // make sure ptp, a seperate process, starts and is using the same interface as endpoint
+ AVB_LOG_ERROR("PTP failed to start - Exiting");
+ break;
+ } else if(x_cfg.bypassAsCapableCheck) {
+ AVB_LOG_WARNING(" ");
+ 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("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.");
+ AVB_LOG_WARNING(" ");
+ }
+
+ x_streamList = NULL;
+
+ if (!openavbQmgrInitialize(x_cfg.fqtss_mode, x_cfg.ifindex, x_cfg.ifname, x_cfg.mtu, x_cfg.link_kbit, x_cfg.nsr_kbit)) {
+ AVB_LOG_ERROR("Failed to initialize QMgr");
+ break;
+ }
+
+ if (!openavbMaapInitialize(x_cfg.ifname, maapRestartCallback)) {
+ AVB_LOG_ERROR("Failed to initialize MAAP");
+ openavbQmgrFinalize();
+ break;
+ }
+
+ if(!x_cfg.noSrp) {
+ // Initialize SRP
+ rc = openavbSrpInitialize(strmAttachCb, strmRegCb, x_cfg.ifname, x_cfg.link_kbit, x_cfg.bypassAsCapableCheck);
+ } else {
+ rc = OPENAVB_SUCCESS;
+ AVB_LOG_WARNING(" ");
+ AVB_LOG_WARNING("Configuration 'preconfigured = 1' is set.");
+ AVB_LOG_WARNING("SRP is disabled. Streams MUST be configured manually");
+ AVB_LOG_WARNING("on each and every device in the network, without exception.");
+ AVB_LOG_WARNING("AN AVB NETWORK WILL NOT FUNCTION AS EXPECTED UNLESS ALL");
+ AVB_LOG_WARNING("STREAMS ARE PROPERLY CONFIGURED ON ALL NETWORK DEVICES.");
+ AVB_LOG_WARNING(" ");
+ }
+
+ if (!IS_OPENAVB_SUCCESS(rc)) {
+ AVB_LOG_ERROR("Failed to initialize SRP");
+ openavbMaapFinalize();
+ openavbQmgrFinalize();
+ break;
+ }
+
+ if (openavbEndpointServerOpen()) {
+
+ while (endpointRunning) {
+ openavbEptSrvrService();
+ }
+
+ openavbEndpointServerClose();
+ }
+
+ if(!x_cfg.noSrp) {
+ // Shutdown SRP
+ openavbSrpShutdown();
+ }
+
+ openavbMaapFinalize();
+ openavbQmgrFinalize();
+
+ retVal = 0;
+
+ } while (0);
+
+ if (!x_cfg.bypassAsCapableCheck && (stopPTP() < 0)) {
+ AVB_LOG_WARNING("Failed to execute PTP stop command: killall -s SIGINT openavb_gptp");
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return retVal;
+}
diff --git a/lib/avtp_pipeline/endpoint/openavb_endpoint.h b/lib/avtp_pipeline/endpoint/openavb_endpoint.h
new file mode 100644
index 00000000..a807eba8
--- /dev/null
+++ b/lib/avtp_pipeline/endpoint/openavb_endpoint.h
@@ -0,0 +1,279 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 code.
+*/
+
+#ifndef OPENAVB_ENDPOINT_H
+#define OPENAVB_ENDPOINT_H
+
+#include "openavb_types.h"
+#include "openavb_srp_api.h"
+#include "openavb_endpoint_cfg.h"
+#include "openavb_tl.h"
+
+#define AVB_ENDPOINT_HANDLE_INVALID (-1)
+#define ENDPOINT_RECONNECT_SECONDS 10
+#define AVB_ENDPOINT_UNIX_PATH "/tmp/avb_endpoint"
+
+typedef enum {
+ clientNone,
+ clientTalker,
+ clientListener
+} clientRole_t;
+
+
+bool openavbEptClntService(int h, int timeout);
+void openavbEptSrvrService(void);
+int avbEndpointLoop(void);
+
+
+typedef enum {
+ // client messages
+ OPENAVB_ENDPOINT_TALKER_REGISTER,
+ OPENAVB_ENDPOINT_LISTENER_ATTACH,
+ OPENAVB_ENDPOINT_CLIENT_STOP,
+ OPENAVB_ENDPOINT_VERSION_REQUEST,
+
+ // server messages
+ OPENAVB_ENDPOINT_TALKER_CALLBACK,
+ OPENAVB_ENDPOINT_LISTENER_CALLBACK,
+ OPENAVB_ENDPOINT_VERSION_CALLBACK,
+} openavbEndpointMsgType_t;
+
+//////////////////////////////
+// Client message parameters
+//////////////////////////////
+typedef struct {
+ U8 destAddr[ETH_ALEN];
+ AVBTSpec_t tSpec;
+ U8 srClass;
+ U8 srRank;
+ U32 latency;
+} openavbEndpointParams_TalkerRegister_t;
+
+typedef struct {
+ openavbSrpLsnrDeclSubtype_t lsnrDecl;
+} openavbEndpointParams_ListenerAttach_t;
+
+typedef struct {
+} openavbEndpointParams_ClientStop_t;
+
+typedef struct {
+} openavbEndpointParams_VersionRequest_t;
+
+//////////////////////////////
+// Server messages parameters
+//////////////////////////////
+typedef struct {
+ char ifname[IFNAMSIZ];
+ U8 destAddr[ETH_ALEN];
+ openavbSrpLsnrDeclSubtype_t lsnrDecl;
+ U32 classRate;
+ U16 vlanID;
+ U8 priority;
+ U16 fwmark;
+} openavbEndpointParams_TalkerCallback_t;
+
+typedef struct {
+ openavbSrpAttribType_t tlkrDecl;
+ char ifname[IFNAMSIZ];
+ U8 destAddr[ETH_ALEN];
+ AVBTSpec_t tSpec;
+ U8 srClass;
+ U32 latency;
+ openavbSrpFailInfo_t failInfo;
+} openavbEndpointParams_ListenerCallback_t;
+
+typedef struct {
+ U32 AVBVersion;
+} openavbEndpointParams_VersionCallback_t;
+
+#define OPENAVB_ENDPOINT_MSG_LEN sizeof(openavbEndpointMessage_t)
+
+typedef struct clientStream_t {
+ struct clientStream_t *next; // next link list pointer
+
+ int clientHandle; // ID that links this info to client (talker or listener)
+
+ // Information provided by the client (talker or listener)
+ AVBStreamID_t streamID; // stream identifier
+ clientRole_t role; // is client a talker or listener?
+
+ // Information provided by the client (talker)
+ AVBTSpec_t tSpec; // traffic specification (bandwidth for reservation)
+ SRClassIdx_t srClass; // AVB class
+ U8 srRank; // AVB rank
+ U32 latency; // internal latency
+
+ // Information provided by SRP
+ U8 priority; // AVB priority to use for stream
+ U16 vlanID; // VLAN ID to use for stream
+ U32 classRate; // observation intervals per second
+
+ // Information provided by MAAP
+ void *hndMaap; // handle for MAAP address allocation
+ U8 destAddr[ETH_ALEN]; // destination MAC address (from config or MAAP)
+
+ // Information provided by QMgr
+ int fwmark; // mark to identify packets of this stream
+} clientStream_t;
+
+int startPTP(void);
+int stopPTP(void);
+
+bool openavbEndpointServerOpen(void);
+void openavbEndpointServerClose(void);
+clientStream_t* findStream(AVBStreamID_t *streamID);
+void delStream(clientStream_t* ps);
+clientStream_t* addStream(int h, AVBStreamID_t *streamID);
+void openavbEndPtLogAllStaticStreams(void);
+bool x_talkerDeregister(clientStream_t *ps);
+bool x_listenerDetach(clientStream_t *ps);
+
+
+openavbRC strmRegCb(void *pv,
+ openavbSrpAttribType_t tlkrDecl,
+ U8 destAddr[],
+ AVBTSpec_t *tSpec,
+ SRClassIdx_t srClass,
+ U32 accumLatency,
+ openavbSrpFailInfo_t *failInfo);
+
+openavbRC strmAttachCb(void* pv,
+ openavbSrpLsnrDeclSubtype_t lsnrDecl);
+
+
+#include "openavb_endpoint_osal.h"
+
+
+/************************** Endpoint Client-Server *************************/
+// There is a single endpoint server for the entire talker/listener device
+// There is an endpoint client for each stream.
+
+// Endpoint client open a connection to endpoint server.
+// (Note that the server never opens a connection to the client.)
+int openavbEptClntOpenSrvrConnection(tl_state_t *pTLState);
+// Endpoint client close its connection to the server.
+void openavbEptClntCloseSrvrConnection(int h);
+// Endpoint server close its connection to the client.
+void openavbEptSrvrCloseClientConnection(int h);
+
+// Immediately after establishing connection with the endpoint server,
+// the endpoint client checks that the server's version is the same as its own.
+// The client sends a request to the cleint for its version.
+// The server handles the request and sends its version to the requesting client.
+// The clinet compares the recevied version to its own.
+bool openavbEptClntRequestVersionFromServer(int h);
+bool openavbEptSrvrHndlVerRqstFromClient(int h);
+void openavbEptSrvrSendServerVersionToClient(int h, U32 AVBVersion);
+void openavbEptClntCheckVerMatchesSrvr(int h, U32 AVBVersion);
+
+
+// Each talker registers its stream with SRP via Endpoint.
+// Endpoint communication is from client to server
+bool openavbEptClntRegisterStream(int h,
+ AVBStreamID_t *streamID,
+ U8 destAddr[],
+ AVBTSpec_t *tSpec,
+ U8 srClass,
+ U8 srRank,
+ U32 latency);
+bool openavbEptSrvrRegisterStream(int h,
+ AVBStreamID_t *streamID,
+ U8 destAddr[],
+ AVBTSpec_t *tSpec,
+ U8 srClass,
+ U8 srRank,
+ U32 latency);
+
+// Each lister attaches to the stream it wants to receive;
+// specifically the listener indicates interest / declaration to SRP.
+// Endpoint communication is from client to server.
+bool openavbEptClntAttachStream(int h,
+ AVBStreamID_t *streamID,
+ openavbSrpLsnrDeclSubtype_t ld);
+bool openavbEptSrvrAttachStream(int h,
+ AVBStreamID_t *streamID,
+ openavbSrpLsnrDeclSubtype_t ld);
+
+
+// SRP notifies the talker when its stream has been established to taken down.
+// Endpoint communication is from server to client.
+void openavbEptSrvrNotifyTlkrOfSrpCb(int h,
+ AVBStreamID_t *streamID,
+ char *ifname,
+ U8 destAddr[],
+ openavbSrpLsnrDeclSubtype_t lsnrDecl,
+ U32 classRate,
+ U16 vlanID,
+ U8 priority,
+ U16 fwmark);
+void openavbEptClntNotifyTlkrOfSrpCb(int h,
+ AVBStreamID_t *streamID,
+ char *ifname,
+ U8 destAddr[],
+ openavbSrpLsnrDeclSubtype_t lsnrDecl,
+ U32 classRate,
+ U16 vlanID,
+ U8 priority,
+ U16 fwmark);
+
+// SRP notifies the listener when its stream is available, failed or gone away.
+// Endpoint communication is from server to client.
+void openavbEptSrvrNotifyLstnrOfSrpCb(int h,
+ AVBStreamID_t *streamID,
+ char *ifname,
+ U8 destAddr[],
+ openavbSrpAttribType_t tlkrDecl,
+ AVBTSpec_t *tSpec,
+ U8 srClass,
+ U32 latency,
+ openavbSrpFailInfo_t *failInfo);
+void openavbEptClntNotifyLstnrOfSrpCb(int h,
+ AVBStreamID_t *streamID,
+ char *ifname,
+ U8 destAddr[],
+ openavbSrpAttribType_t tlkrDecl,
+ AVBTSpec_t *tSpec,
+ U8 srClass,
+ U32 latency,
+ openavbSrpFailInfo_t *failInfo);
+
+
+// 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
+bool openavbEptClntStopStream(int h, AVBStreamID_t *streamID);
+bool openavbEptSrvrStopStream(int h, AVBStreamID_t *streamID);
+
+
+#endif // OPENAVB_ENDPOINT_H
diff --git a/lib/avtp_pipeline/endpoint/openavb_endpoint_client.c b/lib/avtp_pipeline/endpoint/openavb_endpoint_client.c
new file mode 100644
index 00000000..50cb3439
--- /dev/null
+++ b/lib/avtp_pipeline/endpoint/openavb_endpoint_client.c
@@ -0,0 +1,199 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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
+* "endpoint" process to create a reservation for their traffic.
+* 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.
+*
+* Current IPC uses unix sockets. Can change this by creating a new
+* implementations in openavb_enpoint_client.c and openavb_endpoint_server.c
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "openavb_platform.h"
+
+#include "openavb_trace.h"
+#include "openavb_endpoint.h"
+
+#define AVB_LOG_COMPONENT "Endpoint"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+// forward declarations
+static bool openavbEptClntReceiveFromServer(int h, openavbEndpointMessage_t *msg);
+
+// OSAL specific functions for openavb_endpoint_client.c
+#include "openavb_endpoint_client_osal.c"
+
+static bool openavbEptClntReceiveFromServer(int h, openavbEndpointMessage_t *msg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ if (!msg || h == AVB_ENDPOINT_HANDLE_INVALID) {
+ AVB_LOG_ERROR("Client receive; invalid argument passed");
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return FALSE;
+ }
+
+ switch(msg->type) {
+ case OPENAVB_ENDPOINT_TALKER_CALLBACK:
+ openavbEptClntNotifyTlkrOfSrpCb(h,
+ &msg->streamID,
+ msg->params.talkerCallback.ifname,
+ msg->params.talkerCallback.destAddr,
+ msg->params.talkerCallback.lsnrDecl,
+ msg->params.talkerCallback.classRate,
+ msg->params.talkerCallback.vlanID,
+ msg->params.talkerCallback.priority,
+ msg->params.talkerCallback.fwmark);
+ break;
+ case OPENAVB_ENDPOINT_LISTENER_CALLBACK:
+ openavbEptClntNotifyLstnrOfSrpCb(h,
+ &msg->streamID,
+ msg->params.listenerCallback.ifname,
+ msg->params.listenerCallback.destAddr,
+ msg->params.listenerCallback.tlkrDecl,
+ &msg->params.listenerCallback.tSpec,
+ msg->params.listenerCallback.srClass,
+ msg->params.listenerCallback.latency,
+ &msg->params.listenerCallback.failInfo);
+ break;
+ case OPENAVB_ENDPOINT_VERSION_CALLBACK:
+ openavbEptClntCheckVerMatchesSrvr(h, msg->params.versionCallback.AVBVersion);
+ break;
+ default:
+ AVB_LOG_ERROR("Client receive: unexpected message");
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return FALSE;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return TRUE;
+}
+
+bool openavbEptClntRegisterStream(int h,
+ AVBStreamID_t *streamID,
+ U8 destAddr[],
+ AVBTSpec_t *tSpec,
+ U8 srClass,
+ U8 srRank,
+ U32 latency)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+ openavbEndpointMessage_t msgBuf;
+
+ // Check for valid parameters. destAddr is optional and checked later in this function before using.
+ if (!streamID || !tSpec) {
+ AVB_LOG_ERROR("Client register: invalid argument");
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return FALSE;
+ }
+
+ memset(&msgBuf, 0, OPENAVB_ENDPOINT_MSG_LEN);
+ msgBuf.type = OPENAVB_ENDPOINT_TALKER_REGISTER;
+ memcpy(&(msgBuf.streamID), streamID, sizeof(AVBStreamID_t));
+ if (destAddr)
+ memcpy(msgBuf.params.talkerRegister.destAddr, destAddr, ETH_ALEN);
+ 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;
+ bool ret = openavbEptClntSendToServer(h, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return ret;
+}
+
+bool openavbEptClntAttachStream(int h, AVBStreamID_t *streamID,
+ openavbSrpLsnrDeclSubtype_t ld)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+ openavbEndpointMessage_t msgBuf;
+
+ if (!streamID) {
+ AVB_LOG_ERROR("Client attach: invalid argument");
+ 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));
+ msgBuf.params.listenerAttach.lsnrDecl = ld;
+ bool ret = openavbEptClntSendToServer(h, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return ret;
+}
+
+bool openavbEptClntStopStream(int h, AVBStreamID_t *streamID)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+ openavbEndpointMessage_t msgBuf;
+
+ if (!streamID) {
+ AVB_LOG_ERROR("Client stop: invalid argument");
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return FALSE;
+ }
+
+ memset(&msgBuf, 0, OPENAVB_ENDPOINT_MSG_LEN);
+ msgBuf.type = OPENAVB_ENDPOINT_CLIENT_STOP;
+ memcpy(&(msgBuf.streamID), streamID, sizeof(AVBStreamID_t));
+ bool ret = openavbEptClntSendToServer(h, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return ret;
+}
+
+bool openavbEptClntRequestVersionFromServer(int h)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+ openavbEndpointMessage_t msgBuf;
+
+ memset(&msgBuf, 0, OPENAVB_ENDPOINT_MSG_LEN);
+ msgBuf.type = OPENAVB_ENDPOINT_VERSION_REQUEST;
+ bool ret = openavbEptClntSendToServer(h, &msgBuf);
+
+ 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
new file mode 100644
index 00000000..5d3c535b
--- /dev/null
+++ b/lib/avtp_pipeline/endpoint/openavb_endpoint_server.c
@@ -0,0 +1,394 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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
+ * "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.
+ *
+ * Current IPC uses unix sockets. Can change this by creating a new
+ * implementations in openavb_endoint_client.c and openavb_endpoint_server.c
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "openavb_endpoint.h"
+#include "openavb_trace.h"
+
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
+#define AVB_LOG_COMPONENT "Endpoint Server"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+#include "openavb_qmgr.h" // for INVALID_FWMARK
+#include "openavb_maap.h"
+
+// forward declarations
+static bool openavbEptSrvrReceiveFromClient(int h, openavbEndpointMessage_t *msg);
+
+#include "openavb_endpoint_server_osal.c"
+
+// the following are from openavb_endpoint.c
+extern openavb_endpoint_cfg_t x_cfg;
+extern clientStream_t* x_streamList;
+
+
+static bool openavbEptSrvrReceiveFromClient(int h, openavbEndpointMessage_t *msg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ if (!msg) {
+ AVB_LOG_ERROR("Receiving message; invalid argument passed");
+ 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);
+ break;
+ case OPENAVB_ENDPOINT_LISTENER_ATTACH:
+ AVB_LOGF_DEBUG("ListenerAttach from client uid=%d", msg->streamID.uniqueID);
+ ret = openavbEptSrvrAttachStream(h, &msg->streamID,
+ msg->params.listenerAttach.lsnrDecl);
+ break;
+ case OPENAVB_ENDPOINT_CLIENT_STOP:
+ AVB_LOGF_DEBUG("Stop from client uid=%d", msg->streamID.uniqueID);
+ ret = openavbEptSrvrStopStream(h, &msg->streamID);
+ break;
+ case OPENAVB_ENDPOINT_VERSION_REQUEST:
+ AVB_LOG_DEBUG("Version request from client");
+ ret = openavbEptSrvrHndlVerRqstFromClient(h);
+ break;
+ default:
+ AVB_LOG_ERROR("Unexpected message received at server");
+ break;
+ }
+
+ AVB_LOGF_VERBOSE("Message handled, ret=%d", ret);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return ret;
+}
+
+void openavbEptSrvrNotifyTlkrOfSrpCb(int h,
+ AVBStreamID_t *streamID,
+ char *ifname,
+ U8 destAddr[ETH_ALEN],
+ openavbSrpLsnrDeclSubtype_t lsnrDecl,
+ U32 classRate,
+ U16 vlanID,
+ U8 priority,
+ U16 fwmark)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+ openavbEndpointMessage_t msgBuf;
+
+ if (!streamID || !ifname || !destAddr) {
+ AVB_LOG_ERROR("Talker callback; invalid argument passed");
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return;
+ }
+
+ 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);
+ memcpy(msgBuf.params.talkerCallback.destAddr, destAddr, ETH_ALEN);
+ msgBuf.params.talkerCallback.lsnrDecl = lsnrDecl;
+ msgBuf.params.talkerCallback.classRate = classRate;
+ msgBuf.params.talkerCallback.vlanID = vlanID;
+ msgBuf.params.talkerCallback.priority = priority;
+ msgBuf.params.talkerCallback.fwmark = fwmark;
+ openavbEptSrvrSendToClient(h, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+}
+
+void openavbEptSrvrNotifyLstnrOfSrpCb(int h,
+ AVBStreamID_t *streamID,
+ char *ifname,
+ U8 destAddr[],
+ openavbSrpAttribType_t tlkrDecl,
+ AVBTSpec_t *tSpec,
+ U8 srClass,
+ U32 latency,
+ openavbSrpFailInfo_t* failInfo)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+ openavbEndpointMessage_t msgBuf;
+
+ // Check for valid parameters. DestAddr is optional and checked later.
+ if (!streamID || !ifname) {
+ AVB_LOG_ERROR("Listener callback; invalid argument passed");
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return;
+ }
+
+ 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)
+ memcpy(msgBuf.params.listenerCallback.destAddr, destAddr, ETH_ALEN);
+ msgBuf.params.listenerCallback.tlkrDecl = tlkrDecl;
+ if (tSpec)
+ memcpy(&msgBuf.params.listenerCallback.tSpec, tSpec, sizeof(AVBTSpec_t));
+ msgBuf.params.listenerCallback.srClass = srClass;
+ msgBuf.params.listenerCallback.latency = latency;
+ if (failInfo)
+ memcpy(&msgBuf.params.listenerCallback.failInfo, failInfo, sizeof(openavbSrpFailInfo_t));
+ openavbEptSrvrSendToClient(h, &msgBuf);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+}
+
+void openavbEptSrvrSendServerVersionToClient(int h, U32 AVBVersion)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ openavbEndpointMessage_t msgBuf;
+ memset(&msgBuf, 0, OPENAVB_ENDPOINT_MSG_LEN);
+ msgBuf.type = OPENAVB_ENDPOINT_VERSION_CALLBACK;
+ msgBuf.params.versionCallback.AVBVersion = AVBVersion;
+ openavbEptSrvrSendToClient(h, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+}
+
+/* Talker client registers a stream
+ */
+bool openavbEptSrvrRegisterStream(int h,
+ AVBStreamID_t *streamID,
+ U8 destAddr[],
+ AVBTSpec_t *tSpec,
+ U8 srClass,
+ U8 srRank,
+ U32 latency)
+{
+ 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);
+ return FALSE;
+ }
+
+ ps = addStream(h, streamID);
+ if (!ps) {
+ AVB_LOGF_ERROR("Error registering talker; unable to add client stream %d", streamID->uniqueID);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return FALSE;
+ }
+ ps->role = clientTalker;
+ ps->tSpec = *tSpec;
+ ps->srClass = (SRClassIdx_t)srClass;
+ ps->srRank = srRank;
+ ps->latency = latency;
+ ps->fwmark = INVALID_FWMARK;
+
+ if (memcmp(ps->destAddr, destAddr, ETH_ALEN) == 0) {
+ // no client-supplied address, use MAAP
+ struct ether_addr addr;
+ ps->hndMaap = openavbMaapAllocate(1, &addr);
+ if (ps->hndMaap) {
+ memcpy(ps->destAddr, addr.ether_addr_octet, ETH_ALEN);
+ strmAttachCb((void*)ps, openavbSrp_LDSt_Stream_Info); // Inform talker about MAAP
+ }
+ else {
+ AVB_LOG_ERROR("Error registering talker: MAAP failed to allocate MAC address");
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ delStream(ps);
+ return FALSE;
+ }
+ }
+ else {
+ // client-supplied destination MAC address
+ memcpy(ps->destAddr, destAddr, ETH_ALEN);
+ ps->hndMaap = NULL;
+ }
+
+ // Do SRP talker register
+ AVB_LOGF_DEBUG("REGISTER: ps=%p, streamID=%d, tspec=%d,%d, srClass=%d, srRank=%d, latency=%d, da="ETH_FORMAT"",
+ ps, streamID->uniqueID,
+ tSpec->maxFrameSize, tSpec->maxIntervalFrames,
+ ps->srClass, ps->srRank, ps->latency,
+ ETH_OCTETS(ps->destAddr));
+
+
+ if(x_cfg.noSrp) {
+ // we are operating in a mode supporting preconfigured streams; SRP is not in use,
+ // so, as a proxy for SRP, which would normally make this call after establishing
+ // the stream, call the callback from here
+ strmAttachCb((void*)ps, openavbSrp_LDSt_Ready);
+ } else {
+ // normal SRP operation
+ rc = openavbSrpRegisterStream((void*)ps, &ps->streamID,
+ ps->destAddr, &ps->tSpec,
+ ps->srClass, ps->srRank,
+ ps->latency);
+ if (!IS_OPENAVB_SUCCESS(rc)) {
+ if (ps->hndMaap)
+ openavbMaapRelease(ps->hndMaap);
+ delStream(ps);
+ }
+ }
+
+ openavbEndPtLogAllStaticStreams();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return IS_OPENAVB_SUCCESS(rc);
+}
+
+/* Listener client attaches to a stream
+ */
+bool openavbEptSrvrAttachStream(int h,
+ AVBStreamID_t *streamID,
+ openavbSrpLsnrDeclSubtype_t ld)
+{
+ openavbRC rc = OPENAVB_SUCCESS;
+ static U8 emptyMAC[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+ static AVBTSpec_t emptytSpec = {0, 0};
+
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ clientStream_t *ps = findStream(streamID);
+ if (ps && ps->clientHandle != h) {
+ AVB_LOGF_ERROR("Error attaching listener: multiple clients for stream %d", streamID->uniqueID);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return FALSE;
+ }
+
+ if (!ps) {
+ ps = addStream(h, streamID);
+ if (!ps) {
+ AVB_LOGF_ERROR("Error attaching listener: unable to add client stream %d", streamID->uniqueID);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return FALSE;
+ }
+ ps->role = clientListener;
+ }
+
+ if(x_cfg.noSrp) {
+ // we are operating in a mode supporting preconfigured streams; SRP is not in use,
+ if(ld == openavbSrp_LDSt_Interest) {
+ // As a proxy for SRP, which would normally make this call after confirming
+ // availability of the stream, call the callback from here
+ strmRegCb((void*)ps, openavbSrp_AtTyp_TalkerAdvertise,
+ emptyMAC, // a flag to listener to read info from configuration file
+ &emptytSpec,
+ MAX_AVB_SR_CLASSES, // srClass - value doesn't matter because openavbEptSrvrNotifyLstnrOfSrpCb() throws it away
+ 1, // accumLatency
+ NULL); // *failInfo
+ }
+ } else {
+ // Normal SRP Operation so pass to SRP
+ rc = openavbSrpAttachStream((void*)ps, streamID, ld);
+ if (!IS_OPENAVB_SUCCESS(rc))
+ delStream(ps);
+ }
+
+ openavbEndPtLogAllStaticStreams();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return IS_OPENAVB_SUCCESS(rc);
+}
+
+/* Client (talker or listener) going away
+ */
+bool openavbEptSrvrStopStream(int h, AVBStreamID_t *streamID)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ clientStream_t *ps = findStream(streamID);
+ if (!ps || ps->clientHandle != h) {
+ AVB_LOGF_ERROR("Error stopping client: missing record for stream %d", streamID->uniqueID);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return FALSE;
+ }
+
+ bool rc = FALSE;
+ if (ps->role == clientTalker)
+ rc = x_talkerDeregister(ps);
+ else if (ps->role == clientListener)
+ rc = x_listenerDetach(ps);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return rc;
+}
+
+/* Client version request
+ */
+bool openavbEptSrvrHndlVerRqstFromClient(int h)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ openavbEptSrvrSendServerVersionToClient(h, AVB_CORE_VER_FULL);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return TRUE;
+}
+
+/* Called if a client closes their end of the IPC
+ */
+void openavbEptSrvrCloseClientConnection(int h)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ clientStream_t **lpp;
+ for(lpp = &x_streamList; *lpp != NULL; lpp = &(*lpp)->next) {
+ if ((*lpp)->clientHandle == h)
+ {
+ if ((*lpp)->role == clientTalker)
+ x_talkerDeregister((*lpp));
+ else if ((*lpp)->role == clientListener)
+ x_listenerDetach((*lpp));
+ break;
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+}
+
diff --git a/lib/avtp_pipeline/endpoint/shutdown_openavb_endpoint.sh b/lib/avtp_pipeline/endpoint/shutdown_openavb_endpoint.sh
new file mode 100644
index 00000000..7020ec85
--- /dev/null
+++ b/lib/avtp_pipeline/endpoint/shutdown_openavb_endpoint.sh
@@ -0,0 +1,23 @@
+#! /bin/sh
+#
+# AVB endpoint clean-up script
+#
+# Only needs to be run if the endpoint process crashes.
+#
+# Removes resources created/loaded by the endpoint, so that a new
+# instance can run.
+
+IFACES=$(cat /proc/net/dev | grep -- : | cut -d: -f1)
+
+echo "removing endpoint resources"
+
+killall -s SIGINT openavb_endpoint > /dev/null 2>&1
+killall -s SIGINT openavb_gptp > /dev/null 2>&1
+rm -f /tmp/avb_endpoint > /dev/null 2>&1
+
+for I in ${IFACES}
+do
+ ./tc qdisc del dev ${I} root > /dev/null 2>&1
+done
+
+rmmod sch_avb > /dev/null 2>&1
diff --git a/lib/avtp_pipeline/include/avb_sched.h b/lib/avtp_pipeline/include/avb_sched.h
new file mode 100644
index 00000000..a4c7106c
--- /dev/null
+++ b/lib/avtp_pipeline/include/avb_sched.h
@@ -0,0 +1,126 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 AVB_SCHED_H
+#define AVB_SCHED_H
+
+// Macros to map stream/class into 16-bit fwmark
+// Bottom 8 bits are used for stream index (allows 32 streams/class)
+// Upper 8 bits are used for class index
+//
+// The fwmark is attached to the socket, and the kernel uses it to
+// steer AVTP frames into the correct queues.
+//
+// If we ever want more than 256 classes (won't happen) or 256 streams
+// per class (very unlikely) we'll need to shift the boundary between
+// the bits used for the class idex and those used for stream idx.
+//
+// If the combination of the two needs more than 16 bits, we'll have
+// to use something other than the FWMARK to communicate with the kernel.
+//
+#define TC_AVB_CLASS_SHIFT 8
+#define TC_AVB_STREAM_MASK ((1 << TC_AVB_CLASS_SHIFT) - 1)
+#define TC_AVB_MARK_CLASS(M) (((M) >> TC_AVB_CLASS_SHIFT) - 1)
+#define TC_AVB_MARK_STREAM(M) ((M) & TC_AVB_STREAM_MASK)
+#define TC_AVB_MARK(C,S) (((C + 1) << TC_AVB_CLASS_SHIFT) | (TC_AVB_STREAM_MASK & (S)))
+
+#ifndef AVB_CLASS_LABEL
+#define AVB_CLASS_LABEL(C) ('A'+C)
+#endif
+
+#define AVB_ENABLE_HWQ_PER_CLASS 1
+
+// Modes for qdisc shaping
+//
+typedef enum {
+ // Disable FQTSS
+ AVB_SHAPER_DISABLED,
+ // Drop all frames
+ AVB_SHAPER_DROP_ALL,
+ // Treat everything as non-SR traffic
+ AVB_SHAPER_ALL_NONSR,
+ // Drop all AVB stream frames
+ AVB_SHAPER_DROP_SR,
+ // Shaping done in SW
+ // - Credit-based shaping per-class (in software)
+ // - Priority between classes
+ // - WRR for streams within each class
+ AVB_SHAPER_SW,
+#ifdef AVB_ENABLE_HWQ_PER_CLASS
+ // Shaping in HW w/TXQ per AVB class
+ // - Each AVB class gets its own txq w/shaping in HW
+ // - SW does round-robin among classes to keep all TX queues fed
+ // - SW does WRR for streams within each class
+ AVB_SHAPER_HWQ_PER_CLASS,
+#endif
+#ifdef AVB_ENABLE_HWQ_PER_STREAM
+ // Shaping in HW w/TXQ per AVB stream
+ // - Each AVB stream gets its own txq w/shaping in HW
+ // - SW does round-robin among streams to keep all TX queues fed
+ AVB_SHAPER_HWQ_PER_STREAM
+#endif
+} avb_shaper_mode;
+
+/* Options/Stats for AVB qdisc
+ * (information passed back/forth between kernel and userland)
+ */
+struct tc_avb_qopt {
+ __u16 limit; // number of packets that may be queued in qdisc
+ __u16 num_classes; // number of SR classes
+ __u16 num_streams; // number of streams per SR class
+ __u16 linkBytesPerSec; // link speed
+ __u8 mode; // shaping mode (HW or SW)
+};
+
+/* Options/Stats for AVB streams
+ * (information passed back/forth between kernel and userland)
+ */
+struct tc_avb_sopt {
+ __u32 mark; // mark associated with stream
+ __u32 streamBytesPerSec; // reserved bandwith (non-zero for established stream)
+ __u16 maxIntervalFrames; // max frames per interval
+ __u16 maxFrameSize; // max frame size
+ __u32 nDropped, nQueued, nSent;
+};
+
+enum {
+ TCA_AVB_UNSPEC,
+ TCA_AVB_QOPT,
+ TCA_AVB_SOPT,
+ __TCA_AVB_MAX,
+};
+
+#define TCA_AVB_MAX (__TCA_AVB_MAX - 1)\
+
+#define AVB_CLASS_A 2
+#define AVB_CLASS_B 1
+#define AVB_CLASS_NR 0
+
+#endif
diff --git a/lib/avtp_pipeline/include/openavb_audio_pub.h b/lib/avtp_pipeline/include/openavb_audio_pub.h
new file mode 100644
index 00000000..769481ff
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_audio_pub.h
@@ -0,0 +1,157 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : General Audio Types Public
+*/
+
+#ifndef AVB_AUDIO_PUB_H
+#define AVB_AUDIO_PUB_H 1
+
+/** \file
+ * General audio types
+ */
+
+/** Audio rate
+ */
+typedef enum {
+ /// 8000
+ AVB_AUDIO_RATE_8KHZ = 8000,
+ /// 11025
+ AVB_AUDIO_RATE_11_025KHZ = 11025,
+ /// 16000
+ AVB_AUDIO_RATE_16KHZ = 16000,
+ /// 22050
+ AVB_AUDIO_RATE_22_05KHZ = 22050,
+ /// 32000
+ AVB_AUDIO_RATE_32KHZ = 32000,
+ /// 44100
+ AVB_AUDIO_RATE_44_1KHZ = 44100,
+ /// 48000
+ AVB_AUDIO_RATE_48KHZ = 48000,
+ /// 64000
+ AVB_AUDIO_RATE_64KHZ = 64000,
+ /// 88200
+ AVB_AUDIO_RATE_88_2KHZ = 88200,
+ /// 96000
+ AVB_AUDIO_RATE_96KHZ = 96000,
+ /// 176400
+ AVB_AUDIO_RATE_176_4KHZ = 176400,
+ /// 192000
+ AVB_AUDIO_RATE_192KHZ = 192000
+} avb_audio_rate_t;
+
+/** Defines what type is data.
+ *
+ * Information is needed together with endianes and bit depth to configure the
+ * sample format correctly
+ */
+typedef enum {
+ /// Data type undefined
+ AVB_AUDIO_TYPE_UNSPEC,
+ /// Data type int
+ AVB_AUDIO_TYPE_INT,
+ /// Data type unsigned int
+ AVB_AUDIO_TYPE_UINT,
+ /// Data type float
+ AVB_AUDIO_TYPE_FLOAT,
+} avb_audio_type_t;
+
+/** Defines endianess of data.
+ *
+ * Information is needed together with data type and bit depth to configure the
+ * sample format correctly
+ */
+typedef enum {
+ /// Unspecified
+ AVB_AUDIO_ENDIAN_UNSPEC,
+ /// Little endian
+ AVB_AUDIO_ENDIAN_LITTLE,
+ /// Big endian
+ AVB_AUDIO_ENDIAN_BIG,
+} avb_audio_endian_t;
+
+/** Bit depth of audio.
+ *
+ * Information is needed together with endianes and data type to configure the
+ * sample format correctly
+ */
+typedef enum {
+ /// 1 bit
+ AVB_AUDIO_BIT_DEPTH_1BIT = 1,
+ /// 8 bit
+ AVB_AUDIO_BIT_DEPTH_8BIT = 8,
+ /// 16 bit
+ AVB_AUDIO_BIT_DEPTH_16BIT = 16,
+ /// 20 bit
+ AVB_AUDIO_BIT_DEPTH_20BIT = 20,
+ /// 24 bit
+ AVB_AUDIO_BIT_DEPTH_24BIT = 24,
+ /// 32 bit
+ AVB_AUDIO_BIT_DEPTH_32BIT = 32,
+ /// 48 bit
+ AVB_AUDIO_BIT_DEPTH_48BIT = 48,
+ /// 64 bit
+ AVB_AUDIO_BIT_DEPTH_64BIT = 64
+} avb_audio_bit_depth_t;
+
+/** Number of channels
+ */
+typedef enum {
+ /// 1 channel
+ AVB_AUDIO_CHANNELS_1 = 1,
+ /// 2 channels
+ AVB_AUDIO_CHANNELS_2 = 2,
+ /// 3 channels
+ AVB_AUDIO_CHANNELS_3 = 3,
+ /// 4 channels
+ AVB_AUDIO_CHANNELS_4 = 4,
+ /// 5 channels
+ AVB_AUDIO_CHANNELS_5 = 5,
+ /// 6 channels
+ AVB_AUDIO_CHANNELS_6 = 6,
+ /// 7 channels
+ AVB_AUDIO_CHANNELS_7 = 7,
+ /// 8 channels
+ AVB_AUDIO_CHANNELS_8 = 8
+} avb_audio_channels_t;
+
+/** Media Clock Recovery.
+ */
+typedef enum {
+ /// No Media Clock Recovery is Done, this is the default
+ AVB_MCR_NONE,
+ /// Media Clock Recovery done by using AVTP timestamps
+ AVB_MCR_AVTP_TIMESTAMP,
+ /// Media Clock Recovery done by using 1722(a), Clock Reference Stream (CRS)
+ AVB_MCR_CRS
+}avb_audio_mcr_t;
+
+#endif // AVB_AUDIO_PUB_H
diff --git a/lib/avtp_pipeline/include/openavb_intf_pub.h b/lib/avtp_pipeline/include/openavb_intf_pub.h
new file mode 100755
index 00000000..fdd00a11
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_intf_pub.h
@@ -0,0 +1,230 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Common interface module public header
+*/
+
+#ifndef OPENAVB_INTF_PUB_H
+#define OPENAVB_INTF_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_mediaq_pub.h"
+
+/** \file
+ * Common interface module public header.
+ */
+
+/** Configuration callback into the interface module.
+ *
+ * This callback function is called during the reading of the configuration file
+ * by the talker and listener for any named configuration item starting with
+ * "intf_nv".
+ * This is a convenient way to store new configuration name/value pairs that are
+ * needed in an interface module.
+ *
+ * \param pMediaQ A pointer to the media queue for this stream
+ * \param name The item name from the configuration file
+ * \param value The item value from the configuration file
+ */
+typedef void (*openavb_intf_cfg_cb_t)(media_q_t *pMediaQ, const char *name, const char *value);
+
+/** General initialize callback regardless if a talker or listener.
+ *
+ * This callback function is called when the openavbTLOpen() function is called for
+ * the EAVB SDK API.
+ *
+ * \param pMediaQ A pointer to the media queue for this stream
+ */
+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
+ * successfully within a talker process. It does not get called when running
+ * within a listener process.
+ *
+ * \param pMediaQ A pointer to the media queue for this stream
+ */
+typedef void (*openavb_intf_tx_init_cb_t)(media_q_t *pMediaQ);
+
+/** Transmit callback into the interface module.
+ *
+ * This is the transmit callback function for the interface module.
+ * This function will typically be called thousands of times per second
+ * depending the SR class type (A or B). This frequency may also be changed by
+ * the mapping module and at times configurable by mapping modules for example
+ * with the map_nv_tx_rate configuration value.
+ * If pacing is done in the interface module by:
+ *
+ * cfg->tx_blocking_in_intf = FALSE;
+ *
+ * Then this callback will suspend task execution until there is media data
+ * available for the mapping module.
+ *
+ * \param pMediaQ A pointer to the media queue for this stream
+ */
+typedef bool (*openavb_intf_tx_cb_t)(media_q_t *pMediaQ);
+
+/** Initialize the receive callback into the interface module.
+ *
+ * This callback function is called anytime a stream reservation has completed
+ * successfully within a listener process. It does not get called when running
+ * within a talker process.
+ *
+ * \param pMediaQ A pointer to the media queue for this stream
+ */
+typedef void (*openavb_intf_rx_init_cb_t)(media_q_t *pMediaQ);
+
+/** Translate RX data callback.
+ *
+ * This callback that may be used by mapping modules to allow
+ * interfaces to translate packet data as it arrives and before
+ * it gets packed into the media queue Item. Mapping modules
+ * MUST expose a function pointer var in their public data and
+ * the interface module must set it for the CB to be used.
+ *
+ * \param pMediaQ A pointer to the media queue for this stream
+ * \param pPubDataQ A pointer to the data
+ * \param length Length of the data
+ */
+typedef void (*openavb_intf_rx_translate_cb_t)(media_q_t *pMediaQ, U8 *pPubData, U32 length);
+
+/** Receive callback into the interface module.
+ *
+ * This callback function is called when AVB packet data is received or when
+ * tail data item within the media queue has reached the presentation time
+ *
+ * \param pMediaQ A pointer to the media queue for this stream
+ */
+typedef bool (*openavb_intf_rx_cb_t)(media_q_t *pMediaQ);
+
+/** Callback when the stream is ending.
+ *
+ * This callback function is called when a stream is closing.
+ *
+ * \param pMediaQ A pointer to the media queue for this stream
+ */
+typedef void (*openavb_intf_end_cb_t)(media_q_t *pMediaQ);
+
+/** General shutdown callback into the interface module.
+ *
+ * This callback function is called when the openavbTLClose() function is called for
+ * the EAVB SDK API
+ *
+ * \param pMediaQ A pointer to the media queue for this stream
+ */
+typedef void (*openavb_intf_gen_end_cb_t)(media_q_t *pMediaQ);
+
+/** Query the interface for source bitrate.
+ *
+ * This callback is called to get the maximum bitrate of the source (in bits per
+ * second). For example for a mpeg2ts file interface this callback returns the
+ * maximum bitrate of the mpeg2ts file.
+ * \param pMediaQ A pointer to the media queue for this stream
+ * \return Maximum bitrate of the source.
+ *
+ * \note This callback is optional, does not need to be implemented in the
+ * interface module.
+ */
+typedef unsigned int (*openavb_intf_get_src_bitrate_t)(media_q_t *pMediaQ);
+
+/** Interface callbacks structure.
+ */
+typedef struct {
+ /// Configuration callback.
+ 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.
+ openavb_intf_tx_cb_t intf_tx_cb;
+ /// Initialize receive callback.
+ openavb_intf_rx_init_cb_t intf_rx_init_cb;
+ // openavb_intf_rx_translate_cb_t intf_rx_translate_cb; // Hidden since it is for direct mapping -> interface CBs
+ /// Receive callback.
+ openavb_intf_rx_cb_t intf_rx_cb;
+ /// Stream end callback.
+ openavb_intf_end_cb_t intf_end_cb;
+ /// General shutdown callback.
+ openavb_intf_gen_end_cb_t intf_gen_end_cb;
+ /// Pointer to interface specific callbacks that a hosting application may call.
+ /// It is pointer to openavb_intf_host_cb_list_t structure.
+ void * intf_host_cb_list;
+ /// Source bit rate callback.
+ openavb_intf_get_src_bitrate_t intf_get_src_bitrate_cb;
+} openavb_intf_cb_t;
+
+/** Main initialization entry point into the interface module.
+ *
+ * This is the main entry point into the interface module. Every interface
+ * module must define this function. The talker process and listener process
+ * call this function directly while the configuration file it being read. The
+ * function address is discovered via the settings in the talker and listener
+ * configuration structure. For example:
+ *
+ * osalCfg.pIntfInitFn = openavbIntfJ6Video;
+ *
+ * Within this function the callbacks must all be set into the structure pointer
+ * parameter.
+ * Any interface module initialization can take place during this call such as
+ * setting default values into configuration settings.
+ * Private interface module should be allocated during this call. This can be
+ * used to hold configuration data as well as functional variable data.
+ *
+ * \param pMediaQ A pointer to the media queue for this stream
+ * \param pIntfCB Pointer to the callback structure. All the members of this
+ * structure must be set during this function call
+ * \return TRUE on success or FALSE on failure
+ */
+typedef bool (*openavb_intf_initialize_fn_t)(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+
+/** \example openavb_intf_echo.c
+ * \brief A source code for a complete sample interface module.
+ */
+#endif // OPENAVB_INTF_PUB_H
+
diff --git a/lib/avtp_pipeline/include/openavb_log.h b/lib/avtp_pipeline/include/openavb_log.h
new file mode 100644
index 00000000..d5069111
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_log.h
@@ -0,0 +1,43 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Provide a simple logging facility for use
+* during development. Expect that this logging will be switched
+* off eventually. Uses macros that can be redefined to empty.
+* Details have been moved to the public interface.
+*/
+
+#ifndef OPENAVB_LOG_H
+#define OPENAVB_LOG_H 1
+
+#include "openavb_log_pub.h"
+
+#endif // OPENAVB_LOG_H
diff --git a/lib/avtp_pipeline/include/openavb_log_pub.h b/lib/avtp_pipeline/include/openavb_log_pub.h
new file mode 100644
index 00000000..92a93c98
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_log_pub.h
@@ -0,0 +1,246 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : A simple logging facility for use during
+* development.
+*/
+
+#ifndef OPENAVB_LOG_PUB_H
+#define OPENAVB_LOG_PUB_H 1
+
+// ********
+// Merge Issue
+// TODO: Restructure to remove #ifdef code.
+// ********
+
+#include "openavb_platform_pub.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "openavb_types_pub.h"
+
+// Uncomment AVB_LOG_ON to enable logging.
+#define AVB_LOG_ON 1
+
+// Uncomment AVB_LOG_ON_OVERRIDE to override all AVB_LOG_ON usage in the stack to ensure all logs are off.
+//#define AVB_LOG_ON_OVERRIDE 1
+
+#ifdef AVB_LOG_ON_OVERRIDE
+#ifdef AVB_LOG_ON
+#undef AVB_LOG_ON
+#endif
+#endif
+
+#define AVB_LOG_LEVEL_NONE 0
+#define AVB_LOG_LEVEL_ERROR 1
+#define AVB_LOG_LEVEL_WARNING 2
+#define AVB_LOG_LEVEL_INFO 3
+#define AVB_LOG_LEVEL_STATUS 4
+#define AVB_LOG_LEVEL_DEBUG 5
+#define AVB_LOG_LEVEL_VERBOSE 6
+
+// Special case development logging levels for use with AVB_LOGF_DEV and AVB_LOG_DEV
+#define AVB_LOG_LEVEL_DEV_ON AVB_LOG_LEVEL_NONE
+#define AVB_LOG_LEVEL_DEV_OFF AVB_LOG_LEVEL_VERBOSE + 1
+
+// Default log level, can override in source files
+#ifndef AVB_LOG_LEVEL
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_ERROR
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_INFO
+#define AVB_LOG_LEVEL AVB_LOG_LEVEL_STATUS
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_VERBOSE
+#endif
+
+#ifndef AVB_LOG_COMPANY
+#define AVB_LOG_COMPANY "OPENAVB"
+#endif
+
+#ifndef AVB_LOG_COMPONENT
+#define AVB_LOG_COMPONENT "AVB Stack"
+#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
+
+static const bool OPENAVB_LOG_TIME_INFO = FALSE;
+#define LOG_TIME_LEN 9
+//#define LOG_TIME_LEN 1
+
+static const bool OPENAVB_LOG_TIMESTAMP_INFO = TRUE;
+#define LOG_TIMESTAMP_LEN 32
+//#define LOG_TIMESTAMP_LEN 1
+
+static const bool OPENAVB_LOG_FILE_INFO = FALSE;
+//#define LOG_FILE_LEN 256
+#define LOG_FILE_LEN 1
+
+static const bool OPENAVB_LOG_PROC_INFO = FALSE;
+//#define LOG_PROC_LEN 64
+#define LOG_PROC_LEN 1
+
+static const bool OPENAVB_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 AVB_LOG_OUTPUT_FD stderr
+//#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.
+// 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
+// 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;
+
+// When using the OPENAVB_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: LOG_ONCE AVB_LOG_INFO(...)
+#define IF_LOG_ONCE() static U32 LOG_VAR(logOnce,__LINE__); 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)))
+
+
+#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_ARGS(s) (s)->addr[0],(s)->addr[1],(s)->addr[2],(s)->addr[3],(s)->addr[4],(s)->addr[5],(s)->uniqueID
+
+void avbLogInit(void);
+
+void avbLogExit(void);
+
+void avbLogFn(
+ int level,
+ const char *tag,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line,
+ const char *fmt,
+ ...);
+
+void avbLogRT(int level, bool bBegin, bool bItem, bool bEnd, char *pFormat, log_rt_datatype_t dataType, void *pVar);
+
+
+#define avbLogFn2(level, tag, company, component, path, line, fmt, ...) \
+ ({\
+ if (level <= AVB_LOG_LEVEL) \
+ avbLogFn(0, tag, company, component, path, line, fmt, __VA_ARGS__); \
+ })
+
+#ifdef AVB_LOG_ON
+#define AVB_LOGF_DEV(LEVEL, FMT, ...) avbLogFn2(LEVEL, "DEV", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define AVB_LOGF_ERROR(FMT, ...) avbLogFn2(AVB_LOG_LEVEL_ERROR, "ERROR", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define AVB_LOGF_WARNING(FMT, ...) avbLogFn2(AVB_LOG_LEVEL_WARNING, "WARNING", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define AVB_LOGF_INFO(FMT, ...) avbLogFn2(AVB_LOG_LEVEL_INFO, "INFO", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#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_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)
+#else
+#define AVB_LOGF_DEV(LEVEL, FMT, ...)
+#define AVB_LOGF_ERROR(FMT, ...)
+#define AVB_LOGF_WARNING(FMT, ...)
+#define AVB_LOGF_INFO(FMT, ...)
+#define AVB_LOGF_STATUS(FMT, ...)
+#define AVB_LOGF_DEBUG(FMT, ...)
+#define AVB_LOGF_VERBOSE(FMT, ...)
+#define AVB_LOG_DEV(LEVEL, FMT, ...)
+#define AVB_LOG_ERROR(MSG)
+#define AVB_LOG_WARNING(MSG)
+#define AVB_LOG_INFO(MSG)
+#define AVB_LOG_STATUS(MSG)
+#define AVB_LOG_DEBUG(MSG)
+#define AVB_LOG_VERBOSE(MSG)
+#define AVB_LOGRT_ERROR(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOGRT_WARNING(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOGRT_INFO(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#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)
+#endif // AVB_LOG_ON
+
+// 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);
+
+#endif // OPENAVB_LOG_PUB_H
diff --git a/lib/avtp_pipeline/include/openavb_map_pub.h b/lib/avtp_pipeline/include/openavb_map_pub.h
new file mode 100755
index 00000000..ff5e2a72
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_map_pub.h
@@ -0,0 +1,240 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Common mapper module public interface
+*/
+
+#ifndef OPENAVB_MAP_PUB_H
+#define OPENAVB_MAP_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_mediaq_pub.h"
+
+/** \file
+ * Common mapper module public interface.
+ */
+
+/// Vendor Specific format used in AVTP headers.
+#define MAP_NULL_OPENAVB_FORMAT 0x00
+
+/// Vendor Specific format used in AVTP headers.
+#define MAP_PIPE_OPENAVB_FORMAT 0x01
+
+/// Vendor Specific CTRL format used in AVTP headers.
+#define MAP_CTRL_OPENAVB_FORMAT 0x00
+
+/** Return value of talker callback.
+ */
+typedef enum {
+ TX_CB_RET_PACKET_NOT_READY = 0, ///< Packet will not be sent on this callback interval
+ TX_CB_RET_PACKET_READY, ///< Packet will be sent on this callback interal.
+ TX_CB_RET_MORE_PACKETS ///< Packet will be sent and the callback called immediately again.
+} tx_cb_ret_t;
+
+/** Configuration callback.
+ *
+ * Each configuration name value pair for this mapping will result in this
+ * callback being called.
+ * \param pMediaQ A pointer to the media queue for this stream
+ * \param name configuration item name
+ * \param value configuration item value
+ */
+typedef void (*openavb_map_cfg_cb_t)(media_q_t *pMediaQ, const char *name, const char *value);
+
+/** AVB subtype callback.
+ *
+ * \return The AVB subtype for this mapping.
+ */
+typedef U8(*openavb_map_subtype_cb_t)();
+
+/** AVTP version callback.
+ *
+ * \return The AVTP version for this mapping.
+ */
+typedef U8(*openavb_map_avtp_version_cb_t)();
+
+/** Maximum data size callback.
+ *
+ * \param pMediaQ A pointer to the media queue for this stream
+ * \return The maximum data size that will be used.
+ */
+typedef U16(*openavb_map_max_data_size_cb_t)(media_q_t *pMediaQ);
+
+/** Transmit interval callback.
+ *
+ * \param pMediaQ A pointer to the media queue for this stream
+ * \return The intended transmit interval (in frames per second).
+ * 0 = default for talker / class.
+ */
+typedef U32(*openavb_map_transmit_interval_cb_t)(media_q_t *pMediaQ);
+
+/** General initialize callback regardless if a talker or listener.
+ *
+ * Called once during openavbTLOpen().
+ * \param pMediaQ A pointer to the media queue for this stream
+ */
+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.
+ * \param pMediaQ A pointer to the media queue for this stream
+ */
+typedef void (*openavb_map_tx_init_cb_t)(media_q_t *pMediaQ);
+
+/** This talker callback will be called for each AVB observation interval.
+ *
+ * \param pMediaQ A pointer to the media queue for this stream
+ * \param pData pointer to data
+ * \param dataLen length of data
+ * \return One of enum \ref tx_cb_ret_t values.
+ */
+typedef tx_cb_ret_t(*openavb_map_tx_cb_t)(media_q_t *pMediaQ, U8 *pData, U32 *datalen);
+
+/** A call to this callback indicates that this mapping module will be
+ * a listener.
+ *
+ * Any listener initialization can be done in this function.
+ * \param pMediaQ A pointer to the media queue for this stream
+ */
+typedef void (*openavb_map_rx_init_cb_t)(media_q_t *pMediaQ);
+
+/** This callback occurs when running as a listener and data is available.
+ *
+ * \param pMediaQ A pointer to the media queue for this stream
+ * \param pData pointer to data
+ * \param dataLen length of data
+ */
+typedef bool (*openavb_map_rx_cb_t)(media_q_t *pMediaQ, U8 *pData, U32 datalen);
+
+/** This callback will be called when the stream is closing.
+ *
+ * \param pMediaQ A pointer to the media queue for this stream
+ */
+typedef void (*openavb_map_end_cb_t)(media_q_t *pMediaQ);
+
+/** General shutdown callback regardless if a talker or listener.
+ *
+ * Called once during openavbTLClose().
+ * \param pMediaQ A pointer to the media queue for this stream
+ */
+typedef void (*openavb_map_gen_end_cb_t)(media_q_t *pMediaQ);
+
+/** Set source bitrate callback.
+ *
+ * Used to inform mapping module on the bitrate of the data source (computed by
+ * the interface module). The reported bitrate is used by the
+ * openavb_map_get_max_interval_frames_cb_t() callback.
+ * \param pMediaQ A pointer to the media queue for this stream
+ * \param bitrate Data source bitrate
+ *
+ * \note This callback is optional, does not need to be implemented in the
+ * mapping module.
+ */
+typedef void (*openavb_map_set_src_bitrate_cb_t)(media_q_t *pMediaQ, unsigned int bitrate);
+
+/** Get max interval frames.
+ *
+ * Called to get the maximum number of frames per interval for the talker. The
+ * calculation is based on the source bitrate provided in the call to
+ * openavb_map_set_src_bitrate_cb_t(). Will override ini file "max_interval_frames"
+ * configuration option.
+ * \param pMediaQ A pointer to the media queue for this stream
+ * \param sr_class Stream reservation class
+ * \return Maximum number of frames per interval
+ *
+ * \note This callback is optional, does not need to be implemented in the
+ * mapping module.
+ */
+typedef unsigned int (*openavb_map_get_max_interval_frames_cb_t)(media_q_t *pMediaQ, SRClassIdx_t sr_class);
+
+/** Mapping callbacks structure.
+ */
+typedef struct {
+ /// Configuration callback.
+ openavb_map_cfg_cb_t map_cfg_cb;
+ /// AVB subtype callback.
+ openavb_map_subtype_cb_t map_subtype_cb;
+ /// AVTP version callback.
+ openavb_map_avtp_version_cb_t map_avtp_version_cb;
+ /// Maximum data size callback.
+ openavb_map_max_data_size_cb_t map_max_data_size_cb;
+ /// Transmit interval callback.
+ 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.
+ openavb_map_tx_cb_t map_tx_cb;
+ /// Initialize receive callback.
+ openavb_map_rx_init_cb_t map_rx_init_cb;
+ /// Receive callback.
+ openavb_map_rx_cb_t map_rx_cb;
+ /// Stream end callback.
+ openavb_map_end_cb_t map_end_cb;
+ /// General shutdown callback.
+ openavb_map_gen_end_cb_t map_gen_end_cb;
+ /// Set source bit rate callback.
+ openavb_map_set_src_bitrate_cb_t map_set_src_bitrate_cb;
+ /// Max interval frames callback.
+ openavb_map_get_max_interval_frames_cb_t map_get_max_interval_frames_cb;
+} openavb_map_cb_t;
+
+/** Main initialization entry point into the mapping module.
+ *
+ * \param pMediaQ A pointer to the media queue for this stream
+ * \param[out] pMapCB Pointer to the callback structure. All the members of this
+ * structure must be set during this function call.
+ * \param inMaxTransitUsec maximum expected latency.
+ */
+typedef bool (*openavb_map_initialize_fn_t)(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
+
+#endif // OPENAVB_MAP_PUB_H
+
diff --git a/lib/avtp_pipeline/include/openavb_platform.h b/lib/avtp_pipeline/include/openavb_platform.h
new file mode 100644
index 00000000..fb079d51
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_platform.h
@@ -0,0 +1,47 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Interface for platform functionality
+* Each platform is comprised of a HAL and an OSAL layer.
+* The build scripts must correctly establish the include
+* paths for each of these.
+*/
+
+#ifndef _OPENAVB_PLATFORM_H
+#define _OPENAVB_PLATFORM_H
+
+#include "openavb_types_base.h"
+#include "openavb_osal.h"
+#include "openavb_mem_tcal.h"
+#include <stdint.h>
+#include "openavb_types.h"
+
+#endif // _OPENAVB_PLATFORM_H
diff --git a/lib/avtp_pipeline/include/openavb_platform_pub.h b/lib/avtp_pipeline/include/openavb_platform_pub.h
new file mode 100644
index 00000000..61233712
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_platform_pub.h
@@ -0,0 +1,42 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Public interface for platform specific functionality
+*/
+
+#ifndef _OPENAVB_PLATFORM_PUB_H
+#define _OPENAVB_PLATFORM_PUB_H
+
+#include "openavb_types_pub.h"
+#include "openavb_osal_pub.h"
+#include "openavb_mem_tcal_pub.h"
+
+#endif // _OPENAVB_PLATFORM_PUB_H
diff --git a/lib/avtp_pipeline/include/openavb_pub.h b/lib/avtp_pipeline/include/openavb_pub.h
new file mode 100644
index 00000000..1f67f10e
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_pub.h
@@ -0,0 +1,87 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : General header file for the AVB stack
+*/
+
+#ifndef AVB_PUB_H
+#define AVB_PUB_H 1
+
+#include "openavb_log_pub.h"
+
+/////////////////////////////////////////////////////////
+// AVB Core version related macros
+//
+// These must NOT be edited for project related work
+/////////////////////////////////////////////////////////
+#define AVB_CORE_NAME "AVTP Pipeline"
+
+#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)
+
+// Standard release designations. Uncomment one AVB_RELEASE_TYPE
+#define AVB_CORE_RELEASE_TYPE "Development"
+//#define AVB_CORE_RELEASE_TYPE "Alpha"
+//#define AVB_CORE_RELEASE_TYPE "Beta"
+//#define AVB_CORE_RELEASE_TYPE "Release"
+
+#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)
+
+
+
+/////////////////////////////////////////////////////////
+// AVB Project version related macros
+//
+// These can be used for project solutions
+/////////////////////////////////////////////////////////
+#define AVB_PROJECT_NAME "Sample AVB Solution"
+
+#define AVB_PROJECT_VER_MAJOR (1)
+#define AVB_PROJECT_VER_MINOR (0)
+#define AVB_PROJECT_VER_REVISION (0)
+
+#define AVB_PROJECT_VER_FULL (AVB_PROJECT_VER_MAJOR << 16 | AVB_PROJECT_VER_MINOR << 8 | AVB_PROJECT_VER_REVISION)
+
+// Standard release designations. Uncomment one AVB_RELEASE_TYPE
+#define AVB_PROJECT_RELEASE_TYPE "Development"
+//#define AVB_PROJECT_RELEASE_TYPE "Alpha"
+//#define AVB_PROJECT_RELEASE_TYPE "Beta"
+//#define AVB_PROJECT_RELEASE_TYPE "Release"
+
+#define LOG_EAVB_PROJECT_VERSION() AVB_LOGF_INFO("%s: %i.%i.%i (%s)", AVB_PROJECT_NAME, AVB_PROJECT_VER_MAJOR, AVB_PROJECT_VER_MINOR, AVB_PROJECT_VER_REVISION, AVB_PROJECT_RELEASE_TYPE)
+
+
+
+
+#endif // AVB_PUB_H
diff --git a/lib/avtp_pipeline/include/openavb_trace.h b/lib/avtp_pipeline/include/openavb_trace.h
new file mode 100644
index 00000000..fd58cde6
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_trace.h
@@ -0,0 +1,78 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Provide a simple tracing facility for use
+* during development.
+*
+* Based off of the openavb_log facility.
+*
+* NOTE: The Tracing uses a high resolution timer and therefore
+* librt must be linked into any application that uses this
+* facility.
+*/
+
+#ifndef AVB_TRACE_H
+#define AVB_TRACE_H 1
+
+#include "openavb_trace_pub.h"
+
+// Features to trace. 1 is enabled, 0 is disabled.
+#define AVB_TRACE_ACMP 0
+#define AVB_TRACE_ADP 0
+#define AVB_TRACE_AECP 0
+#define AVB_TRACE_AEM 0
+#define AVB_TRACE_AVDECC 0
+#define AVB_TRACE_AVTP 1
+#define AVB_TRACE_AVTP_DETAIL 1
+#define AVB_TRACE_AVTP_TIME 0
+#define AVB_TRACE_AVTP_TIME_DETAIL 0
+#define AVB_TRACE_ENDPOINT 0
+#define AVB_TRACE_MEDIAQ 0
+#define AVB_TRACE_MEDIAQ_DETAIL 0
+#define AVB_TRACE_QUEUE_MANAGER 0
+#define AVB_TRACE_MAAP 0
+#define AVB_TRACE_RAWSOCK 1
+#define AVB_TRACE_RAWSOCK_DETAIL 1
+#define AVB_TRACE_SRP_PUBLIC 0
+#define AVB_TRACE_SRP_PRIVATE 0
+#define AVB_TRACE_TL 0
+#define AVB_TRACE_TL_DETAIL 0
+#define AVB_TRACE_PTP 0
+#define AVB_TRACE_FQTSS 0
+#define AVB_TRACE_FQTSS_DETAIL 0
+#define AVB_TRACE_HR_TMR 0
+#define AVB_TRACE_NANOSLEEP 0
+#define AVB_TRACE_TIME 0
+#define AVB_TRACE_HAL_ETHER 0
+#define AVB_TRACE_HAL_ETHER_DETAIL 0
+#define AVB_TRACE_HAL_TASK_TIMER 0
+#define AVB_TRACE_DEBUG 0
+#endif // AVB_TRACE_H
diff --git a/lib/avtp_pipeline/include/openavb_trace_pub.h b/lib/avtp_pipeline/include/openavb_trace_pub.h
new file mode 100644
index 00000000..c90a83d3
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_trace_pub.h
@@ -0,0 +1,247 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Provide a simple tracing facility for use
+* during development.
+*
+* Based off of the openavb_log facility.
+*
+* NOTE: The Tracing uses a high resolution timer and therefore
+* librt must be linked into any application that uses this
+* facility.
+*/
+
+#ifndef AVB_TRACE_PUB_H
+#define AVB_TRACE_PUB_H 1
+
+#include "openavb_platform_pub.h"
+#include <stdio.h>
+#include "openavb_types_pub.h"
+
+// Uncomment AVB_TRACE_ON to enable tracing.
+//#define AVB_TRACE_ON 1
+
+// Specific reporting modes
+#define AVB_TRACE_MODE_NONE 0
+#define AVB_TRACE_MODE_MINIMAL 1
+#define AVB_TRACE_MODE_NORMAL 2
+#define AVB_TRACE_MODE_DELTA_TIME 3
+#define AVB_TRACE_MODE_DELTA_STATS 4
+#define AVB_TRACE_MODE_FUNC_TIME 5
+#define AVB_TRACE_MODE_DOC 6
+
+// One of the above reporting modes must be set here
+#define AVB_TRACE_MODE AVB_TRACE_MODE_NORMAL
+
+// Delta Stats Interval
+#define AVB_TRACE_OPT_DELTA_STATS_INTERVAL 80000
+
+// Function Time interval
+#define AVB_TRACE_OPT_FUNC_TIME_INTERVAL 80000
+//#define AVB_TRACE_OPT_FUNC_TIME_INTERVAL 100
+
+// Option to show file name
+//#define AVB_TRACE_OPT_SHOW_FILE_NAME 1
+
+
+//#define AVB_TRACE_PRINTF(FMT, ...) fprintf(stderr, FMT, __VA_ARGS__)
+//#define AVB_TRACE_PRINTF(FMT, ...) fprintf(stdout, FMT, __VA_ARGS__)
+#define AVB_TRACE_PRINTF(FMT, ...) printf(FMT, __VA_ARGS__)
+
+
+// Features to trace. 1 is enabled, 0 is disabled.
+#define AVB_TRACE_MAP 0
+#define AVB_TRACE_MAP_DETAIL 0
+#define AVB_TRACE_MAP_LINE 0
+#define AVB_TRACE_INTF 0
+#define AVB_TRACE_INTF_DETAIL 0
+#define AVB_TRACE_INTF_LINE 0
+#define AVB_TRACE_HOST 0
+
+#define TRACE_VAR1(x, y) x ## y
+#define TRACE_VAR2(x, y) TRACE_VAR1(x, y)
+
+#ifdef AVB_TRACE_OPT_SHOW_FILE_NAME
+#define TRACE_FILE_NAME __FILE__
+#else
+#define TRACE_FILE_NAME ""
+#endif
+
+
+#if !defined(AVB_TRACE_ON) || (AVB_TRACE_MODE == AVB_TRACE_MODE_NONE)
+#define AVB_TRACE_LINE(FEATURE)
+#define AVB_TRACE_ENTRY(FEATURE)
+#define AVB_TRACE_EXIT(FEATURE)
+#define AVB_TRACE_LOOP_ENTRY(FEATURE)
+#define AVB_TRACE_LOOP_EXIT(FEATURE)
+#elif (AVB_TRACE_MODE == AVB_TRACE_MODE_MINIMAL)
+#define AVB_TRACE_LINE(FEATURE) avbTraceMinimalFn(FEATURE, "TRACE LINE ", __FUNCTION__, TRACE_FILE_NAME, __LINE__)
+#define AVB_TRACE_ENTRY(FEATURE) avbTraceMinimalFn(FEATURE, "TRACE ENTRY", __FUNCTION__, TRACE_FILE_NAME, __LINE__)
+#define AVB_TRACE_EXIT(FEATURE) avbTraceMinimalFn(FEATURE, "TRACE EXIT ", __FUNCTION__, TRACE_FILE_NAME, __LINE__)
+#define AVB_TRACE_LOOP_ENTRY(FEATURE) avbTraceMinimalFn(FEATURE, "TRACE LOOP{", __FUNCTION__, TRACE_FILE_NAME, __LINE__)
+#define AVB_TRACE_LOOP_EXIT(FEATURE) avbTraceMinimalFn(FEATURE, "TRACE LOOP}", __FUNCTION__, TRACE_FILE_NAME, __LINE__)
+#elif (AVB_TRACE_MODE == AVB_TRACE_MODE_NORMAL)
+#define AVB_TRACE_LINE(FEATURE) avbTraceNormalFn(FEATURE, "TRACE LINE ", __FUNCTION__, TRACE_FILE_NAME, __LINE__)
+#define AVB_TRACE_ENTRY(FEATURE) avbTraceNormalFn(FEATURE, "TRACE ENTRY", __FUNCTION__, TRACE_FILE_NAME, __LINE__)
+#define AVB_TRACE_EXIT(FEATURE) avbTraceNormalFn(FEATURE, "TRACE EXIT ", __FUNCTION__, TRACE_FILE_NAME, __LINE__)
+#define AVB_TRACE_LOOP_ENTRY(FEATURE) avbTraceNormalFn(FEATURE, "TRACE LOOP{", __FUNCTION__, TRACE_FILE_NAME, __LINE__)
+#define AVB_TRACE_LOOP_EXIT(FEATURE) avbTraceNormalFn(FEATURE, "TRACE LOOP}", __FUNCTION__, TRACE_FILE_NAME, __LINE__)
+#elif (AVB_TRACE_MODE == AVB_TRACE_MODE_DELTA_TIME)
+#define AVB_TRACE_LINE(FEATURE) avbTraceDeltaTimeFn(FEATURE, "TRACE LINE ", __FUNCTION__, TRACE_FILE_NAME, __LINE__, NULL, NULL)
+#define AVB_TRACE_ENTRY(FEATURE) avbTraceDeltaTimeFn(FEATURE, "TRACE ENTRY", __FUNCTION__, TRACE_FILE_NAME, __LINE__, NULL, NULL)
+#define AVB_TRACE_EXIT(FEATURE) avbTraceDeltaTimeFn(FEATURE, "TRACE EXIT ", __FUNCTION__, TRACE_FILE_NAME, __LINE__, NULL, NULL)
+#define AVB_TRACE_LOOP_ENTRY(FEATURE) avbTraceDeltaTimeFn(FEATURE, "TRACE LOOP{", __FUNCTION__, TRACE_FILE_NAME, __LINE__, NULL, NULL)
+#define AVB_TRACE_LOOP_EXIT(FEATURE) avbTraceDeltaTimeFn(FEATURE, "TRACE LOOP}", __FUNCTION__, TRACE_FILE_NAME, __LINE__, NULL, NULL)
+#elif (AVB_TRACE_MODE == AVB_TRACE_MODE_DELTA_STATS)
+#define AVB_TRACE_LINE(FEATURE) static U64 TRACE_VAR2(traceCnt,__LINE__); static U64 TRACE_VAR2(traceNSec, __LINE__); avbTraceDeltaTimeFn(FEATURE, "TRACE LINE ", __FUNCTION__, TRACE_FILE_NAME, __LINE__, &TRACE_VAR2(traceCnt,__LINE__), &TRACE_VAR2(traceNSec, __LINE__))
+#define AVB_TRACE_ENTRY(FEATURE) static U64 TRACE_VAR2(traceCnt,__LINE__); static U64 TRACE_VAR2(traceNSec, __LINE__); avbTraceDeltaTimeFn(FEATURE, "TRACE ENTRY", __FUNCTION__, TRACE_FILE_NAME, __LINE__, &TRACE_VAR2(traceCnt,__LINE__), &TRACE_VAR2(traceNSec, __LINE__))
+#define AVB_TRACE_EXIT(FEATURE) static U64 TRACE_VAR2(traceCnt,__LINE__); static U64 TRACE_VAR2(traceNSec, __LINE__); avbTraceDeltaTimeFn(FEATURE, "TRACE EXIT ", __FUNCTION__, TRACE_FILE_NAME, __LINE__, &TRACE_VAR2(traceCnt,__LINE__), &TRACE_VAR2(traceNSec, __LINE__))
+#define AVB_TRACE_LOOP_ENTRY(FEATURE) static U64 TRACE_VAR2(traceCnt,__LINE__); static U64 TRACE_VAR2(traceNSec, __LINE__); avbTraceDeltaTimeFn(FEATURE, "TRACE LOOP{", __FUNCTION__, TRACE_FILE_NAME, __LINE__, &TRACE_VAR2(traceCnt,__LINE__), &TRACE_VAR2(traceNSec, __LINE__))
+#define AVB_TRACE_LOOP_EXIT(FEATURE) static U64 TRACE_VAR2(traceCnt,__LINE__); static U64 TRACE_VAR2(traceNSec, __LINE__); avbTraceDeltaTimeFn(FEATURE, "TRACE LOOP}", __FUNCTION__, TRACE_FILE_NAME, __LINE__, &TRACE_VAR2(traceCnt,__LINE__), &TRACE_VAR2(traceNSec, __LINE__))
+#elif (AVB_TRACE_MODE == AVB_TRACE_MODE_FUNC_TIME)
+#define AVB_TRACE_LINE(FEATURE)
+#define AVB_TRACE_ENTRY(FEATURE) static struct timespec TRACE_VAR2(tsFuncEntry,__FUNCTION__); avbTraceFuncTimeFn(FEATURE, TRUE, __FUNCTION__, TRACE_FILE_NAME, __LINE__, &TRACE_VAR2(tsFuncEntry,__FUNCTION__), NULL, NULL)
+#define AVB_TRACE_EXIT(FEATURE) static U64 TRACE_VAR2(traceCnt,__LINE__); static U64 TRACE_VAR2(traceNSec, __LINE__); avbTraceFuncTimeFn(FEATURE, FALSE, __FUNCTION__, TRACE_FILE_NAME, __LINE__, &TRACE_VAR2(tsFuncEntry,__FUNCTION__), &TRACE_VAR2(traceCnt,__LINE__), &TRACE_VAR2(traceNSec, __LINE__))
+#define AVB_TRACE_LOOP_ENTRY(FEATURE) static struct timespec TRACE_VAR2(tsLoopEntry,__FUNCTION__); avbTraceFuncTimeFn(FEATURE, TRUE, __FUNCTION__, TRACE_FILE_NAME, __LINE__, &TRACE_VAR2(tsLoopEntry,__FUNCTION__), NULL, NULL)
+#define AVB_TRACE_LOOP_EXIT(FEATURE) static U64 TRACE_VAR2(traceCnt,__LINE__); static U64 TRACE_VAR2(traceNSec, __LINE__); avbTraceFuncTimeFn(FEATURE, FALSE, __FUNCTION__, TRACE_FILE_NAME, __LINE__, &TRACE_VAR2(tsLoopEntry,__FUNCTION__), &TRACE_VAR2(traceCnt,__LINE__), &TRACE_VAR2(traceNSec, __LINE__))
+#elif (AVB_TRACE_MODE == AVB_TRACE_MODE_DOC)
+#define AVB_TRACE_LINE(FEATURE) avbTraceDocFn(FEATURE, "|", __FUNCTION__, TRACE_FILE_NAME, __LINE__, NULL, NULL)
+#define AVB_TRACE_ENTRY(FEATURE) avbTraceDocFn(FEATURE, ">", __FUNCTION__, TRACE_FILE_NAME, __LINE__, NULL, NULL)
+#define AVB_TRACE_EXIT(FEATURE) avbTraceDocFn(FEATURE, "<", __FUNCTION__, TRACE_FILE_NAME, __LINE__, NULL, NULL)
+#define AVB_TRACE_LOOP_ENTRY(FEATURE)
+#define AVB_TRACE_LOOP_EXIT(FEATURE)
+#endif
+
+#ifdef AVB_TRACE_ON
+
+static inline void avbTraceMinimalFn(int featureOn, const char *tag, const char *function, const char *file, int line)
+{
+ if (featureOn) {
+ AVB_TRACE_PRINTF("%s: %s():%d %s\n", tag, function, line, file);
+ }
+}
+
+static inline void avbTraceNormalFn(int featureOn, const char *tag, const char *function, const char *file, int line)
+{
+ if (featureOn) {
+ time_t tNow = time(NULL);
+ struct tm tmNow;
+ localtime_r(&tNow, &tmNow);
+
+ AVB_TRACE_PRINTF("[%2.2d:%2.2d:%2.2d] [P:%5.5d T:%lu] %s: %s():%d %s\n",
+ tmNow.tm_hour, tmNow.tm_min, tmNow.tm_sec, GET_PID(), THREAD_SELF(), tag, function, line, file);
+ }
+}
+
+static inline void avbTraceDeltaTimeFn(int featureOn, const char *tag, const char *function, const char *file, int line, U64 *pCnt, U64 *pNSec)
+{
+ if (featureOn) {
+ static struct timespec traceDeltaTimePrevTS;
+
+ struct timespec nowTS;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &nowTS);
+
+ time_t tNow = time(NULL);
+ struct tm tmNow;
+ localtime_r(&tNow, &tmNow);
+
+ U64 prevNSec = ((U64)traceDeltaTimePrevTS.tv_sec * (U64)NANOSECONDS_PER_SECOND) + (U64)traceDeltaTimePrevTS.tv_nsec;
+ U64 nowNSec = ((U64)nowTS.tv_sec * (U64)NANOSECONDS_PER_SECOND) + (U64)nowTS.tv_nsec;
+ U64 deltaNSec = nowNSec - prevNSec;
+
+ if (pCnt && pNSec) {
+ // Delta Stats
+ (*pCnt)++;
+ *pNSec += deltaNSec;
+
+ if (*pCnt % AVB_TRACE_OPT_DELTA_STATS_INTERVAL == 0) {
+ AVB_TRACE_PRINTF("[%2.2d:%2.2d:%2.2d] [P:%5.5d T:%lu] [cnt:%6llu deltaUS:%10llu totalUS:%10llu] %s: %s():%d %s\n",
+ tmNow.tm_hour, tmNow.tm_min, tmNow.tm_sec, GET_PID(), THREAD_SELF(), (unsigned long long)(*pCnt), (unsigned long long)(deltaNSec / 1000), (unsigned long long)(*pNSec / 1000), tag, function, line, file);
+ }
+ }
+ else {
+ AVB_TRACE_PRINTF("[%2.2d:%2.2d:%2.2d] [P:%5.5d T:%lu] [deltaUS:%10llu] %s: %s():%d %s\n",
+ tmNow.tm_hour, tmNow.tm_min, tmNow.tm_sec, GET_PID(), THREAD_SELF(), (unsigned long long)(deltaNSec / 1000), tag, function, line, file);
+ }
+
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &traceDeltaTimePrevTS);
+ }
+}
+
+static inline void avbTraceFuncTimeFn(int featureOn, bool bEntry, const char *function, const char *file, int line, struct timespec *pTS, U64 *pCnt, U64 *pNSec)
+{
+ if (featureOn) {
+ if (bEntry) {
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, pTS);
+ }
+ else {
+ struct timespec nowTS;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &nowTS);
+
+ time_t tNow = time(NULL);
+ struct tm tmNow;
+ localtime_r(&tNow, &tmNow);
+
+ U64 entryNSec = ((U64)pTS->tv_sec * (U64)NANOSECONDS_PER_SECOND) + (U64)pTS->tv_nsec;
+ U64 nowNSec = ((U64)nowTS.tv_sec * (U64)NANOSECONDS_PER_SECOND) + (U64)nowTS.tv_nsec;
+ U64 deltaNSec = nowNSec - entryNSec;
+
+ (*pCnt)++;
+ *pNSec += deltaNSec;
+
+ if (*pCnt % AVB_TRACE_OPT_FUNC_TIME_INTERVAL == 0) {
+ AVB_TRACE_PRINTF("[%2.2d:%2.2d:%2.2d] [P:%5.5d T:%lu] [cnt:%6llu lastUS:%10llu totalUS:%10llu avgUS:%10llu] %s():%d %s\n",
+ tmNow.tm_hour, tmNow.tm_min, tmNow.tm_sec, GET_PID(), THREAD_SELF(), (unsigned long long)(*pCnt), (unsigned long long)(deltaNSec / 1000), (unsigned long long)(*pNSec / 1000), (unsigned long long)((*pNSec / *pCnt) / 1000), function, line, file);
+ }
+ }
+ }
+}
+
+static inline void avbTraceDocFn(int featureOn, const char *tag, const char *function, const char *file, int line, U64 *pCnt, U64 *pNSec)
+{
+ if (featureOn) {
+ static int depthTrace = 0;
+ if (tag[0] == '>') {
+ AVB_TRACE_PRINTF("%*s%s %s [%s]\n", depthTrace * 4, "", tag, function, file);
+ depthTrace++;
+ }
+ else if (tag[0] == '<') {
+ depthTrace--;
+ AVB_TRACE_PRINTF("%*s%s %s [%s]\n", depthTrace * 4, "", tag, function, file);
+ }
+ else {
+ AVB_TRACE_PRINTF("%*s%s %s [%s]\n", depthTrace * 4, "", tag, function, file);
+ }
+ }
+}
+
+#endif // AVB_TRACE_ON
+#endif // AVB_TRACE_PUB_H
diff --git a/lib/avtp_pipeline/include/openavb_types.h b/lib/avtp_pipeline/include/openavb_types.h
new file mode 100644
index 00000000..c042c24c
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_types.h
@@ -0,0 +1,45 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Provide common types and defines for use in AVB
+*/
+
+#ifndef AVB_TYPES_H
+#define AVB_TYPES_H 1
+
+#include "openavb_platform.h"
+
+typedef struct { // per IEEE 802.1Q-2011 Section 35.2.2.8.2
+ U8 addr[ETH_ALEN];
+ U16 uniqueID;
+} AVBStreamID_t;
+
+#endif // AVB_TYPES_H
diff --git a/lib/avtp_pipeline/include/openavb_types_base.h b/lib/avtp_pipeline/include/openavb_types_base.h
new file mode 100644
index 00000000..1a3e2628
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_types_base.h
@@ -0,0 +1,79 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Internal AVB Base Types (have no dependencies)
+*/
+
+#ifndef AVB_TYPES_BASE_H
+#define AVB_TYPES_BASE_H 1
+
+#include <assert.h>
+#include "openavb_types_base_pub.h"
+#include "openavb_result_codes.h"
+
+typedef struct { // per IEEE 802.1Q-2011 Section 35.2.2.8.4
+ U16 maxFrameSize;
+ U16 maxIntervalFrames;
+} AVBTSpec_t;
+
+// Ethernet Frame overhead
+// L2 includes MAC src/dest, VLAN tag, Ethertype
+#define OPENAVB_AVTP_L2_OVERHEAD 18
+// L1 includes preamble, start-of-frame, FCS, interframe gap
+#define OPENAVB_AVTP_L1_OVERHEAD 24
+// All of the above
+#define OPENAVB_AVTP_ETHER_FRAME_OVERHEAD (OPENAVB_AVTP_L1_OVERHEAD + OPENAVB_AVTP_L2_OVERHEAD)
+
+// Maximum number of streams per class
+// (Fixed number for efficiency in FQTSS kernel module)
+#define MAX_AVB_STREAMS_PER_CLASS 16
+// Maximum number of streams that we handle
+#define MAX_AVB_STREAMS (MAX_AVB_SR_CLASSES * MAX_AVB_STREAMS_PER_CLASS)
+
+#define SR_CLASS_IS_VALID(C) (C>=0 && C<MAX_AVB_SR_CLASSES)
+#define AVB_CLASS_LABEL(C) ('A'+C)
+
+#define OPENAVB_DEFAULT_CLASSA_MAX_LATENCY (2 * NANOSECONDS_PER_MSEC)
+#define OPENAVB_DEFAULT_CLASSB_MAX_LATENCY (50 * NANOSECONDS_PER_MSEC)
+
+// Ethernet MAC Address Length - 6 bytes
+#define ETH_MAC_ADDR_LEN 6
+
+// For production builds, use the first define here to turn assert off
+// For debug builds, use the second define here to turn assert on
+// CAUTION: Any executable code in _AST_ will not be included in production code.
+//#define OPENAVB_ASSERT(_AST_)
+#define OPENAVB_ASSERT(_AST_) assert(_AST_)
+
+// Features
+//#define OPENAVB_GST_PIPELINE_INSTRUMENTATION 1
+
+#endif // AVB_TYPES_BASE_H
diff --git a/lib/avtp_pipeline/include/openavb_types_base_pub.h b/lib/avtp_pipeline/include/openavb_types_base_pub.h
new file mode 100644
index 00000000..f568477a
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_types_base_pub.h
@@ -0,0 +1,120 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Public AVB Base Types (have no dependencies)
+*/
+
+#ifndef AVB_TYPES_BASE_PUB_H
+#define AVB_TYPES_BASE_PUB_H 1
+
+#include "openavb_types_base_tcal_pub.h"
+#include <stdbool.h>
+#include <inttypes.h>
+
+/** \file
+ * Common Base AVB Types that are exposed outside of the AVB
+ * stack.
+ */
+
+/*
+ * Useful types for OPENAVB AVB
+ *
+ */
+/// Number of nanoseconds in second
+#define NANOSECONDS_PER_SECOND (1000000000ULL)
+/// Number of nanoseconds in milisecond
+#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 milisecond
+#define MICROSECONDS_PER_MSEC (1000L)
+
+#ifndef TRUE // possible confict with gboolean
+/// True boolean value
+#define TRUE true
+/// False boolean value
+#define FALSE false
+#endif
+
+#ifndef NULL
+/// Null pointer value
+#define NULL 0
+#endif
+
+/// Signed 8 bit type
+typedef int8_t S8;
+/// Unsigned 8 bit type
+typedef uint8_t U8;
+/// Signed 16 bit type
+typedef int16_t S16;
+/// Unsigned 16 bit type
+typedef uint16_t U16;
+/// Signed 32 bit type
+typedef int32_t S32;
+/// Unsigned 32 bit type
+typedef uint32_t U32;
+/// Signed 64 bit type
+typedef int64_t S64;
+/// Unsigned 64 bit type
+typedef uint64_t U64;
+
+/// Describes role of the host
+typedef enum {
+ /// Role undefined or wrong handle
+ AVB_ROLE_UNDEFINED = 0,
+ /// Host acts as a talker
+ AVB_ROLE_TALKER,
+ /// Host acts as a listener
+ AVB_ROLE_LISTENER
+} avb_role_t;
+
+
+
+/// Supported AVB classes.
+typedef enum {
+ /// Stream reservation class A. 8000 packets per second
+ SR_CLASS_A,
+ /// Stream reservation class B. 4000 packets per second
+ SR_CLASS_B,
+// SR_CLASS_C,
+// SR_CLASS_D,
+ /// Number of supported stream reservation classes
+ MAX_AVB_SR_CLASSES
+} SRClassIdx_t;
+
+/// Regular
+#define SR_RANK_REGULAR 1
+/// Emergency
+#define SR_RANK_EMERGENCY 0
+
+#endif // AVB_TYPES_BASE_PUB_H
diff --git a/lib/avtp_pipeline/include/openavb_types_pub.h b/lib/avtp_pipeline/include/openavb_types_pub.h
new file mode 100644
index 00000000..02e61466
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_types_pub.h
@@ -0,0 +1,48 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Common AVB Types that are exposed outside of the
+* AVB stack.
+*/
+
+#ifndef AVB_TYPES_PUB_H
+#define AVB_TYPES_PUB_H 1
+
+#include "openavb_types_base_pub.h"
+
+// Visiblity; used to define which function need to be externally visible
+#if __GNUC__ >= 4
+#define DLL_EXPORT __attribute__ ((visibility ("default")))
+#else
+#define DLL_EXPORT
+#endif
+
+#endif // AVB_TYPES_PUB_H
diff --git a/lib/avtp_pipeline/inih/CMakeLists.txt b/lib/avtp_pipeline/inih/CMakeLists.txt
new file mode 100644
index 00000000..1876de1e
--- /dev/null
+++ b/lib/avtp_pipeline/inih/CMakeLists.txt
@@ -0,0 +1,5 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/inih/ini.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/inih/LICENSE.txt b/lib/avtp_pipeline/inih/LICENSE.txt
new file mode 100644
index 00000000..44a3093a
--- /dev/null
+++ b/lib/avtp_pipeline/inih/LICENSE.txt
@@ -0,0 +1,27 @@
+
+The "inih" library is distributed under the New BSD license:
+
+Copyright (c) 2009, Brush Technology
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+ * Neither the name of Brush Technology nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''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 BRUSH TECHNOLOGY 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/lib/avtp_pipeline/inih/README.TXT b/lib/avtp_pipeline/inih/README.TXT
new file mode 100644
index 00000000..b8f4536e
--- /dev/null
+++ b/lib/avtp_pipeline/inih/README.TXT
@@ -0,0 +1,15 @@
+"inih" is an .ini file parser. I'm currently using it for the
+prototype talker and listener. It uses a BSD license, which requires
+a copyright notification in releases of derived works, but does not
+require the source code for derived works to be released.
+
+The description from the project page on Google code:
+
+ inih (INI Not Invented Here) is a simple .INI file parser written in C.
+ It's only a couple of pages of code, and it was designed to be small
+ and simple, so it's good for embedded systems. It's also more or
+ less compatible with Python's ConfigParser style of .INI files,
+ including RFC 822-style multi-line syntax and name: value entries.
+
+Downloaded from:
+ http://code.google.com/p/inih/
diff --git a/lib/avtp_pipeline/inih/ini.c b/lib/avtp_pipeline/inih/ini.c
new file mode 100644
index 00000000..4fad5c51
--- /dev/null
+++ b/lib/avtp_pipeline/inih/ini.c
@@ -0,0 +1,292 @@
+/* inih -- simple .INI file parser
+
+inih is released under the New BSD license (see LICENSE.txt). Go to the project
+home page for more info:
+
+http://code.google.com/p/inih/
+
+*/
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include "ini.h"
+
+#if !INI_USE_STACK
+#include <stdlib.h>
+#endif
+
+#define MAX_SECTION 50
+#define MAX_NAME 50
+
+/* Strip whitespace chars off end of given string, in place. Return s. */
+static char* rstrip(char* s)
+{
+ char* p = s + strlen(s);
+ while (p > s && isspace(*--p))
+ *p = '\0';
+ return s;
+}
+
+/* Return pointer to first non-whitespace char in given string. */
+static char* lskip(const char* s)
+{
+ while (*s && isspace(*s))
+ s++;
+ return (char*)s;
+}
+
+/* Return pointer to first char c or ';' comment in given string, or pointer to
+ null at end of string if neither found. ';' must be prefixed by a whitespace
+ character to register as a comment. */
+static char* find_char_or_comment(const char* s, char c)
+{
+ int was_whitespace = 0;
+ while (*s && *s != c && !(was_whitespace && *s == ';')) {
+ was_whitespace = isspace(*s);
+ s++;
+ }
+ return (char*)s;
+}
+
+/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
+static char* strncpy0(char* dest, const char* src, size_t size)
+{
+ strncpy(dest, src, size);
+ dest[size - 1] = '\0';
+ return dest;
+}
+
+/* See documentation in header file. */
+int ini_parse_file(FILE* file,
+ int (*handler)(void*, const char*, const char*,
+ const char*),
+ void* user)
+{
+ /* Uses a fair bit of stack (use heap instead if you need to) */
+#if INI_USE_STACK
+ char line[INI_MAX_LINE];
+#else
+ char* line;
+#endif
+ char section[MAX_SECTION] = "";
+ char prev_name[MAX_NAME] = "";
+
+ char* start;
+ char* end;
+ char* name;
+ char* value;
+ int lineno = 0;
+ int error = 0;
+
+#if !INI_USE_STACK
+ line = (char*)malloc(INI_MAX_LINE);
+ if (!line) {
+ return -2;
+ }
+#endif
+
+ /* Scan through file line by line */
+ while (fgets(line, INI_MAX_LINE, file) != NULL) {
+ lineno++;
+
+ start = line;
+#if INI_ALLOW_BOM
+ if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
+ (unsigned char)start[1] == 0xBB &&
+ (unsigned char)start[2] == 0xBF) {
+ start += 3;
+ }
+#endif
+ start = lskip(rstrip(start));
+
+ if (*start == ';' || *start == '#') {
+ /* Per Python ConfigParser, allow '#' comments at start of line */
+ }
+#if INI_ALLOW_MULTILINE
+ else if (*prev_name && *start && start > line) {
+ /* Non-black line with leading whitespace, treat as continuation
+ of previous name's value (as per Python ConfigParser). */
+ if (!handler(user, section, prev_name, start) && !error)
+ error = lineno;
+ }
+#endif
+ else if (*start == '[') {
+ /* A "[section]" line */
+ end = find_char_or_comment(start + 1, ']');
+ if (*end == ']') {
+ *end = '\0';
+ strncpy0(section, start + 1, sizeof(section));
+ *prev_name = '\0';
+ }
+ else if (!error) {
+ /* No ']' found on section line */
+ error = lineno;
+ }
+ }
+ else if (*start && *start != ';') {
+ /* Not a comment, must be a name[=:]value pair */
+ end = find_char_or_comment(start, '=');
+ if (*end != '=') {
+ end = find_char_or_comment(start, ':');
+ }
+ if (*end == '=' || *end == ':') {
+ *end = '\0';
+ name = rstrip(start);
+ value = lskip(end + 1);
+ end = find_char_or_comment(value, '\0');
+ if (*end == ';')
+ *end = '\0';
+ rstrip(value);
+
+ /* Valid name[=:]value pair found, call handler */
+ strncpy0(prev_name, name, sizeof(prev_name));
+ if (!handler(user, section, name, value) && !error)
+ error = lineno;
+ }
+ else if (!error) {
+ /* No '=' or ':' found on name[=:]value line */
+ error = lineno;
+ }
+ }
+ }
+
+#if !INI_USE_STACK
+ free(line);
+#endif
+
+ return error;
+}
+
+#define NULL_CHAR '\0'
+#define COMMA ','
+
+int ini_parse_override(char *override,
+ int (*handler)(void*, const char*, const char*,
+ const char*),
+ void* user)
+{
+#if INI_USE_STACK
+ char line[INI_MAX_LINE];
+#else
+ char* line;
+#endif
+ char section[MAX_SECTION] = "";
+ char *name, *value;
+
+ char *src = override;
+ int error = -1;
+ int i, j;
+
+#if !INI_USE_STACK
+ line = (char*)malloc(INI_MAX_LINE);
+ if (!line) {
+ return -2;
+ }
+#endif
+
+ while (*src != NULL_CHAR)
+ {
+ if (*src == COMMA) {
+ src++;
+ }
+ else if (*src == '[') {
+ // section
+ src++; // skip opening delim
+ for (i = 0; i < MAX_SECTION; i++) {
+ section[i] = *src++;
+ if (section[i] == NULL_CHAR) {
+ // error, section not completed
+ goto out;
+ }
+ else if (section[i] == ']') {
+ section[i] = NULL_CHAR;
+ break;
+ }
+ }
+ if (i > MAX_SECTION)
+ goto out; // error, overflowed buffer
+ }
+ else {
+ // name/value
+ name = &line[0];
+ for (i = 0; i < MAX_NAME; i++) {
+ line[i] = *src++;
+ if (line[i] == NULL_CHAR) {
+ // error, name not completed
+ goto out;
+ }
+ else if (line[i] == COMMA) {
+ // error, no value
+ goto out;
+ }
+ else if (line[i] == '=') {
+ line[i] = NULL_CHAR;
+ break;
+ }
+ }
+ if (i > MAX_NAME)
+ goto out; // error, overflowed buffer
+
+ value = &line[i + 1];
+ for (j = i + 1; j < INI_MAX_LINE; j++) {
+ line[j] = *src++;
+ if (line[j] == ',') {
+ line[j] = NULL_CHAR;
+ break;
+ }
+ if (line[j] == NULL_CHAR) {
+ src--; // oops!
+ break;
+ }
+
+ }
+ if (j > INI_MAX_LINE)
+ goto out; // error, overflowed buffer
+
+ if (!handler(user, section, name, value) && !error)
+ error = -3;
+ }
+ }
+
+ // all parsed!
+ error = 0;
+
+ out:
+#if !INI_USE_STACK
+ free(line);
+#endif
+ return error;
+}
+
+/* See documentation in header file. */
+int ini_parse(const char* filename,
+ int (*handler)(void*, const char*, const char*, const char*),
+ void* user)
+{
+ FILE* file;
+ int error;
+ char *pvtFilename = strdup(filename);
+ if (!pvtFilename) {
+ return -1;
+ }
+
+ char *override = strchr(pvtFilename, COMMA);
+ if (override)
+ *override++ = '\0';
+
+ file = fopen(pvtFilename, "r");
+ if (!file) {
+ free (pvtFilename);
+ return -1;
+ }
+ error = ini_parse_file(file, handler, user);
+
+ if (error == 0 && override)
+ error = ini_parse_override(override, handler, user);
+ fclose(file);
+ free (pvtFilename);
+
+ return error;
+}
diff --git a/lib/avtp_pipeline/inih/ini.h b/lib/avtp_pipeline/inih/ini.h
new file mode 100644
index 00000000..9ebfd492
--- /dev/null
+++ b/lib/avtp_pipeline/inih/ini.h
@@ -0,0 +1,72 @@
+/* inih -- simple .INI file parser
+
+inih is released under the New BSD license (see LICENSE.txt). Go to the project
+home page for more info:
+
+http://code.google.com/p/inih/
+
+*/
+
+#ifndef __INI_H__
+#define __INI_H__
+
+/* Make this header file easier to include in C++ code */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+
+/* Parse given INI-style file. May have [section]s, name=value pairs
+ (whitespace stripped), and comments starting with ';' (semicolon). Section
+ is "" if name=value pair parsed before any section heading. name:value
+ pairs are also supported as a concession to Python's ConfigParser.
+
+ For each name=value pair parsed, call handler function with given user
+ pointer as well as section, name, and value (data only valid for duration
+ of handler call). Handler should return nonzero on success, zero on error.
+
+ Returns 0 on success, line number of first error on parse error (doesn't
+ stop on first error), -1 on file open error, or -2 on memory allocation
+ error (only when INI_USE_STACK is zero).
+*/
+int ini_parse(const char* filename,
+ int (*handler)(void* user, const char* section,
+ const char* name, const char* value),
+ void* user);
+
+/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
+ close the file when it's finished -- the caller must do that. */
+int ini_parse_file(FILE* file,
+ int (*handler)(void* user, const char* section,
+ const char* name, const char* value),
+ void* user);
+
+/* Nonzero to allow multi-line value parsing, in the style of Python's
+ ConfigParser. If allowed, ini_parse() will call the handler with the same
+ name for each subsequent line parsed. */
+#ifndef INI_ALLOW_MULTILINE
+#define INI_ALLOW_MULTILINE 1
+#endif
+
+/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
+ the file. See http://code.google.com/p/inih/issues/detail?id=21 */
+#ifndef INI_ALLOW_BOM
+#define INI_ALLOW_BOM 1
+#endif
+
+/* Nonzero to use stack, zero to use heap (malloc/free). */
+#ifndef INI_USE_STACK
+#define INI_USE_STACK 1
+#endif
+
+/* Maximum line length for any line in INI file. */
+#ifndef INI_MAX_LINE
+#define INI_MAX_LINE 512
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INI_H__ */
diff --git a/lib/avtp_pipeline/inih/inih_r23.zip b/lib/avtp_pipeline/inih/inih_r23.zip
new file mode 100644
index 00000000..a8ffc5d0
--- /dev/null
+++ b/lib/avtp_pipeline/inih/inih_r23.zip
Binary files differ
diff --git a/lib/avtp_pipeline/intf_ctrl/CMakeLists.txt b/lib/avtp_pipeline/intf_ctrl/CMakeLists.txt
new file mode 100644
index 00000000..6fe11ae9
--- /dev/null
+++ b/lib/avtp_pipeline/intf_ctrl/CMakeLists.txt
@@ -0,0 +1,6 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/intf_ctrl/openavb_intf_ctrl.c
+ PARENT_SCOPE
+)
+
+
diff --git a/lib/avtp_pipeline/intf_ctrl/ctrl_intf.md b/lib/avtp_pipeline/intf_ctrl/ctrl_intf.md
new file mode 100644
index 00000000..2aaa37a4
--- /dev/null
+++ b/lib/avtp_pipeline/intf_ctrl/ctrl_intf.md
@@ -0,0 +1,32 @@
+Ctrl interface {#ctrl_intf}
+==============
+
+# Description
+
+Control interface module.
+
+This interface module sends and receives control messages. There are
+two modes this interface module can be configured for normal mode and mux
+mode. In normal mode the control messages are exchanged with the host
+application. In mux mode the control messages will be multiplexed from
+multiple control streams into one out-going talker control stream. This
+is part of the dispatch model for configuring the control message system
+in the OPENAVB AVB stack.
+
+<br>
+# Interface module configuration parameters
+
+Name | Description
+--------------------------|---------------------------
+intf_nv_mux_mode | If set to 1 the multiplier mode for the control \
+ interface is enabled. This is used for the dispatch \
+ model of control message configuration. <br>For a \
+ listener the in mux mode any incoming control \
+ message is immediatedly placed in the ctrl mux \
+ talkers media queue for retransmission.<br> \
+ When using mux mode, the talker MUST be created \
+ prior to listeners and remain running as long as any\
+ listeners are running.
+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.
diff --git a/lib/avtp_pipeline/intf_ctrl/ctrl_listener.ini b/lib/avtp_pipeline/intf_ctrl/ctrl_listener.ini
new file mode 100644
index 00000000..08c509a5
--- /dev/null
+++ b/lib/avtp_pipeline/intf_ctrl/ctrl_listener.ini
@@ -0,0 +1,106 @@
+#####################################################################
+# Control Listener configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = listener
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: see description in talker.ini
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+#max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# ptp_type: 0 = none, 1 = system clock, 2 = ptp from audioscience (L0.3), 3 = ptp from OPENAVB
+# ptp_type = 3
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_ctrl.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapCtrlInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 400
+
+#map_nv_max_payload_size: The maximum payload size of the control commands.
+map_nv_max_payload_size = 200
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+intf_lib = ./libopenavb_intf_ctrl.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfCtrlInitialize
+
+# intf_nv_mux_mode: When enabled with a value of 1 the multipler mode for the control interface is enabled.
+# This is used for the dispatch model of control message configuration. For a listener the in mux mode any
+# incoming control message is immediatedly placed in the ctrl mux talkers media queue for retransmission.
+# When using mux mode, the talker MUST be created prior to listeners and remain running as long as any
+# listeners are running.
+intf_nv_mux_mode = 0
+
+# intf_nv_ignore_timestamp: The If set the listener will ignore the timestamp on media queue items.
+#intf_nv_ignore_timestamp = 0
diff --git a/lib/avtp_pipeline/intf_ctrl/ctrl_mux_listener.ini b/lib/avtp_pipeline/intf_ctrl/ctrl_mux_listener.ini
new file mode 100644
index 00000000..19d6be55
--- /dev/null
+++ b/lib/avtp_pipeline/intf_ctrl/ctrl_mux_listener.ini
@@ -0,0 +1,106 @@
+#####################################################################
+# Control Listener configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = listener
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: see description in talker.ini
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+#max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# ptp_type: 0 = none, 1 = system clock, 2 = ptp from audioscience (L0.3), 3 = ptp from OPENAVB
+# ptp_type = 3
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_ctrl.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapCtrlInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 400
+
+#map_nv_max_payload_size: The maximum payload size of the control commands.
+map_nv_max_payload_size = 200
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+intf_lib = ./libopenavb_intf_ctrl.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfCtrlInitialize
+
+# intf_nv_mux_mode: When enabled with a value of 1 the multipler mode for the control interface is enabled.
+# This is used for the dispatch model of control message configuration. For a listener the in mux mode any
+# incoming control message is immediatedly placed in the ctrl mux talkers media queue for retransmission.
+# When using mux mode, the talker MUST be created prior to listeners and remain running as long as any
+# listeners are running.
+intf_nv_mux_mode = 1
+
+# intf_nv_ignore_timestamp: The If set the listener will ignore the timestamp on media queue items.
+#intf_nv_ignore_timestamp = 0
diff --git a/lib/avtp_pipeline/intf_ctrl/ctrl_mux_talker.ini b/lib/avtp_pipeline/intf_ctrl/ctrl_mux_talker.ini
new file mode 100644
index 00000000..ad4c0716
--- /dev/null
+++ b/lib/avtp_pipeline/intf_ctrl/ctrl_mux_talker.ini
@@ -0,0 +1,144 @@
+#####################################################################
+# General Talker configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = talker
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: destination multicast address for the stream.
+#
+# If using SRP and MAAP, dynamic destination addresses are generated
+# automatically by the talker and passed to the listner, and don't
+# need to be configured.
+#
+# Without MAAP, locally administered (static) addresses must be
+# configured. Thouse 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.
+#
+# When SRP is being used the static destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set (to the same value) in both the talker and listener.
+#
+# 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.
+#
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 50000
+
+# max_transmit_deficit_usec: Allows setting the maximum packet transmit rate deficit that will
+# be recovered when a talker falls behind. This is only used on a talker side. 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. Typically this value can be set to the expected buffer size (in usec) that listeners are
+# expected to be buffering. 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.
+max_transmit_deficit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# ptp_type: 0 = none, 1 = system clock, 2 = ptp from audioscience (L0.3), 3 = ptp from OPENAVB
+# ptp_type = 3
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_ctrl.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapCtrlInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 100
+
+# map_nv_tx_rate: Transmit rate.
+# If not set default of the talker class will be used.
+map_nv_tx_rate = 1000
+
+#map_nv_max_payload_size: The maximum payload size that the pipe will use.
+map_nv_max_payload_size = 200
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+intf_lib = ./libopenavb_intf_ctrl.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfCtrlInitialize
+
+# intf_nv_mux_mode: When enabled with a value of 1 the multipler mode for the control interface is enabled.
+# This is used for the dispatch model of control message configuration. For a listener the in mux mode any
+# incoming control message is immediatedly placed in the ctrl mux talkers media queue for retransmission.
+# When using mux mode, the talker MUST be created prior to listeners and remain running as long as any
+# listeners are running.
+intf_nv_mux_mode = 1
+
+
+
+
+
+
+
diff --git a/lib/avtp_pipeline/intf_ctrl/ctrl_talker.ini b/lib/avtp_pipeline/intf_ctrl/ctrl_talker.ini
new file mode 100644
index 00000000..ef33fa59
--- /dev/null
+++ b/lib/avtp_pipeline/intf_ctrl/ctrl_talker.ini
@@ -0,0 +1,147 @@
+#####################################################################
+# General Talker configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = talker
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: destination multicast address for the stream.
+#
+# If using SRP and MAAP, dynamic destination addresses are generated
+# automatically by the talker and passed to the listner, and don't
+# need to be configured.
+#
+# Without MAAP, locally administered (static) addresses must be
+# configured. Thouse 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.
+#
+# When SRP is being used the static destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set (to the same value) in both the talker and listener.
+#
+# 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.
+#
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 50000
+
+# max_transmit_deficit_usec: Allows setting the maximum packet transmit rate deficit that will
+# be recovered when a talker falls behind. This is only used on a talker side. 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. Typically this value can be set to the expected buffer size (in usec) that listeners are
+# expected to be buffering. 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.
+max_transmit_deficit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# ptp_type: 0 = none, 1 = system clock, 2 = ptp from audioscience (L0.3), 3 = ptp from OPENAVB
+# ptp_type = 3
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_ctrl.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapCtrlInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 100
+
+# map_nv_tx_rate: Transmit rate.
+# If not set default of the talker class will be used.
+map_nv_tx_rate = 1000
+
+#map_nv_max_payload_size: The maximum payload size that the pipe will use.
+map_nv_max_payload_size = 200
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+intf_lib = ./libopenavb_intf_ctrl.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfCtrlInitialize
+
+# intf_nv_mux_mode: When enabled with a value of 1 the multipler mode for the control interface is enabled.
+# This is used for the dispatch model of control message configuration. For a listener the in mux mode any
+# incoming control message is immediatedly placed in the ctrl mux talkers media queue for retransmission.
+# When using mux mode, the talker MUST be created prior to listeners and remain running as long as any
+# listeners are running.
+intf_nv_mux_mode = 0
+
+
+
+
+
+
+
diff --git a/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl.c b/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl.c
new file mode 100755
index 00000000..3a7ddec0
--- /dev/null
+++ b/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl.c
@@ -0,0 +1,385 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Control interface module.
+*
+* This interface module sends and receives control messages. There are
+* two modes this interface module can be configured for normal mode and mux
+* mode. In normal mode the control messages are exchanged with the host
+* application. In mux mode the control messages will be multiplexed from
+* multiple control streams into one out-going talker control stream. This
+* is part of the dispatch model for configuring the control message system
+* in the OPENAVB AVB stack.
+*/
+
+// WORK IN PROGRESS
+
+#include <stdlib.h>
+#include <string.h>
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_intf_pub.h"
+#include "openavb_intf_ctrl_pub.h"
+
+#define AVB_LOG_COMPONENT "Control Interface"
+#include "openavb_log_pub.h"
+
+// Forward Declarations
+bool openavbIntfCtrlSendControl(void *pIntfHandle, U8 *pData, U32 dataLength, U32 usecDelay);
+
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ // Multiplexing mode. Multiple lister streams flowing into one talker stream.
+ bool muxMode;
+
+ // Ignore timestamp at listener.
+ bool ignoreTimestamp;
+
+ /////////////
+ // Variable data
+ /////////////
+ // Callback into the hosting application when control messages are received.
+ openavb_intf_ctrl_receive_cb_t openavbIntfCtrlReceiveControlFn;
+
+ // Handle to pass back to the hosting application.
+ void *pTLHandle;
+
+ // Flag indication that the mux talker is owned by this interface instance.
+ bool bOwnsCtrlMuxMediaQ;
+
+} pvt_data_t;
+
+// This is the talker mux media queue. The media queue will be set as thread safe mode and loccking for head and tail operations
+// will be handled within the MediaQ. This interface module is designed such that there can only be 1 ctrl mux talker in a process.
+media_q_t *pCtrlMuxMediaQ = NULL;
+
+openavb_intf_host_cb_list_t openavbIntfHostCBList;
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbIntfCtrlCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ if (pMediaQ) {
+ char *pEnd;
+ long tmp;
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ if (strcmp(name, "intf_nv_mux_mode") == 0) {
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1) {
+ pPvtData->muxMode = (tmp == 1);
+ }
+ }
+ else if (strcmp(name, "intf_nv_ignore_timestamp") == 0) {
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1) {
+ pPvtData->ignoreTimestamp = (tmp == 1);
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfCtrlGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// A call to this callback indicates that this interface module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbIntfCtrlTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ // Talker control interfaces will always enable MediaQ thread safety.
+ openavbMediaQThreadSafeOn(pMediaQ);
+
+ if (pPvtData->muxMode) {
+ if (!pPvtData->bOwnsCtrlMuxMediaQ) {
+ pCtrlMuxMediaQ = pMediaQ;
+ pPvtData->bOwnsCtrlMuxMediaQ = TRUE;
+ }
+ else {
+ AVB_LOG_ERROR("Only one MUX talker is allowed per process.");
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Control transmission is handled in openavbIntfCtrlSendControl()
+bool openavbIntfCtrlTxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+}
+
+// A call to this callback indicates that this interface module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbIntfCtrlRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback is called when acting as a listener.
+bool openavbIntfCtrlRxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ if (pMediaQ) {
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ media_q_item_t *pMediaQItem = NULL;
+
+ pMediaQItem = openavbMediaQTailLock(pMediaQ, pPvtData->ignoreTimestamp);
+ if (pMediaQItem) {
+ if (pMediaQItem->dataLen) {
+ if (pPvtData->muxMode) {
+ if (pCtrlMuxMediaQ) {
+ if (!openavbIntfCtrlSendControl(pCtrlMuxMediaQ, pMediaQItem->pPubData, pMediaQItem->dataLen, 0)) {
+ openavbMediaQTailPull(pMediaQ);
+ AVB_LOG_ERROR("Failed to retransmit the control message.");
+ return FALSE;
+ }
+ else {
+ openavbMediaQTailPull(pMediaQ);
+ return TRUE;
+ }
+ }
+ else {
+ openavbMediaQTailPull(pMediaQ);
+ AVB_LOG_ERROR("Control mux talker not found.");
+ return FALSE;
+ }
+ }
+ else {
+ if (pPvtData->openavbIntfCtrlReceiveControlFn) {
+ pPvtData->openavbIntfCtrlReceiveControlFn(pPvtData->pTLHandle, pMediaQItem->pPubData, pMediaQItem->dataLen);
+ openavbMediaQTailPull(pMediaQ);
+ return TRUE;
+ }
+ else {
+ openavbMediaQTailPull(pMediaQ);
+ AVB_LOG_ERROR("Control receive callback not defined.");
+ return FALSE;
+ }
+
+ }
+ }
+ openavbMediaQTailPull(pMediaQ);
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+}
+
+// This callback will be called when the stream is closing.
+void openavbIntfCtrlEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ // If this instance of interface owns the mux talker remove it now
+ if (pPvtData->bOwnsCtrlMuxMediaQ) {
+ pCtrlMuxMediaQ = NULL;
+ pPvtData->bOwnsCtrlMuxMediaQ = FALSE;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// General shutdown callback regardless if a talker or listener. Called once during openavbTLClose()
+void openavbIntfCtrlGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Host side callback
+extern bool DLL_EXPORT openavbIntfCtrlRegisterReceiveControlCB(void *pIntfHandle, void *pTLHandle, openavb_intf_ctrl_receive_cb_t openavbIntfCtrlReceiveControlFn)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ media_q_t *pMediaQ = pIntfHandle;
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ pPvtData->openavbIntfCtrlReceiveControlFn = openavbIntfCtrlReceiveControlFn;
+ pPvtData->pTLHandle = pTLHandle;
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return FALSE;
+}
+
+extern bool DLL_EXPORT openavbIntfCtrlUnregisterReceiveControlCB(void *pIntfHandle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ media_q_t *pMediaQ = pIntfHandle;
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ pPvtData->openavbIntfCtrlReceiveControlFn = NULL;
+ pPvtData->pTLHandle = NULL;
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return FALSE;
+}
+
+// Host side callback
+extern bool DLL_EXPORT openavbIntfCtrlSendControl(void *pIntfHandle, U8 *pData, U32 dataLength, U32 usecDelay)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+
+ media_q_t *pMediaQ = pIntfHandle;
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ if (pMediaQItem->itemSize >= dataLength) {
+ memcpy(pMediaQItem->pPubData, pData, dataLength);
+ pMediaQItem->dataLen = dataLength;
+ }
+ else {
+ AVB_LOG_ERROR("Control data too large for media queue.");
+ openavbMediaQHeadUnlock(pMediaQ);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+ }
+
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ openavbAvtpTimeAddUSec(pMediaQItem->pAvtpTime, usecDelay);
+ openavbMediaQHeadPush(pMediaQ);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE; // Media queue full
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+}
+
+// Main initialization entry point into the interface module
+extern bool DLL_EXPORT openavbIntfCtrlInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pMediaQ->pPvtIntfInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pPvtIntfInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for AVTP interface module.");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ pIntfCB->intf_cfg_cb = openavbIntfCtrlCfgCB;
+ pIntfCB->intf_gen_init_cb = openavbIntfCtrlGenInitCB;
+ pIntfCB->intf_tx_init_cb = openavbIntfCtrlTxInitCB;
+ pIntfCB->intf_tx_cb = openavbIntfCtrlTxCB;
+ pIntfCB->intf_rx_init_cb = openavbIntfCtrlRxInitCB;
+ pIntfCB->intf_rx_cb = openavbIntfCtrlRxCB;
+ pIntfCB->intf_end_cb = openavbIntfCtrlEndCB;
+ pIntfCB->intf_gen_end_cb = openavbIntfCtrlGenEndCB;
+
+ openavbIntfHostCBList.register_receive_control_cb = openavbIntfCtrlRegisterReceiveControlCB;
+ openavbIntfHostCBList.unregister_receive_control_cb = openavbIntfCtrlUnregisterReceiveControlCB;
+ openavbIntfHostCBList.send_control_cb = openavbIntfCtrlSendControl;
+ pIntfCB->intf_host_cb_list = (void *)&openavbIntfHostCBList;
+
+ pPvtData->muxMode = FALSE;
+ pPvtData->ignoreTimestamp = FALSE;
+ pPvtData->openavbIntfCtrlReceiveControlFn = NULL;
+ pPvtData->pTLHandle = NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+}
+
diff --git a/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl_pub.h b/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl_pub.h
new file mode 100755
index 00000000..6f4fc104
--- /dev/null
+++ b/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl_pub.h
@@ -0,0 +1,66 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Control interface module public interface
+*/
+
+#ifndef OPENAVB_INTF_CTRL_PUB_H
+#define OPENAVB_INTF_CTRL_PUB_H 1
+
+#include "openavb_types_pub.h"
+
+/** \file
+ * Control interface module public interface
+ */
+
+/// This callback once registered will be called for each control command received by the listener.
+typedef void (*openavb_intf_ctrl_receive_cb_t)(void *pTLHandle, U8 *pData, U32 dataLength);
+
+/// Register a callback for received control commands.
+typedef bool (*openavb_intf_ctrl_register_receive_control_fn_t)(void *pIntfHandle, void *pTLHandle, openavb_intf_ctrl_receive_cb_t openavbIntfCtrlReceiveCommandCB);
+
+/// Register a callback for received control commands.
+typedef bool (*openavb_intf_ctrl_unregister_receive_control_fn_t)(void *pIntfHandle);
+
+/// Submit a control command for transmission.
+typedef bool (*openavb_intf_ctrl_send_control_fn_t)(void *pIntfHandle, U8 *pData, U32 dataLength, U32 usecDelay);
+
+/// Callbacks to control functions
+typedef struct {
+ /// Registering callback function
+ openavb_intf_ctrl_register_receive_control_fn_t register_receive_control_cb;
+ /// Unregistering callback function
+ openavb_intf_ctrl_unregister_receive_control_fn_t unregister_receive_control_cb;
+ /// Submitting control command
+ openavb_intf_ctrl_send_control_fn_t send_control_cb;
+} openavb_intf_host_cb_list_t;
+
+#endif // OPENAVB_INTF_CTRL_PUB_H
diff --git a/lib/avtp_pipeline/intf_echo/CMakeLists.txt b/lib/avtp_pipeline/intf_echo/CMakeLists.txt
new file mode 100644
index 00000000..0439ee04
--- /dev/null
+++ b/lib/avtp_pipeline/intf_echo/CMakeLists.txt
@@ -0,0 +1,5 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/intf_echo/openavb_intf_echo.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/intf_echo/echo_host_intf.md b/lib/avtp_pipeline/intf_echo/echo_host_intf.md
new file mode 100644
index 00000000..d99a2e30
--- /dev/null
+++ b/lib/avtp_pipeline/intf_echo/echo_host_intf.md
@@ -0,0 +1,29 @@
+Echo interface {#echo_host_intf}
+==============
+
+# Description
+
+This interface module as a talker will push a configured string into the Media
+Queue for transmission. As a listener it will echo the received data to stdout.
+This is strictly for testing purposes and is generally intended to work with the
+[Pipe mapping](@ref pipe_map) module
+
+<br>
+# Interface module configuration parameters
+
+Name | Description
+--------------------------|---------------------------
+intf_nv_echo_string | String that will be sent by the talker
+intf_nv_echo_string_repeat| Number of copies of the string to send in each \
+ packet. <br> \
+ The repeat setting if used must come after the \
+ intf_nv_echo_string in this file
+intf_nv_echo_increment | If set to 1 an incrementing number will be appended\
+ to the string
+intf_nv_tx_local_echo | If set to 1 locally output the string to stdout \
+ at the talker
+intf_nv_echo_no_newline | If set to 1 a newline will not be printed to the \
+ stdout
+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.
diff --git a/lib/avtp_pipeline/intf_echo/echo_listener.ini b/lib/avtp_pipeline/intf_echo/echo_listener.ini
new file mode 100644
index 00000000..e926dd5b
--- /dev/null
+++ b/lib/avtp_pipeline/intf_echo/echo_listener.ini
@@ -0,0 +1,110 @@
+#####################################################################
+# General Listener configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = listener
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: see description in talker.ini
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+#max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+report_seconds = 1
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_pipe.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapPipeInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 400
+
+#map_nv_max_payload_size: The maximum payload size that the pipe will use.
+map_nv_max_payload_size = 200
+
+# map_nv_push_header
+map_nv_push_header = 0
+
+# map_nv_pull_header
+map_nv_pull_header = 0
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+intf_lib = ./libopenavb_intf_echo.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfEchoInitialize
+
+# intf_nv_echo_increment: Append an incrementing number to the string. Works on both talker and listener.
+# If both talker and listener have this option enable long tests can be preformed to see if the increments
+# are the same at the end of the run indicating every packet the talker sent the listener received.
+intf_nv_echo_increment = 1
+
+# intf_nv_echo_no_newline: Do not include a newline in the stdout output.
+#intf_nv_echo_no_newline = 1
+
+# intf_nv_ignore_timestamp: If set the listener will ignore the timestamp on media queue items.
+#intf_nv_ignore_timestamp = 1
diff --git a/lib/avtp_pipeline/intf_echo/echo_listener_auto.ini b/lib/avtp_pipeline/intf_echo/echo_listener_auto.ini
new file mode 100644
index 00000000..b3a9642e
--- /dev/null
+++ b/lib/avtp_pipeline/intf_echo/echo_listener_auto.ini
@@ -0,0 +1,110 @@
+#####################################################################
+# General Listener configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = listener
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 11
+
+# dest_addr: see description in talker.ini
+dest_addr = 91:e0:f0:00:fe:11
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+#max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+report_seconds = 1
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_pipe.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapPipeInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 400
+
+#map_nv_max_payload_size: The maximum payload size that the pipe will use.
+map_nv_max_payload_size = 200
+
+# map_nv_push_header
+map_nv_push_header = 0
+
+# map_nv_pull_header
+map_nv_pull_header = 0
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+intf_lib = ./libopenavb_intf_echo.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfEchoInitialize
+
+# intf_nv_echo_increment: Append an incrementing number to the string. Works on both talker and listener.
+# If both talker and listener have this option enable long tests can be preformed to see if the increments
+# are the same at the end of the run indicating every packet the talker sent the listener received.
+intf_nv_echo_increment = 1
+
+# intf_nv_echo_no_newline: Do not include a newline in the stdout output.
+#intf_nv_echo_no_newline = 1
+
+# intf_nv_ignore_timestamp: If set the listener will ignore the timestamp on media queue items.
+#intf_nv_ignore_timestamp = 1
diff --git a/lib/avtp_pipeline/intf_echo/echo_talker.ini b/lib/avtp_pipeline/intf_echo/echo_talker.ini
new file mode 100644
index 00000000..69a0f988
--- /dev/null
+++ b/lib/avtp_pipeline/intf_echo/echo_talker.ini
@@ -0,0 +1,159 @@
+#####################################################################
+# General Talker configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = talker
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: destination multicast address for the stream.
+#
+# If using SRP and MAAP, dynamic destination addresses are generated
+# automatically by the talker and passed to the listner, and don't
+# need to be configured.
+#
+# Without MAAP, locally administered (static) addresses must be
+# configured. Thouse 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.
+#
+# When SRP is being used the static destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set (to the same value) in both the talker and listener.
+#
+# 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.
+#
+dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 50000
+
+# max_transmit_deficit_usec: Allows setting the maximum packet transmit rate deficit that will
+# be recovered when a talker falls behind. This is only used on a talker side. 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. Typically this value can be set to the expected buffer size (in usec) that listeners are
+# expected to be buffering. 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.
+max_transmit_deficit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+report_seconds = 1
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_pipe.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapPipeInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+# map_nv_tx_rate: Transmit rate.
+# If not set default of the talker class will be used.
+map_nv_tx_rate = 4000
+
+#map_nv_max_payload_size: The maximum payload size that the pipe will use.
+map_nv_max_payload_size = 70
+
+# map_nv_push_header
+map_nv_push_header = 0
+
+# map_nv_pull_header
+map_nv_pull_header = 0
+
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+intf_lib = ./libopenavb_intf_echo.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfEchoInitialize
+
+# intf_nv_echo_string: Echo string used by the talker.
+intf_nv_echo_string = Send this string over the AVB network:
+
+# intf_nv_echo_string_repeat: Number of copies of the string to send in each packet.
+# The repeat setting if used must come after the intf_nv_echo_string in this file.
+intf_nv_echo_string_repeat = 1
+
+# intf_nv_echo_increment: Append an incrementing number to the string.
+intf_nv_echo_increment = 1
+
+# intf_nv_tx_local_echo: Output locally at the talker.
+# intf_nv_tx_local_echo = 1
+
+# intf_nv_echo_no_newline: Do not include a newline in the stdout output.
+# intf_nv_echo_no_newline = 1
+
+
+
+
+
+
diff --git a/lib/avtp_pipeline/intf_echo/echo_talker_auto.ini b/lib/avtp_pipeline/intf_echo/echo_talker_auto.ini
new file mode 100644
index 00000000..d6ec7280
--- /dev/null
+++ b/lib/avtp_pipeline/intf_echo/echo_talker_auto.ini
@@ -0,0 +1,159 @@
+#####################################################################
+# General Talker configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = talker
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 11
+
+# dest_addr: destination multicast address for the stream.
+#
+# If using SRP and MAAP, dynamic destination addresses are generated
+# automatically by the talker and passed to the listner, and don't
+# need to be configured.
+#
+# Without MAAP, locally administered (static) addresses must be
+# configured. Thouse 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.
+#
+# When SRP is being used the static destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set (to the same value) in both the talker and listener.
+#
+# 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.
+#
+dest_addr = 91:e0:f0:00:fe:11
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 50000
+
+# max_transmit_deficit_usec: Allows setting the maximum packet transmit rate deficit that will
+# be recovered when a talker falls behind. This is only used on a talker side. 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. Typically this value can be set to the expected buffer size (in usec) that listeners are
+# expected to be buffering. 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.
+max_transmit_deficit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+report_seconds = 1
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_pipe.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapPipeInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+# map_nv_tx_rate: Transmit rate.
+# If not set default of the talker class will be used.
+map_nv_tx_rate = 4000
+
+#map_nv_max_payload_size: The maximum payload size that the pipe will use.
+map_nv_max_payload_size = 70
+
+# map_nv_push_header
+map_nv_push_header = 0
+
+# map_nv_pull_header
+map_nv_pull_header = 0
+
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+intf_lib = ./libopenavb_intf_echo.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfEchoInitialize
+
+# intf_nv_echo_string: Echo string used by the talker.
+intf_nv_echo_string = Send this string over the AVB network:
+
+# intf_nv_echo_string_repeat: Number of copies of the string to send in each packet.
+# The repeat setting if used must come after the intf_nv_echo_string in this file.
+intf_nv_echo_string_repeat = 1
+
+# intf_nv_echo_increment: Append an incrementing number to the string.
+intf_nv_echo_increment = 1
+
+# intf_nv_tx_local_echo: Output locally at the talker.
+# intf_nv_tx_local_echo = 1
+
+# intf_nv_echo_no_newline: Do not include a newline in the stdout output.
+# intf_nv_echo_no_newline = 1
+
+
+
+
+
+
diff --git a/lib/avtp_pipeline/intf_echo/openavb_intf_echo.c b/lib/avtp_pipeline/intf_echo/openavb_intf_echo.c
new file mode 100755
index 00000000..4bc2f6ae
--- /dev/null
+++ b/lib/avtp_pipeline/intf_echo/openavb_intf_echo.c
@@ -0,0 +1,349 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Echo interface module.
+*
+* This interface module as a talker to push a configured string out. As
+* a listener it will echo the data to stdout. This is strickly for
+* testing purposes and is generally intented to work with the Pipe
+* mapping module.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_intf_pub.h"
+
+#define AVB_LOG_COMPONENT "Echo Interface"
+#include "openavb_log_pub.h"
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ // intf_nv_echo_string: sets a string that will be sent by the talker.
+ char *pEchoString;
+
+ // String repeat
+ U32 echoStringRepeat;
+
+ // calculated value from pEchoString.
+ U32 echoStringLen;
+
+ // Append an incrementing number to the string.
+ bool increment;
+
+ // Output locally at the talker.
+ bool txLocalEcho;
+
+ // No new line.
+ bool noNewline;
+
+ // Ignore timestamp at listener.
+ bool ignoreTimestamp;
+
+ /////////////
+ // Variable data
+ /////////////
+ // When increment is enable this is the counter
+ U32 Counter;
+} pvt_data_t;
+
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbIntfEchoCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ if (pMediaQ) {
+ char *pEnd;
+ long tmp;
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ if (strcmp(name, "intf_nv_echo_string") == 0) {
+ if (pPvtData->pEchoString)
+ free(pPvtData->pEchoString);
+ pPvtData->pEchoString = strdup(value);
+ if (pPvtData->pEchoString) {
+ pPvtData->echoStringLen = strlen(pPvtData->pEchoString);
+ }
+ }
+ else if (strcmp(name, "intf_nv_echo_string_repeat") == 0) {
+ pPvtData->echoStringRepeat = strtol(value, &pEnd, 10);
+
+ // Repeat the string if needed
+ if (pPvtData->echoStringRepeat > 1 && pPvtData->pEchoString) {
+ char *pEchoStringRepeat = calloc(1, (pPvtData->echoStringLen * pPvtData->echoStringRepeat) + 1);
+
+ int i1;
+ for (i1 = 0; i1 < pPvtData->echoStringRepeat; i1++) {
+ strcat(pEchoStringRepeat, pPvtData->pEchoString);
+ }
+
+ free(pPvtData->pEchoString);
+ pPvtData->pEchoString = pEchoStringRepeat;
+ pPvtData->echoStringLen = strlen(pPvtData->pEchoString);
+ }
+ }
+ else if (strcmp(name, "intf_nv_echo_increment") == 0) {
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1) {
+ pPvtData->increment = (tmp == 1);
+ }
+ }
+ else if (strcmp(name, "intf_nv_tx_local_echo") == 0) {
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1) {
+ pPvtData->txLocalEcho = (tmp == 1);
+ }
+ }
+ else if (strcmp(name, "intf_nv_echo_no_newline") == 0) {
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1) {
+ pPvtData->noNewline = (tmp == 1);
+ }
+ }
+ else if (strcmp(name, "intf_nv_ignore_timestamp") == 0) {
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1) {
+ pPvtData->ignoreTimestamp = (tmp == 1);
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfEchoGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// A call to this callback indicates that this interface module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbIntfEchoTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ pPvtData->Counter = 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback will be called for each AVB transmit interval. Commonly this will be
+// 4000 or 8000 times per second.
+bool openavbIntfEchoTxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ 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;
+ }
+ else {
+ memcpy(pMediaQItem->pPubData, pPvtData->pEchoString, pPvtData->echoStringLen);
+ pMediaQItem->dataLen = pPvtData->echoStringLen;
+ }
+ }
+ else {
+ memcpy(pMediaQItem->pPubData, pPvtData->pEchoString, pMediaQItem->itemSize);
+ pMediaQItem->dataLen = pMediaQItem->itemSize;
+ }
+
+ if (pPvtData->txLocalEcho) {
+ if (pPvtData->noNewline)
+ printf("%s ", (char *)pMediaQItem->pPubData);
+ else
+ printf("%s\n\r", (char *)pMediaQItem->pPubData);
+ }
+
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ openavbMediaQHeadPush(pMediaQ);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE; // Media queue full
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+}
+
+// A call to this callback indicates that this interface module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbIntfEchoRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ pPvtData->Counter = 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback is called when acting as a listener.
+bool openavbIntfEchoRxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ if (pMediaQ) {
+ bool moreItems = TRUE;
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ media_q_item_t *pMediaQItem = NULL;
+ while (moreItems) {
+ pMediaQItem = openavbMediaQTailLock(pMediaQ, pPvtData->ignoreTimestamp);
+ if (pMediaQItem) {
+ if (pMediaQItem->dataLen) {
+ if (pMediaQItem->itemSize > pMediaQItem->dataLen) {
+ *((char*)pMediaQItem->pPubData + pMediaQItem->dataLen) = 0; //End string with 0
+ }
+ if (pPvtData->noNewline) {
+ printf("%s ", (char *)pMediaQItem->pPubData);
+ }
+ else {
+ if (pPvtData->increment) {
+ printf("%s : %u\n\r", (char *)pMediaQItem->pPubData, pPvtData->Counter++);
+ }
+ else {
+ printf("%s\n\r", (char *)pMediaQItem->pPubData);
+ }
+ }
+ }
+ openavbMediaQTailPull(pMediaQ);
+ }
+ else {
+ moreItems = FALSE;
+ }
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+}
+
+// This callback will be called when the stream is closing.
+void openavbIntfEchoEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// General shutdown callback regardless if a talker or listener. Called once during openavbTLClose()
+void openavbIntfEchoGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ if (pPvtData->pEchoString) {
+ free(pPvtData->pEchoString);
+ pPvtData->pEchoString = NULL;
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Main initialization entry point into the interface module
+extern bool DLL_EXPORT openavbIntfEchoInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pMediaQ->pPvtIntfInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pPvtIntfInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for AVTP interface module.");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ pIntfCB->intf_cfg_cb = openavbIntfEchoCfgCB;
+ pIntfCB->intf_gen_init_cb = openavbIntfEchoGenInitCB;
+ pIntfCB->intf_tx_init_cb = openavbIntfEchoTxInitCB;
+ pIntfCB->intf_tx_cb = openavbIntfEchoTxCB;
+ pIntfCB->intf_rx_init_cb = openavbIntfEchoRxInitCB;
+ pIntfCB->intf_rx_cb = openavbIntfEchoRxCB;
+ pIntfCB->intf_end_cb = openavbIntfEchoEndCB;
+ pIntfCB->intf_gen_end_cb = openavbIntfEchoGenEndCB;
+
+ pPvtData->pEchoString = NULL;
+ pPvtData->echoStringRepeat = 1;
+ pPvtData->echoStringLen = 0;
+ pPvtData->increment = FALSE;
+ pPvtData->txLocalEcho = FALSE;
+ pPvtData->noNewline = FALSE;
+ pPvtData->ignoreTimestamp = FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/intf_logger/CMakeLists.txt b/lib/avtp_pipeline/intf_logger/CMakeLists.txt
new file mode 100644
index 00000000..c27cce55
--- /dev/null
+++ b/lib/avtp_pipeline/intf_logger/CMakeLists.txt
@@ -0,0 +1,5 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/intf_logger/openavb_intf_logger.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/intf_logger/openavb_intf_logger.c b/lib/avtp_pipeline/intf_logger/openavb_intf_logger.c
new file mode 100644
index 00000000..38adaecc
--- /dev/null
+++ b/lib/avtp_pipeline/intf_logger/openavb_intf_logger.c
@@ -0,0 +1,201 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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.
+*************************************************************************************************************/
+
+/*
+* Usage Notes: It is expected that there will be at most only 1 logger
+* interface module running.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_intf_pub.h"
+
+#define AVB_LOG_COMPONENT "Logger Interface"
+#include "openavb_log_pub.h"
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ // Ignore timestamp at listener.
+ bool ignoreTimestamp;
+
+ /////////////
+ // Variable data
+ /////////////
+} pvt_data_t;
+
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbIntfLoggerCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ if (pMediaQ) {
+ //char *pEnd;
+ //long tmp;
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfLoggerGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// A call to this callback indicates that this interface module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbIntfLoggerTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback will be called for each AVB transmit interval. Commonly this will be
+// 4000 or 8000 times per second.
+bool openavbIntfLoggerTxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ U32 dataLen = avbLogGetMsg(pMediaQItem->pPubData, pMediaQItem->itemSize);
+ if (dataLen) {
+ pMediaQItem->dataLen = dataLen;
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ openavbMediaQHeadPush(pMediaQ);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+ }
+ else {
+ openavbMediaQHeadUnlock(pMediaQ);
+ }
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE; // Media queue full
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+}
+
+// A call to this callback indicates that this interface module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbIntfLoggerRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback is called when acting as a listener.
+bool openavbIntfLoggerRxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+}
+
+// This callback will be called when the stream is closing.
+void openavbIntfLoggerEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// General shutdown callback regardless if a talker or listener. Called once during openavbTLClose()
+void openavbIntfLoggerGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Main initialization entry point into the interface module
+extern bool DLL_EXPORT openavbIntfLoggerInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pMediaQ->pPvtIntfInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pPvtIntfInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for AVTP interface module.");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ pIntfCB->intf_cfg_cb = openavbIntfLoggerCfgCB;
+ pIntfCB->intf_gen_init_cb = openavbIntfLoggerGenInitCB;
+ pIntfCB->intf_tx_init_cb = openavbIntfLoggerTxInitCB;
+ pIntfCB->intf_tx_cb = openavbIntfLoggerTxCB;
+ pIntfCB->intf_rx_init_cb = openavbIntfLoggerRxInitCB;
+ pIntfCB->intf_rx_cb = openavbIntfLoggerRxCB;
+ pIntfCB->intf_end_cb = openavbIntfLoggerEndCB;
+ pIntfCB->intf_gen_end_cb = openavbIntfLoggerGenEndCB;
+
+ pPvtData->ignoreTimestamp = FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/intf_logger/openavb_intf_logger.md b/lib/avtp_pipeline/intf_logger/openavb_intf_logger.md
new file mode 100644
index 00000000..015a09f5
--- /dev/null
+++ b/lib/avtp_pipeline/intf_logger/openavb_intf_logger.md
@@ -0,0 +1,24 @@
+Logger Interface {#logger_intf}
+================
+
+# Description
+
+This interface module is a talker only and design to send OPENAVB AVB
+internally log message over AVB for a listener to act on (such as
+display). One use case of this interface module is for low end devices
+that either have no provisions for console output or are restricted in
+CPU cycle to lot messages.
+
+For this interface module to be used the logging system must be built
+with the option OPENAVB_LOG_PULL_MODE set to TRUE.
+
+Typically the TX rate for this interface module can be quite low. The
+actual value will depend on how much data is expected to be logged. For
+general purpose use it is recommended to use 1000 packet per second or
+less.
+
+<br>
+# Interface module configuration parameters
+
+There are no configuration parameters for this interface module.
+
diff --git a/lib/avtp_pipeline/intf_null/CMakeLists.txt b/lib/avtp_pipeline/intf_null/CMakeLists.txt
new file mode 100644
index 00000000..bf0d4c35
--- /dev/null
+++ b/lib/avtp_pipeline/intf_null/CMakeLists.txt
@@ -0,0 +1,5 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/intf_null/openavb_intf_null.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/intf_null/null_host_intf.md b/lib/avtp_pipeline/intf_null/null_host_intf.md
new file mode 100644
index 00000000..8ef34d18
--- /dev/null
+++ b/lib/avtp_pipeline/intf_null/null_host_intf.md
@@ -0,0 +1,17 @@
+NULL interface {#null_host_intf}
+==============
+
+# Description
+
+This NULL interface module neither sends or receives data but will
+exercise the various functions and callback and can be used as an example
+or a template for new interfaces.
+
+<br>
+# Interface module configuration parameters
+
+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.
diff --git a/lib/avtp_pipeline/intf_null/null_listener.ini b/lib/avtp_pipeline/intf_null/null_listener.ini
new file mode 100644
index 00000000..2645f0fa
--- /dev/null
+++ b/lib/avtp_pipeline/intf_null/null_listener.ini
@@ -0,0 +1,98 @@
+#####################################################################
+# General Listener configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = listener
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: see description in talker.ini
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+#max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+#sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+#max_transit_usec = 2000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_null.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapNullInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+#map_nv_max_payload_size: The maximum payload size that the pipe will use.
+#map_nv_max_payload_size = 200;
+
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+intf_lib = ./libopenavb_intf_null.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfNullInitialize
+
+# intf_nv_ignore_timestamp: If set the listener will ignore the timestamp on media queue items.
+#intf_nv_ignore_timestamp = 1
+
diff --git a/lib/avtp_pipeline/intf_null/null_talker.ini b/lib/avtp_pipeline/intf_null/null_talker.ini
new file mode 100644
index 00000000..088c2009
--- /dev/null
+++ b/lib/avtp_pipeline/intf_null/null_talker.ini
@@ -0,0 +1,136 @@
+#####################################################################
+# General Talker configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = talker
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: destination multicast address for the stream.
+#
+# If using SRP and MAAP, dynamic destination addresses are generated
+# automatically by the talker and passed to the listner, and don't
+# need to be configured.
+#
+# Without MAAP, locally administered (static) addresses must be
+# configured. Thouse 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.
+#
+# When SRP is being used the static destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set (to the same value) in both the talker and listener.
+#
+# 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.
+#
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+#sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 2000
+
+# max_transmit_deficit_usec: Allows setting the maximum packet transmit rate deficit that will
+# be recovered when a talker falls behind. This is only used on a talker side. 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. Typically this value can be set to the expected buffer size (in usec) that listeners are
+# expected to be buffering. 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.
+max_transmit_deficit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_null.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapNullInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+#map_nv_max_payload_size: The maximum payload size that the pipe will use.
+#map_nv_max_payload_size = 200;
+
+# map_nv_tx_rate: Transmit rate
+# If not set default of the talker class will be used.
+#map_nv_tx_rate = 2000
+
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+intf_lib = ./libopenavb_intf_null.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfNullInitialize
+
+
+
+
+
diff --git a/lib/avtp_pipeline/intf_null/openavb_intf_null.c b/lib/avtp_pipeline/intf_null/openavb_intf_null.c
new file mode 100755
index 00000000..6ce7bc42
--- /dev/null
+++ b/lib/avtp_pipeline/intf_null/openavb_intf_null.c
@@ -0,0 +1,208 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : NULL interface module.
+*
+* This NULL interface module neither sends or receives data but will
+* exercise the various functions and callback and can be used as an example
+* or a template for new interfaces.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_intf_pub.h"
+
+#define AVB_LOG_COMPONENT "Null Interface"
+#include "openavb_log_pub.h"
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ // Ignore timestamp at listener.
+ bool ignoreTimestamp;
+
+ /////////////
+ // Variable data
+ /////////////
+} pvt_data_t;
+
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbIntfNullCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ char *pEnd;
+ long tmp;
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ if (strcmp(name, "intf_nv_ignore_timestamp") == 0) {
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1) {
+ pPvtData->ignoreTimestamp = (tmp == 1);
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfNullGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// A call to this callback indicates that this interface module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbIntfNullTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback will be called for each AVB transmit interval. Commonly this will be
+// 4000 or 8000 times per second.
+bool openavbIntfNullTxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ if (pMediaQ) {
+ //pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+
+ // Set 1 byte
+ *(U8 *)(pMediaQItem->pPubData) = 0xff;
+ pMediaQItem->dataLen = 1;
+
+ openavbMediaQHeadPush(pMediaQ);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE; // Media queue full
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+}
+
+// A call to this callback indicates that this interface module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbIntfNullRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback is called when acting as a listener.
+bool openavbIntfNullRxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ if (pMediaQ) {
+ bool moreItems = TRUE;
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ while (moreItems) {
+ media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, pPvtData->ignoreTimestamp);
+ if (pMediaQItem) {
+ openavbMediaQTailPull(pMediaQ);
+ }
+ else {
+ moreItems = FALSE;
+ }
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+}
+
+// This callback will be called when the interface needs to be closed. All shutdown should
+// occur in this function.
+void openavbIntfNullEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfNullGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Main initialization entry point into the interface module
+extern DLL_EXPORT bool openavbIntfNullInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pMediaQ->pPvtIntfInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pPvtIntfInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for AVTP interface module.");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ pIntfCB->intf_cfg_cb = openavbIntfNullCfgCB;
+ pIntfCB->intf_gen_init_cb = openavbIntfNullGenInitCB;
+ pIntfCB->intf_tx_init_cb = openavbIntfNullTxInitCB;
+ pIntfCB->intf_tx_cb = openavbIntfNullTxCB;
+ pIntfCB->intf_rx_init_cb = openavbIntfNullRxInitCB;
+ pIntfCB->intf_rx_cb = openavbIntfNullRxCB;
+ pIntfCB->intf_end_cb = openavbIntfNullEndCB;
+ pIntfCB->intf_gen_end_cb = openavbIntfNullGenEndCB;
+
+ pPvtData->ignoreTimestamp = FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/intf_tonegen/CMakeLists.txt b/lib/avtp_pipeline/intf_tonegen/CMakeLists.txt
new file mode 100644
index 00000000..7b55d40f
--- /dev/null
+++ b/lib/avtp_pipeline/intf_tonegen/CMakeLists.txt
@@ -0,0 +1,4 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/intf_tonegen/openavb_intf_tonegen.c
+ PARENT_SCOPE
+)
diff --git a/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.c b/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.c
new file mode 100644
index 00000000..d9b214a8
--- /dev/null
+++ b/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.c
@@ -0,0 +1,524 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Tone generator interface module. Talker only.
+*
+* - This interface module generates and audio tone for use with -6 and AAF mappings
+* - Requires an OSAL sin implementation of reasonable performance.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "openavb_platform_pub.h"
+#include "openavb_osal_pub.h"
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_map_uncmp_audio_pub.h"
+#include "openavb_map_aaf_audio_pub.h"
+#include "openavb_intf_pub.h"
+
+#define AVB_LOG_COMPONENT "Tone Gen Interface"
+#include "openavb_log_pub.h"
+
+#define PI 3.14159265358979f
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ // intf_nv_tone_hz: The tone hz to generate
+ U32 toneHz;
+
+ // intf_nv_on_off_interval_msec: Interval for turning tone on and off. A value of zero will keep the tone on.
+ U32 onOffIntervalMSec;
+
+ // Simple melody
+ char *pMelodyString;
+
+ // intf_nv_audio_rate
+ avb_audio_rate_t audioRate;
+
+ // intf_nv_audio_type
+ avb_audio_bit_depth_t audioType;
+
+ // intf_nv_audio_bit_depth
+ avb_audio_bit_depth_t audioBitDepth;
+
+ // intf_nv_audio_endian
+ avb_audio_bit_depth_t audioEndian;
+
+ // intf_nv_channels
+ avb_audio_channels_t audioChannels;
+
+ /////////////
+ // Variable data
+ /////////////
+
+ // Packing interval
+ U32 intervalCounter;
+
+ // Keeps track of if the tone is currently on or off
+ U32 freq;
+
+ // Keeps track of how long before toggling the tone on / off
+ U32 freqCountdown;
+
+ // Ratio precalc
+ float ratio;
+
+ // Index to into the melody string
+ U32 melodyIdx;
+
+ // Length of the melody string
+ U32 melodyLen;
+
+} pvt_data_t;
+
+#define MSEC_PER_COUNT 250
+static void xGetMelodyToneAndDuration(char note, char count, U32 *freq, U32 *sampleMSec)
+{
+ switch (note) {
+ case 'A':
+ *freq = 220;
+ break;
+ case 'B':
+ *freq = 246;
+ break;
+ case 'C':
+ *freq = 261;
+ break;
+ case 'D':
+ *freq = 293;
+ break;
+ case 'E':
+ *freq = 329;
+ break;
+ case 'F':
+ *freq = 349;
+ break;
+ case 'G':
+ *freq = 391;
+ break;
+ case 'a':
+ *freq = 440;
+ break;
+ case 'b':
+ *freq = 493;
+ break;
+ case 'c':
+ *freq = 523;
+ break;
+ case 'd':
+ *freq = 587;
+ break;
+ case 'e':
+ *freq = 659;
+ break;
+ case 'f':
+ *freq = 698;
+ break;
+ case 'g':
+ *freq = 783;
+ break;
+ case '-':
+ default:
+ *freq = 0;
+ break;
+ }
+
+ switch (count) {
+ case '1':
+ *sampleMSec = MSEC_PER_COUNT * 1;
+ break;
+ case '2':
+ *sampleMSec = MSEC_PER_COUNT * 2;
+ break;
+ case '3':
+ *sampleMSec = MSEC_PER_COUNT * 3;
+ break;
+ case '4':
+ *sampleMSec = MSEC_PER_COUNT * 4;
+ break;
+ default:
+ *sampleMSec = MSEC_PER_COUNT * 4;
+ break;
+ }
+}
+
+static bool xSupportedMappingFormat(media_q_t *pMediaQ)
+{
+ if (pMediaQ) {
+ if (pMediaQ->pMediaQDataFormat) {
+ if (strcmp(pMediaQ->pMediaQDataFormat, MapUncmpAudioMediaQDataFormat) == 0 || strcmp(pMediaQ->pMediaQDataFormat, MapAVTPAudioMediaQDataFormat) == 0) {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbIntfToneGenCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ char *pEnd;
+ U32 val;
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo;
+ pPubMapUncmpAudioInfo = (media_q_pub_map_uncmp_audio_info_t *)pMediaQ->pPubMapInfo;
+ if (!pPubMapUncmpAudioInfo) {
+ AVB_LOG_ERROR("Public map data for audio info not allocated.");
+ return;
+ }
+
+ if (strcmp(name, "intf_nv_tone_hz") == 0) {
+ pPvtData->toneHz = strtol(value, &pEnd, 10);
+ }
+
+ else if (strcmp(name, "intf_nv_on_off_interval_msec") == 0) {
+ pPvtData->onOffIntervalMSec = strtol(value, &pEnd, 10);
+ }
+
+ else if (strcmp(name, "intf_nv_melody_string") == 0) {
+ if (pPvtData->pMelodyString)
+ free(pPvtData->pMelodyString);
+ pPvtData->pMelodyString = strdup(value);
+ if (pPvtData->pMelodyString) {
+ pPvtData->melodyLen = strlen(pPvtData->pMelodyString);
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_audio_rate") == 0) {
+ val = strtol(value, &pEnd, 10);
+ // TODO: Should check for specific values
+ if (val >= AVB_AUDIO_RATE_8KHZ && val <= AVB_AUDIO_RATE_192KHZ) {
+ pPvtData->audioRate = (avb_audio_rate_t)val;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid audio rate configured for intf_nv_audio_rate.");
+ pPvtData->audioRate = AVB_AUDIO_RATE_44_1KHZ;
+ }
+
+ // Give the audio parameters to the mapping module.
+ if (xSupportedMappingFormat(pMediaQ)) {
+ pPubMapUncmpAudioInfo->audioRate = pPvtData->audioRate;
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_audio_bit_depth") == 0) {
+ val = strtol(value, &pEnd, 10);
+ // TODO: Should check for specific values
+ if (val >= AVB_AUDIO_BIT_DEPTH_1BIT && val <= AVB_AUDIO_BIT_DEPTH_64BIT) {
+ pPvtData->audioBitDepth = (avb_audio_bit_depth_t)val;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid audio type configured for intf_nv_audio_bits.");
+ pPvtData->audioBitDepth = AVB_AUDIO_BIT_DEPTH_24BIT;
+ }
+
+ // Give the audio parameters to the mapping module.
+ if (xSupportedMappingFormat(pMediaQ)) {
+ pPubMapUncmpAudioInfo->audioBitDepth = pPvtData->audioBitDepth;
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_audio_type") == 0) {
+ if (strncasecmp(value, "float", 5) == 0)
+ pPvtData->audioType = (avb_audio_bit_depth_t)AVB_AUDIO_TYPE_FLOAT;
+ else if (strncasecmp(value, "sign", 4) == 0 || strncasecmp(value, "int", 4) == 0)
+ pPvtData->audioType = (avb_audio_bit_depth_t)AVB_AUDIO_TYPE_INT;
+ else if (strncasecmp(value, "unsign", 6) == 0 || strncasecmp(value, "uint", 4) == 0)
+ pPvtData->audioType = (avb_audio_bit_depth_t)AVB_AUDIO_TYPE_UINT;
+ else {
+ AVB_LOG_ERROR("Invalid audio type configured for intf_nv_audio_type.");
+ pPvtData->audioType = (avb_audio_bit_depth_t)AVB_AUDIO_TYPE_UNSPEC;
+ }
+
+ // Give the audio parameters to the mapping module.
+ if (xSupportedMappingFormat(pMediaQ)) {
+ pPubMapUncmpAudioInfo->audioType = (avb_audio_type_t)pPvtData->audioType;
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_audio_endian") == 0) {
+ if (strncasecmp(value, "big", 3) == 0)
+ pPvtData->audioType = (avb_audio_bit_depth_t)AVB_AUDIO_ENDIAN_BIG;
+ else if (strncasecmp(value, "little", 6) == 0)
+ pPvtData->audioType = (avb_audio_bit_depth_t)AVB_AUDIO_ENDIAN_LITTLE;
+ else {
+ AVB_LOG_ERROR("Invalid audio type configured for intf_nv_audio_endian.");
+ pPvtData->audioType = (avb_audio_bit_depth_t)AVB_AUDIO_ENDIAN_UNSPEC;
+ }
+
+ // Give the audio parameters to the mapping module.
+ if (xSupportedMappingFormat(pMediaQ)) {
+ pPubMapUncmpAudioInfo->audioEndian = (avb_audio_endian_t)pPvtData->audioEndian;
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_audio_channels") == 0) {
+ val = strtol(value, &pEnd, 10);
+ // TODO: Should check for specific values
+ if (val >= AVB_AUDIO_CHANNELS_1 && val <= AVB_AUDIO_CHANNELS_8) {
+ pPvtData->audioChannels = (avb_audio_channels_t)val;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid audio channels configured for intf_nv_audio_channels.");
+ pPvtData->audioChannels = (avb_audio_channels_t)AVB_AUDIO_CHANNELS_2;
+ }
+
+ // Give the audio parameters to the mapping module.
+ if (xSupportedMappingFormat(pMediaQ)) {
+ pPubMapUncmpAudioInfo->audioChannels = pPvtData->audioChannels;
+ }
+ }
+
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfToneGenGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// A call to this callback indicates that this interface module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbIntfToneGenTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+
+ // U8 b;
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo;
+ pPubMapUncmpAudioInfo = (media_q_pub_map_uncmp_audio_info_t *)pMediaQ->pPubMapInfo;
+ if (!pPubMapUncmpAudioInfo) {
+ AVB_LOG_ERROR("Public map data for audio info not allocated.");
+ return;
+ }
+
+ // Will get toggle on at the first tx cb
+ if (pPvtData->onOffIntervalMSec > 0) {
+ pPvtData->freq = pPvtData->toneHz;
+ pPvtData->freqCountdown = 0;
+ }
+ else {
+ pPvtData->freq = 0;
+ pPvtData->freqCountdown = 0;
+ }
+
+ pPvtData->melodyIdx = 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// 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)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+
+ if (pMediaQ) {
+ media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo = pMediaQ->pPubMapInfo;
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ if (pPvtData->intervalCounter++ % pPubMapUncmpAudioInfo->packingFactor != 0)
+ return TRUE;
+
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ if (pMediaQItem->itemSize < pPubMapUncmpAudioInfo->itemSize) {
+ AVB_LOG_ERROR("Media queue item not large enough for samples");
+ }
+
+ // Tone on
+ static U32 runningFrameCnt = 0;
+ U32 frameCnt;
+ U32 channelCnt;
+ U32 idx = 0;
+ for (frameCnt = 0; frameCnt < pPubMapUncmpAudioInfo->framesPerItem; frameCnt++) {
+
+ // Check for tone on / off toggle
+ if (!pPvtData->freqCountdown) {
+ if (pPvtData->pMelodyString) {
+ // Melody logic
+ U32 intervalMSec;
+ xGetMelodyToneAndDuration(
+ pPvtData->pMelodyString[pPvtData->melodyIdx],
+ pPvtData->pMelodyString[pPvtData->melodyIdx + 1],
+ &pPvtData->freq, &intervalMSec);
+ pPvtData->melodyIdx += 2;
+
+ pPvtData->freqCountdown = (pPubMapUncmpAudioInfo->audioRate / 1000) * intervalMSec;
+ if (pPvtData->melodyIdx >= pPvtData->melodyLen)
+ pPvtData->melodyIdx = 0;
+ }
+ else {
+ // Fixed tone
+ if (pPvtData->onOffIntervalMSec > 0) {
+ if (pPvtData->freq == 0)
+ pPvtData->freq = pPvtData->toneHz;
+ else
+ pPvtData->freq = 0;
+ pPvtData->freqCountdown = (pPubMapUncmpAudioInfo->audioRate / 1000) * pPvtData->onOffIntervalMSec;
+ }
+ else {
+ pPvtData->freqCountdown = pPubMapUncmpAudioInfo->audioRate; // Just run steady for 1 sec
+ }
+ }
+ pPvtData->ratio = pPvtData->freq / (float)pPubMapUncmpAudioInfo->audioRate;
+ }
+ pPvtData->freqCountdown--;
+
+
+ float value = SIN(2 * PI * (runningFrameCnt++ % pPubMapUncmpAudioInfo->audioRate) * pPvtData->ratio);
+
+ if (pPubMapUncmpAudioInfo->itemSampleSizeBytes == 2) {
+ // 16 bit audio
+ S16 sample = (S16)(value * 15000);
+ for (channelCnt = 0; channelCnt < pPubMapUncmpAudioInfo->audioChannels; channelCnt++) {
+ unsigned char c;
+ U8 *pData = pMediaQItem->pPubData;
+ c = (unsigned)sample % 256;
+ pData[idx++] = c;
+ c = (unsigned)sample / 256 % 256;
+ pData[idx++] = c;
+ }
+ }
+ else {
+ // CORE_TODO
+ AVB_LOG_ERROR("Audio sample size format not implemented yet for tone generator interface module");
+ }
+ }
+
+ pMediaQItem->dataLen = pPubMapUncmpAudioInfo->itemSize;
+
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ openavbMediaQHeadPush(pMediaQ);
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE; // Media queue full
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+}
+
+// A call to this callback indicates that this interface module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbIntfToneGenRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback is called when acting as a listener.
+bool openavbIntfToneGenRxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+}
+
+// This callback will be called when the interface needs to be closed. All shutdown should
+// occur in this function.
+void openavbIntfToneGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfToneGenGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Main initialization entry point into the interface module
+extern DLL_EXPORT bool openavbIntfToneGenInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pMediaQ->pPvtIntfInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pPvtIntfInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for AVTP interface module.");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ pIntfCB->intf_cfg_cb = openavbIntfToneGenCfgCB;
+ pIntfCB->intf_gen_init_cb = openavbIntfToneGenGenInitCB;
+ pIntfCB->intf_tx_init_cb = openavbIntfToneGenTxInitCB;
+ pIntfCB->intf_tx_cb = openavbIntfToneGenTxCB;
+ pIntfCB->intf_rx_init_cb = openavbIntfToneGenRxInitCB;
+ pIntfCB->intf_rx_cb = openavbIntfToneGenRxCB;
+ pIntfCB->intf_end_cb = openavbIntfToneGenEndCB;
+ pIntfCB->intf_gen_end_cb = openavbIntfToneGenGenEndCB;
+
+ pPvtData->intervalCounter = 0;
+ pPvtData->melodyIdx = 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.md b/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.md
new file mode 100644
index 00000000..6afd810a
--- /dev/null
+++ b/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.md
@@ -0,0 +1,30 @@
+Tone Generator Interface {#tonegen_intf}
+========================
+
+# Description
+
+This interface module is a talker only and is used to generate an audio
+tone for testing purposes. It is designed to work with the AAF (AVTP
+Audio Format) mapping but could be quickly adjusted to work with the
+61883-6 mapping module as well.
+
+# Interface module configuration parameters
+
+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
+
diff --git a/lib/avtp_pipeline/intf_tonegen/tonegen_talker.ini b/lib/avtp_pipeline/intf_tonegen/tonegen_talker.ini
new file mode 100644
index 00000000..dbbc9f2d
--- /dev/null
+++ b/lib/avtp_pipeline/intf_tonegen/tonegen_talker.ini
@@ -0,0 +1,148 @@
+#####################################################################
+# General Talker configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = talker
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: destination multicast address for the stream.
+#
+# If using SRP and MAAP, dynamic destination addresses are generated
+# automatically by the talker and passed to the listner, and don't
+# need to be configured.
+#
+# Without MAAP, locally administered (static) addresses must be
+# configured. Thouse 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.
+#
+# When SRP is being used the static destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set (to the same value) in both the talker and listener.
+#
+# 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.
+#
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = A
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 2000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_aaf_audio.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapAVTPAudioInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+# map_nv_tx_rate: Transmit rate.
+# This must be set for the uncompressed audio mapping module.
+map_nv_tx_rate = 8000
+
+# map_nv_packing_factor: Multiple of how many packets of audio frames to place in a media queue item.
+# Note: Typically when decreasing the map_nv_tx_rate the packing factor will also be decreased since
+# the number of frames per packet will be increasing.
+map_nv_packing_factor = 1
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. 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.
+intf_lib = ./libopenavb_intf_tonegen.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfTonegenInitialize
+
+# intf_nv_tone_hz: The frequence of the tone
+intf_nv_tone_hz = 261
+
+# intf_nv_on_off_interval_msec: How many millisecs to turn on and off the tone
+intf_nv_on_off_interval_msec = 1000
+
+# intf_nv_melody_string: A simple melody to play. When a melody string is set the on/off tone hz is not used.
+# Full range of supported notes
+# intf_nv_melody_string = A4B4C4D4E4F4G4a4b4c4d4e4f4g4
+# DoRaMi...
+# intf_nv_melody_string = A4B4C4D4E4F4G4a4
+# Twinkle Twinkle little star
+# intf_nv_melody_string = C2C2G2G2a2a2G2 2F2F2E2E2D2D2C2 2C2C2G2G2a2a2G2 2F2F2E2E2D2D2C2 2G2G2F2F2E2E2D2 2G2G2F2F2E2E2D2 2C2C2G2G2a2a2G2 2F2F2E2E2D2D2C2 2
+
+# intf_nv_audio_rate: Sampling rate of the generated audio
+intf_nv_audio_rate = 48000
+
+# intf_nv_audio_bit_depth: Bit depth of the generated audio
+intf_nv_audio_bit_depth = 16
+
+# intf_nv_audio_channels: The number of channels of the generated audio
+intf_nv_audio_channels = 2
+
+
+
+
+
+
+
diff --git a/lib/avtp_pipeline/intf_viewer/CMakeLists.txt b/lib/avtp_pipeline/intf_viewer/CMakeLists.txt
new file mode 100644
index 00000000..0cf98998
--- /dev/null
+++ b/lib/avtp_pipeline/intf_viewer/CMakeLists.txt
@@ -0,0 +1,6 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/intf_viewer/openavb_intf_viewer.c
+ PARENT_SCOPE
+)
+
+
diff --git a/lib/avtp_pipeline/intf_viewer/latency_listener.ini b/lib/avtp_pipeline/intf_viewer/latency_listener.ini
new file mode 100644
index 00000000..b85d4e18
--- /dev/null
+++ b/lib/avtp_pipeline/intf_viewer/latency_listener.ini
@@ -0,0 +1,126 @@
+#####################################################################
+# The Latency Talker and Latency Listener configurations are designed
+# to test the total latency from the talker to the listener. This
+# includes both network tranmission and AVB stack overhead. The max
+# latency reported at the listener over time can be used as a basis for
+# setting up the max_transit_usec in a real configuration to allow for
+# synchronization of multiple listeners. To fine tune this max_transit_usec
+# setting the real talker should be used.
+#####################################################################
+
+#####################################################################
+# General Listener configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = listener
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: see description in talker.ini
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+#max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+#sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+#max_transit_usec = 2000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_pipe.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapPipeInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+#map_nv_max_payload_size: The maximum payload size that the pipe will use.
+map_nv_max_payload_size = 200
+
+# map_nv_push_header
+map_nv_push_header = 1
+
+# map_nv_pull_header
+map_nv_pull_header = 1
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+intf_lib = ./libopenavb_intf_viewer.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfViewerInitialize
+
+# intf_nv_view_type: Type of viewing output.
+intf_nv_view_type = 3
+
+# intf_nv_view_interval: Frequency of output (in packet count)
+intf_nv_view_interval = 4000
+
+# intf_nv_raw_offset: Offest into the raw frame to output
+intf_nv_raw_offset = 0
+
+# intf_nv_raw_length: Length of the raw frame to output. 0 = all.
+intf_nv_raw_length = 0
+
+# intf_nv_ignore_timestamp: If set the listener will ignore the timestamp on media queue items.
+# intf_nv_ignore_timestamp = 1
+
+
diff --git a/lib/avtp_pipeline/intf_viewer/latency_talker.ini b/lib/avtp_pipeline/intf_viewer/latency_talker.ini
new file mode 100644
index 00000000..823ae3b9
--- /dev/null
+++ b/lib/avtp_pipeline/intf_viewer/latency_talker.ini
@@ -0,0 +1,168 @@
+#####################################################################
+# The Latency Talker and Latency Listener configurations are designed
+# to test the total latency from the talker to the listener. This
+# includes both network tranmission and AVB stack overhead. The max
+# latency reported at the listener over time can be used as a basis for
+# setting up the max_transit_usec in a real configuration to allow for
+# synchronization of multiple listeners. To fine tune this max_transit_usec
+# setting the real talker should be used.
+#####################################################################
+
+#####################################################################
+# General Talker configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = talker
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: destination multicast address for the stream.
+#
+# If using SRP and MAAP, dynamic destination addresses are generated
+# automatically by the talker and passed to the listner, and don't
+# need to be configured.
+#
+# Without MAAP, locally administered (static) addresses must be
+# configured. Thouse 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.
+#
+# When SRP is being used the static destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set (to the same value) in both the talker and listener.
+#
+# 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.
+#
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+#sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 0
+
+# max_transmit_deficit_usec: Allows setting the maximum packet transmit rate deficit that will
+# be recovered when a talker falls behind. This is only used on a talker side. 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. Typically this value can be set to the expected buffer size (in usec) that listeners are
+# expected to be buffering. 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.
+max_transmit_deficit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_pipe.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapPipeInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+# map_nv_tx_rate: Transmit rate.
+# If not set default of the talker class will be used.
+#map_nv_tx_rate = 4000
+
+#map_nv_max_payload_size: The maximum payload size that the pipe will use.
+map_nv_max_payload_size = 100;
+
+# map_nv_push_header
+map_nv_push_header = 0
+
+# map_nv_pull_header
+map_nv_pull_header = 0
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+intf_lib = ./libopenavb_intf_echo.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfEchoInitialize
+
+# intf_nv_echo_string: Echo string used by the talker.
+intf_nv_echo_string = Latency test:
+
+# intf_nv_echo_string_repeat: Number of copies of the string to send in each packet.
+# The repeat setting if used must come after the intf_nv_echo_string in this file.
+intf_nv_echo_string_repeat = 1
+
+# intf_nv_echo_increment: Append an incrementing number to the string.
+intf_nv_echo_increment = 1
+
+# intf_nv_tx_local_echo: Output locally at the talker.
+# intf_nv_tx_local_echo = 1
+
+# intf_nv_echo_no_newline: Do not include a newline in the stdout output.
+# intf_nv_echo_no_newline = 1
+
+
+
+
+
+
diff --git a/lib/avtp_pipeline/intf_viewer/openavb_intf_viewer.c b/lib/avtp_pipeline/intf_viewer/openavb_intf_viewer.c
new file mode 100755
index 00000000..3ad743ca
--- /dev/null
+++ b/lib/avtp_pipeline/intf_viewer/openavb_intf_viewer.c
@@ -0,0 +1,520 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Viewer interface module.
+*
+* This interface module is only a listener and is used to simply display
+* contents recieved in a number of different formats. Additionally it is
+* mapping type aware and can display header values for different mappings
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "openavb_platform_pub.h"
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_intf_pub.h"
+
+#define AVB_LOG_COMPONENT "Viewer Interface"
+#include "openavb_log_pub.h"
+
+typedef enum {
+ VIEWER_MODE_DETAIL = 0,
+ VIEWER_MODE_MAPPING_AWARE = 1,
+ VIEWER_MODE_AVTP_TIMESTAMP = 2,
+ VIEWER_MODE_LATENCY = 3,
+ VIEWER_MODE_SELECTIVE_TIMESTAMP = 4,
+ VIEWER_MODE_LATE = 5,
+ VIEWER_MODE_GAP = 6,
+} viewer_mode_t;
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ viewer_mode_t viewType;
+
+ // Frequency of output
+ U32 viewInterval;
+
+ // Offest into the raw frame to output
+ U32 rawOffset;
+
+ // Length of the raw frame to output
+ U32 rawLength;
+
+ // Ignore timestamp at listener.
+ bool ignoreTimestamp;
+
+ /////////////
+ // Variable data
+ /////////////
+ U32 servicedCount;
+
+ S64 accumLateNS;
+
+ S32 maxLateNS;
+
+ U64 accumGapNS;
+
+ U32 maxGapNS;
+
+ U64 prevNowTime;
+
+ S64 accumAvtpDeltaNS;
+
+ S32 maxAvtpDeltaNS;
+
+ U64 prevAvtpTimestampTime;
+
+ U32 skipCountdown;
+
+ float jitter;
+
+ S32 avgForJitter;
+
+} pvt_data_t;
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbIntfViewerCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ char *pEnd;
+ long tmp;
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ // intf_nv_view_type: Type of viewing output. 0 = raw, 1 = mapping aware, 2 = timestamps only, 3 = latency output, 4 = Selective timestamp error reporting
+ if (strcmp(name, "intf_nv_view_type") == 0) {
+ pPvtData->viewType = (viewer_mode_t)strtol(value, &pEnd, 10);
+ }
+
+ else if (strcmp(name, "intf_nv_view_interval") == 0) {
+ pPvtData->viewInterval = strtol(value, &pEnd, 10);
+ if (pPvtData->viewInterval == 0) {
+ pPvtData->viewInterval = 1000;
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_raw_offset") == 0) {
+ pPvtData->rawOffset = strtol(value, &pEnd, 10);
+ }
+
+ else if (strcmp(name, "intf_nv_raw_length") == 0) {
+ pPvtData->rawLength = strtol(value, &pEnd, 10);
+ if (pPvtData->rawLength < 1)
+ pPvtData->rawLength = 1000;
+ }
+
+ else if (strcmp(name, "intf_nv_ignore_timestamp") == 0) {
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1) {
+ pPvtData->ignoreTimestamp = (tmp == 1);
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfViewerGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// No talker functionality in this interface
+void openavbIntfViewerTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// No talker functionality in this interface
+bool openavbIntfViewerTxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+}
+
+// A call to this callback indicates that this interface module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbIntfViewerRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback is called when acting as a listener.
+bool openavbIntfViewerRxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, pPvtData->ignoreTimestamp);
+ if (pMediaQItem) {
+
+ // The skip countdown allow the viewer modes to set a number of packets to ignore
+ // after logging to reduce or eliminate the logging from affecting the stats.
+ if (pPvtData->skipCountdown)
+ pPvtData->skipCountdown--;
+
+ if (pMediaQItem->dataLen && !pPvtData->skipCountdown) {
+ pPvtData->servicedCount++;
+
+ if (pPvtData->viewType == VIEWER_MODE_DETAIL) {
+ U32 avtpTimestamp;
+ U64 avtpTimestampTime;
+ bool avtpTimestampValid;
+ U32 nowTimestamp;
+ U64 nowTimestampTime;
+ bool nowTimestampValid;
+ U64 nowTime;
+ S32 lateNS = 0;
+ U64 gapNS = 0;
+
+ avtpTimestamp = openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime);
+ avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
+ avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
+
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ nowTimestamp = openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime);
+ nowTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
+ nowTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
+
+ CLOCK_GETTIME64(OPENAVB_CLOCK_REALTIME, &nowTime);
+
+ if (avtpTimestampValid && nowTimestampValid) {
+ lateNS = nowTimestampTime - avtpTimestampTime;
+ if (lateNS > pPvtData->maxLateNS) {
+ pPvtData->maxLateNS = lateNS;
+ }
+ pPvtData->accumLateNS += lateNS;
+
+ if (pPvtData->servicedCount > 1) {
+ gapNS = nowTime - pPvtData->prevNowTime;
+ if (gapNS > pPvtData->maxGapNS) {
+ pPvtData->maxGapNS = gapNS;
+ }
+ pPvtData->accumGapNS += gapNS;
+ }
+ pPvtData->prevNowTime = nowTime;
+
+ if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
+ S32 lateAvg = pPvtData->accumLateNS / pPvtData->servicedCount;
+ S32 gapAvg = pPvtData->accumGapNS / (pPvtData->servicedCount - 1);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "****************************", LOG_RT_DATATYPE_CONST_STR, NULL);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Packets: %u", LOG_RT_DATATYPE_U32, &pPvtData->servicedCount);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "AVTP Timestamp: %u NS", LOG_RT_DATATYPE_U32, &avtpTimestamp);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Now Timestamp: %u NS", LOG_RT_DATATYPE_U32, &nowTimestamp);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Late: %d NS", LOG_RT_DATATYPE_S32, &lateNS);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Late Avg: %d NS", LOG_RT_DATATYPE_S32, &lateAvg);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Late Max: %d NS", LOG_RT_DATATYPE_S32, &pPvtData->maxLateNS);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Gap: %u NS", LOG_RT_DATATYPE_U32, &gapNS);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Gap Avg: %u NS", LOG_RT_DATATYPE_U32, &gapAvg);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Gap Max: %u NS", LOG_RT_DATATYPE_U32, &pPvtData->maxGapNS);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Data length: %u", LOG_RT_DATATYPE_U32, &pMediaQItem->dataLen);
+
+ pPvtData->accumLateNS = 0;
+ pPvtData->maxLateNS = 0;
+ pPvtData->accumGapNS = 0;
+ pPvtData->maxGapNS = 0;
+ pPvtData->prevNowTime = 0;
+ pPvtData->servicedCount = 0;
+ pPvtData->skipCountdown = 10;
+ }
+ }
+ }
+
+ else if (pPvtData->viewType == VIEWER_MODE_MAPPING_AWARE) {
+ }
+
+ else if (pPvtData->viewType == VIEWER_MODE_AVTP_TIMESTAMP) {
+ U64 avtpTimestampTime;
+ bool avtpTimestampValid;
+ S32 deltaNS = 0;
+
+ avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
+ avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
+
+ if (avtpTimestampValid) {
+ if (pPvtData->servicedCount > 1) {
+ deltaNS = avtpTimestampTime - pPvtData->prevAvtpTimestampTime;
+ if (deltaNS > pPvtData->maxAvtpDeltaNS) {
+ pPvtData->maxAvtpDeltaNS = deltaNS;
+ }
+ pPvtData->accumAvtpDeltaNS += deltaNS;
+
+ if (pPvtData->avgForJitter != 0) {
+ S32 deltaJitter = pPvtData->avgForJitter - deltaNS;
+ if (deltaJitter < 0) deltaJitter = -deltaJitter;
+ pPvtData->jitter += (1.0/16.0) * ((float)deltaJitter - pPvtData->jitter);
+ }
+ }
+ pPvtData->prevAvtpTimestampTime = avtpTimestampTime;
+
+ if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
+ S32 deltaAvg = pPvtData->accumAvtpDeltaNS / (pPvtData->servicedCount - 1);
+ U32 jitter = (U32)(pPvtData->jitter);
+
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "AVTP Timestamp Delta: %d NS ", LOG_RT_DATATYPE_S32, &deltaNS);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "AVTP Timestamp Delta Avg: %d NS ", LOG_RT_DATATYPE_S32, &deltaAvg);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "AVTP Timestamp Delta Max: %d NS ", LOG_RT_DATATYPE_S32, &pPvtData->maxAvtpDeltaNS);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter);
+
+ pPvtData->accumAvtpDeltaNS = 0;
+ pPvtData->maxAvtpDeltaNS = 0;
+ pPvtData->servicedCount = 0;
+ pPvtData->prevAvtpTimestampTime = 0;
+ pPvtData->skipCountdown = 10;
+ pPvtData->jitter = 0.0;
+ pPvtData->avgForJitter = deltaAvg;
+ }
+ }
+ }
+
+ else if (pPvtData->viewType == VIEWER_MODE_LATENCY) {
+ U64 avtpTimestampTime;
+ bool avtpTimestampValid;
+ U64 nowTimestampTime;
+ bool nowTimestampValid;
+ S32 lateNS = 0;
+
+ avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
+ avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
+
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ nowTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
+ nowTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
+
+ if (avtpTimestampValid && nowTimestampValid) {
+ lateNS = nowTimestampTime - avtpTimestampTime;
+ if (lateNS > pPvtData->maxLateNS) {
+ pPvtData->maxLateNS = lateNS;
+ }
+ pPvtData->accumLateNS += lateNS;
+
+ if (pPvtData->avgForJitter != 0) {
+ S32 lateJitter = pPvtData->avgForJitter - lateNS;
+ if (lateJitter < 0) lateJitter = -lateJitter;
+ pPvtData->jitter += (1.0/16.0) * ((float)lateJitter - pPvtData->jitter);
+ }
+
+ if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
+ S32 lateAvg = pPvtData->accumLateNS / pPvtData->servicedCount;
+ U32 jitter = (U32)(pPvtData->jitter);
+
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "Latency: %d NS ", LOG_RT_DATATYPE_S32, &lateNS);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Latency Avg: %d NS ", LOG_RT_DATATYPE_S32, &lateAvg);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Latency Max: %d NS ", LOG_RT_DATATYPE_S32, &pPvtData->maxLateNS);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter);
+
+ pPvtData->accumLateNS = 0;
+ pPvtData->maxLateNS = 0;
+ pPvtData->servicedCount = 0;
+ pPvtData->skipCountdown = 10;
+ pPvtData->jitter = 0.0;
+ pPvtData->avgForJitter = lateAvg;
+ }
+ }
+ }
+
+ else if (pPvtData->viewType == VIEWER_MODE_SELECTIVE_TIMESTAMP) {
+ }
+
+ else if (pPvtData->viewType == VIEWER_MODE_LATE) {
+ U64 avtpTimestampTime;
+ bool avtpTimestampValid;
+ U64 nowTimestampTime;
+ bool nowTimestampValid;
+ S32 lateNS = 0;
+
+ avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
+ avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
+
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ nowTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
+ nowTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
+
+ if (avtpTimestampValid && nowTimestampValid) {
+ lateNS = nowTimestampTime - avtpTimestampTime;
+ if (lateNS > pPvtData->maxLateNS) {
+ pPvtData->maxLateNS = lateNS;
+ }
+ pPvtData->accumLateNS += lateNS;
+
+ if (pPvtData->avgForJitter != 0) {
+ S32 lateJitter = pPvtData->avgForJitter - lateNS;
+ if (lateJitter < 0) lateJitter = -lateJitter;
+ pPvtData->jitter += (1.0/16.0) * ((float)lateJitter - pPvtData->jitter);
+ }
+
+ if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
+ S32 lateAvg = pPvtData->accumLateNS / pPvtData->servicedCount;
+ U32 jitter = (U32)(pPvtData->jitter);
+
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "Late: %d NS ", LOG_RT_DATATYPE_S32, &lateNS);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Late Avg: %d NS ", LOG_RT_DATATYPE_S32, &lateAvg);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Late Max: %d NS ", LOG_RT_DATATYPE_S32, &pPvtData->maxLateNS);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter);
+
+ pPvtData->accumLateNS = 0;
+ pPvtData->maxLateNS = 0;
+ pPvtData->servicedCount = 0;
+ pPvtData->skipCountdown = 10;
+ pPvtData->jitter = 0.0;
+ pPvtData->avgForJitter = lateAvg;
+ }
+ }
+ }
+
+ else if (pPvtData->viewType == VIEWER_MODE_GAP) {
+ U64 nowTime;
+ U64 gapNS = 0;
+
+ CLOCK_GETTIME64(OPENAVB_CLOCK_REALTIME, &nowTime);
+
+ if (pPvtData->servicedCount > 1) {
+ gapNS = nowTime - pPvtData->prevNowTime;
+ if (gapNS > pPvtData->maxGapNS) {
+ pPvtData->maxGapNS = gapNS;
+ }
+ pPvtData->accumGapNS += gapNS;
+
+ if (pPvtData->avgForJitter != 0) {
+ S32 gapJitter = pPvtData->avgForJitter - gapNS;
+ if (gapJitter < 0) gapJitter = -gapJitter;
+ pPvtData->jitter += (1.0/16.0) * ((float)gapJitter - pPvtData->jitter);
+ }
+ }
+ pPvtData->prevNowTime = nowTime;
+
+ if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
+ S32 gapAvg = pPvtData->accumGapNS / (pPvtData->servicedCount - 1);
+ U32 jitter = (U32)(pPvtData->jitter);
+
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "Gap: %d NS ", LOG_RT_DATATYPE_S32, &gapNS);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Gap Avg: %d NS ", LOG_RT_DATATYPE_S32, &gapAvg);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Gap Max: %d NS ", LOG_RT_DATATYPE_S32, &pPvtData->maxGapNS);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter);
+
+ pPvtData->accumGapNS = 0;
+ pPvtData->maxGapNS = 0;
+ pPvtData->prevNowTime = 0;
+ pPvtData->servicedCount = 0;
+ pPvtData->skipCountdown = 10;
+ pPvtData->jitter = 0.0;
+ pPvtData->avgForJitter = gapAvg;
+ }
+ }
+
+ }
+ openavbMediaQTailPull(pMediaQ);
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+}
+
+
+// This callback will be called when the interface needs to be closed. All shutdown should
+// occur in this function.
+void openavbIntfViewerEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfViewerGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Main initialization entry point into the interface module
+extern DLL_EXPORT bool openavbIntfViewerInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pMediaQ->pPvtIntfInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pPvtIntfInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for AVTP interface module.");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ pIntfCB->intf_cfg_cb = openavbIntfViewerCfgCB;
+ pIntfCB->intf_gen_init_cb = openavbIntfViewerGenInitCB;
+ pIntfCB->intf_tx_init_cb = openavbIntfViewerTxInitCB;
+ pIntfCB->intf_tx_cb = openavbIntfViewerTxCB;
+ pIntfCB->intf_rx_init_cb = openavbIntfViewerRxInitCB;
+ pIntfCB->intf_rx_cb = openavbIntfViewerRxCB;
+ pIntfCB->intf_end_cb = openavbIntfViewerEndCB;
+ pIntfCB->intf_gen_end_cb = openavbIntfViewerGenEndCB;
+
+ pPvtData->viewType = VIEWER_MODE_DETAIL;
+ pPvtData->viewInterval = 1000;
+ pPvtData->rawOffset = 0;
+ pPvtData->rawLength = 20;
+ pPvtData->ignoreTimestamp = FALSE;
+ pPvtData->skipCountdown = 0;
+ pPvtData->jitter = 0.0;
+ pPvtData->avgForJitter = 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/intf_viewer/viewer_intf.md b/lib/avtp_pipeline/intf_viewer/viewer_intf.md
new file mode 100644
index 00000000..3d97940c
--- /dev/null
+++ b/lib/avtp_pipeline/intf_viewer/viewer_intf.md
@@ -0,0 +1,31 @@
+Viewer interface {#viewer_intf}
+================
+
+# Description
+
+Viewer interface module.
+
+The viewer interface module is a listener only module. It is designed
+for testing purposes and will evaluate and display AVTP stream data in a
+number of formats.
+
+
+<br>
+# Interface module configuration parameters
+
+Name | Description
+--------------------------|---------------------------
+intf_nv_view_type | Mode of operation. Acceptable values are<ul> \
+ <li>0 - Full details</li> \
+ <li>1 - mapping aware (not implemented)</li> \
+ <li>2 - Timestamp mode</li> \
+ <li>3 - Latency measurement</li> \
+ <li>4 - Selective timestamp mode</li> \
+ <li>5 - Late packet measurement</li> \
+ <li>6 - Packet gap measurement</li></ul>
+intf_nv_view_interval | Frequency of output (in packet count)
+intf_nv_raw_offset | Offset into the raw frame to output
+intf_nv_raw_length | Length of the raw frame to output (0 = all)
+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.
diff --git a/lib/avtp_pipeline/intf_viewer/viewer_listener.ini b/lib/avtp_pipeline/intf_viewer/viewer_listener.ini
new file mode 100644
index 00000000..01e4f726
--- /dev/null
+++ b/lib/avtp_pipeline/intf_viewer/viewer_listener.ini
@@ -0,0 +1,123 @@
+#####################################################################
+# General Listener configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = listener
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: see description in talker.ini
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+#max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+#sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+#max_transit_usec = 2000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_pipe.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapPipeInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+#map_nv_max_payload_size: The maximum payload size that the pipe will use.
+map_nv_max_payload_size = 1000;
+
+# map_nv_push_header
+map_nv_push_header = 1
+
+# map_nv_pull_header
+map_nv_pull_header = 1
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+intf_lib = ./libopenavb_intf_viewer.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfViewerInitialize
+
+# intf_nv_view_type: Type of viewing output.
+# VIEWER_MODE_DETAIL = 0
+# VIEWER_MODE_MAPPING_AWARE = 1 (Not implemented)
+# VIEWER_MODE_AVTP_TIMESTAMP = 2
+# VIEWER_MODE_LATENCY = 3
+# VIEWER_MODE_SELECTIVE_TIMESTAMP = 4
+# VIEWER_MODE_LATE = 5
+# VIEWER_MODE_GAP = 6
+intf_nv_view_type = 0
+
+# intf_nv_view_interval: Frequency of output (in packet count)
+intf_nv_view_interval = 4000
+
+# intf_nv_raw_offset: Offest into the raw frame to output
+intf_nv_raw_offset = 0
+
+# intf_nv_raw_length: Length of the raw frame to output. 0 = all.
+intf_nv_raw_length = 0
+
+# intf_nv_ignore_timestamp: If set the listener will ignore the timestamp on media queue items.
+#intf_nv_ignore_timestamp = 1
+
+
diff --git a/lib/avtp_pipeline/maap/openavb_maap.h b/lib/avtp_pipeline/maap/openavb_maap.h
new file mode 100644
index 00000000..acf9ffcc
--- /dev/null
+++ b/lib/avtp_pipeline/maap/openavb_maap.h
@@ -0,0 +1,61 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_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);
+void openavbMaapFinalize();
+
+// 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);
+// 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/CMakeLists.txt b/lib/avtp_pipeline/map_aaf_audio/CMakeLists.txt
new file mode 100644
index 00000000..26d7e5f1
--- /dev/null
+++ b/lib/avtp_pipeline/map_aaf_audio/CMakeLists.txt
@@ -0,0 +1,5 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/map_aaf_audio/openavb_map_aaf_audio.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/map_aaf_audio/README.TXT b/lib/avtp_pipeline/map_aaf_audio/README.TXT
new file mode 100644
index 00000000..f59b628d
--- /dev/null
+++ b/lib/avtp_pipeline/map_aaf_audio/README.TXT
@@ -0,0 +1,42 @@
+Notes on the AVTP Audio Format mapping module:
+
+Implements AAF (or "AVTP Audio Format") as described in IEEE-1722a (Draft 11).
+
+Works with the ALSA interface and the WAV file interface.
+
+The transmit rate (map_nv_tx_rate) for the mapping module
+should be set according to the sample rate, so that the transmit
+interval meets the suggested values in 1722a:
+
+For audio sample rates which are a multiple of 8000hz: use 8000 for class A, 4000 for class B
+For audio sample rates which are a multiple of 44100hz: use 7350 for class A, 3675 for class B
+
+AAF supports the following ALSA sample parameters:
+
+- sample rate:
+ intf_nv_audio_rate = 8, 16, 32, 44.1, 48, 88.2, 96, 176.4 or 192Khz
+- signed integer, unsigned integer or floating point samples
+ intf_nv_audio_type = int, uint or float
+- bit depth
+ intf_nv_audio_bit_depth = 16, 24 or 32 for integers; 32 for float
+- number of audio channels
+ intf_nv_audio_channels = 1 - 8
+- sample endian-ness
+ intf_nv_audio_end = big or little
+
+The ALSA library on various platforms will only support certain
+combinations of the sample parameters. Typically, only sample rate and
+bit depth need to be configured, and the other parameters may be left
+to their defaults.
+
+The WAV file interface will send data that matches the encoding of the
+WAV file.
+
+Both the talker and listner must be configured with matching sample
+parameters. If the received data does not match the configured
+parameters on the listener, the stream will still be setup and data
+will still flow - but no audio will be played.
+
+Sample talker and listener ini files are provided in aaf_talker.ini
+and aaf_listener.ini.
+
diff --git a/lib/avtp_pipeline/map_aaf_audio/aaf_audio_map.md b/lib/avtp_pipeline/map_aaf_audio/aaf_audio_map.md
new file mode 100644
index 00000000..6b067a62
--- /dev/null
+++ b/lib/avtp_pipeline/map_aaf_audio/aaf_audio_map.md
@@ -0,0 +1,58 @@
+AAF audio Mapping {#aaf_audio_map}
+=================
+
+# Description
+
+Implements AAF (or "AVTP Audio Format") as described in IEEE-1722a.
+
+Works with the ALSA interface and the WAV file interface.
+
+# Mapping module configuration parameters
+
+Name | Description
+--------------------|---------------------------
+map_nv_item_count |The number of Media Queue items to hold.
+map_nv_tx_rate or map_nv_tx_interval | Transmit interval in frames per second. \
+ 0 = default for talker class. <br> The transmit rate for \
+ the mapping module should be set according to the sample \
+ rate, so that the transmit interval meets the suggested \
+ values in 1722a <ul><li>sample rate which are multiple of \
+ 8000Hz <ul><li>8000 for class <b>A</b></li><li>4000 for \
+ class <b>B</b></li></ul></li><li>sample rate which are \
+ multiple of 44100Hz<ul><li>7350 for class <b>A</b></li> \
+ <li>3675 for class <b>B</b></li></ul></li></ul>
+map_nv_packing_factor|How many AVTP packets worth of audio data to accept in one Media Queue item
+
+<br>
+# Notes
+
+There are additional parameters that have to be set by the interface module
+during the configuration process to ensure all sizes and rates calculate
+properly inside the mapping module. Those variables have to be set before
+*map_gen_init_cb* is being called. Commonly these additional values are set
+during the interface module configuration which does occur before the
+gen_init_cb.
+
+These are the fields of the @ref media_q_pub_map_uncmp_audio_info_t structure
+that have to be set during the interface module configuration:
+
+Name | Description
+-------------------|----------------------------
+audioRate |Rate of the audio @ref avb_audio_rate_t
+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
+
+Below you can find description of how to set up those variables in interfaces
+* [wav file interface](@ref wav_file_intf)
+* [alsa interface](@ref alsa_intf)
+
+**Note**: If any of these fields are not set correct the mapping module will not
+configure the Media Queue correctly.
+
+**Note**: Both the talker and listener must be configured with matching audio
+parameters. If the received data on the listener does not match the configured
+parameters the stream will still be started and data
+will still flow but no audio will be played.
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
new file mode 100755
index 00000000..d9e3fc0c
--- /dev/null
+++ b/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c
@@ -0,0 +1,792 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Implementation for AAF mapping module
+ *
+ * AAF is defined in IEEE 1722-rev1/D12 (still in draft as of Feb 2015).
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "openavb_mcr_hal_pub.h"
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_avtp_time_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_map_pub.h"
+#include "openavb_map_aaf_audio_pub.h"
+
+#define AVB_LOG_COMPONENT "AAF Mapping"
+#include "openavb_log_pub.h"
+
+#define AVTP_SUBTYPE_AAF 2
+
+// Header sizes (bytes)
+#define AVTP_V0_HEADER_SIZE 12
+#define AAF_HEADER_SIZE 12
+#define TOTAL_HEADER_SIZE (AVTP_V0_HEADER_SIZE + AAF_HEADER_SIZE)
+
+// - 1 Byte - TV bit (timestamp valid)
+#define HIDX_AVTP_HIDE7_TV1 1
+
+// - 1 Byte - TU bit (timestamp uncertain)
+#define HIDX_AVTP_HIDE7_TU1 3
+
+// - 1 Byte - SP bit (sparse mode)
+#define HIDX_AVTP_HIDE7_SP 22
+#define SP_M0_BIT (1 << 4)
+
+typedef enum {
+ AAF_RATE_UNSPEC = 0,
+ AAF_RATE_8K,
+ AAF_RATE_16K,
+ AAF_RATE_32K,
+ AAF_RATE_44K1,
+ AAF_RATE_48K,
+ AAF_RATE_88K2,
+ AAF_RATE_96K,
+ AAF_RATE_176K4,
+ AAF_RATE_192K,
+} aaf_nominal_sample_rate_t;
+
+typedef enum {
+ AAF_FORMAT_UNSPEC = 0,
+ AAF_FORMAT_FLOAT_32,
+ AAF_FORMAT_INT_32,
+ AAF_FORMAT_INT_24,
+ AAF_FORMAT_INT_16,
+} aaf_sample_format_t;
+
+typedef enum {
+ AAF_STATIC_CHANNELS_LAYOUT = 0,
+ AAF_MONO_CHANNELS_LAYOUT = 1,
+ AAF_STEREO_CHANNELS_LAYOUT = 2,
+ AAF_5_1_CHANNELS_LAYOUT = 3,
+ AAF_7_1_CHANNELS_LAYOUT = 4,
+ AAF_MAX_CHANNELS_LAYOUT = 15,
+} aaf_automotive_channels_layout_t;
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ // map_nv_item_count
+ U32 itemCount;
+
+ // Transmit interval in frames per second. 0 = default for talker class.
+ U32 txInterval;
+
+ // A multiple of how many frames of audio to accept in an media queue item and
+ // into the AVTP payload above the minimal needed.
+ U32 packingFactor;
+
+ // MCR mode
+ avb_audio_mcr_t audioMcr;
+
+ // MCR timestamp interval
+ U32 mcrTimestampInterval;
+
+ // MCR clock recovery interval
+ U32 mcrRecoveryInterval;
+
+ /////////////
+ // Variable data
+ /////////////
+ U32 maxTransitUsec; // In microseconds
+
+ aaf_nominal_sample_rate_t aaf_rate;
+ aaf_sample_format_t aaf_format;
+ U8 aaf_bit_depth;
+ U32 payloadSize;
+
+ U8 aaf_event_field;
+
+ bool dataValid;
+
+ U32 intervalCounter;
+
+ U32 sparseMode;
+
+ bool mediaQItemSyncTS;
+
+} pvt_data_t;
+
+static void x_calculateSizes(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ if (pMediaQ) {
+ 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;
+ }
+
+ switch (pPubMapInfo->audioRate) {
+ case AVB_AUDIO_RATE_8KHZ:
+ pPvtData->aaf_rate = AAF_RATE_8K;
+ break;
+ case AVB_AUDIO_RATE_16KHZ:
+ pPvtData->aaf_rate = AAF_RATE_16K;
+ break;
+ case AVB_AUDIO_RATE_32KHZ:
+ pPvtData->aaf_rate = AAF_RATE_32K;
+ break;
+ case AVB_AUDIO_RATE_44_1KHZ:
+ pPvtData->aaf_rate = AAF_RATE_44K1;
+ break;
+ case AVB_AUDIO_RATE_48KHZ:
+ pPvtData->aaf_rate = AAF_RATE_48K;
+ break;
+ case AVB_AUDIO_RATE_88_2KHZ:
+ pPvtData->aaf_rate = AAF_RATE_88K2;
+ break;
+ case AVB_AUDIO_RATE_96KHZ:
+ pPvtData->aaf_rate = AAF_RATE_96K;
+ break;
+ case AVB_AUDIO_RATE_176_4KHZ:
+ pPvtData->aaf_rate = AAF_RATE_176K4;
+ break;
+ case AVB_AUDIO_RATE_192KHZ:
+ pPvtData->aaf_rate = AAF_RATE_192K;
+ break;
+ default:
+ AVB_LOG_ERROR("Invalid audio frequency configured");
+ pPvtData->aaf_rate = AAF_RATE_UNSPEC;
+ break;
+ }
+ AVB_LOGF_INFO("aaf_rate=%d (%dKhz)", pPvtData->aaf_rate, pPubMapInfo->audioRate);
+
+ char *typeStr = "int";
+ if (pPubMapInfo->audioType == AVB_AUDIO_TYPE_FLOAT) {
+ typeStr = "float";
+ switch (pPubMapInfo->audioBitDepth) {
+ case AVB_AUDIO_BIT_DEPTH_32BIT:
+ pPvtData->aaf_format = AAF_FORMAT_FLOAT_32;
+ pPubMapInfo->itemSampleSizeBytes = 4;
+ pPubMapInfo->packetSampleSizeBytes = 4;
+ pPvtData->aaf_bit_depth = 32;
+ break;
+ default:
+ AVB_LOG_ERROR("Invalid audio bit-depth configured for float");
+ pPvtData->aaf_format = AAF_FORMAT_UNSPEC;
+ break;
+ }
+ }
+ else {
+ switch (pPubMapInfo->audioBitDepth) {
+ case AVB_AUDIO_BIT_DEPTH_32BIT:
+ pPvtData->aaf_format = AAF_FORMAT_INT_32;
+ pPubMapInfo->itemSampleSizeBytes = 4;
+ pPubMapInfo->packetSampleSizeBytes = 4;
+ pPvtData->aaf_bit_depth = 32;
+ break;
+ case AVB_AUDIO_BIT_DEPTH_24BIT:
+ pPvtData->aaf_format = AAF_FORMAT_INT_24;
+ pPubMapInfo->itemSampleSizeBytes = 3;
+ pPubMapInfo->packetSampleSizeBytes = 3;
+ pPvtData->aaf_bit_depth = 24;
+ break;
+ case AVB_AUDIO_BIT_DEPTH_16BIT:
+ pPvtData->aaf_format = AAF_FORMAT_INT_16;
+ pPubMapInfo->itemSampleSizeBytes = 2;
+ pPubMapInfo->packetSampleSizeBytes = 2;
+ pPvtData->aaf_bit_depth = 16;
+ break;
+#if 0
+ // should work - test content?
+ case AVB_AUDIO_BIT_DEPTH_20BIT:
+ pPvtData->aaf_format = AAF_FORMAT_INT_24;
+ pPubMapInfo->itemSampleSizeBytes = 3;
+ pPubMapInfo->packetSampleSizeBytes = 3;
+ pPvtData->aaf_bit_depth = 20;
+ break;
+ // would require byte-by-byte copy
+ case AVB_AUDIO_BIT_DEPTH_8BIT:
+ pPvtData->aaf_format = AAF_FORMAT_INT_24;
+ pPubMapInfo->itemSampleSizeBytes = 1;
+ pPubMapInfo->packetSampleSizeBytes = 2;
+ pPvtData->aaf_bit_depth = 8;
+ break;
+#endif
+ default:
+ AVB_LOG_ERROR("Invalid audio bit-depth configured");
+ pPvtData->aaf_format = AAF_FORMAT_UNSPEC;
+ break;
+ }
+ }
+ AVB_LOGF_INFO("aaf_format=%d (%s%d)",
+ pPvtData->aaf_format, typeStr, pPubMapInfo->audioBitDepth);
+
+ // Audio frames per packet
+ pPubMapInfo->framesPerPacket = (pPubMapInfo->audioRate / pPvtData->txInterval);
+ if (pPubMapInfo->audioRate % pPvtData->txInterval != 0) {
+ AVB_LOGF_WARNING("Audio rate (%d) is not integer multiple of TX interval (%d)",
+ pPubMapInfo->audioRate, pPvtData->txInterval);
+ pPubMapInfo->framesPerPacket += 1;
+ }
+ AVB_LOGF_INFO("Frames/packet = %d", pPubMapInfo->framesPerPacket);
+
+ // AAF packet size calculations
+ pPubMapInfo->packetFrameSizeBytes = pPubMapInfo->packetSampleSizeBytes * pPubMapInfo->audioChannels;
+ pPvtData->payloadSize = 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);
+
+ // MediaQ item size calculations
+ pPubMapInfo->packingFactor = pPvtData->packingFactor;
+ pPubMapInfo->framesPerItem = pPubMapInfo->framesPerPacket * pPvtData->packingFactor;
+ pPubMapInfo->itemFrameSizeBytes = pPubMapInfo->itemSampleSizeBytes * pPubMapInfo->audioChannels;
+ pPubMapInfo->itemSize = pPubMapInfo->itemFrameSizeBytes * pPubMapInfo->framesPerItem;
+ AVB_LOGF_INFO("item: sampleSz=%d * channels=%d => frameSz=%d * %d * packing=%d => itemSz=%d",
+ pPubMapInfo->itemSampleSizeBytes,
+ pPubMapInfo->audioChannels,
+ pPubMapInfo->itemFrameSizeBytes,
+ pPubMapInfo->framesPerPacket,
+ pPubMapInfo->packingFactor,
+ pPubMapInfo->itemSize);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbMapAVTPAudioCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+
+ if (strcmp(name, "map_nv_item_count") == 0) {
+ char *pEnd;
+ pPvtData->itemCount = strtol(value, &pEnd, 10);
+ }
+ else if (strcmp(name, "map_nv_packing_factor") == 0) {
+ char *pEnd;
+ pPvtData->packingFactor = strtol(value, &pEnd, 10);
+ }
+ else if (strcmp(name, "map_nv_tx_rate") == 0
+ || strcmp(name, "map_nv_tx_interval") == 0) {
+ char *pEnd;
+ pPvtData->txInterval = strtol(value, &pEnd, 10);
+ }
+ else if (strcmp(name, "map_nv_sparse_mode") == 0) {
+ char* pEnd;
+ U32 tmp;
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1) {
+ pPvtData->sparseMode = TS_SPARSE_MODE_ENABLED;
+ }
+ else if (*pEnd == '\0' && tmp == 0) {
+ pPvtData->sparseMode = TS_SPARSE_MODE_DISABLED;
+ }
+ }
+ else if (strcmp(name, "map_nv_audio_mcr") == 0) {
+ char *pEnd;
+ pPvtData->audioMcr = (avb_audio_mcr_t)strtol(value, &pEnd, 10);
+ }
+ else if (strcmp(name, "map_nv_mcr_timestamp_interval") == 0) {
+ char *pEnd;
+ pPvtData->mcrTimestampInterval = strtol(value, &pEnd, 10);
+ }
+ else if (strcmp(name, "map_nv_mcr_recovery_interval") == 0) {
+ char *pEnd;
+ pPvtData->mcrRecoveryInterval = strtol(value, &pEnd, 10);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+U8 openavbMapAVTPAudioSubtypeCB()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return AVTP_SUBTYPE_AAF; // AAF AVB subtype
+}
+
+// Returns the AVTP version used by this mapping
+U8 openavbMapAVTPAudioAvtpVersionCB()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return 0x00; // Version 0
+}
+
+U16 openavbMapAVTPAudioMaxDataSizeCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return pPvtData->payloadSize + TOTAL_HEADER_SIZE;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0;
+}
+
+// Returns the intended transmit interval (in frames per second). 0 = default for talker / class.
+U32 openavbMapAVTPAudioTransmitIntervalCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return pPvtData->txInterval;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0;
+}
+
+void openavbMapAVTPAudioGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ media_q_pub_map_uncmp_audio_info_t *pPubMapInfo = pMediaQ->pPubMapInfo;
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+
+ x_calculateSizes(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);
+}
+
+// A call to this callback indicates that this mapping module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbMapAVTPAudioTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ 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
+// 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.
+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 (!pData || !dataLen) {
+ AVB_LOG_ERROR("Mapping module data or data length argument incorrect.");
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ if (pMediaQ)
+ pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
+
+ 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)) {
+
+ // Add the max transit time.
+ openavbAvtpTimeAddUSec(pMediaQItem->pAvtpTime, pPvtData->maxTransitUsec);
+
+ // Set timestamp valid flag
+ pHdrV0[HIDX_AVTP_HIDE7_TV1] |= 0x01;
+
+ // Set (clear) timestamp uncertain flag
+ if (openavbAvtpTimeTimestampIsUncertain(pMediaQItem->pAvtpTime))
+ pHdrV0[HIDX_AVTP_HIDE7_TU1] |= 0x01;
+ else pHdrV0[HIDX_AVTP_HIDE7_TU1] &= ~0x01;
+
+ // - 4 bytes avtp_timestamp
+ *pHdr++ = htonl(openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime));
+
+ 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;
+ tmp32 |= pPvtData->aaf_rate << 20;
+ tmp32 |= pPubMapInfo->audioChannels << 8;
+ tmp32 |= pPvtData->aaf_bit_depth;
+ *pHdr++ = htonl(tmp32);
+
+ // - 4 bytes packet info (data length, evt field)
+ tmp32 = pPvtData->payloadSize << 16;
+ tmp32 |= pPvtData->aaf_event_field << 8;
+ *pHdr++ = htonl(tmp32);
+
+ // Set (clear) sparse mode flag
+ if (pPvtData->sparseMode == TS_SPARSE_MODE_ENABLED) {
+ pHdrV0[HIDX_AVTP_HIDE7_SP] |= SP_M0_BIT;
+ } else {
+ 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");
+ openavbMediaQTailPull(pMediaQ);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ memcpy(pPayload, (uint8_t *)pMediaQItem->pPubData + pMediaQItem->readIdx, pPvtData->payloadSize);
+
+ pMediaQItem->readIdx += pPvtData->payloadSize;
+ if (pMediaQItem->readIdx >= pMediaQItem->dataLen) {
+ // Finished reading the entire item
+ openavbMediaQTailPull(pMediaQ);
+ }
+ else {
+ // 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
+ }
+
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY;
+}
+
+// A call to this callback indicates that this mapping module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbMapAVTPAudioRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+ if (pPvtData->audioMcr != AVB_MCR_NONE) {
+ HAL_INIT_MCR_V2(pPvtData->txInterval, pPvtData->packingFactor, pPvtData->mcrTimestampInterval, pPvtData->mcrRecoveryInterval);
+ }
+ bool badPckFctrValue = FALSE;
+ if (pPvtData->sparseMode == TS_SPARSE_MODE_ENABLED) {
+ // 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) {
+ // check if power of 2
+ if ((pPvtData->packingFactor & (pPvtData->packingFactor - 1)) != 0) {
+ badPckFctrValue = TRUE;
+ }
+ } else {
+ // check if multiple of 8
+ if (pPvtData->packingFactor % 8 != 0) {
+ badPckFctrValue = TRUE;
+ }
+ }
+ if (badPckFctrValue) {
+ AVB_LOGF_WARNING("Wrong packing factor value set (%d) for sparse timestamping mode", pPvtData->packingFactor);
+ }
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// This callback occurs when running as a listener and data is available.
+bool openavbMapAVTPAudioRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ if (pMediaQ && pData) {
+ 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 FALSE;
+ }
+
+ int tmp;
+ bool dataValid = TRUE;
+
+ U32 timestamp = ntohl(*pHdr++);
+ U32 format_info = ntohl(*pHdr++);
+ U32 packet_info = ntohl(*pHdr++);
+
+ bool listenerSparseMode = (pPvtData->sparseMode == TS_SPARSE_MODE_ENABLED) ? TRUE : FALSE;
+ bool streamSparseMode = (pHdrV0[HIDX_AVTP_HIDE7_SP] & SP_M0_BIT) ? TRUE : 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 ((tmp = ((format_info >> 20) & 0x0F)) != pPvtData->aaf_rate) {
+ if (pPvtData->dataValid)
+ AVB_LOGF_ERROR("Listener sample rate (%d) doesn't match received data (%d)",
+ pPvtData->aaf_rate, tmp);
+ dataValid = FALSE;
+ }
+ if ((tmp = ((format_info >> 8) & 0x3FF)) != pPubMapInfo->audioChannels) {
+ if (pPvtData->dataValid)
+ AVB_LOGF_ERROR("Listener channel count (%d) doesn't match received data (%d)",
+ pPubMapInfo->audioChannels, tmp);
+ dataValid = FALSE;
+ }
+ if ((tmp = (format_info & 0xFF)) != pPvtData->aaf_bit_depth) {
+ if (pPvtData->dataValid)
+ AVB_LOGF_ERROR("Listener bit depth (%d) doesn't match received data (%d)",
+ pPvtData->aaf_bit_depth, tmp);
+ 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 ((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 (dataValid) {
+ if (!pPvtData->dataValid) {
+ AVB_LOG_INFO("RX data valid, stream un-muted");
+ pPvtData->dataValid = TRUE;
+ }
+
+ // Get item pointer in media queue
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ // set timestamp if first data written to item
+ if (pMediaQItem->dataLen == 0) {
+
+ // Set timestamp valid flag
+ openavbAvtpTimeSetTimestampValid(pMediaQItem->pAvtpTime, (pHdrV0[HIDX_AVTP_HIDE7_TV1] & 0x01) ? TRUE : FALSE);
+
+ if (openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime)) {
+ // Get the timestamp and place it in the media queue item.
+ openavbAvtpTimeSetToTimestamp(pMediaQItem->pAvtpTime, timestamp);
+
+ openavbAvtpTimeSubUSec(pMediaQItem->pAvtpTime, pPubMapInfo->presentationLatencyUSec);
+
+ // Set timestamp uncertain flag
+ openavbAvtpTimeSetTimestampUncertain(pMediaQItem->pAvtpTime, (pHdrV0[HIDX_AVTP_HIDE7_TU1] & 0x01) ? TRUE : FALSE);
+ // Set flag to inform that MediaQ is synchronized with timestamped packets
+ pPvtData->mediaQItemSyncTS = TRUE;
+ }
+ else if (!pPvtData->mediaQItemSyncTS) {
+ //we need packet with valid TS for first data written to item
+ AVB_LOG_DEBUG("Timestamp not valid for MediaQItem - initial packets dropped");
+ IF_LOG_INTERVAL(1000) AVB_LOG_ERROR("Timestamp not valid for MediaQItem - initial packets dropped");
+ dataValid = FALSE;
+ }
+ }
+ if (dataValid) {
+ 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);
+ pMediaQItem->dataLen += pPvtData->payloadSize;
+ }
+
+ if (pMediaQItem->dataLen < pMediaQItem->itemSize) {
+ // More data can be written to the item
+ openavbMediaQHeadUnlock(pMediaQ);
+ }
+ else {
+ // The item is full push it.
+ openavbMediaQHeadPush(pMediaQ);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TRUE; // Normal exit
+ }
+ else {
+ IF_LOG_INTERVAL(1000) AVB_LOG_ERROR("Media queue full");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE; // Media queue full
+ }
+ }
+ else {
+ if (pPvtData->dataValid) {
+ AVB_LOG_INFO("RX data invalid, stream muted");
+ pPvtData->dataValid = FALSE;
+ }
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE;
+}
+
+// This callback will be called when the mapping module needs to be closed.
+// All cleanup should occur in this function.
+void openavbMapAVTPAudioEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+
+ if (pPvtData->audioMcr != AVB_MCR_NONE) {
+ HAL_CLOSE_MCR_V2();
+ }
+
+ pPvtData->mediaQItemSyncTS = FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+void openavbMapAVTPAudioGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Initialization entry point into the mapping module. Will need to be included in the .ini file.
+extern DLL_EXPORT bool openavbMapAVTPAudioInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ if (pMediaQ) {
+ pMediaQ->pMediaQDataFormat = strdup(MapAVTPAudioMediaQDataFormat);
+ pMediaQ->pPubMapInfo = calloc(1, sizeof(media_q_pub_map_aaf_audio_info_t)); // Memory freed by the media queue when the media queue is destroyed.
+ pMediaQ->pPvtMapInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pMediaQDataFormat || !pMediaQ->pPubMapInfo || !pMediaQ->pPvtMapInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for mapping module");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+
+ pMapCB->map_cfg_cb = openavbMapAVTPAudioCfgCB;
+ pMapCB->map_subtype_cb = openavbMapAVTPAudioSubtypeCB;
+ pMapCB->map_avtp_version_cb = openavbMapAVTPAudioAvtpVersionCB;
+ pMapCB->map_max_data_size_cb = openavbMapAVTPAudioMaxDataSizeCB;
+ pMapCB->map_transmit_interval_cb = openavbMapAVTPAudioTransmitIntervalCB;
+ pMapCB->map_gen_init_cb = openavbMapAVTPAudioGenInitCB;
+ pMapCB->map_tx_init_cb = openavbMapAVTPAudioTxInitCB;
+ pMapCB->map_tx_cb = openavbMapAVTPAudioTxCB;
+ pMapCB->map_rx_init_cb = openavbMapAVTPAudioRxInitCB;
+ pMapCB->map_rx_cb = openavbMapAVTPAudioRxCB;
+ pMapCB->map_end_cb = openavbMapAVTPAudioEndCB;
+ pMapCB->map_gen_end_cb = openavbMapAVTPAudioGenEndCB;
+
+ pPvtData->itemCount = 20;
+ pPvtData->txInterval = 4000; // default to something that wont cause divide by zero
+ pPvtData->packingFactor = 1;
+ pPvtData->maxTransitUsec = inMaxTransitUsec;
+ pPvtData->sparseMode = TS_SPARSE_MODE_DISABLED;
+ pPvtData->mcrTimestampInterval = 144;
+ pPvtData->mcrRecoveryInterval = 512;
+ pPvtData->aaf_event_field = AAF_STATIC_CHANNELS_LAYOUT;
+ pPvtData->intervalCounter = 0;
+ pPvtData->mediaQItemSyncTS = FALSE;
+ openavbMediaQSetMaxLatency(pMediaQ, inMaxTransitUsec);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return TRUE;
+}
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
new file mode 100755
index 00000000..c7761b80
--- /dev/null
+++ b/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio_pub.h
@@ -0,0 +1,52 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : AVTP Audio Format mapping module public interface
+ *
+ * AAF is defined in IEEE 1722a (still in draft as of Feb 2015).
+ *
+ * map_nv_tx_rate must be set in the .ini file.
+ */
+
+#ifndef OPENAVB_MAP_AVTP_AUDIO_PUB_H
+#define OPENAVB_MAP_AVTP_AUDIO_PUB_H 1
+
+// For now, use the same data format as the uncompressed audio mapping
+// We will need to change the WAV and ALSA interface modules if we change this
+//
+#include "openavb_map_uncmp_audio_pub.h"
+#define media_q_pub_map_aaf_audio_info_t media_q_pub_map_uncmp_audio_info_t
+
+// NOTE: A define is used for the MediaQDataFormat identifier because it is needed in separate execution units (static / dynamic libraries)
+// that is why a single static (static/extern pattern) definition can not be used.
+#define MapAVTPAudioMediaQDataFormat "AVTPAudioFormat"
+
+#endif // OPENAVB_MAP_AVTP_AUDIO_PUB_H
diff --git a/lib/avtp_pipeline/map_ctrl/CMakeLists.txt b/lib/avtp_pipeline/map_ctrl/CMakeLists.txt
new file mode 100644
index 00000000..9c84c7c2
--- /dev/null
+++ b/lib/avtp_pipeline/map_ctrl/CMakeLists.txt
@@ -0,0 +1,5 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/map_ctrl/openavb_map_ctrl.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/map_ctrl/ctrl_map.md b/lib/avtp_pipeline/map_ctrl/ctrl_map.md
new file mode 100644
index 00000000..b38e1ad1
--- /dev/null
+++ b/lib/avtp_pipeline/map_ctrl/ctrl_map.md
@@ -0,0 +1,19 @@
+Ctrl Mapping {#ctrl_map}
+============
+
+# Description
+
+Control mapping module.
+
+The Control mapping is an AVTP control subtype with an vender specific
+type defined to carry control command payloads between custom interface
+modules. This is compliant with 1722a-D6
+
+# Mapping module configuration parameters
+
+Name | Description
+--------------------|---------------------------
+map_nv_item_count |The number of media queue elements to hold.
+map_nv_tx_rate or map_nv_tx_interval | Transmit interval in frames per second. \
+ 0 = default for talker class
+map_nv_max_payload_size| Maximum payload that will be send in one ethernet frame
diff --git a/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl.c b/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl.c
new file mode 100755
index 00000000..34a353e8
--- /dev/null
+++ b/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl.c
@@ -0,0 +1,484 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Control mapping module.
+*
+* The Control mapping is an AVTP control subtype with an vender specific
+* type defined to carry control command payloads between custom interface
+* modules. This is compliant with 1722a-D6
+*
+*----------------------------------------------------------------*
+*
+* HEADERS
+*
+* -+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-
+* |C| |S| |M| |F|T| | |T|
+* |D|subtype |V|vers |R|R|V|V|sequence number|reserved |U|
+* --+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+--
+* | |
+* | |
+* - -
+* | |
+* |stream id |
+* --+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+--
+* | |
+* |AVTP timestamp |
+* --+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+--
+* | |
+* |format info |
+* --+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+--
+* | |proto | |number of |
+* |stream data length |type |reserve|messages |
+* --+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+--
+* |OPENAVB control | | |
+* |format |OPENAVB data length |OPENAVB reserved |
+* --+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+--
+*
+******* Standard AVTP header fields for the AVTP_CONTROL subtype IEEE 1722a Section 10.
+*
+* CD : Standard AVTP
+* Subtype : AVTP Control 0x04
+* SV : Standard AVTP
+* Ver` : Standard AVTP
+* MR : Standard AVTP
+* R : Standard AVTP
+* FV : Standard AVTP Set to zero (0)
+* TV : Standard AVTP
+* Sequence number : Standard AVTP
+* Reserved : Standard AVTP
+* TU : Standard AVTP
+* Stream ID : Standard AVTP
+* AVTP timestamp : Standard AVTP
+* Format info : Standard AVTP (unused for AVTP control streams)
+* Data Length : Length of the data payload
+* Protocol type : Set to "F" for CTL_PROPRIETARY
+* Reserved : Standard AVTP
+* Number of messages: This mapping module will always transport just 1 message.
+*
+******* OPENAVB Vendor headers
+*
+* OPENAVB Ctrl format : OPENAVB specific control format. 0x01 for this mapping.
+* OPENAVB data length : Data length of the OPENAVB control payload.
+* OPENAVB reserved : reserved
+*
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_avtp_time_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_map_pub.h"
+#include "openavb_map_ctrl_pub.h"
+
+#define AVB_LOG_COMPONENT "Control Mapping"
+#include "openavb_log_pub.h"
+
+#define AVTP_V0_HEADER_SIZE 12
+#define SUBTYPE_HEADER_SIZE 12
+#define OPENAVB_FORMAT_HEADER_SIZE 4
+
+#define AVTP_HEADER_SIZE (AVTP_V0_HEADER_SIZE + SUBTYPE_HEADER_SIZE)
+#define TOTAL_HEADER_SIZE (AVTP_HEADER_SIZE + OPENAVB_FORMAT_HEADER_SIZE)
+
+//////
+// AVTP Version 0 Header
+//////
+
+#define HIDX_AVTP_VERZERO96 0
+
+// - 1 Byte - TV bit (timestamp valid)
+#define HIDX_AVTP_HIDE7_TV1 1
+
+// - 1 Byte - TU bit (timestamp uncertain)
+#define HIDX_AVTP_HIDE7_TU1 3
+
+
+//////
+// Mapping specific header
+//////
+
+// - 4 bytes avtp_timestamp
+#define HIDX_AVTP_TIMESPAMP32 12
+
+// - 4 bytes format information
+#define HIDX_AVTP_FORMAT_INFO32 16
+
+// - 2 bytes data length
+#define HIDX_AVTP_DATA_LENGTH16 20
+
+// - 1 byte protocol type | Reserved
+#define HIDX_PROTO4_RESERVED4 22
+
+// - 1 byte Number of messages
+#define HIDX_NUMMESS8 23
+
+
+//////
+// OPENAVB specific header
+//////
+
+// - 1 byte OPENAVB format
+#define HIDX_OPENAVB_CTRL_FORMAT8 24
+
+// - 2 bytes stream_data_len
+#define HIDX_OPENAVB_CTRL_DATALEN16 25
+
+// - 1 bytes OPENAVB reserved
+#define HIDX_OPENAVB_RESERVEDA8 27
+
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ // map_nv_item_count
+ U32 itemCount;
+
+ // Transmit interval in frames per second. 0 = default for talker class.
+ U32 txInterval;
+
+
+ /////////////
+ // Variable data
+ /////////////
+ // Max payload size
+ U32 maxPayloadSize;
+
+ // Maximum data size
+ U32 maxDataSize;
+
+ // Maximum media queue item size
+ U32 itemSize;
+
+ // Maximum transit time
+ U32 maxTransitUsec; // In microseconds
+
+} pvt_data_t;
+
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbMapCtrlCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ char *pEnd;
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+
+ if (strcmp(name, "map_nv_item_count") == 0) {
+ pPvtData->itemCount = strtol(value, &pEnd, 10);
+ }
+ else if (strcmp(name, "map_nv_tx_rate") == 0
+ || strcmp(name, "map_nv_tx_interval") == 0) {
+ pPvtData->txInterval = strtol(value, &pEnd, 10);
+ }
+ else if (strcmp(name, "map_nv_max_payload_size") == 0) {
+ pPvtData->maxPayloadSize = strtol(value, &pEnd, 10);
+ pPvtData->maxDataSize = (pPvtData->maxPayloadSize + TOTAL_HEADER_SIZE);
+ pPvtData->itemSize = pPvtData->maxDataSize;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+U8 openavbMapCtrlSubtypeCB()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0x04; // AVTP Control subtype 1722a 5.2.1.2 subtype field
+}
+
+// Returns the AVTP version used by this mapping
+U8 openavbMapCtrlAvtpVersionCB()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return 0x00; // Version 0
+}
+
+U16 openavbMapCtrlMaxDataSizeCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return pPvtData->maxDataSize;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0;
+}
+
+// Returns the intended transmit interval (in frames per second). 0 = default for talker / class.
+U32 openavbMapCtrlTransmitIntervalCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return pPvtData->txInterval;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0;
+}
+
+void openavbMapCtrlGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+
+ openavbMediaQSetSize(pMediaQ, pPvtData->itemCount, pPvtData->itemSize);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// A call to this callback indicates that this mapping module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbMapCtrlTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// This talker callback will be called for each AVB observation interval.
+tx_cb_ret_t openavbMapCtrlTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ if (pMediaQ && pData && dataLen) {
+ U8 *pHdr = pData;
+ U8 *pPayload = pData + TOTAL_HEADER_SIZE;
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
+
+ if (pMediaQItem) {
+ if (pMediaQItem->dataLen > 0) {
+ if (pMediaQItem->dataLen > pPvtData->maxPayloadSize) {
+ AVB_LOGF_ERROR("Media queue data item size too large. Reported size: %d Max Size: %d", pMediaQItem->dataLen, pPvtData->maxPayloadSize);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ openavbMediaQTailPull(pMediaQ);
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ // PTP walltime already set in the interface module. Just add the max transit time.
+ openavbAvtpTimeAddUSec(pMediaQItem->pAvtpTime, pPvtData->maxTransitUsec);
+
+ // Set timestamp valid flag
+ if (openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime))
+ pHdr[HIDX_AVTP_HIDE7_TV1] |= 0x01; // Set
+ else {
+ pHdr[HIDX_AVTP_HIDE7_TV1] &= ~0x01; // Clear
+ }
+
+ // Set timestamp uncertain flag
+ if (openavbAvtpTimeTimestampIsUncertain(pMediaQItem->pAvtpTime))
+ pHdr[HIDX_AVTP_HIDE7_TU1] |= 0x01; // Set
+ else
+ pHdr[HIDX_AVTP_HIDE7_TU1] &= ~0x01; // Clear
+
+ *(U32 *)(&pHdr[HIDX_AVTP_TIMESPAMP32]) = htonl(openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime));
+ *(U32 *)(&pHdr[HIDX_AVTP_FORMAT_INFO32]) = 0x00000000;
+ *(U16 *)(&pHdr[HIDX_AVTP_DATA_LENGTH16]) = htons(pMediaQItem->dataLen + OPENAVB_FORMAT_HEADER_SIZE);
+ pHdr[HIDX_PROTO4_RESERVED4] = 0xF0; // 1722a 10.2.2 protocol_type field. F for CTL_PROPRIETARY
+ pHdr[HIDX_NUMMESS8] = 0x01; // Always 1 control message
+
+ pHdr[HIDX_OPENAVB_CTRL_FORMAT8] = MAP_CTRL_OPENAVB_FORMAT;
+ *(U16 *)(&pHdr[HIDX_OPENAVB_CTRL_DATALEN16]) = htons(pMediaQItem->dataLen);
+ pHdr[HIDX_OPENAVB_RESERVEDA8] = 0x00;
+
+ memcpy(pPayload, pMediaQItem->pPubData, pMediaQItem->dataLen);
+ *dataLen = pMediaQItem->dataLen + TOTAL_HEADER_SIZE;
+
+ openavbMediaQTailPull(pMediaQ);
+ AVB_TRACE_LINE(AVB_TRACE_MAP_LINE);
+ 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
+ }
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY; // Media queue empty
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY;
+}
+
+// A call to this callback indicates that this mapping module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbMapCtrlRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// This callback occurs when running as a listener and data is available.
+bool openavbMapCtrlRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ if (pMediaQ && pData) {
+ const U8 *pHdr = pData;
+ U8 *pPayload = pData + TOTAL_HEADER_SIZE;
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return FALSE;
+ }
+
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ U32 timestamp = ntohl(*(U32 *)(&pHdr[HIDX_AVTP_TIMESPAMP32]));
+ openavbAvtpTimeSetToTimestamp(pMediaQItem->pAvtpTime, timestamp);
+
+ // Set timestamp valid and timestamp uncertain flags
+ openavbAvtpTimeSetTimestampValid(pMediaQItem->pAvtpTime, (pHdr[HIDX_AVTP_HIDE7_TV1] & 0x01) ? TRUE : FALSE);
+ openavbAvtpTimeSetTimestampUncertain(pMediaQItem->pAvtpTime, (pHdr[HIDX_AVTP_HIDE7_TU1] & 0x01) ? TRUE : FALSE);
+
+ if (pHdr[HIDX_OPENAVB_CTRL_FORMAT8] == MAP_CTRL_OPENAVB_FORMAT) {
+ U16 payloadLen = ntohs(*(U16 *)(&pHdr[HIDX_OPENAVB_CTRL_DATALEN16]));
+ if (pMediaQItem->itemSize >= payloadLen) {
+ memcpy(pMediaQItem->pPubData, pPayload, payloadLen);
+ pMediaQItem->dataLen = payloadLen;
+ }
+ else {
+ AVB_LOG_ERROR("Data to large for media queue.");
+ pMediaQItem->dataLen = 0;
+ }
+ }
+ else {
+ AVB_LOG_ERROR("Unexpected control stream format.");
+ pMediaQItem->dataLen = 0;
+ }
+
+ openavbMediaQHeadPush(pMediaQ);
+ AVB_TRACE_LINE(AVB_TRACE_MAP_LINE);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TRUE;
+ }
+ else {
+ IF_LOG_INTERVAL(1000) AVB_LOG_ERROR("Media queue full.");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE; // Media queue full
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE;
+}
+
+// This callback will be called when the mapping module needs to be closed.
+// All cleanup should occur in this function.
+void openavbMapCtrlEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+void openavbMapCtrlGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Initialization entry point into the mapping module. Will need to be included in the .ini file.
+extern DLL_EXPORT bool openavbMapCtrlInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ if (pMediaQ) {
+ pMediaQ->pMediaQDataFormat = strdup(MapCtrlMediaQDataFormat);
+ pMediaQ->pPvtMapInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pMediaQDataFormat || !pMediaQ->pPvtMapInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for mapping module.");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+
+ pMapCB->map_cfg_cb = openavbMapCtrlCfgCB;
+ pMapCB->map_subtype_cb = openavbMapCtrlSubtypeCB;
+ pMapCB->map_avtp_version_cb = openavbMapCtrlAvtpVersionCB;
+ pMapCB->map_max_data_size_cb = openavbMapCtrlMaxDataSizeCB;
+ pMapCB->map_transmit_interval_cb = openavbMapCtrlTransmitIntervalCB;
+ pMapCB->map_gen_init_cb = openavbMapCtrlGenInitCB;
+ pMapCB->map_tx_init_cb = openavbMapCtrlTxInitCB;
+ pMapCB->map_tx_cb = openavbMapCtrlTxCB;
+ pMapCB->map_rx_init_cb = openavbMapCtrlRxInitCB;
+ pMapCB->map_rx_cb = openavbMapCtrlRxCB;
+ pMapCB->map_end_cb = openavbMapCtrlEndCB;
+ pMapCB->map_gen_end_cb = openavbMapCtrlGenEndCB;
+
+ pPvtData->itemCount = 20;
+ pPvtData->txInterval = 0;
+ pPvtData->maxTransitUsec = inMaxTransitUsec;
+
+ pPvtData->maxPayloadSize = 1024;
+ pPvtData->maxDataSize = (pPvtData->maxPayloadSize + TOTAL_HEADER_SIZE);
+ pPvtData->itemSize = pPvtData->maxDataSize;
+
+ openavbMediaQSetMaxLatency(pMediaQ, inMaxTransitUsec);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return TRUE;
+}
+
diff --git a/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl_pub.h b/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl_pub.h
new file mode 100755
index 00000000..a89429b0
--- /dev/null
+++ b/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl_pub.h
@@ -0,0 +1,44 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Control mapping module public interface
+*/
+
+#ifndef OPENAVB_MAP_CTRL_PUB_H
+#define OPENAVB_MAP_CTRL_PUB_H 1
+
+#include "openavb_types_pub.h"
+
+// NOTE: A define is used for the MapCtrlMediaQDataFormat identifier because it is needed in separate execution units (static / dynamic libraries)
+// that is why a single static (static/extern pattern) definition can not be used.
+#define MapCtrlMediaQDataFormat "OPENAVBControl"
+
+#endif // OPENAVB_MAP_CTRL_PUB_H
diff --git a/lib/avtp_pipeline/map_h264/CMakeLists.txt b/lib/avtp_pipeline/map_h264/CMakeLists.txt
new file mode 100644
index 00000000..c6f658b8
--- /dev/null
+++ b/lib/avtp_pipeline/map_h264/CMakeLists.txt
@@ -0,0 +1,5 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/map_h264/openavb_map_h264.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/map_h264/openavb_map_h264.c b/lib/avtp_pipeline/map_h264/openavb_map_h264.c
new file mode 100755
index 00000000..6898a5ad
--- /dev/null
+++ b/lib/avtp_pipeline/map_h264/openavb_map_h264.c
@@ -0,0 +1,461 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : H.264 mapping module conforming to 1722A D6 9.4.3.
+*/
+
+//////////////////////////////////////////////////////////////////
+// WORK IN PROGRESS
+//////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////
+// WORK IN PROGRESS
+//////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////
+// WORK IN PROGRESS
+//////////////////////////////////////////////////////////////////
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_avtp_time_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_map_pub.h"
+#include "openavb_map_h264_pub.h"
+
+#define AVB_LOG_COMPONENT "H.264 Mapping"
+#include "openavb_log_pub.h"
+
+// Header sizes
+#define AVTP_V0_HEADER_SIZE 12
+#define MAP_HEADER_SIZE 12
+
+#define TOTAL_HEADER_SIZE (AVTP_V0_HEADER_SIZE + MAP_HEADER_SIZE)
+
+#define MAX_PAYLOAD_SIZE 1412
+
+//////
+// AVTP Version 0 Header
+//////
+
+// This mapping does not directly set or read these.
+#define HIDX_AVTP_VERZERO96 0
+
+// - 1 Byte - TV bit (timestamp valid)
+#define HIDX_AVTP_HIDE7_TV1 1
+
+// - 1 Byte - TU bit (timestamp uncertain)
+#define HIDX_AVTP_HIDE7_TU1 3
+
+
+//////
+// Mapping specific header
+//////
+
+// - 4 bytes avtp_timestamp
+#define HIDX_AVTP_TIMESPAMP32 12
+
+// - 1 bytes Format information = 0x02 RTP Video
+#define HIDX_FORMAT8 16
+
+// - 1 bytes Format subtype = 0x01 H.264
+#define HIDX_FORMAT_SUBTYPE8 17
+
+// - 2 bytes Reserved = 0x0000
+#define HIDX_RESV16 18
+
+// - 2 bytes Stream data length
+#define HIDX_STREAM_DATA_LEN16 20
+
+// 1 bit M3 = binary 0
+// 1 bit M2 = binary 0
+// 1 bit M1 = binary 0
+// 1 bit M0 = Set by interface module
+// 2 bits EVT = binary 00
+// 2 bits Reserved = binary 00
+#define HIDX_M31_M21_M11_M01_EVT2_RESV2 22
+
+// - 1 byte Reserved = binary 0x00
+#define HIDX_RESV8 23
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ // map_nv_item_count
+ U32 itemCount;
+
+ // Transmit interval in frames per second. 0 = default for talker class.
+ U32 txInterval;
+
+ // Max payload size
+ U32 maxPayloadSize;
+
+ /////////////
+ // Variable data
+ /////////////
+ // Maximum transit time in microseconds
+ U32 maxTransitUsec;
+
+ // Maximum data size. This is the RTP payload size. See RFC 6184 for details.
+ U32 maxDataSize;
+
+ // Maximum media queue item size
+ U32 itemSize;
+
+} pvt_data_t;
+
+
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbMapH264CfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+
+ char *pEnd;
+
+ if (strcmp(name, "map_nv_item_count") == 0) {
+ pPvtData->itemCount = strtol(value, &pEnd, 10);
+ }
+ else if (strcmp(name, "map_nv_tx_rate") == 0
+ || strcmp(name, "map_nv_tx_interval") == 0) {
+ pPvtData->txInterval = strtol(value, &pEnd, 10);
+ }
+ else if (strcmp(name, "map_nv_max_payload_size") == 0) {
+ U32 size = strtol(value, &pEnd, 10);
+ if (size > MAX_PAYLOAD_SIZE) {
+ AVB_LOGF_WARNING("map_nv_max_payload_size too large. Parameter set to default: %d", MAX_PAYLOAD_SIZE);
+ size = MAX_PAYLOAD_SIZE;
+ }
+ pPvtData->maxPayloadSize = size;
+ pPvtData->maxDataSize = (pPvtData->maxPayloadSize + TOTAL_HEADER_SIZE);
+ pPvtData->itemSize = pPvtData->maxPayloadSize;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+U8 openavbMapH264SubtypeCB()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0x03; // AVTP Video subtype
+}
+
+// Returns the AVTP version used by this mapping
+U8 openavbMapH264AvtpVersionCB()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return 0x00; // Version 0
+}
+
+U16 openavbMapH264MaxDataSizeCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return pPvtData->maxDataSize;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0;
+}
+
+// Returns the intended transmit interval (in frames per second). 0 = default for talker / class.
+U32 openavbMapH264TransmitIntervalCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return pPvtData->txInterval;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0;
+}
+
+void openavbMapH264GenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+
+ openavbMediaQSetSize(pMediaQ, pPvtData->itemCount, pPvtData->itemSize);
+ openavbMediaQAllocItemMapData(pMediaQ, sizeof(media_q_item_map_h264_pub_data_t), 0);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// A call to this callback indicates that this mapping module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbMapH264TxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// This talker callback will be called for each AVB observation interval.
+tx_cb_ret_t openavbMapH264TxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ if (pMediaQ && pData && dataLen) {
+ U8 *pHdr = pData;
+ U8 *pPayload = pData + TOTAL_HEADER_SIZE;
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ //pHdr[HIDX_AVTP_TIMESPAMP32] = 0x00; // Set later
+ pHdr[HIDX_FORMAT8] = 0x02; // RTP Payload type
+ pHdr[HIDX_FORMAT_SUBTYPE8] = 0x01; // H.264 subtype
+ pHdr[HIDX_RESV16] = 0x0000; // Reserved
+ //pHdr[HIDX_STREAM_DATA_LEN16] = 0x0000; // Set later
+ //pHdr[HIDX_M31_M21_M11_M01_EVT2_RESV2] = 0x00; // M0 set later
+ pHdr[HIDX_RESV8] = 0x00;
+
+ media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
+ if (pMediaQItem) {
+ if (pMediaQItem->dataLen > 0) {
+ if (pMediaQItem->dataLen > pPvtData->itemSize) {
+ AVB_LOGF_ERROR("Media queue data item size too large. Reported size: %d Max Size: %d", pMediaQItem->dataLen, pPvtData->itemSize);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ openavbMediaQTailPull(pMediaQ);
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ // PTP walltime already set in the interface module. Just add the max transit time.
+ openavbAvtpTimeAddUSec(pMediaQItem->pAvtpTime, pPvtData->maxTransitUsec);
+
+ // Set timestamp valid flag
+ if (openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime))
+ pHdr[HIDX_AVTP_HIDE7_TV1] |= 0x01; // Set
+ else {
+ pHdr[HIDX_AVTP_HIDE7_TV1] &= ~0x01; // Clear
+ }
+
+ // Set timestamp uncertain flag
+ if (openavbAvtpTimeTimestampIsUncertain(pMediaQItem->pAvtpTime))
+ pHdr[HIDX_AVTP_HIDE7_TU1] |= 0x01; // Set
+ else pHdr[HIDX_AVTP_HIDE7_TU1] &= ~0x01; // Clear
+
+ // Set the timestamp.
+ *(U32 *)(&pHdr[HIDX_AVTP_TIMESPAMP32]) = htonl(openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime));
+
+ if (((media_q_item_map_h264_pub_data_t *)pMediaQItem->pPubMapData)->lastPacket) {
+ pHdr[HIDX_M31_M21_M11_M01_EVT2_RESV2] = 0x10;;
+ }
+ else {
+ pHdr[HIDX_M31_M21_M11_M01_EVT2_RESV2] = 0x00;
+ }
+
+ // Copy the JPEG fragment into the outgoing avtp packet.
+ memcpy(pPayload, pMediaQItem->pPubData, pMediaQItem->dataLen);
+
+ *(U16 *)(&pHdr[HIDX_STREAM_DATA_LEN16]) = htons(pMediaQItem->dataLen);
+
+ // Set out bound data length (entire packet length)
+ *dataLen = pMediaQItem->dataLen + TOTAL_HEADER_SIZE;
+
+ AVB_TRACE_LINE(AVB_TRACE_MAP_LINE);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ openavbMediaQTailPull(pMediaQ);
+ return TX_CB_RET_PACKET_READY;
+ }
+ openavbMediaQTailPull(pMediaQ);
+ }
+ }
+
+ if (dataLen) {
+ // Set out bound data length (entire packet length)
+ *dataLen = 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY;
+}
+
+// A call to this callback indicates that this mapping module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbMapH264RxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// This callback occurs when running as a listener and data is available.
+bool openavbMapH264RxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ if (pMediaQ && pData) {
+ U8 *pHdr = pData;
+ U8 *pPayload = pData + TOTAL_HEADER_SIZE;
+
+
+ //pHdr[HIDX_AVTP_TIMESPAMP32]
+ //pHdr[HIDX_FORMAT8]
+ //pHdr[HIDX_FORMAT_SUBTYPE8]
+ //pHdr[HIDX_RESV16]
+ //pHdr[HIDX_STREAM_DATA_LEN16]
+ U16 payloadLen = ntohs(*(U16 *)(&pHdr[HIDX_STREAM_DATA_LEN16]));
+ //pHdr[HIDX_M31_M21_M11_M01_EVT2_RESV2]
+ //pHdr[HIDX_RESV8]
+
+ // validate header
+ if (payloadLen > dataLen - TOTAL_HEADER_SIZE) {
+ IF_LOG_INTERVAL(1000) AVB_LOG_ERROR("header data len > actual data len");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE;
+ }
+
+ // Get item pointer in media queue
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ // Get the timestamp and place it in the media queue item.
+ U32 timestamp = ntohl(*(U32 *)(&pHdr[HIDX_AVTP_TIMESPAMP32]));
+ openavbAvtpTimeSetToTimestamp(pMediaQItem->pAvtpTime, timestamp);
+
+ // Set timestamp valid and timestamp uncertain flags
+ openavbAvtpTimeSetTimestampValid(pMediaQItem->pAvtpTime, (pHdr[HIDX_AVTP_HIDE7_TV1] & 0x01) ? TRUE : FALSE);
+ openavbAvtpTimeSetTimestampUncertain(pMediaQItem->pAvtpTime, (pHdr[HIDX_AVTP_HIDE7_TU1] & 0x01) ? TRUE : FALSE);
+
+ if (pHdr[HIDX_M31_M21_M11_M01_EVT2_RESV2] & 0x10)
+ ((media_q_item_map_h264_pub_data_t *)pMediaQItem->pPubMapData)->lastPacket = TRUE;
+ else
+ ((media_q_item_map_h264_pub_data_t *)pMediaQItem->pPubMapData)->lastPacket = FALSE;
+
+ if (pMediaQItem->itemSize >= payloadLen) {
+ memcpy(pMediaQItem->pPubData, pPayload, payloadLen);
+ pMediaQItem->dataLen = payloadLen;
+ }
+ else {
+ AVB_LOGF_ERROR("Data to large for media queue (itemSize %d, data size %d).", pMediaQItem->itemSize, payloadLen);
+ pMediaQItem->dataLen = 0;
+ }
+
+ openavbMediaQHeadPush(pMediaQ);
+ AVB_TRACE_LINE(AVB_TRACE_MAP_LINE);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TRUE;
+ }
+ else {
+ IF_LOG_INTERVAL(1000) AVB_LOG_ERROR("Media queue full");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE; // Media queue full
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE;
+}
+
+// This callback will be called when the mapping module needs to be closed.
+// All cleanup should occur in this function.
+void openavbMapH264EndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+void openavbMapH264GenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Initialization entry point into the mapping module. Will need to be included in the .ini file.
+extern DLL_EXPORT bool openavbMapH264Initialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ if (pMediaQ) {
+ pMediaQ->pMediaQDataFormat = strdup(MapH264MediaQDataFormat);
+ pMediaQ->pPvtMapInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pMediaQDataFormat || !pMediaQ->pPvtMapInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for mapping module.");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+
+ pMapCB->map_cfg_cb = openavbMapH264CfgCB;
+ pMapCB->map_subtype_cb = openavbMapH264SubtypeCB;
+ pMapCB->map_avtp_version_cb = openavbMapH264AvtpVersionCB;
+ pMapCB->map_max_data_size_cb = openavbMapH264MaxDataSizeCB;
+ pMapCB->map_transmit_interval_cb = openavbMapH264TransmitIntervalCB;
+ pMapCB->map_gen_init_cb = openavbMapH264GenInitCB;
+ pMapCB->map_tx_init_cb = openavbMapH264TxInitCB;
+ pMapCB->map_tx_cb = openavbMapH264TxCB;
+ pMapCB->map_rx_init_cb = openavbMapH264RxInitCB;
+ pMapCB->map_rx_cb = openavbMapH264RxCB;
+ pMapCB->map_end_cb = openavbMapH264EndCB;
+ pMapCB->map_gen_end_cb = openavbMapH264GenEndCB;
+
+ pPvtData->itemCount = 20;
+ pPvtData->txInterval = 0;
+ pPvtData->maxTransitUsec = inMaxTransitUsec;
+
+ pPvtData->maxPayloadSize = MAX_PAYLOAD_SIZE;
+ pPvtData->maxDataSize = (pPvtData->maxPayloadSize + TOTAL_HEADER_SIZE);
+ pPvtData->itemSize = pPvtData->maxPayloadSize;
+
+ openavbMediaQSetMaxLatency(pMediaQ, inMaxTransitUsec);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/map_h264/openavb_map_h264_pub.h b/lib/avtp_pipeline/map_h264/openavb_map_h264_pub.h
new file mode 100755
index 00000000..c685d967
--- /dev/null
+++ b/lib/avtp_pipeline/map_h264/openavb_map_h264_pub.h
@@ -0,0 +1,58 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Motion JPEG mapping module public interface conforming to 1722A RTP payload encapsulation.
+*
+* Refer to RFC 2435 for details of the fragment structure.
+*
+* As defined 1722a the timestamp must be the same for each fragment of a JPEG frame. This means the interface module
+* must set this same timestamp in the media queue for each item tht is a JPEG fragment of the frame. In addition the
+* Interface module must set the lastFragment flag of the item public map data structure for each fragment placed into
+* the media queue (TRUE if not the last fragment of the frame, FALSE if it is the last fragment of a frame).
+*
+* The payload will be as defined in RFC 2435 and will include the JPEG headers as well as the JPEG data.
+*/
+
+#ifndef OPENAVB_MAP_H264_PUB_H
+#define OPENAVB_MAP_H264_PUB_H 1
+
+#include "openavb_types_pub.h"
+
+// NOTE: A define is used for the MapH264MediaQDataFormat identifier because it is needed in separate execution units (static / dynamic libraries)
+// that is why a single static (static/extern pattern) definition can not be used.
+#define MapH264MediaQDataFormat "H.264"
+
+typedef struct {
+ // Last fragment of frame flag.
+ bool lastPacket; // For details see 1722a 9.4.3.1.1 M0 field
+} media_q_item_map_h264_pub_data_t;
+
+#endif // OPENAVB_MAP_H264_PUB_H
diff --git a/lib/avtp_pipeline/map_mjpeg/CMakeLists.txt b/lib/avtp_pipeline/map_mjpeg/CMakeLists.txt
new file mode 100644
index 00000000..f0765be0
--- /dev/null
+++ b/lib/avtp_pipeline/map_mjpeg/CMakeLists.txt
@@ -0,0 +1,5 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/map_mjpeg/openavb_map_mjpeg.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/map_mjpeg/mjpeg_map.md b/lib/avtp_pipeline/map_mjpeg/mjpeg_map.md
new file mode 100644
index 00000000..103763a6
--- /dev/null
+++ b/lib/avtp_pipeline/map_mjpeg/mjpeg_map.md
@@ -0,0 +1,24 @@
+mjpeg Mapping {#mjpeg_map}
+=============
+
+# Description
+
+Motion Jpeg mapping module conforming to 1722A RTP payload encapsulation.
+
+# Mapping module configuration parameters
+
+Name | Description
+--------------------|---------------------------
+map_nv_item_count |The number of media queue elements to hold.
+map_nv_tx_rate or map_nv_tx_interval | Transmit interval in frames per second. \
+ 0 = default for talker class
+
+# Notes
+
+This module also uses the field media_q_item_map_mjpeg_pub_data_t::lastFragment
+in both RX and TX. The usage depends on situation, for:
+- TX - stores in the AVTP header information that this is the last fragment of
+this frame. The interface module has to set this variable to correct value,
+* RX - extracts from the AVTP header information if this fragment is the last one
+of current video frame and sets field accordingly. The interface module might use
+it later during frame composition.
diff --git a/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg.c b/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg.c
new file mode 100755
index 00000000..a348439a
--- /dev/null
+++ b/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg.c
@@ -0,0 +1,427 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Motion Jpeg mapping module conforming to 1722A RTP payload encapsulation.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_avtp_time_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_map_pub.h"
+#include "openavb_map_mjpeg_pub.h"
+
+#define AVB_LOG_COMPONENT "MJPEG Mapping"
+#include "openavb_log_pub.h"
+
+// Header sizes
+#define AVTP_V0_HEADER_SIZE 12
+#define MAP_HEADER_SIZE 12
+
+#define TOTAL_HEADER_SIZE (AVTP_V0_HEADER_SIZE + MAP_HEADER_SIZE)
+
+// MJPEG Payload is a JPEG fragment per packet plus its headers
+//#define MAX_JPEG_PAYLOAD_SIZE 1024
+#define MAX_JPEG_PAYLOAD_SIZE 1412
+
+#define MAX_DATA_SIZE (MAX_JPEG_PAYLOAD_SIZE + TOTAL_HEADER_SIZE);
+
+#define ITEM_SIZE MAX_JPEG_PAYLOAD_SIZE
+
+//////
+// AVTP Version 0 Header
+//////
+
+// This mapping does not directly set or read these.
+#define HIDX_AVTP_VERZERO96 0
+
+// - 1 Byte - TV bit (timestamp valid)
+#define HIDX_AVTP_HIDE7_TV1 1
+
+// - 1 Byte - TU bit (timestamp uncertain)
+#define HIDX_AVTP_HIDE7_TU1 3
+
+
+//////
+// Mapping specific header
+//////
+
+// - 4 bytes avtp_timestamp
+#define HIDX_AVTP_TIMESTAMP32 12
+
+// - 1 bytes Format information = 0x02 RTP Video
+#define HIDX_FORMAT8 16
+
+// - 1 byte Format subtype = 0x00
+#define HIDX_FORMAT_SUBTYPE8 17
+
+// - 2 bytes Reserved = binary 0x0000
+#define HIDX_RESV16 18
+
+// - 2 bytes Stream data length
+#define HIDX_STREAM_DATA_LEN16 20
+
+// 1 bit M3 = binary 0
+// 1 bit M2 = binary 0
+// 1 bit M1 = binary 0
+// 1 bit M0 = binary 0
+// 2 bit evt = binary 00
+// 2 bit Reserved = binary 00
+#define HIDX_M11_M01_EVT2_RESV2 22
+
+// - 1 byte Reserved = binary 0x00
+#define HIDX_RESV8 23
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ // map_nv_item_count
+ U32 itemCount;
+
+ // Transmit interval in frames per second. 0 = default for talker class.
+ U32 txInterval;
+
+ /////////////
+ // Variable data
+ /////////////
+ U32 maxTransitUsec; // In microseconds
+
+ U32 timestamp;
+ bool tsvalid;
+} pvt_data_t;
+
+
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbMapMjpegCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+
+ if (strcmp(name, "map_nv_item_count") == 0) {
+ char *pEnd;
+ pPvtData->itemCount = strtol(value, &pEnd, 10);
+ }
+ else if (strcmp(name, "map_nv_tx_rate") == 0
+ || strcmp(name, "map_nv_tx_interval") == 0) {
+ char *pEnd;
+ pPvtData->txInterval = strtol(value, &pEnd, 10);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+U8 openavbMapMjpegSubtypeCB()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0x03; // AVTP Video subtype
+}
+
+// Returns the AVTP version used by this mapping
+U8 openavbMapMjpegAvtpVersionCB()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return 0x00; // Version 0
+}
+
+U16 openavbMapMjpegMaxDataSizeCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return MAX_DATA_SIZE;
+}
+
+// Returns the intended transmit interval (in frames per second). 0 = default for talker / class.
+U32 openavbMapMjpegTransmitIntervalCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return pPvtData->txInterval;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0;
+}
+
+void openavbMapMjpegGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+
+ pPvtData->timestamp = 0;
+ pPvtData->tsvalid = FALSE;
+
+ openavbMediaQSetSize(pMediaQ, pPvtData->itemCount, ITEM_SIZE);
+ openavbMediaQAllocItemMapData(pMediaQ, sizeof(media_q_item_map_mjpeg_pub_data_t), 0);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// A call to this callback indicates that this mapping module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbMapMjpegTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// This talker callback will be called for each AVB observation interval.
+tx_cb_ret_t openavbMapMjpegTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ if (pMediaQ && pData && dataLen) {
+ U8 *pHdr = pData;
+ U8 *pPayload = pData + TOTAL_HEADER_SIZE;
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ //pHdr[HIDX_AVTP_TIMESTAMP32] = 0x00; // Set later
+ pHdr[HIDX_FORMAT8] = 0x02; // RTP Payload type
+ *(U16 *)(&pHdr[HIDX_FORMAT_SUBTYPE8]) = 0x00; // MJPEG format (RFC 2435)
+ //pHdr[HIDX_STREAM_DATA_LEN16] = 0x00; // Set later
+ pHdr[HIDX_RESV16] = 0x00;
+ pHdr[HIDX_RESV16+1] = 0x00;
+ pHdr[HIDX_M11_M01_EVT2_RESV2] = 0x00;
+ pHdr[HIDX_RESV8] = 0x00;
+
+ media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
+ if (pMediaQItem) {
+ if (pMediaQItem->dataLen > 0) {
+ if (pMediaQItem->dataLen > ITEM_SIZE) {
+ AVB_LOGF_ERROR("Media queue data item size too large. Reported size: %d Max Size: %d", pMediaQItem->dataLen, ITEM_SIZE);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ openavbMediaQTailPull(pMediaQ);
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ // PTP walltime already set in the interface module. Just add the max transit time.
+ openavbAvtpTimeAddUSec(pMediaQItem->pAvtpTime, pPvtData->maxTransitUsec);
+
+ // Set timestamp valid flag
+ if (openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime)) {
+ pHdr[HIDX_AVTP_HIDE7_TV1] |= 0x01; // Set
+ }
+ else {
+ pHdr[HIDX_AVTP_HIDE7_TV1] &= ~0x01; // Clear
+ }
+
+ // Set timestamp uncertain flag
+ if (openavbAvtpTimeTimestampIsUncertain(pMediaQItem->pAvtpTime)) {
+ pHdr[HIDX_AVTP_HIDE7_TU1] |= 0x01; // Set
+ }
+ else {
+ pHdr[HIDX_AVTP_HIDE7_TU1] &= ~0x01; // Clear
+ }
+
+ // Set the timestamp.
+ // 1722a-D6: The avtp_timestamp represents the presentation time associated with the given frame. The same avtp_timestamp
+ // shall appear in each fragment of a given frame. The M0 marker bit shall be set in the last packet of a frame.
+ if (!pPvtData->tsvalid)
+ {
+ pPvtData->timestamp = openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime);
+ pPvtData->tsvalid = TRUE;
+ }
+ *(U32 *)(&pHdr[HIDX_AVTP_TIMESTAMP32]) = htonl(pPvtData->timestamp);
+
+ if (((media_q_item_map_mjpeg_pub_data_t *)pMediaQItem->pPubMapData)->lastFragment) {
+ pHdr[HIDX_M11_M01_EVT2_RESV2] = 0x00 | (1 << 4);
+ pPvtData->tsvalid = FALSE;
+ }
+ else {
+ pHdr[HIDX_M11_M01_EVT2_RESV2] = 0x00;
+ }
+
+ // Copy the JPEG fragment into the outgoing avtp packet.
+ memcpy(pPayload, pMediaQItem->pPubData, pMediaQItem->dataLen);
+
+ *(U16 *)(&pHdr[HIDX_STREAM_DATA_LEN16]) = pMediaQItem->dataLen;
+
+ // Set out bound data length (entire packet length)
+ *dataLen = pMediaQItem->dataLen + TOTAL_HEADER_SIZE;
+
+ AVB_TRACE_LINE(AVB_TRACE_MAP_LINE);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ openavbMediaQTailPull(pMediaQ);
+ return TX_CB_RET_PACKET_READY;
+ }
+ openavbMediaQTailPull(pMediaQ);
+ }
+ }
+
+ if (dataLen) {
+ // Set out bound data length (entire packet length)
+ *dataLen = 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY;
+}
+
+// A call to this callback indicates that this mapping module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbMapMjpegRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// This callback occurs when running as a listener and data is available.
+bool openavbMapMjpegRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ if (pMediaQ && pData) {
+ U8 *pHdr = pData;
+ U8 *pPayload = pData + TOTAL_HEADER_SIZE;
+
+// U16 payloadLen = ntohs(*(U16 *)(&pHdr[HIDX_STREAM_DATA_LEN16]));
+ U16 payloadLen = *(U16 *)(&pHdr[HIDX_STREAM_DATA_LEN16]);
+
+ // Get item pointer in media queue
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ // Get the timestamp and place it in the media queue item.
+ U32 timestamp = ntohl(*(U32 *)(&pHdr[HIDX_AVTP_TIMESTAMP32]));
+ openavbAvtpTimeSetToTimestamp(pMediaQItem->pAvtpTime, timestamp);
+
+ // Set timestamp valid and timestamp uncertain flags
+ openavbAvtpTimeSetTimestampValid(pMediaQItem->pAvtpTime, (pHdr[HIDX_AVTP_HIDE7_TV1] & 0x01) ? TRUE : FALSE);
+ openavbAvtpTimeSetTimestampUncertain(pMediaQItem->pAvtpTime, (pHdr[HIDX_AVTP_HIDE7_TU1] & 0x01) ? TRUE : FALSE);
+
+ if (pHdr[HIDX_M11_M01_EVT2_RESV2] & 0x10) {
+ ((media_q_item_map_mjpeg_pub_data_t *)pMediaQItem->pPubMapData)->lastFragment = TRUE;
+ }
+ else {
+ ((media_q_item_map_mjpeg_pub_data_t *)pMediaQItem->pPubMapData)->lastFragment = FALSE;
+ }
+
+ if (pMediaQItem->itemSize >= dataLen - TOTAL_HEADER_SIZE) {
+ memcpy(pMediaQItem->pPubData, pPayload, payloadLen);
+ pMediaQItem->dataLen = dataLen - TOTAL_HEADER_SIZE;
+ }
+ else {
+ AVB_LOG_ERROR("Data to large for media queue.");
+ pMediaQItem->dataLen = 0;
+ }
+
+ openavbMediaQHeadPush(pMediaQ);
+ AVB_TRACE_LINE(AVB_TRACE_MAP_LINE);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TRUE;
+ }
+ else {
+ IF_LOG_INTERVAL(1000) AVB_LOG_ERROR("Media queue full.");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE; // Media queue full
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE;
+}
+
+// This callback will be called when the mapping module needs to be closed.
+// All cleanup should occur in this function.
+void openavbMapMjpegEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+void openavbMapMjpegGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Initialization entry point into the mapping module. Will need to be included in the .ini file.
+extern DLL_EXPORT bool openavbMapMjpegInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ if (pMediaQ) {
+ pMediaQ->pMediaQDataFormat = strdup(MapMjpegMediaQDataFormat);
+ pMediaQ->pPvtMapInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pMediaQDataFormat || !pMediaQ->pPvtMapInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for mapping module.");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+
+ pMapCB->map_cfg_cb = openavbMapMjpegCfgCB;
+ pMapCB->map_subtype_cb = openavbMapMjpegSubtypeCB;
+ pMapCB->map_avtp_version_cb = openavbMapMjpegAvtpVersionCB;
+ pMapCB->map_max_data_size_cb = openavbMapMjpegMaxDataSizeCB;
+ pMapCB->map_transmit_interval_cb = openavbMapMjpegTransmitIntervalCB;
+ pMapCB->map_gen_init_cb = openavbMapMjpegGenInitCB;
+ pMapCB->map_tx_init_cb = openavbMapMjpegTxInitCB;
+ pMapCB->map_tx_cb = openavbMapMjpegTxCB;
+ pMapCB->map_rx_init_cb = openavbMapMjpegRxInitCB;
+ pMapCB->map_rx_cb = openavbMapMjpegRxCB;
+ pMapCB->map_end_cb = openavbMapMjpegEndCB;
+ pMapCB->map_gen_end_cb = openavbMapMjpegGenEndCB;
+
+ pPvtData->itemCount = 20;
+ pPvtData->txInterval = 0;
+ pPvtData->maxTransitUsec = inMaxTransitUsec;
+
+ openavbMediaQSetMaxLatency(pMediaQ, inMaxTransitUsec);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg_pub.h b/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg_pub.h
new file mode 100755
index 00000000..41cf34f0
--- /dev/null
+++ b/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg_pub.h
@@ -0,0 +1,77 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Motion JPEG mapping module public interface conforming to 1722A RTP payload encapsulation.
+*
+* Refer to RFC 2435 for details of the fragment structure.
+*
+* As defined 1722a the timestamp must be the same for each fragment of a JPEG frame. This means the interface module
+* must set this same timestamp in the media queue for each item tht is a JPEG fragment of the frame. In addition the
+* Interface module must set the lastFragment flag of the item public map data structure for each fragment placed into
+* the media queue (TRUE if not the last fragment of the frame, FALSE if it is the last fragment of a frame).
+*
+* The payload will be as defined in RFC 2435 and will include the JPEG headers as well as the JPEG data.
+*/
+
+#ifndef OPENAVB_MAP_MJPEG_PUB_H
+#define OPENAVB_MAP_MJPEG_PUB_H 1
+
+#include "openavb_types_pub.h"
+
+/** \file
+ * Motion JPEG mapping module public interface conforming to 1722A RTP payload
+ * encapsulation.
+ *
+ * As defined 1722a the timestamp must be the same for each fragment of a JPEG
+ * frame. This means the interface module must set this same timestamp in the
+ * media queue for each item tht is a JPEG fragment of the frame.
+ * In addition the Interface module must set the lastFragment flag of the item
+ * public map data structure for each fragment placed into the media queue
+ * (FALSE if not the last fragment of the frame, TRUE if it is the last
+ * fragment of a frame).
+ *
+ * The payload will be as defined in RFC 2435 and will include the JPEG header
+ * as well as the JPEG data.
+ */
+
+/** \note A define is used for the MediaQDataFormat identifier because it is
+ * needed in separate execution units (static / dynamic libraries) that is why
+ * a single static (static/extern pattern) definition can not be used.
+ */
+#define MapMjpegMediaQDataFormat "Mjpeg"
+
+/// Additional public map data structure
+typedef struct {
+ /// Is this fragment the last one of this frame.
+ bool lastFragment;
+} media_q_item_map_mjpeg_pub_data_t;
+
+#endif // OPENAVB_MAP_MJPEG_PUB_H
diff --git a/lib/avtp_pipeline/map_mpeg2ts/CMakeLists.txt b/lib/avtp_pipeline/map_mpeg2ts/CMakeLists.txt
new file mode 100644
index 00000000..98d38e47
--- /dev/null
+++ b/lib/avtp_pipeline/map_mpeg2ts/CMakeLists.txt
@@ -0,0 +1,5 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/map_mpeg2ts/openavb_map_mpeg2ts.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/map_mpeg2ts/demo_listener.ini b/lib/avtp_pipeline/map_mpeg2ts/demo_listener.ini
new file mode 100644
index 00000000..f48dbba4
--- /dev/null
+++ b/lib/avtp_pipeline/map_mpeg2ts/demo_listener.ini
@@ -0,0 +1,89 @@
+#####################################################################
+# General Listener configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = listener
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: When SRP is being used the destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set in both side the talker and listener.
+# 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.
+# At this time they need to be locally administered and must be in the range
+# of 91:E0:F0:00:FE:00 - 91:E0:F0:00:FE:FF.
+# Typically :00 for the first stream, :01 for the second, etc.
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+#max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+#sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+#max_transit_usec = 2000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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_tx_buffers = 1
+
+# 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.
+raw_rx_buffers = 50000
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_mpeg2ts.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapMpeg2tsInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+intf_lib = ./libopenavb_intf_mpeg2ts_file.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfMpeg2tsFileInitialize
+
+# Leave filename empty to use stdout
+#intf_nv_file_name = listener.ts
+
+# intf_nv_ignore_timestamp: If set the listener will ignore the timestamp on media queue items.
+# intf_nv_ignore_timestamp = 1
diff --git a/lib/avtp_pipeline/map_mpeg2ts/demo_talker.ini b/lib/avtp_pipeline/map_mpeg2ts/demo_talker.ini
new file mode 100644
index 00000000..77e6d698
--- /dev/null
+++ b/lib/avtp_pipeline/map_mpeg2ts/demo_talker.ini
@@ -0,0 +1,114 @@
+#####################################################################
+# General Talker configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = talker
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: destination multicast address for the stream.
+#
+# If using SRP and MAAP, dynamic destination addresses are generated
+# automatically by the talker and passed to the listner, and don't
+# need to be configured.
+#
+# Without MAAP, locally administered (static) addresses must be
+# configured. Thouse 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.
+#
+# When SRP is being used the static destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set (to the same value) in both the talker and listener.
+#
+# 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.
+#
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+#sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 2000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_mpeg2ts.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapMpeg2tsInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+# map_nv_tx_rate: Transmit rate
+# If not set default of the talker class will be used.
+#map_nv_tx_rate = 300
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. 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.
+intf_lib = ./libopenavb_intf_mpeg2ts_file.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfMpeg2tsFileInitialize
+
+# intf_nv_file_name: The fully qualified file name used both the talker and listener.
+#intf_nv_file_name = input.ts
+intf_nv_file_name = AMCTelematics2010.ts
+
+# intf_nv_repeat: Continually repeat the file stream when running as a talker.
+intf_nv_repeat = 1
+
+# Seconds before allowing rewind. Delays buffer overflow on RX side,
+# at least for short files
+intf_nv_repeat_seconds = 29
diff --git a/lib/avtp_pipeline/map_mpeg2ts/mpeg2ts_map.md b/lib/avtp_pipeline/map_mpeg2ts/mpeg2ts_map.md
new file mode 100644
index 00000000..266b38e4
--- /dev/null
+++ b/lib/avtp_pipeline/map_mpeg2ts/mpeg2ts_map.md
@@ -0,0 +1,38 @@
+MPEG2 TS Mapping {#mpeg2ts_map}
+================
+
+# Description
+
+Mpeg2 TS mapping module conforming to AVB 61883-4 encapsulation.
+
+Refer to IEC 61883-4 for details of the "source packet" structure.
+
+This mapping module module as a talker requires an interface module to push
+one source packet of 192 octets into the media queue along with a media queue
+time value when the first data block of the source packet was obtained.
+There is no need to place the timestamp within the source packet header,
+this will be done within the mapping module when the maximum transit time is
+added. The mapping module may bundle multiple source packets into one AVTP
+packet before sending it.
+
+This mapping module module as a listener will parse source packets from the AVTP
+packet and place each source packet of 192 octets into the media queue along
+with the correct timestamp from the source packet header. The interface module
+will pull each source packet from the media queue and present has needed.
+
+The protocol_specific_header, CIP header and the mpeg2 ts source packet header
+are all taken care of in the mapping module.
+
+<br>
+# Mapping module configuration parameters
+
+Name | Description
+--------------------|---------------------------
+map_nv_item_count |The number of Media Queue items to hold.
+map_nv_item_size |Size of data in each Media Queue item
+map_nv_ts_packet_size|Size of transport stream packets passed to/from interface\
+ module (188 or 192)
+map_nv_num_source_packets|Number of source packets to send an in AVTP frame \
+ (**Talker only**)
+map_nv_tx_rate or map_nv_tx_interval | Transmit interval in frames per second. \
+ 0 = default for talker class
diff --git a/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts.c b/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts.c
new file mode 100755
index 00000000..8b12bdb3
--- /dev/null
+++ b/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts.c
@@ -0,0 +1,734 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Mpeg2 TS mapping module conforming to AVB 61883-4 encapsulation.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_avtp_time_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_map_pub.h"
+#include "openavb_map_mpeg2ts_pub.h"
+#include "openavb_types.h"
+#include <assert.h>
+
+#define AVB_LOG_COMPONENT "MPEG2TS Mapping"
+#include "openavb_log_pub.h"
+
+// Base MPEG2 Transport Stream packet size
+#define MPEG2_TS_PKT_SIZE 188
+// MPEG2TS sync byte
+#define MPEG2_TS_SYNC_BYTE 0x47
+
+// GStreamer likes to pass 4096-byte buffers, so we want a buffer
+// bigger than that. And, we're more efficient if the interface layer
+// passes us whole TS packets, so let's use a default value that's a
+// multiple of both 188 and 192
+#define MPEG2TS_MQITEM_SIZE 9024
+#define MPEG2TS_MQITEM_COUNT 20
+
+// MPEG2TS packets with 4 byte timestamp (192 bytes) are called "source packets" in AVTP
+#define MPEGTS_SRC_PKT_HDR_SIZE 4
+#define MPEGTS_SRC_PKT_SIZE (MPEG2_TS_PKT_SIZE + MPEGTS_SRC_PKT_HDR_SIZE)
+
+// AVTP payload: we allow for 5 source packets (192 * 5) plus the CIP header (8) = 968
+// TODO: make the number of packet configurable
+#define AVTP_DFLT_SRC_PKTS 7
+
+// AVTP Header sizes
+#define AVTP_V0_HEADER_SIZE 12
+#define MAP_HEADER_SIZE 12
+#define CIP_HEADER_SIZE 8
+
+#define TOTAL_HEADER_SIZE (AVTP_V0_HEADER_SIZE + MAP_HEADER_SIZE + CIP_HEADER_SIZE)
+
+#define BLOCKS_PER_SRC_PKT 8
+#define BLOCKS_PER_AVTP_PKT (BLOCKS_PER_SRC_PKT * AVTP_NUM_SRC_PKTS)
+
+//////
+// AVTP Version 0 Header
+//////
+
+// This mapping does not directly set or read these.
+#define HIDX_AVTP_VERZERO96 0
+
+// - 1 Byte - TV bit (timestamp valid)
+#define HIDX_AVTP_HIDE7_TV1 1
+
+// - 1 Byte - TU bit (timestamp uncertain)
+#define HIDX_AVTP_HIDE7_TU1 3
+
+
+//////
+// Mapping specific header
+//////
+
+// - 4 bytes avtp_timestamp
+#define HIDX_AVTP_TIMESTAMP32 12
+
+// - 4 bytes gateway_info
+#define HIDX_GATEWAY32 16
+
+// - 2 bytes stream_data_len (save a pointer for later use)
+#define HIDX_DATALEN16 20
+
+// 2 bit tag = binary 01 (CIP header - included)
+// 6 bit channel = 31 / 0x1F (Native AVB)
+#define HIDX_TAG2_CHANNEL6 22
+
+// 4 bits tcode = 0xA
+// 4 bits sy (application-specific) = 0
+#define HIDX_TCODE4_SY4 23
+
+//////
+// CIP Header - 2 quadlets (8 bytes)
+//////
+
+// 2 bits cip flag = binary 00
+// 6 bits sid (source identifier) = 63 / 0x3F (On the AVB network)
+#define HIDX_CIP2_SID6 24
+
+// 8 bits dbs (data block size) = 6 (6 quadlets per block)
+#define HIDX_DBS8 25
+
+// 2 bits FN (fraction number) = Bx11 (8 data blocks)
+// 3 bits QPC (quadlet padding count) = Bx000
+// 1 bit SPH (source packet header) = Bx1 (using source packet headers)
+// 2 bits RSV (reserved) = Bx00
+#define HIDX_FN2_QPC3_SPH1_RSV2 26
+
+// 8 bits DBC (data block counter) = counter
+#define HIDX_DBC8 27
+
+// 2 bits cip flag (2nd quadlet) = binary 10
+// 6 bits fmt (stream format) = binary 100000 (MPEG2-TS)
+#define HIDX_CIP2_FMT6 28
+
+// 3 bytes fdf (format dependant)
+// i.e. for MPEG2-TS
+// 1 bit tsf (time shift flag) = 0
+// 23 bits reserved = 0
+#define HIDX_TSF1_RESA7 29
+#define HIDX_RESB8 30
+#define HIDX_RESC8 31
+
+#define DEFAULT_SRC_PKTS_PER_AVTP_FRAME 5
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+
+ // map_nv_item_count, map_nv_item_size
+ // number of items to allocate in MediaQ, size of data in each item
+ unsigned itemCount, itemSize;
+
+ // map_nv_ts_packet_size
+ // size of transport stream packets passed to/from interface module (188 or 192)
+ unsigned tsPacketSize;
+
+ // Talker-only config
+
+ // map_nv_num_source_packets
+ // Number of source packets to send in AVTP frame
+ unsigned numSourcePackets;
+
+ // map_nv_tx_rate
+ // Transmit rate in frames per second. 0 = default for talker class.
+ unsigned txRate;
+
+ /////////////
+ // Variable data
+ /////////////
+ unsigned maxTransitUsec; // In microseconds
+
+ // Data block continuity counter
+ U32 DBC;
+
+ // Saved partial source packet
+ char savedBytes[200];
+ int nSavedBytes;
+
+ // Is the input stream out of synch?
+ bool unsynched;
+
+ unsigned int srcBitrate;
+
+} pvt_data_t;
+
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbMapMpeg2tsCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+
+ char *pEnd;
+ unsigned long tmp;
+ bool nameOK = TRUE, valueOK = FALSE;
+
+ if (strcmp(name, "map_nv_item_count") == 0) {
+ tmp = strtoul(value, &pEnd, 10);
+ if (pEnd != value && *pEnd == '\0') {
+ pPvtData->itemCount = tmp;
+ valueOK = TRUE;
+ }
+ }
+ else if (strcmp(name, "map_nv_item_size") == 0) {
+ tmp = strtoul(value, &pEnd, 10);
+ if (pEnd != value && *pEnd == '\0') {
+ pPvtData->itemSize = tmp;
+ valueOK = TRUE;
+ }
+ }
+ else if (strcmp(name, "map_nv_ts_packet_size") == 0) {
+ tmp = strtoul(value, &pEnd, 10);
+ if (pEnd != value && *pEnd == '\0' && (tmp == 188 || tmp == 192)) {
+ pPvtData->tsPacketSize = tmp;
+ valueOK = TRUE;
+ }
+ }
+ else if (strcmp(name, "map_nv_num_source_packets") == 0) {
+ tmp = strtoul(value, &pEnd, 10);
+ if (pEnd != value && *pEnd == '\0') {
+ pPvtData->numSourcePackets = tmp;
+ valueOK = TRUE;
+ }
+ }
+ else if (strcmp(name, "map_nv_tx_rate") == 0
+ || strcmp(name, "map_nv_tx_interval") == 0) {
+ tmp = strtoul(value, &pEnd, 10);
+ if (pEnd != value && *pEnd == '\0') {
+ pPvtData->txRate = tmp;
+ valueOK = TRUE;
+ }
+ }
+ else {
+ AVB_LOGF_WARNING("Unknown configuration item: %s", name);
+ nameOK = FALSE;
+ }
+
+ if (nameOK && !valueOK) {
+ AVB_LOGF_WARNING("Bad value for configuration item: %s = %s", name, value);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+U8 openavbMapMpeg2tsSubtypeCB()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0x00; // 61883 AVB subtype
+}
+
+// Returns the AVTP version used by this mapping
+U8 openavbMapMpeg2tsAvtpVersionCB()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return 0x00; // Version 0
+}
+
+U16 openavbMapMpeg2tsMaxDataSizeCB(media_q_t *pMediaQ)
+{
+ U16 retval = 0;
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return 0;
+ }
+
+ retval = MPEGTS_SRC_PKT_SIZE * pPvtData->numSourcePackets + TOTAL_HEADER_SIZE;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return retval;
+}
+
+// Returns the intended transmit interval (in frames per second). 0 = default for talker / class.
+U32 openavbMapMpeg2tsTransmitIntervalCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return 0;
+ }
+
+ return pPvtData->txRate;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0;
+}
+
+void openavbMapMpeg2tsGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+
+ openavbMediaQSetSize(pMediaQ, pPvtData->itemCount, pPvtData->itemSize);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// A call to this callback indicates that this mapping module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbMapMpeg2tsTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+static int syncScan(media_q_item_t *pMediaQItem, int startIdx)
+{
+ char *data = pMediaQItem->pPubData;
+ int offset;
+ for (offset = startIdx; offset < pMediaQItem->dataLen; offset++) {
+ if (data[offset] == MPEG2_TS_SYNC_BYTE)
+ break;
+ }
+
+ AVB_LOGF_WARNING("Dropped %d bytes", offset - startIdx);
+ if (offset >= pMediaQItem->dataLen)
+ offset = -1;
+
+ return offset;
+}
+
+// This talker callback will be called for each AVB observation interval.
+tx_cb_ret_t openavbMapMpeg2tsTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ if (pMediaQ && pData && dataLen) {
+ U8 *pHdr = pData;
+ U8 *pPayload = pData + TOTAL_HEADER_SIZE;
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ //pHdr[HIDX_AVTP_TIMESTAMP32] = 0x00; // Set later
+ *(U32 *)(&pHdr[HIDX_GATEWAY32]) = 0x00000000;
+ //pHdr[HIDX_DATALEN16] = 0x00; // Set Later
+ pHdr[HIDX_TAG2_CHANNEL6] = (1 << 6) | 0x1f;
+ pHdr[HIDX_TCODE4_SY4] = (0x0a << 4) | 0;
+
+ // Set the majority of the CIP header now.
+ pHdr[HIDX_CIP2_SID6] = (0x00 << 6) | 0x3f;
+ pHdr[HIDX_DBS8] = 0x06;
+ pHdr[HIDX_FN2_QPC3_SPH1_RSV2] = (0x03 << 6) | (0x00 << 3) | (0x01 << 2) | 0x00;
+ // pHdr[HIDX_DBC8] = 0; // This will be set later.
+ pHdr[HIDX_CIP2_FMT6] = (0x02 << 6) | 0xa0;
+ pHdr[HIDX_TSF1_RESA7] = (0x01 << 7) | 0x00;
+ pHdr[HIDX_RESB8] = 0x00;
+ pHdr[HIDX_RESC8] = 0x00;
+
+ media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
+ int sourcePacketsAdded = 0;
+ int nItemBytes, nAvailBytes;
+ int offset, bytesNeeded;
+ U32 timestamp;
+ bool moreSourcePackets = TRUE;
+
+ while (pMediaQItem && moreSourcePackets) {
+
+ if (pPvtData->unsynched) {
+ // Scan forward, looking for next sync byte.
+ offset = syncScan(pMediaQItem, 0);
+ if (offset >= 0)
+ pMediaQItem->readIdx = offset;
+ else {
+ pPvtData->unsynched = TRUE;
+ pMediaQItem->dataLen = 0;
+ pMediaQItem->readIdx = 0;
+ }
+ }
+
+ nItemBytes = pMediaQItem->dataLen - pMediaQItem->readIdx;
+ nAvailBytes = nItemBytes + pPvtData->nSavedBytes;
+
+ if (nItemBytes == 0) {
+ // Empty MQ item, ignore
+ }
+ else if (nAvailBytes >= pPvtData->tsPacketSize) {
+ // PTP walltime already set in the interface module. Just add the max transit time.
+ // If this is a new mq item, add the AVTP transit time to the timestamp
+ if (pMediaQItem->readIdx == 0) {
+ openavbAvtpTimeAddUSec(pMediaQItem->pAvtpTime, pPvtData->maxTransitUsec);
+ }
+
+ timestamp = openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime);
+
+ // Set timestamp valid flag
+ if (openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime))
+ pHdr[HIDX_AVTP_HIDE7_TV1] |= 0x01; // Set
+ else {
+ pHdr[HIDX_AVTP_HIDE7_TV1] &= ~0x01; // Clear
+ }
+
+ // Set timestamp uncertain flag
+ if (openavbAvtpTimeTimestampIsUncertain(pMediaQItem->pAvtpTime))
+ pHdr[HIDX_AVTP_HIDE7_TU1] |= 0x01; // Set
+ else pHdr[HIDX_AVTP_HIDE7_TU1] &= ~0x01; // Clear
+
+ // Set the timestamp.
+ if (sourcePacketsAdded == 0) {
+ // TODO: I think this is wrong with source packets
+ *(U32 *)(&pHdr[HIDX_AVTP_TIMESTAMP32]) = htonl(timestamp);
+ }
+
+ /* Copy the TS packets into the outgoing AVTP frame
+ */
+ offset = 0, bytesNeeded = pPvtData->tsPacketSize;
+
+ // If getting 188-byte packets from interface, need to add source packet header
+ if (pPvtData->tsPacketSize == MPEG2_TS_PKT_SIZE) {
+ // Set the timestamp on this source packet
+ *((U32 *)pPayload) = htonl(timestamp);
+ offset = MPEGTS_SRC_PKT_HDR_SIZE;
+ }
+
+ // Use any leftover data from last MQ item
+ if (pPvtData->nSavedBytes) {
+ memcpy(pPayload + offset, pPvtData->savedBytes, pPvtData->nSavedBytes);
+ offset += pPvtData->nSavedBytes;
+ bytesNeeded -= pPvtData->nSavedBytes;
+ pPvtData->nSavedBytes = 0;
+ }
+
+ // Now, copy data from current MQ item
+ memcpy(pPayload + offset, pMediaQItem->pPubData + pMediaQItem->readIdx, bytesNeeded);
+
+ // Check that the data we've copied is synchronized
+ /// i.e. that the transport stream packet starts
+ // where we think it should
+ if (pPayload[4] == MPEG2_TS_SYNC_BYTE) {
+ // OK, now we can update the read index
+ pMediaQItem->readIdx += bytesNeeded;
+ // and move the payload ptr for the next source packet
+ pPayload += MPEGTS_SRC_PKT_SIZE;
+
+ // Keep track of how many source packets have been added to the outgoing packet
+ sourcePacketsAdded++;
+ }
+ else {
+ AVB_LOG_WARNING("Alignment problem");
+
+ // Scan forward, looking for next sync byte.
+ // Start scan after 4-byte header if getting 192 byte packets.
+ // Ignore saved data if there was any, start from what's in current item.
+ offset = syncScan(pMediaQItem, pMediaQItem->readIdx + (pPvtData->tsPacketSize - MPEG2_TS_PKT_SIZE) + 1);
+ if (offset >= 0)
+ pMediaQItem->readIdx = offset;
+ else {
+ pPvtData->unsynched = TRUE;
+ pMediaQItem->dataLen = 0;
+ pMediaQItem->readIdx = 0;
+ }
+ }
+ }
+ else {
+ // Arghhh - a partial packet.
+ assert(pPvtData->nSavedBytes + nItemBytes <= MPEG2_TS_PKT_SIZE);
+
+ memcpy(pPvtData->savedBytes + pPvtData->nSavedBytes,
+ pMediaQItem->pPubData + pMediaQItem->readIdx,
+ nItemBytes);
+ pPvtData->nSavedBytes += nItemBytes;
+
+ pMediaQItem->dataLen = 0;
+ pMediaQItem->readIdx = 0;
+ }
+
+ // Have we reached our target?
+ if (sourcePacketsAdded >= pPvtData->numSourcePackets)
+ moreSourcePackets = FALSE;
+
+ // Have we used up the data in the MQ item?
+ if (pMediaQItem->dataLen - pMediaQItem->readIdx == 0) {
+ // release used-up item
+ openavbMediaQTailPull(pMediaQ);
+
+ // and get a new one, if needed
+ if (moreSourcePackets)
+ pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
+ else pMediaQItem = NULL;
+ }
+
+ } // while (pMediaQItem && moreSourcePackets)
+
+ if (pMediaQItem) {
+ // holds more data, leave it in the queue
+ openavbMediaQTailUnlock(pMediaQ);
+ }
+
+ if (sourcePacketsAdded > 0) {
+
+ // Set the block continuity and data length
+ pHdr[HIDX_DBC8] = pPvtData->DBC;
+ pPvtData->DBC = (pPvtData->DBC + (sourcePacketsAdded * BLOCKS_PER_SRC_PKT)) & 0x000000ff;
+
+ U16 datalen = (sourcePacketsAdded * MPEGTS_SRC_PKT_SIZE) + CIP_HEADER_SIZE;
+ *(U16 *)(pHdr + HIDX_DATALEN16) = htons(datalen);
+
+ // Set out bound data length (entire packet length)
+ *dataLen = (sourcePacketsAdded * MPEGTS_SRC_PKT_SIZE) + TOTAL_HEADER_SIZE;
+
+ AVB_TRACE_LINE(AVB_TRACE_MAP_LINE);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_READY;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY;
+}
+
+// A call to this callback indicates that this mapping module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbMapMpeg2tsRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// This callback occurs when running as a listener and data is available.
+bool openavbMapMpeg2tsRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ if (pMediaQ && pData) {
+ U8 *pHdr = pData;
+ U8 *pPayload = pData + TOTAL_HEADER_SIZE;
+ U8 sourcePacketCount = 0;
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return FALSE;
+ }
+
+ //pHdr[HIDX_AVTP_TIMESTAMP32];
+ //pHdr[HIDX_GATEWAY32];
+ //pHdr[HIDX_DATALEN16];
+
+ //pHdr[HIDX_TAG2_CHANNEL6];
+ //pHdr[HIDX_TCODE4_SY4];
+ //pHdr[HIDX_CIP2_SID6];
+ //pHdr[HIDX_DBS8];
+ //pHdr[HIDX_FN2_QPC3_SPH1_RSV2];
+
+ // Only support full source packets.
+ // TODO: This mapper could be enhanced to support partial source packets and assemble the datablocks
+ // recieved across multiple avtp packets.
+ if ((pHdr[HIDX_DBC8] % 8) > 0) {
+ AVB_LOG_ERROR("Unsupported MPEG2TS block count received, payload discarded.");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE;
+ }
+
+ // TODO: validate DBC
+
+ // Determine the number of source packets bundled into the AVTP payload.
+ U16 datalen = ntohs(*(U16 *)(pHdr + HIDX_DATALEN16));
+ sourcePacketCount = (datalen - CIP_HEADER_SIZE) / MPEGTS_SRC_PKT_SIZE;
+
+ //pHdr[HIDX_CIP2_FMT6];
+ //pHdr[HIDX_TSF1_RESA7];
+ //pHdr[HIDX_RESB8];
+ //pHdr[HIDX_RESC8];
+
+ if (sourcePacketCount > 0) {
+ // Get item in media queue
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ if (pMediaQItem->dataLen == 0) {
+ // Get the timestamp and place it in the media queue item.
+ U32 timestamp = ntohl(*(U32 *)(&pHdr[HIDX_AVTP_TIMESTAMP32]));
+ openavbAvtpTimeSetToTimestamp(pMediaQItem->pAvtpTime, timestamp);
+
+ // Set timestamp valid and timestamp uncertain flags
+ openavbAvtpTimeSetTimestampValid(pMediaQItem->pAvtpTime, (pHdr[HIDX_AVTP_HIDE7_TV1] & 0x01) ? TRUE : FALSE);
+ openavbAvtpTimeSetTimestampUncertain(pMediaQItem->pAvtpTime, (pHdr[HIDX_AVTP_HIDE7_TU1] & 0x01) ? TRUE : FALSE);
+ }
+
+ int i;
+ for (i = 0; i < sourcePacketCount; i++) {
+ if (pMediaQItem->itemSize - pMediaQItem->dataLen >= pPvtData->tsPacketSize) {
+ memcpy(pMediaQItem->pPubData + pMediaQItem->dataLen,
+ pPayload + MPEGTS_SRC_PKT_SIZE - pPvtData->tsPacketSize,
+ pPvtData->tsPacketSize);
+ pMediaQItem->dataLen += pPvtData->tsPacketSize;
+ pPayload += MPEGTS_SRC_PKT_SIZE;
+ }
+ else {
+ AVB_LOG_ERROR("Data too large for media queue");
+ pMediaQItem->dataLen = 0;
+ break;
+ }
+ }
+
+ // TODO: try to pack more data into MQ item?
+ openavbMediaQHeadPush(pMediaQ);
+ }
+ else {
+ // Media queue full, data dropped
+ IF_LOG_INTERVAL(1000) AVB_LOG_ERROR("Media queue full");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE;
+ }
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE;
+}
+
+// This callback will be called when the mapping module needs to be closed.
+// All cleanup should occur in this function.
+void openavbMapMpeg2tsEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+void openavbMapMpeg2tsGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbMapMpeg2tsSetSrcBitrateCB(media_q_t *pMediaQ, unsigned int bitrate)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ ((pvt_data_t*)pMediaQ->pPvtMapInfo)->srcBitrate = (unsigned int)((double)bitrate * ((double)MPEGTS_SRC_PKT_SIZE)/((double)MPEG2_TS_PKT_SIZE));
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+unsigned int calculateBitrate(const int intervalsPerSecond, const int num_source_packets, const int number_of_frames)
+{
+ unsigned int bitrate = intervalsPerSecond * num_source_packets * number_of_frames * (MPEGTS_SRC_PKT_SIZE) * 8;
+ return bitrate;
+}
+
+unsigned int openavbMapMpeg2tsGetMaxIntervalFramesCB(media_q_t *pMediaQ, SRClassIdx_t sr_class)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ unsigned int interval_frames = 1;
+ unsigned int classRate = 0;
+ switch (sr_class) {
+ case SR_CLASS_A:
+ classRate = 8000;
+ break;
+ case SR_CLASS_B:
+ classRate = 4000;
+ break;
+ case MAX_AVB_SR_CLASSES: // Case included to avoid warning on some toolchains
+ break;
+ }
+
+ ((pvt_data_t*)pMediaQ->pPvtMapInfo)->numSourcePackets = 1;
+ while (calculateBitrate(classRate,((pvt_data_t*)pMediaQ->pPvtMapInfo)->numSourcePackets,interval_frames) < ((pvt_data_t*)pMediaQ->pPvtMapInfo)->srcBitrate)
+ {
+ ++((pvt_data_t*)pMediaQ->pPvtMapInfo)->numSourcePackets;
+ if (((pvt_data_t*)pMediaQ->pPvtMapInfo)->numSourcePackets > 7)
+ {
+ ((pvt_data_t*)pMediaQ->pPvtMapInfo)->numSourcePackets = 1;
+ ++interval_frames;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return interval_frames;
+}
+
+// Initialization entry point into the mapping module. Will need to be included in the .ini file.
+extern DLL_EXPORT bool openavbMapMpeg2tsInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ if (pMediaQ) {
+ pMediaQ->pMediaQDataFormat = strdup(MapMpeg2tsMediaQDataFormat);
+ pMediaQ->pPvtMapInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pMediaQDataFormat || !pMediaQ->pPvtMapInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for mapping module.");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+
+ pMapCB->map_cfg_cb = openavbMapMpeg2tsCfgCB;
+ pMapCB->map_subtype_cb = openavbMapMpeg2tsSubtypeCB;
+ pMapCB->map_avtp_version_cb = openavbMapMpeg2tsAvtpVersionCB;
+ pMapCB->map_max_data_size_cb = openavbMapMpeg2tsMaxDataSizeCB;
+ pMapCB->map_transmit_interval_cb = openavbMapMpeg2tsTransmitIntervalCB;
+ pMapCB->map_gen_init_cb = openavbMapMpeg2tsGenInitCB;
+ pMapCB->map_tx_init_cb = openavbMapMpeg2tsTxInitCB;
+ pMapCB->map_tx_cb = openavbMapMpeg2tsTxCB;
+ pMapCB->map_rx_init_cb = openavbMapMpeg2tsRxInitCB;
+ pMapCB->map_rx_cb = openavbMapMpeg2tsRxCB;
+ pMapCB->map_end_cb = openavbMapMpeg2tsEndCB;
+ pMapCB->map_gen_end_cb = openavbMapMpeg2tsGenEndCB;
+ pMapCB->map_set_src_bitrate_cb = openavbMapMpeg2tsSetSrcBitrateCB;
+ pMapCB->map_get_max_interval_frames_cb = openavbMapMpeg2tsGetMaxIntervalFramesCB;
+
+ pPvtData->tsPacketSize = MPEG2_TS_PKT_SIZE;
+ pPvtData->numSourcePackets = AVTP_DFLT_SRC_PKTS;
+ pPvtData->itemCount = MPEG2TS_MQITEM_COUNT;
+ pPvtData->itemSize = MPEG2TS_MQITEM_SIZE;
+ pPvtData->txRate = 0;
+ pPvtData->maxTransitUsec = inMaxTransitUsec;
+ pPvtData->DBC = 0;
+
+ openavbMediaQSetMaxLatency(pMediaQ, inMaxTransitUsec);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts_pub.h b/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts_pub.h
new file mode 100755
index 00000000..7f4257dd
--- /dev/null
+++ b/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts_pub.h
@@ -0,0 +1,62 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Mpeg2 TS mapping module public interface
+*
+* Refer to IEC 61883-4 for details of the "source packet" structure.
+*
+* This mapping module module as a talker requires an interface module to push
+* one source packet of 192 octets into the media queue along with a media queue
+* time value when the first data block of the source packet was obtained.
+* There is no need to place the timestamp witin the source packet header,
+* this will be done within the mapping module were the max transit time will be
+* added. The mapping module may bundle multiple source packets into one avtp packet
+* before sending it.
+*
+* This mapping module module as a listener will parse source packets from the
+* avtp packet and place each source packet of 192 octets into the media queue along
+* with the correct time stamp from the source packet header. The interface module
+* will pull each source packet from the media queue and present has needed.
+*
+* The protocol_specific_header, CIP header and the mpeg2 ts source packet header are
+* all taken care of in the mapping module.
+*/
+
+#ifndef OPENAVB_MAP_MPEG2TS_PUB_H
+#define OPENAVB_MAP_MPEG2TS_PUB_H 1
+
+#include "openavb_types_pub.h"
+
+// NOTE: A define is used for the MediaQDataFormat identifier because it is needed in separate execution units (static / dynamic libraries)
+// that is why a single static (static/extern pattern) definition can not be used.
+#define MapMpeg2tsMediaQDataFormat "Mpeg2ts"
+
+#endif // OPENAVB_MAP_MPEG2TS_PUB_H
diff --git a/lib/avtp_pipeline/map_mpeg2ts/ts_packet_size.c b/lib/avtp_pipeline/map_mpeg2ts/ts_packet_size.c
new file mode 100644
index 00000000..a9b30998
--- /dev/null
+++ b/lib/avtp_pipeline/map_mpeg2ts/ts_packet_size.c
@@ -0,0 +1,117 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : stand-alone program to detect packet size in file
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+#define BASE_TS_PACKET_SIZE 188
+#define SYNC_BYTE 0x47
+
+#define SCAN_COUNT 300
+#define CHECK_COUNT 30
+
+int find_first(FILE* pFile)
+{
+ int i; char b;
+ assert(pFile);
+
+ // scan forward to first sync byte
+ for (i = 0; i < SCAN_COUNT; i++) {
+ b = fgetc(pFile);
+ if (b == SYNC_BYTE) {
+ fprintf(stderr, "first sync byte at position %d\n", i);
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+// Check if packet size is SIZE by looking for the first N sync bytes
+int check_size(FILE* pFile, int size, int first)
+{
+ int i; char b;
+ assert(pFile);
+ assert(size >= BASE_TS_PACKET_SIZE);
+ assert(first >= 0);
+
+ for (i = 0; i < CHECK_COUNT; i++) {
+ fseek(pFile, first + i * size, 0);
+ b = fgetc(pFile);
+ if (b != SYNC_BYTE)
+ return 0;
+ }
+
+ fprintf(stderr, "transport packet size is %d\n", size);
+ return size;
+}
+
+int
+main(int argc, char *argv[])
+{
+ FILE *pFile = NULL;
+
+ if (argc == 1) {
+ pFile = stdin;
+ }
+ else if (argc == 2) {
+ pFile = fopen(argv[1], "rb");
+ if (!pFile) {
+ fprintf(stderr, "could not open input file: %s\n", argv[1]);
+ exit(-2);
+ }
+ }
+ else {
+ fprintf(stderr, "error: usage is:\n\t%s [filename]\n", argv[0]);
+ exit(-1);
+ }
+
+ int first = find_first(pFile);
+ if (first < 0) {
+ fprintf(stderr, "could not find first sync byte\n");
+ }
+ else {
+ if (check_size(pFile, 188, first))
+ ;
+ else if (check_size(pFile, 192, first))
+ ;
+ else
+ fprintf(stderr, "could not determine packet size of the input file\n");
+ }
+
+ fclose(pFile);
+ pFile = NULL;
+ exit(0);
+}
diff --git a/lib/avtp_pipeline/map_null/CMakeLists.txt b/lib/avtp_pipeline/map_null/CMakeLists.txt
new file mode 100644
index 00000000..ce67f4bd
--- /dev/null
+++ b/lib/avtp_pipeline/map_null/CMakeLists.txt
@@ -0,0 +1,5 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/map_null/openavb_map_null.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/map_null/null_map.md b/lib/avtp_pipeline/map_null/null_map.md
new file mode 100644
index 00000000..33fb069a
--- /dev/null
+++ b/lib/avtp_pipeline/map_null/null_map.md
@@ -0,0 +1,17 @@
+NULL Mapping {#null_map}
+============
+
+# Description
+
+This NULL mapping does not pack or unpack any Mmedia Queue data in AVB packer.
+It does however exercise the various functions and callback and can be
+used as an example or a template for new mapping modules.
+
+<br>
+# Mapping module configuration parameters
+
+Name | Description
+--------------------|---------------------------
+map_nv_item_count |The number of media queue elements to hold.
+map_nv_tx_rate |Transmit interval in frames per second. \
+ 0 = default for talker class
diff --git a/lib/avtp_pipeline/map_null/openavb_map_null.c b/lib/avtp_pipeline/map_null/openavb_map_null.c
new file mode 100755
index 00000000..7dd24556
--- /dev/null
+++ b/lib/avtp_pipeline/map_null/openavb_map_null.c
@@ -0,0 +1,386 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : NULL mapping module.
+*
+* This NULL mapping does not pack or unpack any media data in AVB packer.
+* It does however exercise the various functions and callback and can be
+* used as an example or a template for new mapping modules.
+*
+*----------------------------------------------------------------*
+*
+* HEADERS
+*
+* -+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-
+* |C| |S| |M| |G|T| | |T|
+* |D|subtype |V|vers |R|R|V|V|sequence number|reserved |U|
+* --+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+--
+* | |
+* | |
+* - -
+* | |
+* |stream id |
+* --+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+--
+* | |
+* |AVTP timestamp |
+* --+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+--
+* | | |
+* |OPENAVB format |OPENAVB reserved |
+* --+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+--
+* | |
+* |OPENAVB format specific |
+* -+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-
+*
+* CD : Standard AVTP
+* Subtype : Vendor specific 0x6f (Introduced in 1722A(D)
+* SV : Standard AVTP
+* Ver` : Standard AVTP
+* MR : Standard AVTP
+* R : Standard AVTP
+* GV : Standard AVTP
+* TV : Standard AVTP
+* Sequence number : Standard AVTP
+* Reserved : Standard AVTP
+* TU : Standard AVTP
+* Stream ID : Standard AVTP
+* AVTP timestamp : Standard AVTP
+* OPENAVB format : Null Mapping 0x00
+* OPENAVB reserved :
+* OPENAVB format spec. }
+*
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_avtp_time_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_map_pub.h"
+#include "openavb_map_null_pub.h"
+
+#define AVB_LOG_COMPONENT "Null Mapping"
+#include "openavb_log_pub.h"
+
+#define AVTP_V0_HEADER_SIZE 12
+#define MAP_HEADER_SIZE 12
+
+#define TOTAL_HEADER_SIZE (AVTP_V0_HEADER_SIZE + MAP_HEADER_SIZE)
+
+#define MAX_PAYLOAD_SIZE 14
+#define MAX_DATA_SIZE (MAX_PAYLOAD_SIZE + TOTAL_HEADER_SIZE)
+
+#define ITEM_SIZE MAX_DATA_SIZE
+
+
+//////
+// AVTP Version 0 Header
+//////
+
+// This mapping does not directly set or read these.
+#define HIDX_AVTP_VERZERO96 0
+
+// - 1 Byte - TV bit (timestamp valid)
+#define HIDX_AVTP_HIDE7_TV1 1
+
+// - 1 Byte - TU bit (timestamp uncertain)
+#define HIDX_AVTP_HIDE7_TU1 3
+
+//////
+// Mapping specific header
+//////
+
+// - 4 bytes avtp_timestamp
+#define HIDX_AVTP_TIMESPAMP32 12
+
+// - 1 byte OPENAVB format
+#define HIDX_OPENAVB_FORMAT8 16
+
+// - 3 bytes OPENAVB reserved
+#define HIDX_OPENAVB_RESERVEDA8 17
+#define HIDX_OPENAVB_RESERVEDB8 18
+#define HIDX_OPENAVB_RESERVEDC8 19
+
+// - 4 bytes OPENAVB format specific
+#define HIDX_OPENAVB_FORMAT_SPEC32 20
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ // map_nv_item_count
+ U32 itemCount;
+
+ // Transmit interval in frames per second. 0 = default for talker class.
+ U32 txInterval;
+
+ /////////////
+ // Variable data
+ /////////////
+ U32 maxTransitUsec; // In microseconds
+
+} pvt_data_t;
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbMapNullCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+
+ if (strcmp(name, "map_nv_item_count") == 0) {
+ char *pEnd;
+ pPvtData->itemCount = strtol(value, &pEnd, 10);
+ }
+ else if (strcmp(name, "map_nv_tx_rate") == 0
+ || strcmp(name, "map_nv_tx_interval") == 0) {
+ char *pEnd;
+ pPvtData->txInterval = strtol(value, &pEnd, 10);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// Returns the AVB subtype for this mapping
+U8 openavbMapNullSubtypeCB()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0x7F; // Experimental AVB subtype
+}
+
+// Returns the AVTP version used by this mapping
+U8 openavbMapNullAvtpVersionCB()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return 0x00; // Version 0
+}
+
+// Returns the max data size
+U16 openavbMapNullMaxDataSizeCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return MAX_DATA_SIZE;
+}
+
+// Returns the intended transmit interval (in frames per second). 0 = default for talker / class.
+U32 openavbMapNullTransmitIntervalCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return pPvtData->txInterval;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0;
+}
+
+void openavbMapNullGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+
+ openavbMediaQSetSize(pMediaQ, pPvtData->itemCount, ITEM_SIZE);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// A call to this callback indicates that this mapping module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbMapNullTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// This talker callback will be called for each AVB observation interval.
+tx_cb_ret_t openavbMapNullTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ if (pMediaQ && pData && dataLen) {
+ U8 *pHdr = pData;
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
+ if (pMediaQItem) {
+ // PTP walltime already set in the interface module. Just add the max transit time.
+ openavbAvtpTimeAddUSec(pMediaQItem->pAvtpTime, pPvtData->maxTransitUsec);
+
+ // Set timestamp valid flag
+ if (openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime))
+ pHdr[HIDX_AVTP_HIDE7_TV1] |= 0x01; // Set
+ else {
+ pHdr[HIDX_AVTP_HIDE7_TV1] &= ~0x01; // Clear
+ }
+
+ // Set timestamp uncertain flag
+ if (openavbAvtpTimeTimestampIsUncertain(pMediaQItem->pAvtpTime))
+ pHdr[HIDX_AVTP_HIDE7_TU1] |= 0x01; // Set
+ else pHdr[HIDX_AVTP_HIDE7_TU1] &= ~0x01; // Clear
+
+ *(U32 *)(&pHdr[HIDX_AVTP_TIMESPAMP32]) = htonl(openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime));
+ pHdr[HIDX_OPENAVB_FORMAT8] = MAP_NULL_OPENAVB_FORMAT;
+ pHdr[HIDX_OPENAVB_RESERVEDA8] = 0x00;
+ pHdr[HIDX_OPENAVB_RESERVEDB8] = 0x00;
+ pHdr[HIDX_OPENAVB_RESERVEDC8] = 0x00;
+ *(U32 *)(&pHdr[HIDX_OPENAVB_FORMAT_SPEC32]) = 0x00000000;
+
+ *dataLen = TOTAL_HEADER_SIZE; // No data
+ openavbMediaQTailPull(pMediaQ);
+ AVB_TRACE_LINE(AVB_TRACE_MAP_LINE);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_READY;
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY; // Media queue empty
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY;
+}
+
+// A call to this callback indicates that this mapping module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbMapNullRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// This callback occurs when running as a listener and data is available.
+bool openavbMapNullRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ if (pMediaQ && pData) {
+ U8 *pHdr = pData;
+
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ // Get the timestamp and place it in the media queue item.
+ U32 timestamp = ntohl(*(U32 *)(&pHdr[HIDX_AVTP_TIMESPAMP32]));
+ openavbAvtpTimeSetToTimestamp(pMediaQItem->pAvtpTime, timestamp);
+
+ // Set timestamp valid and timestamp uncertain flags
+ openavbAvtpTimeSetTimestampValid(pMediaQItem->pAvtpTime, (pHdr[HIDX_AVTP_HIDE7_TV1] & 0x01) ? TRUE : FALSE);
+ openavbAvtpTimeSetTimestampUncertain(pMediaQItem->pAvtpTime, (pHdr[HIDX_AVTP_HIDE7_TU1] & 0x01) ? TRUE : FALSE);
+
+ pMediaQItem->dataLen = 0; // Regardless of what is sent nullify the data to the interface.
+ openavbMediaQHeadPush(pMediaQ);
+ AVB_TRACE_LINE(AVB_TRACE_MAP_LINE);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TRUE;
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE; // Media queue full
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE;
+}
+
+// This callback will be called when the mapping module needs to be closed.
+// All cleanup should occur in this function.
+void openavbMapNullEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+void openavbMapNullGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Initialization entry point into the mapping module. Will need to be included in the .ini file.
+extern DLL_EXPORT bool openavbMapNullInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ if (pMediaQ) {
+ pMediaQ->pMediaQDataFormat = strdup(MapNullMediaQDataFormat);
+ pMediaQ->pPvtMapInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pMediaQDataFormat || !pMediaQ->pPvtMapInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for mapping module.");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+
+ pMapCB->map_cfg_cb = openavbMapNullCfgCB;
+ pMapCB->map_subtype_cb = openavbMapNullSubtypeCB;
+ pMapCB->map_avtp_version_cb = openavbMapNullAvtpVersionCB;
+ pMapCB->map_max_data_size_cb = openavbMapNullMaxDataSizeCB;
+ pMapCB->map_transmit_interval_cb = openavbMapNullTransmitIntervalCB;
+ pMapCB->map_gen_init_cb = openavbMapNullGenInitCB;
+ pMapCB->map_tx_init_cb = openavbMapNullTxInitCB;
+ pMapCB->map_tx_cb = openavbMapNullTxCB;
+ pMapCB->map_rx_init_cb = openavbMapNullRxInitCB;
+ pMapCB->map_rx_cb = openavbMapNullRxCB;
+ pMapCB->map_end_cb = openavbMapNullEndCB;
+ pMapCB->map_gen_end_cb = openavbMapNullGenEndCB;
+
+ pPvtData->itemCount = 20;
+ pPvtData->txInterval = 0;
+ pPvtData->maxTransitUsec = inMaxTransitUsec;
+
+ openavbMediaQSetMaxLatency(pMediaQ, inMaxTransitUsec);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/map_null/openavb_map_null_pub.h b/lib/avtp_pipeline/map_null/openavb_map_null_pub.h
new file mode 100755
index 00000000..7fb086c6
--- /dev/null
+++ b/lib/avtp_pipeline/map_null/openavb_map_null_pub.h
@@ -0,0 +1,44 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : NULL mapping module public interface
+*/
+
+#ifndef OPENAVB_MAP_NULL_PUB_H
+#define OPENAVB_MAP_NULL_PUB_H 1
+
+#include "openavb_types_pub.h"
+
+// NOTE: A define is used for the MediaQDataFormat identifier because it is needed in separate execution units (static / dynamic libraries)
+// that is why a single static (static/extern pattern) definition can not be used.
+#define MapNullMediaQDataFormat "Null"
+
+#endif // OPENAVB_MAP_NULL_PUB_H
diff --git a/lib/avtp_pipeline/map_pipe/CMakeLists.txt b/lib/avtp_pipeline/map_pipe/CMakeLists.txt
new file mode 100644
index 00000000..1216a087
--- /dev/null
+++ b/lib/avtp_pipeline/map_pipe/CMakeLists.txt
@@ -0,0 +1,5 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/map_pipe/openavb_map_pipe.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/map_pipe/openavb_map_pipe.c b/lib/avtp_pipeline/map_pipe/openavb_map_pipe.c
new file mode 100755
index 00000000..016bb8d4
--- /dev/null
+++ b/lib/avtp_pipeline/map_pipe/openavb_map_pipe.c
@@ -0,0 +1,488 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Pipe mapping module.
+*
+* The Pipe mapping is an AVB "experimental" mapping format. It will
+* pass throught any data from interface modules unchanged.
+* This can be useful for development, testing or custom solutions.
+*
+*----------------------------------------------------------------*
+*
+* HEADERS
+*
+* -+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-
+* |C| |S| |M| |G|T| | |T|
+* |D|subtype |V|vers |R|R|V|V|sequence number|reserved |U|
+* --+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+--
+* | |
+* | |
+* - -
+* | |
+* |stream id |
+* --+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+--
+* | |
+* |AVTP timestamp |
+* --+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+--
+* | | | |
+* | Vendor_eui_1 |
+* --+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+--
+* | |
+* | Data Length | Vendor_eui_2 |
+* -+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-
+*
+* CD : Standard AVTP
+* Subtype : Vendor specific 0x6f (Introduced in 1722A(D)
+* SV : Standard AVTP
+* Ver` : Standard AVTP
+* MR : Standard AVTP
+* R : Standard AVTP
+* GV : Standard AVTP
+* TV : Standard AVTP
+* Sequence number : Standard AVTP
+* Reserved : Standard AVTP
+* TU : Standard AVTP
+* Stream ID : Standard AVTP
+* AVTP timestamp : Standard AVTP
+* Vendor_eui_1 : Vendor specific (includes OPENAVB format : Pipe Mapping 0x01)
+* Data Length : Length of the data payload
+* Vendor_eui_2 : Vendor specific
+*
+*/
+
+#include "openavb_platform_pub.h"
+#include <stdlib.h>
+#include <string.h>
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_avtp_time_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_map_pub.h"
+#include "openavb_map_pipe_pub.h"
+
+#define AVB_LOG_COMPONENT "Pipe Mapping"
+#include "openavb_log_pub.h"
+
+#define AVTP_V0_HEADER_SIZE 12
+#define MAP_HEADER_SIZE 12
+
+#define TOTAL_HEADER_SIZE (AVTP_V0_HEADER_SIZE + MAP_HEADER_SIZE)
+
+//////
+// AVTP Version 0 Header
+//////
+
+#define HIDX_AVTP_VERZERO96 0
+
+// - 1 Byte - TV bit (timestamp valid)
+#define HIDX_AVTP_HIDE7_TV1 1
+
+// - 1 Byte - TU bit (timestamp uncertain)
+#define HIDX_AVTP_HIDE7_TU1 3
+
+// - 4 bytes avtp_timestamp
+#define HIDX_AVTP_TIMESPAMP32 12
+
+// - 2 bytes stream_data_len
+#define HIDX_AVTP_DATALEN16 20
+
+//////
+// Mapping specific header
+//////
+
+// - 1 byte OPENAVB format
+#define HIDX_OPENAVB_FORMAT8 16
+
+// - 2 bytes vendor specific
+#define HIDX_VENDOR2_EUI16 22
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ // map_nv_item_count
+ U32 itemCount;
+
+ // Transmit interval in frames per second. 0 = default for talker class.
+ U32 txInterval;
+
+ // map_nv_push_header
+ bool push_header;
+
+ // map_nv_pull_header
+ bool pull_header;
+
+
+ /////////////
+ // Variable data
+ /////////////
+ // Max payload size
+ U32 maxPayloadSize;
+
+ // Maximum data size
+ U32 maxDataSize;
+
+ // Maximum media queue item size
+ U32 itemSize;
+
+ // Maximum transit time
+ U32 maxTransitUsec; // In microseconds
+
+} pvt_data_t;
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbMapPipeCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+
+ if (strcmp(name, "map_nv_item_count") == 0) {
+ char *pEnd;
+ pPvtData->itemCount = strtol(value, &pEnd, 10);
+ }
+ else if (strcmp(name, "map_nv_tx_rate") == 0
+ || strcmp(name, "map_nv_tx_interval") == 0) {
+ char *pEnd;
+ pPvtData->txInterval = strtol(value, &pEnd, 10);
+ }
+ else if (strcmp(name, "map_nv_max_payload_size") == 0) {
+ char *pEnd;
+ pPvtData->maxPayloadSize = strtol(value, &pEnd, 10);
+ pPvtData->maxDataSize = (pPvtData->maxPayloadSize + TOTAL_HEADER_SIZE);
+ pPvtData->itemSize = pPvtData->maxDataSize;
+ }
+ else if (strcmp(name, "map_nv_push_header") == 0) {
+ char *pEnd;
+ long tmp;
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1) {
+ pPvtData->push_header = (tmp == 1);
+ }
+ }
+ else if (strcmp(name, "map_nv_pull_header") == 0) {
+ char *pEnd;
+ long tmp;
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1) {
+ pPvtData->pull_header = (tmp == 1);
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+U8 openavbMapPipeSubtypeCB()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0x6F; // Vendor Specific AVTP subtype
+}
+
+// Returns the AVTP version used by this mapping
+U8 openavbMapPipeAvtpVersionCB()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return 0x00; // Version 0
+}
+
+U16 openavbMapPipeMaxDataSizeCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return pPvtData->maxDataSize + TOTAL_HEADER_SIZE;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0;
+}
+
+// Returns the intended transmit interval (in frames per second). 0 = default for talker / class.
+U32 openavbMapPipeTransmitIntervalCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return pPvtData->txInterval;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0;
+}
+
+void openavbMapPipeGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+
+ openavbMediaQSetSize(pMediaQ, pPvtData->itemCount, pPvtData->itemSize);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// A call to this callback indicates that this mapping module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbMapPipeTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// This talker callback will be called for each AVB observation interval.
+tx_cb_ret_t openavbMapPipeTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ if (pMediaQ && pData && dataLen) {
+ U8 *pHdr = pData;
+ U8 *pPayload = pData + TOTAL_HEADER_SIZE;
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
+
+ if (pMediaQItem) {
+ if (pMediaQItem->dataLen > 0) {
+ if (pMediaQItem->dataLen > pPvtData->maxDataSize) {
+ AVB_LOGF_ERROR("Media queue data item size too large. Reported size: %d Max Size: %d", pMediaQItem->dataLen, pPvtData->maxDataSize);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ openavbMediaQTailPull(pMediaQ);
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ // PTP walltime already set in the interface module. Just add the max transit time.
+ openavbAvtpTimeAddUSec(pMediaQItem->pAvtpTime, pPvtData->maxTransitUsec);
+
+ // Set timestamp valid flag
+ if (openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime))
+ pHdr[HIDX_AVTP_HIDE7_TV1] |= 0x01; // Set
+ else {
+ pHdr[HIDX_AVTP_HIDE7_TV1] &= ~0x01; // Clear
+ }
+
+ // Set timestamp uncertain flag
+ if (openavbAvtpTimeTimestampIsUncertain(pMediaQItem->pAvtpTime))
+ pHdr[HIDX_AVTP_HIDE7_TU1] |= 0x01; // Set
+ else pHdr[HIDX_AVTP_HIDE7_TU1] &= ~0x01; // Clear
+
+ *(U32 *)(&pHdr[HIDX_AVTP_TIMESPAMP32]) = htonl(openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime));
+ *(U32 *)(&pHdr[HIDX_OPENAVB_FORMAT8]) = 0x00000000;
+ pHdr[HIDX_OPENAVB_FORMAT8] = MAP_PIPE_OPENAVB_FORMAT;
+ // for alignment
+ U16 payloadLen = htons(pMediaQItem->dataLen);;
+ memcpy(&pHdr[HIDX_AVTP_DATALEN16], &payloadLen, sizeof(U16));
+
+ *(U16 *)(&pHdr[HIDX_VENDOR2_EUI16]) = 0x0000;
+
+ if (pPvtData->pull_header) {
+ memcpy(pData, pMediaQItem->pPubData, pMediaQItem->dataLen);
+ *dataLen = pMediaQItem->dataLen;
+ }
+ else {
+ memcpy(pPayload, pMediaQItem->pPubData, pMediaQItem->dataLen);
+ *dataLen = pMediaQItem->dataLen + TOTAL_HEADER_SIZE;
+ }
+
+ openavbMediaQTailPull(pMediaQ);
+ AVB_TRACE_LINE(AVB_TRACE_MAP_LINE);
+ 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
+ }
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY; // Media queue empty
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY;
+}
+
+// A call to this callback indicates that this mapping module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbMapPipeRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// This callback occurs when running as a listener and data is available.
+bool openavbMapPipeRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ if (pMediaQ && pData) {
+ const U8 *pHdr = pData;
+ U8 *pPayload = pData + TOTAL_HEADER_SIZE;
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return FALSE;
+ }
+
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ U32 timestamp = ntohl(*(U32 *)(&pHdr[HIDX_AVTP_TIMESPAMP32]));
+ openavbAvtpTimeSetToTimestamp(pMediaQItem->pAvtpTime, timestamp);
+
+ // Set timestamp valid and timestamp uncertain flags
+ openavbAvtpTimeSetTimestampValid(pMediaQItem->pAvtpTime, (pHdr[HIDX_AVTP_HIDE7_TV1] & 0x01) ? TRUE : FALSE);
+ openavbAvtpTimeSetTimestampUncertain(pMediaQItem->pAvtpTime, (pHdr[HIDX_AVTP_HIDE7_TU1] & 0x01) ? TRUE : FALSE);
+
+ if (pPvtData->push_header) {
+ if (pMediaQItem->itemSize >= dataLen) {
+ memcpy(pMediaQItem->pPubData, pData, dataLen);
+ pMediaQItem->dataLen = dataLen;
+ }
+ else {
+ AVB_LOG_ERROR("Data to large for media queue.");
+ pMediaQItem->dataLen = 0;
+ }
+ }
+ else {
+ // for alignment
+ U16 payloadLen;
+ memcpy(&payloadLen, &pHdr[HIDX_AVTP_DATALEN16], sizeof(U16));
+ payloadLen = ntohs(payloadLen);
+
+ if (pMediaQItem->itemSize >= payloadLen) {
+ memcpy(pMediaQItem->pPubData, pPayload, payloadLen);
+ pMediaQItem->dataLen = payloadLen;
+ }
+ else {
+ AVB_LOG_ERROR("Data to large for media queue.");
+ pMediaQItem->dataLen = 0;
+ }
+ }
+
+ openavbMediaQHeadPush(pMediaQ);
+ AVB_TRACE_LINE(AVB_TRACE_MAP_LINE);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TRUE;
+ }
+ else {
+ IF_LOG_INTERVAL(1000) AVB_LOG_INFO("Media queue full");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE; // Media queue full
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE;
+}
+
+// This callback will be called when the mapping module needs to be closed.
+// All cleanup should occur in this function.
+void openavbMapPipeEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+void openavbMapPipeGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Initialization entry point into the mapping module. Will need to be included in the .ini file.
+extern DLL_EXPORT bool openavbMapPipeInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ if (pMediaQ) {
+ pMediaQ->pMediaQDataFormat = strdup(MapPipeMediaQDataFormat);
+ pMediaQ->pPvtMapInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pMediaQDataFormat || !pMediaQ->pPvtMapInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for mapping module.");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+
+ pMapCB->map_cfg_cb = openavbMapPipeCfgCB;
+ pMapCB->map_subtype_cb = openavbMapPipeSubtypeCB;
+ pMapCB->map_avtp_version_cb = openavbMapPipeAvtpVersionCB;
+ pMapCB->map_max_data_size_cb = openavbMapPipeMaxDataSizeCB;
+ pMapCB->map_transmit_interval_cb = openavbMapPipeTransmitIntervalCB;
+ pMapCB->map_gen_init_cb = openavbMapPipeGenInitCB;
+ pMapCB->map_tx_init_cb = openavbMapPipeTxInitCB;
+ pMapCB->map_tx_cb = openavbMapPipeTxCB;
+ pMapCB->map_rx_init_cb = openavbMapPipeRxInitCB;
+ pMapCB->map_rx_cb = openavbMapPipeRxCB;
+ pMapCB->map_end_cb = openavbMapPipeEndCB;
+ pMapCB->map_gen_end_cb = openavbMapPipeGenEndCB;
+
+ pPvtData->itemCount = 20;
+ pPvtData->txInterval = 0;
+ pPvtData->push_header = FALSE;
+ pPvtData->pull_header = FALSE;
+ pPvtData->maxTransitUsec = inMaxTransitUsec;
+
+ pPvtData->maxPayloadSize = 1024;
+ pPvtData->maxDataSize = (pPvtData->maxPayloadSize + TOTAL_HEADER_SIZE);
+ pPvtData->itemSize = pPvtData->maxDataSize;
+
+ openavbMediaQSetMaxLatency(pMediaQ, inMaxTransitUsec);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return TRUE;
+}
+
diff --git a/lib/avtp_pipeline/map_pipe/openavb_map_pipe_pub.h b/lib/avtp_pipeline/map_pipe/openavb_map_pipe_pub.h
new file mode 100755
index 00000000..66e5f338
--- /dev/null
+++ b/lib/avtp_pipeline/map_pipe/openavb_map_pipe_pub.h
@@ -0,0 +1,44 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : NULL mapping module public interface
+*/
+
+#ifndef OPENAVB_MAP_PIPE_PUB_H
+#define OPENAVB_MAP_PIPE_PUB_H 1
+
+#include "openavb_types_pub.h"
+
+// NOTE: A define is used for the MediaQDataFormat identifier because it is needed in separate execution units (static / dynamic libraries)
+// that is why a single static (static/extern pattern) definition can not be used.
+#define MapPipeMediaQDataFormat "Pipe"
+
+#endif // OPENAVB_MAP_PIPE_PUB_H
diff --git a/lib/avtp_pipeline/map_pipe/pipe_map.md b/lib/avtp_pipeline/map_pipe/pipe_map.md
new file mode 100644
index 00000000..5b6f8d6d
--- /dev/null
+++ b/lib/avtp_pipeline/map_pipe/pipe_map.md
@@ -0,0 +1,24 @@
+Pipe Mapping {#pipe_map}
+============
+
+# Description
+
+The Pipe Mapping module is an AVTP vendor specific mapping format. It will pass through
+any data from interface modules unchanged. This can be useful for development,
+testing or custom solutions
+
+<br>
+# Mapping module configuration parameters
+
+Name | Description
+--------------------|---------------------------
+map_nv_item_count |The number of Media Queue items to hold.
+map_nv_tx_rate or map_nv_tx_interval | Transmit interval in frames per second. \
+ 0 = default for talker class
+map_nv_max_payload_size| Maximum payload that will be send in one Ethernet frame
+map_nv_push_header |If set to 1 the Ethernet header should be pushed to the \
+ Media Queue <br> \
+ <b>Note</b>:RX side only - Listener
+map_nv_pull_header |If set to 1 data in Media Queue is with Ethernet header \
+ <br> \
+ <b>Note</b>:TX side only - Talker
diff --git a/lib/avtp_pipeline/map_uncmp_audio/CMakeLists.txt b/lib/avtp_pipeline/map_uncmp_audio/CMakeLists.txt
new file mode 100644
index 00000000..1a2a21d2
--- /dev/null
+++ b/lib/avtp_pipeline/map_uncmp_audio/CMakeLists.txt
@@ -0,0 +1,5 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/map_uncmp_audio/openavb_map_uncmp_audio.c
+ PARENT_SCOPE
+)
+
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
new file mode 100755
index 00000000..7c3ff8aa
--- /dev/null
+++ b/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio.c
@@ -0,0 +1,759 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Uncompressed audio mapping module conforming to AVB 61883-6 encapsulation.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "openavb_types_pub.h"
+#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"
+
+// DEBUG Uncomment to turn on logging for just this module.
+#define AVB_LOG_ON 1
+
+#define AVB_LOG_COMPONENT "61883-6 Mapping"
+#include "openavb_log_pub.h"
+
+// Header sizes
+#define AVTP_V0_HEADER_SIZE 12
+#define MAP_HEADER_SIZE 12
+#define CIP_HEADER_SIZE 8
+
+#define TOTAL_HEADER_SIZE (AVTP_V0_HEADER_SIZE + MAP_HEADER_SIZE + CIP_HEADER_SIZE)
+
+//////
+// AVTP Version 0 Header
+//////
+
+// This mapping does not directly set or read these.
+#define HIDX_AVTP_VERZERO96 0
+
+// - 1 Byte - TV bit (timestamp valid)
+#define HIDX_AVTP_HIDE7_TV1 1
+
+// - 1 Byte - TU bit (timestamp uncertain)
+#define HIDX_AVTP_HIDE7_TU1 3
+
+//////
+// Mapping specific header
+//////
+
+// - 4 bytes avtp_timestamp
+#define HIDX_AVTP_TIMESTAMP32 12
+
+// - 4 bytes gateway_info
+#define HIDX_GATEWAY32 16
+
+// - 2 bytes stream_data_len (save a pointer for later use)
+#define HIDX_DATALEN16 20
+
+// 2 bit tag = binary 01 (CIP header - included)
+// 6 bit channel = 31 / 0x1F (Native AVB)
+#define HIDX_TAG2_CHANNEL6 22
+
+// 4 bits tcode = 0xA
+// 4 bits sy (application-specific) = 0
+#define HIDX_TCODE4_SY4 23
+
+//////
+// CIP Header - 2 quadlets (8 bytes)
+//////
+
+// 2 bits cip flag = binary 00
+// 6 bits sid (source identifier) = 63 / 0x3F (On the AVB network)
+#define HIDX_CIP2_SID6 24
+
+// 8 bits dbs (data block size) = Same as audio frame size. Sample Size * channels
+#define HIDX_DBS8 25
+
+// 2 bits FN (fraction number) = Bx00
+// 3 bits QPC (quadlet padding count) = Bx000
+// 1 bit SPH (source packet header) = Bx0 (not using source packet headers)
+// 2 bits RSV (reserved) = Bx00
+#define HIDX_FN2_QPC3_SPH1_RSV2 26
+
+// 8 bits DBC (data block counter) = counter
+#define HIDX_DBC8 27
+
+// 2 bits cip flag (2nd quadlet) = binary 10
+// 6 bits fmt (stream format) = binary 010000 (61883-6)
+#define HIDX_CIP2_FMT6 28
+
+// 5 bits fdf (format dependant field) = 0
+// 3 bits SFC (sample frequency) = based on rate
+#define HIDX_FDF5_SFC3 29
+
+// 2 bytes syt (synchronization timing) Set to 0xffff according to 1722
+#define HIDX_SYT16 30
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ // map_nv_item_count
+ U32 itemCount;
+
+ // Transmit interval in frames per second. 0 = default for talker class.
+ U32 txInterval;
+
+ // A multiple of how many frames of audio to accept in an media queue item and into the AVTP payload above
+ // the minimal needed.
+ U32 packingFactor;
+
+ /////////////
+ // Variable data
+ /////////////
+ U32 maxTransitUsec; // In microseconds
+
+ U8 cip_sfc;
+
+ U32 AM824_label;
+
+ U32 maxPayloadSize;
+
+ // Data block continuity counter
+ U8 DBC;
+
+ avb_audio_mcr_t audioMcr;
+
+} pvt_data_t;
+
+static void x_calculateSizes(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ if (pMediaQ) {
+ media_q_pub_map_uncmp_audio_info_t *pPubMapInfo = pMediaQ->pPubMapInfo;
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+
+ switch (pPubMapInfo->audioRate) {
+ case AVB_AUDIO_RATE_32KHZ:
+ pPvtData->cip_sfc = 0;
+ pPubMapInfo->sytInterval = 8;
+ break;
+
+ case AVB_AUDIO_RATE_44_1KHZ:
+ pPvtData->cip_sfc = 1;
+ pPubMapInfo->sytInterval = 8;
+ break;
+
+ case AVB_AUDIO_RATE_48KHZ:
+ pPvtData->cip_sfc = 2;
+ pPubMapInfo->sytInterval = 8;
+ break;
+
+ case AVB_AUDIO_RATE_88_2KHZ:
+ pPvtData->cip_sfc = 3;
+ pPubMapInfo->sytInterval = 16;
+ break;
+
+ case AVB_AUDIO_RATE_96KHZ:
+ pPvtData->cip_sfc = 4;
+ pPubMapInfo->sytInterval = 16;
+ break;
+
+ case AVB_AUDIO_RATE_176_4KHZ:
+ pPvtData->cip_sfc = 5;
+ pPubMapInfo->sytInterval = 32;
+ break;
+
+ case AVB_AUDIO_RATE_192KHZ:
+ pPvtData->cip_sfc = 6;
+ pPubMapInfo->sytInterval = 32;
+ break;
+
+ default:
+ AVB_LOG_ERROR("Invalid audio frequency configured.");
+ pPvtData->cip_sfc = 2;
+ pPubMapInfo->sytInterval = 8;
+ break;
+ }
+
+ pPubMapInfo->framesPerPacket = (pPubMapInfo->audioRate / pPvtData->txInterval);
+ if (pPubMapInfo->framesPerPacket < 1) {
+ pPubMapInfo->framesPerPacket = 1;
+ }
+ if (pPubMapInfo->audioRate % pPvtData->txInterval != 0) {
+ AVB_LOGF_WARNING("audio rate (%d) is not an integer multiple of TX rate (%d). Recommend TX rate of (%d)",
+ pPubMapInfo->audioRate, pPvtData->txInterval, pPubMapInfo->audioRate / (pPubMapInfo->framesPerPacket + 1));
+ pPubMapInfo->framesPerPacket += 1;
+ }
+
+ pPubMapInfo->packingFactor = pPvtData->packingFactor;
+ 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;
+ }
+ }
+
+ pPubMapInfo->packetSampleSizeBytes = 4;
+
+ AVB_LOGF_INFO("Rate:%d", pPubMapInfo->audioRate);
+ AVB_LOGF_INFO("Bits:%d", pPubMapInfo->audioBitDepth);
+ AVB_LOGF_INFO("Channels:%d", pPubMapInfo->audioChannels);
+ AVB_LOGF_INFO("Packet Interval:%d", pPvtData->txInterval);
+ AVB_LOGF_INFO("Frames per packet:%d", pPubMapInfo->framesPerPacket);
+ AVB_LOGF_INFO("Packing Factor:%d", pPvtData->packingFactor);
+ AVB_LOGF_INFO("Frames per MediaQ Item:%d", pPubMapInfo->framesPerItem);
+ AVB_LOGF_INFO("Sample Size Bytes:%d", pPubMapInfo->packetSampleSizeBytes);
+
+ if (pPubMapInfo->audioBitDepth == AVB_AUDIO_BIT_DEPTH_16BIT || pPubMapInfo->audioBitDepth == AVB_AUDIO_BIT_DEPTH_20BIT) {
+ // TODO: The 20Bit format was downgraded to 16 bit and therefore 2 bytes
+ pPubMapInfo->itemSampleSizeBytes = 2;
+ }
+ else if (pPubMapInfo->audioBitDepth == AVB_AUDIO_BIT_DEPTH_24BIT) {
+ pPubMapInfo->itemSampleSizeBytes = 3;
+ }
+ else {
+ AVB_LOGF_ERROR("Invalid audio format configured: %u", pPubMapInfo->audioBitDepth);
+ pPubMapInfo->itemSampleSizeBytes = 1;
+ }
+
+ pPubMapInfo->packetFrameSizeBytes = pPubMapInfo->packetSampleSizeBytes * pPubMapInfo->audioChannels;
+ pPubMapInfo->packetAudioDataSizeBytes = pPubMapInfo->framesPerPacket * pPubMapInfo->packetFrameSizeBytes;
+ pPvtData->maxPayloadSize = pPubMapInfo->packetAudioDataSizeBytes + TOTAL_HEADER_SIZE;
+
+ pPubMapInfo->itemFrameSizeBytes = pPubMapInfo->itemSampleSizeBytes * pPubMapInfo->audioChannels;
+ pPubMapInfo->itemSize = pPubMapInfo->itemFrameSizeBytes * pPubMapInfo->framesPerItem;
+
+ switch (pPubMapInfo->audioBitDepth) {
+ case AVB_AUDIO_BIT_DEPTH_16BIT:
+ pPvtData->AM824_label = 0x42000000;
+ break;
+
+ case AVB_AUDIO_BIT_DEPTH_20BIT:
+ AVB_LOG_ERROR("20 bit not currently supported. Downgraded to 16 bit.");
+ pPvtData->AM824_label = 0x42000000;
+ break;
+
+ case AVB_AUDIO_BIT_DEPTH_24BIT:
+ pPvtData->AM824_label = 0x40000000;
+ break;
+
+ default:
+ AVB_LOG_ERROR("Invalid audio format configured.");
+ pPvtData->AM824_label = 0x40000000;
+ break;
+ }
+
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbMapUncmpAudioCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+
+ if (strcmp(name, "map_nv_item_count") == 0) {
+ char *pEnd;
+ pPvtData->itemCount = strtol(value, &pEnd, 10);
+ }
+ else if (strcmp(name, "map_nv_tx_rate") == 0
+ || strcmp(name, "map_nv_tx_interval") == 0) {
+ char *pEnd;
+ pPvtData->txInterval = strtol(value, &pEnd, 10);
+ }
+ else if (strcmp(name, "map_nv_packing_factor") == 0) {
+ char *pEnd;
+ pPvtData->packingFactor = strtol(value, &pEnd, 10);
+ }
+ else if (strcmp(name, "map_nv_audio_mcr") == 0) {
+ char *pEnd;
+ pPvtData->audioMcr = (avb_audio_mcr_t)strtol(value, &pEnd, 10);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+U8 openavbMapUncmpAudioSubtypeCB()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0x00; // 61883 AVB subtype
+}
+
+// Returns the AVTP version used by this mapping
+U8 openavbMapUncmpAudioAvtpVersionCB()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return 0x00; // Version 0
+}
+
+U16 openavbMapUncmpAudioMaxDataSizeCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return pPvtData->maxPayloadSize;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0;
+}
+
+// Returns the intended transmit interval (in frames per second). 0 = default for talker / class.
+U32 openavbMapUncmpAudioTransmitIntervalCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return pPvtData->txInterval;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return 0;
+}
+
+void openavbMapUncmpAudioGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ media_q_pub_map_uncmp_audio_info_t *pPubMapInfo = pMediaQ->pPubMapInfo;
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ return;
+ }
+
+ x_calculateSizes(pMediaQ);
+ openavbMediaQSetSize(pMediaQ, pPvtData->itemCount, pPubMapInfo->itemSize);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ }
+
+void openavbMapUncmpAudioAVDECCInitCB(media_q_t *pMediaQ, U16 configIdx, U16 descriptorType, U16 descriptorIdx)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// A call to this callback indicates that this mapping module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbMapUncmpAudioTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ // Check the media queue for proper allocations to avoid doing it on each tx callback.
+ if (!pMediaQ) {
+ AVB_LOG_ERROR("Media queue not allocated.");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return;
+ }
+
+ media_q_pub_map_uncmp_audio_info_t *pPubMapInfo = pMediaQ->pPubMapInfo;
+ if (!pPubMapInfo) {
+ AVB_LOG_ERROR("Public mapping module data not allocated.");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// This talker callback will be called for each AVB observation interval.
+tx_cb_ret_t openavbMapUncmpAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen)
+{
+ media_q_item_t *pMediaQItem = NULL;
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+
+ if (!pData || !dataLen) {
+ AVB_LOG_ERROR("Mapping module data or data length argument incorrect.");
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ media_q_pub_map_uncmp_audio_info_t *pPubMapInfo = pMediaQ->pPubMapInfo;
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+
+ if (*dataLen - TOTAL_HEADER_SIZE < pPubMapInfo->packetAudioDataSizeBytes) {
+ AVB_LOG_ERROR("Not enough room in packet for audio frames.");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ if (openavbMediaQIsAvailableBytes(pMediaQ, pPubMapInfo->itemFrameSizeBytes * pPubMapInfo->framesPerPacket, TRUE)) {
+ U8 *pHdr = pData;
+ U8 *pPayload = pData + TOTAL_HEADER_SIZE;
+
+ //pHdr[HIDX_AVTP_TIMESTAMP32] = 0x00; // Set later
+ *(U32 *)(&pHdr[HIDX_GATEWAY32]) = 0x00000000;
+ //pHdr[HIDX_DATALEN16] = 0x00; // Set Later
+ pHdr[HIDX_TAG2_CHANNEL6] = (1 << 6) | 0x1f;
+ pHdr[HIDX_TCODE4_SY4] = (0x0a << 4) | 0;
+
+ // Set the majority of the CIP header now.
+ pHdr[HIDX_CIP2_SID6] = (0x00 << 6) | 0x3f;
+ pHdr[HIDX_DBS8] = pPubMapInfo->audioChannels;
+
+ pHdr[HIDX_FN2_QPC3_SPH1_RSV2] = (0x00 << 6) | (0x00 << 3) | (0x00 << 2) | 0x00;
+ // pHdr[HIDX_DBC8] = 0; // Set later
+ pHdr[HIDX_CIP2_FMT6] = (0x02 << 6) | 0x10;
+ pHdr[HIDX_FDF5_SFC3] = 0x00 << 3 | pPvtData->cip_sfc;
+ *(U16 *)(&pHdr[HIDX_SYT16]) = 0xffff;
+
+ U32 framesProcessed = 0;
+ U8 *pAVTPDataUnit = pPayload;
+ bool timestampSet = FALSE; // index of the timestamp
+ while (framesProcessed < pPubMapInfo->framesPerPacket) {
+ pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
+
+ 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
+
+ // PTP walltime already set in the interface module. Just add the max transit time.
+ openavbAvtpTimeAddUSec(pMediaQItem->pAvtpTime, pPvtData->maxTransitUsec);
+
+ // Set timestamp valid flag
+ if (openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime))
+ pHdr[HIDX_AVTP_HIDE7_TV1] |= 0x01; // Set
+ else {
+ pHdr[HIDX_AVTP_HIDE7_TV1] &= ~0x01; // Clear
+ }
+
+ // Set timestamp uncertain flag
+ if (openavbAvtpTimeTimestampIsUncertain(pMediaQItem->pAvtpTime))
+ pHdr[HIDX_AVTP_HIDE7_TU1] |= 0x01; // Set
+ 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++) {
+ if (pPubMapInfo->itemSampleSizeBytes == 2) {
+ S32 sample = *(S16 *)pItemData;
+ sample &= 0x0000ffff;
+ sample = sample << 8;
+ sample |= pPvtData->AM824_label;
+ sample = htonl(sample);
+ *(U32 *)(pAVTPDataUnit) = sample;
+ pAVTPDataUnit += 4;
+ pItemData += 2;
+ }
+ else {
+ S32 sample = *(S32 *)pItemData;
+ sample &= 0x00ffffff;
+ sample |= pPvtData->AM824_label;
+ sample = htonl(sample);
+ *(U32 *)(pAVTPDataUnit) = sample;
+ pAVTPDataUnit += 4;
+ pItemData += 3;
+ }
+ }
+ framesProcessed++;
+ pMediaQItem->readIdx += pPubMapInfo->itemFrameSizeBytes;
+ }
+
+ if (pMediaQItem->readIdx >= pMediaQItem->dataLen) {
+ // Read the entire item
+ openavbMediaQTailPull(pMediaQ);
+ }
+ else {
+ // More to read next interval
+ openavbMediaQTailUnlock(pMediaQ);
+ }
+ }
+ else {
+ openavbMediaQTailPull(pMediaQ);
+ }
+ }
+
+ // Check if timestamp was set
+ if (!timestampSet) {
+ // Timestamp wasn't set so mark it as invalid
+ pHdr[HIDX_AVTP_HIDE7_TV1] &= ~0x01;
+ }
+
+ // Set the block continutity and data length
+ pHdr[HIDX_DBC8] = pPvtData->DBC;
+ pPvtData->DBC += pPubMapInfo->framesPerPacket;
+
+ *(U16 *)(&pHdr[HIDX_DATALEN16]) = htons((pPubMapInfo->framesPerPacket * pPubMapInfo->packetFrameSizeBytes) + CIP_HEADER_SIZE);
+
+ // Set out bound data length (entire packet length)
+ *dataLen = (pPubMapInfo->framesPerPacket * pPubMapInfo->packetFrameSizeBytes) + TOTAL_HEADER_SIZE;
+
+ AVB_TRACE_LINE(AVB_TRACE_MAP_LINE);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_READY;
+
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY;
+}
+
+// A call to this callback indicates that this mapping module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbMapUncmpAudioRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+// This callback occurs when running as a listener and data is available.
+bool openavbMapUncmpAudioRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ if (pMediaQ && pData) {
+ U8 *pHdr = pData;
+ U8 *pPayload = pData + TOTAL_HEADER_SIZE;
+ media_q_pub_map_uncmp_audio_info_t *pPubMapInfo = pMediaQ->pPubMapInfo;
+
+ //pHdr[HIDX_AVTP_TIMESTAMP32];
+ //pHdr[HIDX_GATEWAY32];
+ U16 payloadLen = ntohs(*(U16 *)(&pHdr[HIDX_DATALEN16]));
+
+ //pHdr[HIDX_TAG2_CHANNEL6];
+ //pHdr[HIDX_TCODE4_SY4];
+ //pHdr[HIDX_CIP2_SID6];
+ //pHdr[HIDX_DBS8];
+ //pHdr[HIDX_FN2_QPC3_SPH1_RSV2];
+ U8 dbc = pHdr[HIDX_DBC8];
+ //pHdr[HIDX_CIP2_FMT6];
+ //pHdr[HIDX_TSF1_RESA7];
+ //pHdr[HIDX_RESB8];
+ //pHdr[HIDX_RESC8];
+ bool tsValid = (pHdr[HIDX_AVTP_HIDE7_TV1] & 0x01) ? TRUE : FALSE;
+ bool tsUncertain = (pHdr[HIDX_AVTP_HIDE7_TU1] & 0x01) ? TRUE : FALSE;
+
+ // Per iec61883-6 Secion 7.2
+ // index = mod((SYT_INTERVAL - mod(DBC, SYT_INTERVAL)), SYT_INTERVAL)
+ // U8 dbcIdx = (pPubMapInfo->sytInterval - (dbc % pPubMapInfo->sytInterval)) % pPubMapInfo->sytInterval;
+ // The dbcIdx calculation isn't used from spec because our implmentation only needs to know when the timestamp index is at 0.
+ U8 dbcIdx = dbc % pPubMapInfo->sytInterval;
+ U8 *pAVTPDataUnit = pPayload;
+ U8 *pAVTPDataUnitEnd = pData + AVTP_V0_HEADER_SIZE + MAP_HEADER_SIZE + payloadLen;
+
+ while (((pAVTPDataUnit + pPubMapInfo->packetFrameSizeBytes) <= pAVTPDataUnitEnd)) {
+ // Get item pointer in media queue
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+
+ U32 itemSizeWritten = 0;
+ U8 *pItemData = (U8 *)pMediaQItem->pPubData + pMediaQItem->dataLen;
+ U8 *pItemDataEnd = (U8 *)pMediaQItem->pPubData + pMediaQItem->itemSize;
+
+ // Get the timestamp
+ U32 timestamp = ntohl(*(U32 *)(&pHdr[HIDX_AVTP_TIMESTAMP32]));
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if ((pPvtData->audioMcr != AVB_MCR_NONE) && tsValid && !tsUncertain) {
+ // MCR mode set and timestamp is valid, and timestamp uncertain is not set
+ openavbAvtpTimePushMCR(pMediaQItem->pAvtpTime, timestamp);
+ }
+
+ 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
+ // it is expected not to need to toss packets anymore.
+ openavbMediaQHeadUnlock(pMediaQ);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TRUE;
+ }
+
+ // Set time stamp info on first data write to the media queue
+ // place it in the media queue item.
+ openavbAvtpTimeSetToTimestamp(pMediaQItem->pAvtpTime, timestamp);
+
+ // Set timestamp valid and timestamp uncertain flags
+ openavbAvtpTimeSetTimestampValid(pMediaQItem->pAvtpTime, tsValid);
+ openavbAvtpTimeSetTimestampUncertain(pMediaQItem->pAvtpTime, tsUncertain);
+ }
+
+ while (((pAVTPDataUnit + pPubMapInfo->packetFrameSizeBytes) <= pAVTPDataUnitEnd) && ((pItemData + pPubMapInfo->itemFrameSizeBytes) <= pItemDataEnd)) {
+ int i1;
+ for (i1 = 0; i1 < pPubMapInfo->audioChannels; i1++) {
+ if (pPubMapInfo->itemSampleSizeBytes == 2) {
+ S32 sample = ntohl(*(S32 *)pAVTPDataUnit);
+ sample = sample * 1;
+ *(S16 *)(pItemData) = (sample & 0x00ffffff) >> 8;
+ pAVTPDataUnit += 4;
+ pItemData += 2;
+ itemSizeWritten += 2;
+ }
+ else {
+ S32 sample = ntohl(*(S32 *)pAVTPDataUnit);
+ sample = sample * 1;
+ *(S32 *)(pItemData) = sample & 0x00ffffff;
+ pAVTPDataUnit += 4;
+ pItemData += 3;
+ itemSizeWritten += 3;
+ }
+ }
+ }
+
+ pMediaQItem->dataLen += itemSizeWritten;
+
+ if (pMediaQItem->dataLen < pMediaQItem->itemSize) {
+ // More data can be written to the item
+ openavbMediaQHeadUnlock(pMediaQ);
+ }
+ else {
+ // The item is full push it.
+ openavbMediaQHeadPush(pMediaQ);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TRUE; // Normal exit
+ }
+ else {
+ IF_LOG_INTERVAL(1000) AVB_LOG_INFO("Media queue full");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE; // Media queue full
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TRUE; // Normal exit
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE;
+}
+
+// This callback will be called when the mapping module needs to be closed.
+// All cleanup should occur in this function.
+void openavbMapUncmpAudioEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+}
+
+void openavbMapUncmpAudioGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Initialization entry point into the mapping module. Will need to be included in the .ini file.
+extern DLL_EXPORT bool openavbMapUncmpAudioInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+
+ if (pMediaQ) {
+ pMediaQ->pMediaQDataFormat = strdup(MapUncmpAudioMediaQDataFormat);
+ pMediaQ->pPubMapInfo = calloc(1, sizeof(media_q_pub_map_uncmp_audio_info_t)); // Memory freed by the media queue when the media queue is destroyed.
+ pMediaQ->pPvtMapInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pMediaQDataFormat || !pMediaQ->pPubMapInfo || !pMediaQ->pPvtMapInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for mapping module.");
+ return FALSE;
+ }
+
+ 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;
+ pMapCB->map_avtp_version_cb = openavbMapUncmpAudioAvtpVersionCB;
+ 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;
+ pMapCB->map_rx_cb = openavbMapUncmpAudioRxCB;
+ pMapCB->map_end_cb = openavbMapUncmpAudioEndCB;
+ pMapCB->map_gen_end_cb = openavbMapUncmpAudioGenEndCB;
+
+ pPvtData->itemCount = 20;
+ pPvtData->txInterval = 0;
+ pPvtData->packingFactor = 1;
+ pPvtData->maxTransitUsec = inMaxTransitUsec;
+ pPvtData->DBC = 0;
+ pPvtData->audioMcr = AVB_MCR_NONE;
+
+ pPubMapInfo->sparseMode = TS_SPARSE_MODE_UNSPEC;
+
+ openavbMediaQSetMaxLatency(pMediaQ, inMaxTransitUsec);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
+ return TRUE;
+}
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
new file mode 100755
index 00000000..7a324d46
--- /dev/null
+++ b/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio_pub.h
@@ -0,0 +1,132 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : 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.
+*/
+
+#ifndef OPENAVB_MAP_UNCMP_AUDIO_PUB_H
+#define OPENAVB_MAP_UNCMP_AUDIO_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_audio_pub.h"
+#include "openavb_intf_pub.h"
+
+/** \file
+ * 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.
+ */
+
+/** \note A define is used for the MediaQDataFormat identifier because it is
+ * needed in separate execution units (static / dynamic libraries) that is why
+ * a single static (static/extern pattern) definition can not be used.
+ */
+#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,
+ * - audioType,
+ * - 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.
+ */
+typedef struct {
+ /// Rate of audio
+ avb_audio_rate_t audioRate;
+ /// Sample data type
+ avb_audio_type_t audioType;
+ /// Bit depth of audio
+ avb_audio_bit_depth_t audioBitDepth;
+ /// Sample endianess
+ 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.
+ /// Number of frames for one data packet
+ U32 framesPerPacket;
+ /// Size of one sample in bytes
+ U32 packetSampleSizeBytes;
+ /// Size of one frame in bytes (framesPerPacket * audioChannels)
+ U32 packetFrameSizeBytes;
+ /// Size of packet (packetFrameSizeBytes * framesPerPacket)
+ U32 packetAudioDataSizeBytes;
+ /// Number of frames of audio to accept in one Media Queue Item
+ U32 packingFactor;
+ /// Number of frames per one Media Queue Item
+ U32 framesPerItem;
+ /// Item sample size in bytes (usually the same as packetSampleSizeBytes)
+ U32 itemSampleSizeBytes;
+ /// Media Queue Item Frame size in bytes
+ U32 itemFrameSizeBytes;
+ /// Media Queue Item size
+ U32 itemSize;
+ /// synchronization time interval
+ U32 sytInterval;
+
+ /// 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
new file mode 100644
index 00000000..f826249c
--- /dev/null
+++ b/lib/avtp_pipeline/map_uncmp_audio/uncmp_audio_map.md
@@ -0,0 +1,57 @@
+Uncompressed audio Mapping {#uncmp_audio_map}
+==========================
+
+# Description
+
+Uncompressed audio mapping module conforming to AVB 61883-6 encapsulation.
+
+# Mapping module configuration parameters
+
+Name | Description
+--------------------|---------------------------
+map_nv_item_count |The number of media queue elements to hold.
+map_nv_tx_rate or map_nv_tx_interval | Transmit interval in frames per second. \
+ 0 = default for talker class. <br> The transmit rate for \
+ the mapping module should be set according to the sample \
+ rate, so that the transmit interval meets the suggested \
+ values in 1722a <ul><li>sample rate which are multiple of \
+ 8000Hz <ul><li>8000 for class <b>A</b></li><li>4000 for \
+ class <b>B</b></li></ul></li><li>sample rate which are \
+ multiple of 44100Hz<ul><li>7350 for class <b>A</b></li> \
+ <li>3675 for class <b>B</b></li></ul></li></ul>
+map_nv_packing_factor|How many frames of audio to accept in one media queue item
+map_nv_audio_mcr |Media clock recovery,<ul><li>0 - No Media Clock Recovery \
+ default option</li><li>1 - MCR done using AVTP timestamps\
+ </li><li>2 - MCR using Clock Reference Stream</li></ul>
+
+# Notes
+
+There are additional parameters that have to be set by intf module during
+configuration process to make everything calulated properly inside mapping.
+Those variables have to be set before *map_gen_init_cb* is being called.
+One of the approaches might be setting them during reading of the ini
+configuration and setting of the interface parameters.
+
+Fields of a structure media_q_pub_map_uncmp_audio_info_t that have to be set
+during interface configuration:
+Name | Description
+-------------------|----------------------------
+audioRate |Rate of the audio @ref avb_audio_rate_t
+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)
+* [alsa interface](@ref alsa_intf)
+
+**Note**: If one of those fields will not be set, mapping module will not
+configure media queue correctly.
+
+**Note**: Both the talker and listner must be configured with matching sample
+parameters. If the received data does not match the configured
+parameters on the listener, the stream will still be setup and data
+will still flow - but no audio will be played.
diff --git a/lib/avtp_pipeline/mcr/CMakeLists.txt b/lib/avtp_pipeline/mcr/CMakeLists.txt
new file mode 100644
index 00000000..3e3b4110
--- /dev/null
+++ b/lib/avtp_pipeline/mcr/CMakeLists.txt
@@ -0,0 +1 @@
+# No common code
diff --git a/lib/avtp_pipeline/mcr/openavb_mcr_hal_pub.h b/lib/avtp_pipeline/mcr/openavb_mcr_hal_pub.h
new file mode 100644
index 00000000..ac2eca21
--- /dev/null
+++ b/lib/avtp_pipeline/mcr/openavb_mcr_hal_pub.h
@@ -0,0 +1,65 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Public interface for media clock recovery
+*/
+
+#ifndef OPENAVB_MCR_HAL_PUB_H
+#define OPENAVB_MCR_HAL_PUB_H
+
+#include "openavb_platform_pub.h"
+#include "openavb_types_base_pub.h"
+
+#define HAL_INIT_MCR_V2(packetRate, pushInterval, timestampInterval, recoveryInterval) halInitMCR(packetRate, pushInterval, timestampInterval, recoveryInterval)
+#define HAL_CLOSE_MCR_V2() halCloseMCR()
+#define HAL_PUSH_MCR_V2() halPushMCR()
+
+// Initialize HAL MCR
+bool halInitMCR(U32 packetRate, U32 pushInterval, U32 timeStampInterval, U32 recoveryInterval);
+
+// Close HAL MCR
+bool halCloseMCR(void);
+
+// Push MCR Event
+bool halPushMCR(void);
+
+// MCR timer adjustment. Negative value speed up the media clock. Positive values slow the media clock.
+// Will take effect during the next clock recovery interval. This is completely indepentant from pure MCR and
+// allows for adjustments based on media buffer levels. The value past in works as credit with each
+// MCR timer cycle bump up and down the clock temporarily.
+void halAdjustMCRNSec(S32 adjNSec);
+
+// The granularity is used to set coarseness of the values that will be passed into halAdjustMCRNSec.
+// This is used to balance if the timestamps or values from halAdjustMCRNSec are used to adjust the clock.
+void halAdjustMCRGranularityNSec(U32 adjGranularityNSec);
+
+
+#endif // OPENAVB_MCR_HAL_PUB_H
diff --git a/lib/avtp_pipeline/mediaq/CMakeLists.txt b/lib/avtp_pipeline/mediaq/CMakeLists.txt
new file mode 100644
index 00000000..7bac6aa7
--- /dev/null
+++ b/lib/avtp_pipeline/mediaq/CMakeLists.txt
@@ -0,0 +1,5 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/mediaq/openavb_mediaq.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/mediaq/openavb_mediaq.c b/lib/avtp_pipeline/mediaq/openavb_mediaq.c
new file mode 100644
index 00000000..d79b78fb
--- /dev/null
+++ b/lib/avtp_pipeline/mediaq/openavb_mediaq.c
@@ -0,0 +1,1073 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Media Queue for data transfer betting mapping modules and interface modules.
+*/
+
+#include "openavb_platform.h"
+
+#include <stdlib.h>
+#include "openavb_types_pub.h"
+#include "openavb_trace.h"
+#include "openavb_mediaq.h"
+#include "openavb_avtp_time_pub.h"
+
+#include "openavb_printbuf.h"
+
+#define AVB_LOG_COMPONENT "Media Queue"
+#include "openavb_log.h"
+
+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
+
+#if DUMP_HEAD_PUSH
+FILE *pFileHeadPush = 0;
+#endif
+#if DUMP_TAIL_PULL
+FILE *pFileTailPull = 0;
+#endif
+
+typedef struct {
+ // Maximum number of items the queue can hold.
+ int itemCount;
+
+ // The size in bytes of each item
+ int itemSize;
+
+ // Pointer to the array of items.
+ media_q_item_t *pItems;
+
+ // Next item to be filled
+ int head;
+
+ // True if the head item is locked.
+ bool headLocked;
+
+ // Next item to be pulled
+ int tail;
+
+ // 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;
+
+ // Determines if mutuxes will be used for Head and Tail access.
+ bool threadSafeOn;
+
+ // Maximum stale tail
+ U32 maxStaleTailUsec;
+
+} media_q_info_t;
+
+static void x_openavbMediaQIncrementHead(media_q_info_t *pMediaQInfo)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ_DETAIL);
+
+ // Module internal function therefore not validating pMediaQInfo
+
+ int startingHead = pMediaQInfo->head;
+ while (++pMediaQInfo->head != startingHead)
+ {
+ if (pMediaQInfo->head >= pMediaQInfo->itemCount) {
+ pMediaQInfo->head = 0;
+ }
+
+ // If head catches up with tail deactivate the head.
+ if (pMediaQInfo->head == pMediaQInfo->tail) {
+ break; // Set head to pMediaQInfo->head = -1;
+ }
+
+ if (!pMediaQInfo->pItems[pMediaQInfo->head].taken) {
+ // Found item
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return;
+ }
+ }
+
+ // Deactivate the head
+ pMediaQInfo->head = -1;
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+}
+
+static void x_openavbMediaQIncrementTail(media_q_info_t *pMediaQInfo)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ_DETAIL);
+
+ // Module internal function therefore not validating pMediaQInfo
+
+ int startingTail = pMediaQInfo->tail;
+ while (++pMediaQInfo->tail != startingTail)
+ {
+ if (pMediaQInfo->tail >= pMediaQInfo->itemCount) {
+ pMediaQInfo->tail = 0;
+ }
+
+ // If tail catches up with head deactivate the tail.
+ if (pMediaQInfo->tail == pMediaQInfo->head) {
+ break; // Set head to pMediaQInfo->tail = -1;
+ }
+
+ if (!pMediaQInfo->pItems[pMediaQInfo->tail].taken) {
+ // Found item
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return;
+ }
+ }
+
+ // Deactivate the tail
+ pMediaQInfo->tail = -1;
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+}
+
+
+// CORE_TODO: May need to add mutex protection when merging with OSAL/HAL branch.
+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);
+
+ if (pMediaQInfo->maxStaleTailUsec > 0) {
+ bool bFirst = TRUE;
+ bool bMore = TRUE;
+ while (bMore) {
+ bMore = FALSE;
+ if (pMediaQInfo->itemCount > 0) {
+ if (pMediaQInfo->tail > -1) {
+ media_q_item_t *pTail = &pMediaQInfo->pItems[pMediaQInfo->tail];
+
+ if (pTail) {
+ 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);
+
+ bPurge = TRUE;
+ }
+ bFirst = FALSE;
+ }
+ else {
+ // Once we have triggered a stale tail purge everything past presentation time.
+ if (openavbAvtpTimeIsPast(pTail->pAvtpTime)) {
+ bPurge = TRUE;
+ }
+ }
+
+ if (bPurge) {
+ openavbMediaQTailPull(pMediaQ);
+ pTail = NULL;
+ bMore = TRUE;
+ }
+ else {
+ 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
+
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+}
+
+
+media_q_t* openavbMediaQCreate()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ);
+
+ media_q_t *pMediaQ = calloc(1, sizeof(media_q_t));
+
+ if (pMediaQ) {
+ pMediaQ->pPvtMediaQInfo = calloc(1, sizeof(media_q_info_t));
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ pMediaQInfo->itemCount = 0;
+ pMediaQInfo->itemSize = 0;
+ pMediaQInfo->head = 0;
+ pMediaQInfo->headLocked = FALSE;
+ pMediaQInfo->tail = -1;
+ pMediaQInfo->tailLocked = FALSE;
+ pMediaQInfo->firstFuture = TRUE;
+ pMediaQInfo->maxLatencyUsec = 0;
+ pMediaQInfo->threadSafeOn = FALSE;
+ pMediaQInfo->maxStaleTailUsec = MICROSECONDS_PER_SECOND;
+ }
+ else {
+ openavbMediaQDelete(pMediaQ);
+ pMediaQ = NULL;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return pMediaQ;
+}
+
+void openavbMediaQThreadSafeOn(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ);
+
+ if (pMediaQ) {
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ pMediaQInfo->threadSafeOn = TRUE;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+}
+
+
+
+bool openavbMediaQSetSize(media_q_t *pMediaQ, int itemCount, int itemSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ);
+
+ if (pMediaQ) {
+ if (itemCount < 1 || itemSize < 1) {
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return FALSE;
+ }
+
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+
+ // Don't want to re-allocate new memory each time
+ if (!pMediaQInfo->pItems)
+ {
+ pMediaQInfo->pItems = calloc(itemCount, sizeof(media_q_item_t));
+ if (pMediaQInfo->pItems) {
+ pMediaQInfo->itemCount = itemCount;
+ pMediaQInfo->itemSize = 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].dataLen = 0;
+ pMediaQInfo->pItems[i1].itemSize = itemSize;
+ if (!pMediaQInfo->pItems[i1].pPubData) {
+ AVB_LOG_ERROR("Out of memory creating MediaQ item");
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return FALSE;
+ }
+ }
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return FALSE;
+ }
+ } else if (itemCount != pMediaQInfo->itemCount || itemSize != pMediaQInfo->itemSize){
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return FALSE;
+ }
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return FALSE;
+ }
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return TRUE;
+}
+
+bool openavbMediaQAllocItemMapData(media_q_t *pMediaQ, int itemPubMapSize, int itemPvtMapSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ);
+
+ if (pMediaQ) {
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ if (pMediaQInfo->pItems) {
+ int i1;
+ for (i1 = 0; i1 < pMediaQInfo->itemCount; i1++) {
+ if (itemPubMapSize) {
+ if (!pMediaQInfo->pItems[i1].pPubMapData) {
+ pMediaQInfo->pItems[i1].pPubMapData = calloc(1, itemPubMapSize);
+ if (!pMediaQInfo->pItems[i1].pPubMapData) {
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return FALSE;
+ }
+ }
+ else {
+ AVB_LOG_ERROR("Attemping to reallocate public map data");
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return FALSE;
+ }
+ }
+ if (itemPvtMapSize) {
+ if (!pMediaQInfo->pItems[i1].pPvtMapData) {
+ pMediaQInfo->pItems[i1].pPvtMapData = calloc(1, itemPvtMapSize);
+ if (!pMediaQInfo->pItems[i1].pPvtMapData) {
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return FALSE;
+ }
+ }
+ else {
+ AVB_LOG_ERROR("Attemping to reallocate private map data");
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return FALSE;
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return TRUE;
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return FALSE;
+}
+
+
+bool openavbMediaQAllocItemIntfData(media_q_t *pMediaQ, int itemIntfSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ);
+
+ if (pMediaQ) {
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ if (pMediaQInfo->pItems) {
+ int i1;
+ for (i1 = 0; i1 < pMediaQInfo->itemCount; i1++) {
+ if (!pMediaQInfo->pItems[i1].pPvtIntfData) {
+ pMediaQInfo->pItems[i1].pPvtIntfData = calloc(1, itemIntfSize);
+ if (!pMediaQInfo->pItems[i1].pPvtIntfData) {
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return FALSE;
+ }
+ }
+ else {
+ AVB_LOG_ERROR("Attemping to reallocate private interface data");
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return FALSE;
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return TRUE;
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return FALSE;
+}
+
+bool openavbMediaQDelete(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ);
+
+ if (pMediaQ) {
+
+#if DUMP_HEAD_PUSH
+ if (pFileHeadPush) {
+ fflush(pFileHeadPush);
+ fclose(pFileHeadPush);
+ pFileHeadPush = NULL;
+ }
+#endif
+
+#if DUMP_TAIL_PULL
+ if (pFileTailPull) {
+ fflush(pFileTailPull);
+ fclose(pFileTailPull);
+ pFileTailPull = NULL;
+ }
+#endif
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ if (pMediaQInfo->pItems) {
+ int i1;
+ for (i1 = 0; i1 < pMediaQInfo->itemCount; i1++) {
+
+ if (pMediaQInfo->pItems[i1].taken) {
+ AVB_LOG_ERROR("Deleting MediaQ with an item TAKEN. The item will be orphaned.");
+ }
+ else {
+ openavbAvtpTimeDelete(pMediaQInfo->pItems[i1].pAvtpTime);
+ if (pMediaQInfo->pItems[i1].pPubData) {
+ free(pMediaQInfo->pItems[i1].pPubData);
+ pMediaQInfo->pItems[i1].pPubData = NULL;
+ }
+ if (pMediaQInfo->pItems[i1].pPubMapData) {
+ free(pMediaQInfo->pItems[i1].pPubMapData);
+ pMediaQInfo->pItems[i1].pPubMapData = NULL;
+ }
+ if (pMediaQInfo->pItems[i1].pPvtMapData) {
+ free(pMediaQInfo->pItems[i1].pPvtMapData);
+ pMediaQInfo->pItems[i1].pPvtMapData = NULL;
+ }
+ if (pMediaQInfo->pItems[i1].pPvtIntfData) {
+ free(pMediaQInfo->pItems[i1].pPvtIntfData);
+ pMediaQInfo->pItems[i1].pPvtIntfData = NULL;
+ }
+ }
+ }
+ free(pMediaQInfo->pItems);
+ pMediaQInfo->pItems = NULL;
+ }
+ free(pMediaQ->pPvtMediaQInfo);
+ pMediaQ->pPvtMediaQInfo = NULL;
+
+ if (pMediaQ->pPubMapInfo) {
+ free(pMediaQ->pPubMapInfo);
+ pMediaQ->pPubMapInfo = NULL;
+ }
+
+ if (pMediaQ->pPvtMapInfo) {
+ free(pMediaQ->pPvtMapInfo);
+ pMediaQ->pPvtMapInfo = NULL;
+ }
+
+ if (pMediaQ->pPvtIntfInfo) {
+ free(pMediaQ->pPvtIntfInfo);
+ pMediaQ->pPvtIntfInfo = NULL;
+ }
+ }
+
+ if (pMediaQ->pMediaQDataFormat) {
+ free(pMediaQ->pMediaQDataFormat);
+ pMediaQ->pMediaQDataFormat = NULL;
+ }
+
+ free(pMediaQ);
+ pMediaQ = NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+ return FALSE;
+}
+
+void openavbMediaQSetMaxLatency(media_q_t *pMediaQ, U32 maxLatencyUsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ);
+
+ if (pMediaQ) {
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ pMediaQInfo->maxLatencyUsec = maxLatencyUsec;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+}
+
+void openavbMediaQSetMaxStaleTail(media_q_t *pMediaQ, U32 maxStaleTailUsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ);
+
+ if (pMediaQ) {
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ pMediaQInfo->maxStaleTailUsec = maxStaleTailUsec;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
+}
+
+media_q_item_t *openavbMediaQHeadLock(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ_DETAIL);
+
+ if (pMediaQ) {
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ if (pMediaQInfo->threadSafeOn) {
+ MEDIAQ_LOCK();
+ }
+ if (pMediaQInfo->itemCount > 0) {
+ if (pMediaQInfo->head > -1) {
+ pMediaQInfo->headLocked = TRUE;
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ // Mutex (LOCK()) if acquired stays locked
+ return &pMediaQInfo->pItems[pMediaQInfo->head];
+ }
+ }
+ if (pMediaQInfo->threadSafeOn) {
+ MEDIAQ_UNLOCK();
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return NULL;
+}
+
+void openavbMediaQHeadUnlock(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ_DETAIL);
+
+ if (pMediaQ) {
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ if (pMediaQInfo->itemCount > 0) {
+ if (pMediaQInfo->head > -1) {
+ pMediaQInfo->headLocked = FALSE;
+ if (pMediaQInfo->threadSafeOn) {
+ MEDIAQ_UNLOCK();
+ }
+ }
+ }
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+}
+
+bool openavbMediaQHeadPush(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ_DETAIL);
+
+ if (pMediaQ) {
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ if (pMediaQInfo->itemCount > 0) {
+ if (pMediaQInfo->head > -1) {
+ media_q_item_t *pHead = &pMediaQInfo->pItems[pMediaQInfo->head];
+
+#if DUMP_HEAD_PUSH
+ media_q_item_t *pMediaQItem = &pMediaQInfo->pItems[pMediaQInfo->head];
+ if (!pFileHeadPush) {
+ char filename[128];
+ sprintf(filename, "headpush_%5.5d.dat", GET_PID());
+ pFileHeadPush = fopen(filename, "wb");
+ }
+ if (pFileHeadPush) {
+ size_t result = fwrite(pMediaQItem->pPubData, 1, pMediaQItem->dataLen, pFileHeadPush);
+ if (result != pMediaQItem->dataLen)
+ printf("ERROR writing head push log");
+ }
+#endif
+
+ // If tail not set, set it now
+ if (pMediaQInfo->tail == -1) {
+ pMediaQInfo->tail = pMediaQInfo->head;
+ }
+
+ pHead->readIdx = 0; // Reset read index
+
+ x_openavbMediaQIncrementHead(pMediaQInfo);
+
+ pMediaQInfo->headLocked = FALSE;
+ if (pMediaQInfo->threadSafeOn) {
+ MEDIAQ_UNLOCK();
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return FALSE;
+}
+
+media_q_item_t* openavbMediaQTailLock(media_q_t *pMediaQ, bool ignoreTimestamp)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ_DETAIL);
+
+ if (!ignoreTimestamp) {
+ x_openavbMediaQPurgeStaleTail(pMediaQ);
+ }
+
+ if (pMediaQ) {
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ if (pMediaQInfo->threadSafeOn) {
+ MEDIAQ_LOCK();
+ }
+ if (pMediaQInfo->itemCount > 0) {
+ if (pMediaQInfo->tail > -1) {
+ media_q_item_t *pTail = &pMediaQInfo->pItems[pMediaQInfo->tail];
+
+ // Check if tail item is ready.
+ if (!ignoreTimestamp) {
+ if (!openavbAvtpTimeIsPast(pTail->pAvtpTime)) {
+ if (pMediaQInfo->threadSafeOn) {
+ MEDIAQ_UNLOCK();
+ }
+ return NULL;
+ }
+ }
+
+ pMediaQInfo->tailLocked = TRUE;
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ // Mutex (LOCK()) if acquired stays locked
+ return pTail;
+ }
+ }
+ if (pMediaQInfo->threadSafeOn) {
+ MEDIAQ_UNLOCK();
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return NULL;
+}
+
+void openavbMediaQTailUnlock(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ_DETAIL);
+
+ if (pMediaQ) {
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ if (pMediaQInfo->itemCount > 0) {
+ if (pMediaQInfo->tail > -1) {
+ pMediaQInfo->tailLocked = FALSE;
+ if (pMediaQInfo->threadSafeOn) {
+ MEDIAQ_UNLOCK();
+ }
+ }
+ }
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+}
+
+bool openavbMediaQTailPull(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ_DETAIL);
+
+ if (pMediaQ) {
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ if (pMediaQInfo->itemCount > 0) {
+ if (pMediaQInfo->tail > -1) {
+ media_q_item_t *pTail = &pMediaQInfo->pItems[pMediaQInfo->tail];
+
+#if DUMP_TAIL_PULL
+ media_q_item_t *pMediaQItem = &pMediaQInfo->pItems[pMediaQInfo->tail];
+ if (!pFileTailPull) {
+ char filename[128];
+ sprintf(filename, "tailpull_%5.5d.dat", GET_PID());
+ pFileTailPull = fopen(filename, "wb");
+ }
+ if (pFileTailPull) {
+ size_t result = fwrite(pMediaQItem->pPubData, 1, pMediaQItem->dataLen, pFileTailPull);
+ if (result != pMediaQItem->dataLen)
+ printf("ERROR writing tail pull log");
+ }
+#endif
+
+ // If head not set, set it now
+ if (pMediaQInfo->head == -1) {
+ pMediaQInfo->head = pMediaQInfo->tail;
+ }
+
+ pTail->readIdx = 0; // Reset read index
+ pTail->dataLen = 0; // Clears out the data
+
+ x_openavbMediaQIncrementTail(pMediaQInfo);
+
+ pMediaQInfo->tailLocked = FALSE;
+ if (pMediaQInfo->threadSafeOn) {
+ MEDIAQ_UNLOCK();
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return FALSE;
+}
+
+bool openavbMediaQTailItemTake(media_q_t *pMediaQ, media_q_item_t* pItem)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ_DETAIL);
+
+ if (pMediaQ && pItem) {
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ if (pMediaQInfo->itemCount > 0) {
+ if (pMediaQInfo->tail > -1) {
+
+ x_openavbMediaQIncrementTail(pMediaQInfo);
+
+ pItem->taken = TRUE;
+ pMediaQInfo->tailLocked = FALSE;
+ if (pMediaQInfo->threadSafeOn) {
+ MEDIAQ_UNLOCK();
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return FALSE;
+}
+
+bool openavbMediaQTailItemGive(media_q_t *pMediaQ, media_q_item_t* pItem)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ_DETAIL);
+
+ if (pItem) {
+ pItem->taken = FALSE;
+ pItem->readIdx = 0; // Reset read index
+ pItem->dataLen = 0; // Clears out the data
+
+ if (pMediaQ) {
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ if (pMediaQInfo->threadSafeOn) {
+ MEDIAQ_LOCK();
+ }
+ if (pMediaQInfo->itemCount > 0) {
+ if (pMediaQInfo->head == -1) {
+ // Transition from full mediaq to an available item slot. Find this item that was just give back
+ int i1;
+ for (i1 = 0; i1 < pMediaQInfo->itemCount; i1++)
+ {
+ if (!pMediaQInfo->pItems[i1].taken) {
+ pMediaQInfo->head = i1;
+ break;
+ }
+ }
+ }
+ }
+ if (pMediaQInfo->threadSafeOn) {
+ MEDIAQ_UNLOCK();
+ }
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return TRUE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return FALSE;
+}
+
+
+bool openavbMediaQUsecTillTail(media_q_t *pMediaQ, U32 *pUsecTill)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ_DETAIL);
+
+ if (pMediaQ && pUsecTill) {
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ if (pMediaQInfo->itemCount > 0) {
+ if (pMediaQInfo->tail > -1) {
+ media_q_item_t *pTail = &pMediaQInfo->pItems[pMediaQInfo->tail];
+
+ U32 usecTill;
+
+ if (openavbAvtpTimeUsecTill(pTail->pAvtpTime, &usecTill)) {
+ *pUsecTill = usecTill;
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return FALSE;
+}
+
+bool openavbMediaQIsAvailableBytes(media_q_t *pMediaQ, U32 bytes, bool ignoreTimestamp)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ_DETAIL);
+
+ if (!ignoreTimestamp) {
+ x_openavbMediaQPurgeStaleTail(pMediaQ);
+ }
+
+ int byteCnt = 0;
+
+ if (pMediaQ) {
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ if (pMediaQInfo->itemCount > 0) {
+ if (pMediaQInfo->tail > -1) {
+ // Check if tail item is ready.
+ int tailIdx = pMediaQInfo->tail;
+ int endIdx = pMediaQInfo->head > -1 ? pMediaQInfo->head : pMediaQInfo->tail;
+ if (ignoreTimestamp) {
+ while (1) {
+ media_q_item_t *pTail = &pMediaQInfo->pItems[tailIdx];
+
+ if (!pTail->taken) {
+ byteCnt += pTail->dataLen - pTail->readIdx;
+
+ if (byteCnt >= bytes) {
+ // Met the available byte count
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return TRUE;
+ }
+ }
+
+ tailIdx++;
+ if (tailIdx >= pMediaQInfo->itemCount)
+ tailIdx = 0;
+ if (tailIdx == endIdx)
+ break;
+ }
+ }
+ else {
+ U64 nSecTime;
+ CLOCK_GETTIME64(OPENAVB_CLOCK_WALLTIME, &nSecTime);
+ while (1) {
+ media_q_item_t *pTail = &pMediaQInfo->pItems[tailIdx];
+ assert(pTail);
+
+ if (!pTail->taken) {
+ if (!openavbAvtpTimeIsPastTime(pTail->pAvtpTime, nSecTime))
+ break;
+
+ byteCnt += pTail->dataLen - pTail->readIdx;
+
+ if (byteCnt >= bytes) {
+ // Met the available byte count
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return TRUE;
+ }
+ }
+
+ tailIdx++;
+ if (tailIdx >= pMediaQInfo->itemCount)
+ tailIdx = 0;
+ if (tailIdx == endIdx)
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return FALSE;
+}
+
+U32 openavbMediaQCountItems(media_q_t *pMediaQ, bool ignoreTimestamp)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ_DETAIL);
+
+ if (!ignoreTimestamp) {
+ x_openavbMediaQPurgeStaleTail(pMediaQ);
+ }
+
+ U32 itemCnt = 0;
+
+ if (pMediaQ) {
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ if (pMediaQInfo->itemCount > 0) {
+ if (pMediaQInfo->tail > -1) {
+ // Check if tail item is ready.
+ int tailIdx = pMediaQInfo->tail;
+ if (ignoreTimestamp) {
+ while (1) {
+ media_q_item_t *pTail = &pMediaQInfo->pItems[tailIdx];
+
+ if (!pTail->taken) {
+ itemCnt++;
+ }
+
+ tailIdx++;
+ if (tailIdx >= pMediaQInfo->itemCount)
+ tailIdx = 0;
+ if (tailIdx == pMediaQInfo->head)
+ break;
+ if (itemCnt >= pMediaQInfo->itemCount)
+ break;
+ }
+ }
+ else {
+ U64 nSecTime;
+ CLOCK_GETTIME64(OPENAVB_CLOCK_WALLTIME, &nSecTime);
+ while (1) {
+ media_q_item_t *pTail = &pMediaQInfo->pItems[tailIdx];
+
+ if (!pTail->taken) {
+ if (!openavbAvtpTimeIsPastTime(pTail->pAvtpTime, nSecTime))
+ break;
+
+ itemCnt++;
+ }
+
+ tailIdx++;
+ if (tailIdx >= pMediaQInfo->itemCount)
+ tailIdx = 0;
+ if (tailIdx == pMediaQInfo->head)
+ break;
+ if (itemCnt >= pMediaQInfo->itemCount)
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return itemCnt;
+}
+
+bool openavbMediaQAnyReadyItems(media_q_t *pMediaQ, bool ignoreTimestamp)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ_DETAIL);
+
+ if (!ignoreTimestamp) {
+ x_openavbMediaQPurgeStaleTail(pMediaQ);
+ }
+
+ if (pMediaQ) {
+ if (pMediaQ->pPvtMediaQInfo) {
+ media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
+ if (pMediaQInfo->itemCount > 0) {
+ if (pMediaQInfo->tail > -1) {
+ // Check if tail item is ready.
+ int tailIdx = pMediaQInfo->tail;
+ if (ignoreTimestamp) {
+ media_q_item_t *pTail = &pMediaQInfo->pItems[tailIdx];
+
+ if (!pTail->taken) {
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return TRUE;
+ }
+ }
+ else {
+ U64 nSecTime;
+ CLOCK_GETTIME64(OPENAVB_CLOCK_WALLTIME, &nSecTime);
+ media_q_item_t *pTail = &pMediaQInfo->pItems[tailIdx];
+
+ if (!pTail->taken) {
+ if (openavbAvtpTimeIsPastTime(pTail->pAvtpTime, nSecTime)) {
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
+ return FALSE;
+}
+
diff --git a/lib/avtp_pipeline/mediaq/openavb_mediaq.h b/lib/avtp_pipeline/mediaq/openavb_mediaq.h
new file mode 100644
index 00000000..4a2c031c
--- /dev/null
+++ b/lib/avtp_pipeline/mediaq/openavb_mediaq.h
@@ -0,0 +1,60 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Circular queue for passing data between interfaces
+* and mappers.
+*/
+
+#ifndef OPENAVB_MEDIA_Q_H
+#define OPENAVB_MEDIA_Q_H 1
+
+#include "openavb_mediaq_pub.h"
+
+// These are Public APIs. Details in openavb_mediaq_pub.h
+// However the declarations are included here for easy internal use.
+media_q_t* openavbMediaQCreate();
+void openavbMediaQThreadSafeOn(media_q_t *pMediaQ);
+bool openavbMediaQSetSize(media_q_t *pMediaQ, int itemCount, int itemSize);
+bool openavbMediaQAllocItemMapData(media_q_t *pMediaQ, int itemPubMapSize, int itemPvtMapSize);
+bool openavbMediaQAllocItemIntfData(media_q_t *pMediaQ, int itemIntfSize);
+bool openavbMediaQDelete(media_q_t *pMediaQ);
+void openavbMediaQSetMaxLatency(media_q_t *pMediaQ, U32 maxLatencyUsec);
+void openavbMediaQSetMaxStaleTail(media_q_t *pMediaQ, U32 maxStaleTailUsec);
+media_q_item_t *openavbMediaQHeadLock(media_q_t *pMediaQ);
+void openavbMediaQHeadUnlock(media_q_t *pMediaQ);
+bool openavbMediaQHeadPush(media_q_t *pMediaQ);
+media_q_item_t* openavbMediaQTailLock(media_q_t *pMediaQ, bool ignoreTimestamp);
+void openavbMediaQTailUnlock(media_q_t *pMediaQ);
+bool openavbMediaQTailPull(media_q_t *pMediaQ);
+bool openavbMediaQUsecTillTail(media_q_t *pMediaQ, U32 *pUsecTill);
+bool openavbMediaQIsAvailableBytes(media_q_t *pMediaQ, U32 bytes, bool ignoreTimestamp);
+
+#endif // OPENAVB_MEDIA_Q_H
diff --git a/lib/avtp_pipeline/mediaq/openavb_mediaq_pub.h b/lib/avtp_pipeline/mediaq/openavb_mediaq_pub.h
new file mode 100644
index 00000000..4e479f9d
--- /dev/null
+++ b/lib/avtp_pipeline/mediaq/openavb_mediaq_pub.h
@@ -0,0 +1,365 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Circular queue for passing data between interfaces
+* and mappers.
+*/
+
+#ifndef OPENAVB_MEDIA_Q_PUB_H
+#define OPENAVB_MEDIA_Q_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_avtp_time_pub.h"
+
+/** \file
+ * Media Queue.
+ * Circular queue for passing data between interfaces and mappers.
+ */
+
+/** Media Queue Item structure.
+ */
+typedef struct {
+ /// In a talker process this is the capture time. In a listener process this
+ /// is the presentation time (AVTP timestamp).
+ avtp_time_t *pAvtpTime;
+
+ /// The structure of this memory will be defined per mapper in a public
+ /// header. This is the common data payload format
+ /// that mappers and interfaces will share.
+ void *pPubData;
+
+ /// Read index. User managed. It will be reset to zero when the item is
+ /// pushed and pulled.
+ U32 readIdx;
+
+ /// Length of data in item.
+ U32 dataLen;
+
+ /// Size of the data item
+ U32 itemSize;
+
+ /// Flag indicating mediaQ item has been taken by a call to openavbMediaQTailItemTake()
+ bool taken;
+
+ /// Public extra map data
+ void *pPubMapData;
+
+ /// For use internally by mapping modules. Often may not be used.
+ void *pPvtMapData;
+
+ /// For use internally by the interface. Often may not be used.
+ void *pPvtIntfData;
+} media_q_item_t;
+
+/** Media Queue structure.
+ * The media queue is the conduit between interface modules and mapping modules.
+ * It is internally implemented as a circular FIFO container.
+ * \see \ref working_with_mediaq
+ */
+typedef struct {
+ ///////////////////////////
+ // Shared properties
+ ///////////////////////////
+
+ /// Common name for mapping data format. Set by mapping modules and used by
+ /// interface modules to validate
+ /// the media queue data format compatibility.
+ char *pMediaQDataFormat;
+
+ /// Defined per mapper in the public header.
+ /// The structure of this memory area will be used only the mapper module
+ /// and interface module.
+ void *pPubMapInfo;
+
+ ///////////////////////////
+ // Private properties
+ /// \privatesection
+ ///////////////////////////
+
+ /// For use internally in the media queue
+ void *pPvtMediaQInfo;
+
+ /// For use internally by the mapper
+ void *pPvtMapInfo;
+
+ /// For use internally by the interface
+ void *pPvtIntfInfo;
+} media_q_t;
+
+/** Create a media queue.
+ *
+ * Allocate a media queue structure. Only mapping modules will use this call.
+ *
+ * \return A pointer to a media queue structure. NULL if the creation fails
+ */
+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
+ * 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.
+ *
+ * \param pMediaQ A pointer to the media_q_t structure
+ */
+void openavbMediaQThreadSafeOn(media_q_t *pMediaQ);
+
+/** Set size of media queue.
+ *
+ * Pre-allocate all the items for the media queue. Once allocated the item
+ * storage will be reused as items are added and removed from the queue. Only
+ * mapping modules will use this call. This must be called before using the
+ * MediaQ.
+ *
+ * \param pMediaQ A pointer to the media_q_t structure
+ * \param itemCount Maximum number of items that the queue will hold. These are
+ * pre-allocated
+ * \param itemSize The pre-allocated size of a media queue item
+ * \return TRUE on success or FALSE on failure
+ *
+ * \warning This must be called before using the MediaQ
+ */
+bool openavbMediaQSetSize(media_q_t *pMediaQ, int itemCount, int itemSize);
+
+/** Alloc item map data.
+ *
+ * Items in the media queue may also have per-item data that is managed by the
+ * mapping modules. This function allows mapping modules to specify this
+ * storage.
+ * Only mapping modules will use this call. This must be called before using the
+ * media queue.
+ *
+ * \param pMediaQ A pointer to the media_q_t structure
+ * \param itemPubMapSize The size of the public (shared) per-items data that
+ * will be allocated. Typically this is the size of a structure that is
+ * declared in a public header file associated with the mapping module.
+ * \param itemPvtMapSize The size of the private per-items data that will be
+ * allocated. The structure of this area will not be shared outside of
+ * the mapping module
+ * \return TRUE on success or FALSE on failure
+ *
+ * \warning This must be called before using the MediaQ
+ */
+bool openavbMediaQAllocItemMapData(media_q_t *pMediaQ, int itemPubMapSize, int itemPvtMapSize);
+
+/** Alloc item interface data.
+ *
+ * Items in the media queue may also have per-item data that is managed by the
+ * interface modules. This function allows interface modules to specify this
+ * storage. This must be called before using the media queue.
+ *
+ * \param pMediaQ A pointer to the media_q_t structure
+ * \param itemIntfSize The size of the per-items data to allocate for use by the
+ * interface module
+ * \return TRUE on success or FALSE on failure
+ *
+ * \warning This must be called before using the MediaQ
+ */
+bool openavbMediaQAllocItemIntfData(media_q_t *pMediaQ, int itemIntfSize);
+
+/** Destroy the queue.
+ *
+ * The media queue passed in will be deleted. This includes all allocated memory
+ * both for mapping modules and interface modules. Only mapping modules will use
+ * this call.
+ *
+ * \param pMediaQ A pointer to the media_q_t structure
+ * \return TRUE on success or FALSE on failure
+ */
+bool openavbMediaQDelete(media_q_t *pMediaQ);
+
+/** Sets the maximum latency expected.
+ *
+ * The maximum latency will be set. This value is used by the media queue to
+ * help determine if a media queue item is ready to be released to the listener
+ * interface module for presentation. Typically the mapping module will call
+ * this function with a max latency value derived from the max_latency
+ * configuration value.
+ *
+ * \param pMediaQ A pointer to the media_q_t structure
+ * \param maxLatencyUsec The maximum latency.
+ */
+void openavbMediaQSetMaxLatency(media_q_t *pMediaQ, U32 maxLatencyUsec);
+
+/** Sets the maximum stale tail.
+ *
+ * Used to purge media queue items that are too old.
+ *
+ * \param pMediaQ A pointer to the media_q_t structure
+ * \param maxStaleTailUsec tail element purge threshold in microseconds
+ */
+void openavbMediaQSetMaxStaleTail(media_q_t *pMediaQ, U32 maxStaleTailUsec);
+
+/** Get pointer to the head item and lock it.
+ *
+ * Get the storage location for the next item that can be added to the circle
+ * queue. Once the function is called the item will remained locked until
+ * unlocked or pushed. The lock remains valid across callbacks. An interface
+ * module will use this function when running as a talker to add a new media
+ * element to the queue thereby making it available to the mapping module.
+ *
+ * \param pMediaQ A pointer to the media_q_t structure.
+ * \return A pointer to a media queue item. Returns NULL if head item storage
+ * isn't available.
+ */
+media_q_item_t *openavbMediaQHeadLock(media_q_t *pMediaQ);
+
+/** Unlock the head item.
+ *
+ * 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
+ * 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.
+ *
+ * \param pMediaQ A pointer to the media_q_t structure.
+ */
+void openavbMediaQHeadUnlock(media_q_t *pMediaQ);
+
+/** Unlock the head item and make it available.
+ *
+ * Unlock a locked media queue item from the head of the queue and make it
+ * available for use in the queue to be accessed with the tail function calls.
+ * An interface module will use this function when running as a talker after it
+ * has locked the head item and added data to the item storage area.
+ *
+ * \param pMediaQ A pointer to the media_q_t structure.
+ * \return Returns TRUE on success or FALSE on failure.
+ */
+bool openavbMediaQHeadPush(media_q_t *pMediaQ);
+
+/** Get pointer to the tail item and lock it.
+ *
+ * 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.
+ * At some point after this function call the item must be unlocked with either
+ * openavbMediaQTailUnlockor openavbMediaQTailPull on the same callback or a subsequent
+ * callback.
+ *
+ * \param pMediaQ A pointer to the media_q_t structure.
+ * \param ignoreTimestamp If TRUE ignore the tail item timestamp making the tail
+ * item immediately available.
+ * \return A pointer to a media queue item. Returns NULL if a tail item isn't
+ * available.
+ */
+media_q_item_t* openavbMediaQTailLock(media_q_t *pMediaQ, bool ignoreTimestamp);
+
+/** Unlock the tail item without removing it from the queue.
+ *
+ * Unlock a media queue item that was previously locked with openavbMediaQTailLock.
+ * The item will not be removed from the tail of the media queue.
+ *
+ * \param pMediaQ A pointer to the media_q_t structure.
+ */
+void openavbMediaQTailUnlock(media_q_t *pMediaQ);
+
+/** Unlock the tail item and remove it from the queue.
+ *
+ * Unlock a media queue item that was previously locked with openavbMediaQTailLock
+ * and remove it from the media queue.
+ *
+ * \param pMediaQ A pointer to the media_q_t structure.
+ * \return Returns TRUE on success or FALSE on failure.
+ */
+bool openavbMediaQTailPull(media_q_t *pMediaQ);
+
+/** Take ownership from the MediaQ of an item.
+ *
+ * Take ownership from the MediaQ of an item previously locked
+ * with openavbMediaQTailLock. Will advance the tail. Used in place
+ * of openavbMediaQTailPull()
+ *
+ * \param pMediaQ A pointer to the media_q_t structure.
+ * \param pItem MediaQ item to take ownership of.
+ * \return Returns TRUE on success or FALSE on failure.
+ */
+bool openavbMediaQTailItemTake(media_q_t *pMediaQ, media_q_item_t* pItem);
+
+/** Give itme ownership back to the MediaQ.
+ *
+ * Give ownership back to the MediaQ of an item previously taken
+ * with openavbMediaQTailItemTake()
+ *
+ * \param pMediaQ A pointer to the media_q_t structure.
+ * \param pItem MediaQ item to give back tot he MediaA.
+ * \return Returns TRUE on success or FALSE on failure.
+ */
+bool openavbMediaQTailItemGive(media_q_t *pMediaQ, media_q_item_t* pItem);
+
+/** Get microseconds until tail is ready.
+ *
+ * \param pMediaQ A pointer to the media_q_t structure.
+ * \param pUsecTill An output parameter that is set with the number of
+ * microseconds until the tail item will be available.
+ * \return Return FALSE if greater than 5 seconds otherwise TRUE.
+ */
+bool openavbMediaQUsecTillTail(media_q_t *pMediaQ, U32 *pUsecTill);
+
+/** Check if the number of bytes are available.
+ *
+ * Checks were the given media queue contains bytes, returns true if it does
+ * false otherwise.
+ *
+ * \param pMediaQ A pointer to the media_q_t structure.
+ * \param bytes Number of bytes expected in media queue
+ * \param ignoreTimestamp Ignore timestamp for byte accumulation.
+ * \return TRUE if bytes are available in pMediaQ; FALSE if bytes not available
+ * in pMediaQ.
+ */
+bool openavbMediaQIsAvailableBytes(media_q_t *pMediaQ, U32 bytes, bool ignoreTimestamp);
+
+/** Count 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.
+ * \return The number of available MediaA items.
+ */
+U32 openavbMediaQCountItems(media_q_t *pMediaQ, bool ignoreTimestamp);
+
+/** Check if there are any ready MediaQ items.
+ *
+ * Check if there are any ready MediaQ items.
+ *
+ * \param pMediaQ A pointer to the media_q_t structure.
+ * \param ignoreTimestamp Ignore timestamp for checking
+ * \return TRUE if there is at least 1 MediaQ item available
+ * otherwise FALSE.
+ */
+bool openavbMediaQAnyReadyItems(media_q_t *pMediaQ, bool ignoreTimestamp);
+
+#endif // OPENAVB_MEDIA_Q_PUB_H
diff --git a/lib/avtp_pipeline/openavb_common/README.TXT b/lib/avtp_pipeline/openavb_common/README.TXT
new file mode 100644
index 00000000..23fef516
--- /dev/null
+++ b/lib/avtp_pipeline/openavb_common/README.TXT
@@ -0,0 +1,9 @@
+The files in this folder originated in examples/common
+
+These were copied here because of inconsistancies in implementation of these functions in different examples.
+
+See the each source file for the actual license.
+
+TODO_OPENAVB: It should be considered if these common support functions in avb.c,
+listener_mrp_client.c and talker_mrp_client.c should be moved to a true commmon source
+area in OpenAVB and outside of the examples folder.
diff --git a/lib/avtp_pipeline/openavb_common/avb.c b/lib/avtp_pipeline/openavb_common/avb.c
new file mode 100644
index 00000000..6265858b
--- /dev/null
+++ b/lib/avtp_pipeline/openavb_common/avb.c
@@ -0,0 +1,576 @@
+ /*
+ * Copyright (c) <2013>, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+
+#include <linux/if.h>
+
+#include <netinet/in.h>
+
+#include <pci/pci.h>
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include "avb.h"
+
+int pci_connect(device_t * igb_dev)
+{
+ char devpath[IGB_BIND_NAMESZ];
+ struct pci_access *pacc;
+ struct pci_dev *dev;
+ int err;
+
+ memset(igb_dev, 0, sizeof(device_t));
+
+ pacc = pci_alloc();
+
+ pci_init(pacc);
+
+ pci_scan_bus(pacc);
+
+ for (dev = pacc->devices; dev; dev = dev->next) {
+ pci_fill_info(dev,
+ PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS);
+ igb_dev->pci_vendor_id = dev->vendor_id;
+ igb_dev->pci_device_id = dev->device_id;
+ igb_dev->domain = dev->domain;
+ igb_dev->bus = dev->bus;
+ igb_dev->dev = dev->dev;
+ igb_dev->func = dev->func;
+ snprintf(devpath, IGB_BIND_NAMESZ, "%04x:%02x:%02x.%d",
+ dev->domain, dev->bus, dev->dev, dev->func);
+ err = igb_probe(igb_dev);
+ if (err)
+ continue;
+
+ printf("attaching to %s\n", devpath);
+ err = igb_attach(devpath, igb_dev);
+ if (err) {
+ printf("attach failed! (%s)\n", strerror(err));
+ continue;
+ }
+
+ err = igb_attach_tx(igb_dev);
+ if (err) {
+ printf("attach_tx failed! (%s)\n", strerror(err));
+ continue;
+ }
+
+ goto out;
+ }
+
+ pci_cleanup(pacc);
+ return ENXIO;
+
+out: pci_cleanup(pacc);
+
+ return 0;
+}
+
+int gptpinit(int *shm_fd, char **memory_offset_buffer)
+{
+ *shm_fd = shm_open(SHM_NAME, O_RDWR, 0);
+ if (*shm_fd == -1) {
+ perror("shm_open()");
+ return false;
+ }
+ *memory_offset_buffer =
+ (char *)mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
+ *shm_fd, 0);
+ if (*memory_offset_buffer == (char *)-1) {
+ perror("mmap()");
+ *memory_offset_buffer = NULL;
+ shm_unlink(SHM_NAME);
+ return false;
+ }
+ return true;
+}
+
+void gptpdeinit(int shm_fd, char *memory_offset_buffer)
+{
+ if (memory_offset_buffer != NULL) {
+ munmap(memory_offset_buffer, SHM_SIZE);
+ }
+ if (shm_fd != -1) {
+ close(shm_fd);
+ }
+}
+
+int gptpscaling(gPtpTimeData * td, char *memory_offset_buffer)
+{
+ if (td == NULL)
+ return true;
+
+ pthread_mutex_lock((pthread_mutex_t *) memory_offset_buffer);
+ memcpy(td, memory_offset_buffer + sizeof(pthread_mutex_t), sizeof(*td));
+ pthread_mutex_unlock((pthread_mutex_t *) memory_offset_buffer);
+
+ return true;
+}
+
+bool gptplocaltime(const gPtpTimeData * td, uint64_t* now_local)
+{
+ struct timespec sys_time;
+ uint64_t now_system;
+ uint64_t system_time;
+ int64_t delta_local;
+ int64_t delta_system;
+
+ if (!td || !now_local)
+ return false;
+
+ if (clock_gettime(CLOCK_REALTIME, &sys_time) != 0)
+ return false;
+
+ now_system = (uint64_t)sys_time.tv_sec * 1000000000ULL + (uint64_t)sys_time.tv_nsec;
+
+ system_time = td->local_time + td->ls_phoffset;
+ delta_system = now_system - system_time;
+ delta_local = td->ls_freqoffset * delta_system;
+ *now_local = td->local_time + delta_local;
+
+ return true;
+}
+
+/* setters & getters for seventeen22_header */
+void avb_set_1722_cd_indicator(seventeen22_header *h1722, uint64_t cd_indicator)
+{
+ h1722->cd_indicator = cd_indicator;
+}
+
+uint64_t avb_get_1722_cd_indicator(seventeen22_header *h1722)
+{
+ return h1722->cd_indicator;
+}
+
+void avb_set_1722_subtype(seventeen22_header *h1722, uint64_t subtype)
+{
+ h1722->subtype = subtype;
+}
+
+uint64_t avb_get_1722_subtype(seventeen22_header *h1722)
+{
+ return h1722->subtype;
+}
+
+void avb_set_1722_sid_valid(seventeen22_header *h1722, uint64_t sid_valid)
+{
+ h1722->sid_valid = sid_valid;
+}
+
+uint64_t avb_get_1722_sid_valid(seventeen22_header *h1722)
+{
+ return h1722->sid_valid;
+}
+
+void avb_set_1722_version(seventeen22_header *h1722, uint64_t version)
+{
+ h1722->version = version;
+}
+
+uint64_t avb_get_1722_version(seventeen22_header *h1722)
+{
+ return h1722->version;
+}
+
+void avb_set_1722_reset(seventeen22_header *h1722, uint64_t reset)
+{
+ h1722->reset = reset;
+}
+
+uint64_t avb_get_1722_reset(seventeen22_header *h1722)
+{
+ return h1722->reset;
+}
+
+void avb_set_1722_reserved0(seventeen22_header *h1722, uint64_t reserved0)
+{
+ h1722->reserved0 = reserved0;
+}
+
+uint64_t avb_get_1722_reserved0(seventeen22_header *h1722)
+{
+ return h1722->reserved0;
+}
+
+void avb_set_1722_gateway_valid(seventeen22_header *h1722, uint64_t gateway_valid)
+{
+ h1722->gateway_valid = gateway_valid;
+}
+
+uint64_t avb_get_1722_gateway_valid(seventeen22_header *h1722)
+{
+ return h1722->gateway_valid;
+}
+
+void avb_set_1722_timestamp_valid(seventeen22_header *h1722, uint64_t timestamp_valid)
+{
+ h1722->timestamp_valid = timestamp_valid;
+}
+
+uint64_t avb_get_1722_timestamp_valid(seventeen22_header *h1722)
+{
+ return h1722->timestamp_valid;
+}
+
+void avb_set_1722_reserved1(seventeen22_header *h1722, uint64_t reserved1)
+{
+ h1722->reserved1 = reserved1;
+}
+
+uint64_t avb_get_1722_reserved1(seventeen22_header *h1722)
+{
+ return h1722->reserved1;
+}
+
+void avb_set_1722_stream_id(seventeen22_header *h1722, uint64_t stream_id)
+{
+ h1722->stream_id = stream_id;
+}
+
+uint64_t avb_get_1722_stream_id(seventeen22_header *h1722)
+{
+ return h1722->stream_id;
+}
+
+void avb_set_1722_seq_number(seventeen22_header *h1722, uint64_t seq_number)
+{
+ h1722->seq_number = seq_number;
+}
+
+uint64_t avb_get_1722_seq_number(seventeen22_header *h1722)
+{
+ return h1722->seq_number;
+}
+
+void avb_set_1722_timestamp_uncertain(seventeen22_header *h1722, uint64_t timestamp_uncertain)
+{
+ h1722->timestamp_uncertain = timestamp_uncertain;
+}
+
+uint64_t avb_get_1722_timestamp_uncertain(seventeen22_header *h1722)
+{
+ return h1722->timestamp_uncertain;
+}
+
+void avb_set_1722_timestamp(seventeen22_header *h1722, uint64_t timestamp)
+{
+ h1722->timestamp = timestamp;
+}
+
+uint64_t avb_get_1722_timestamp(seventeen22_header *h1722)
+{
+ return h1722->timestamp;
+}
+
+void avb_set_1722_gateway_info(seventeen22_header *h1722, uint64_t gateway_info)
+{
+ h1722->gateway_info = gateway_info;
+}
+
+uint64_t avb_get_1722_gateway_info(seventeen22_header *h1722)
+{
+ return h1722->gateway_info;
+}
+
+void avb_set_1722_length(seventeen22_header *h1722, uint64_t length)
+{
+ h1722->length = length;
+}
+
+uint64_t avb_get_1722_length(seventeen22_header *h1722)
+{
+ return h1722->length;
+}
+
+/* setters & getters for six1883_header */
+
+void avb_set_61883_packet_channel(six1883_header *h61883, uint16_t packet_channel)
+{
+ h61883->packet_channel = packet_channel;
+}
+
+uint16_t avb_get_61883_length(six1883_header *h61883)
+{
+ return h61883->packet_channel;
+}
+
+void avb_set_61883_format_tag(six1883_header *h61883, uint16_t format_tag)
+{
+ h61883->format_tag = format_tag;
+}
+
+uint16_t avb_get_61883_format_tag(six1883_header *h61883)
+{
+ return h61883->format_tag;
+}
+
+void avb_set_61883_app_control(six1883_header *h61883, uint16_t app_control)
+{
+ h61883->app_control = app_control;
+}
+
+uint16_t avb_get_61883_app_control(six1883_header *h61883)
+{
+ return h61883->app_control;
+}
+
+void avb_set_61883_packet_tcode(six1883_header *h61883, uint16_t packet_tcode)
+{
+ h61883->packet_tcode = packet_tcode;
+}
+
+uint16_t avb_get_61883_packet_tcode(six1883_header *h61883)
+{
+ return h61883->packet_tcode;
+}
+
+void avb_set_61883_source_id(six1883_header *h61883, uint16_t source_id)
+{
+ h61883->source_id = source_id;
+}
+
+uint16_t avb_get_61883_source_id(six1883_header *h61883)
+{
+ return h61883->source_id;
+}
+
+void avb_set_61883_reserved0(six1883_header *h61883, uint16_t reserved0)
+{
+ h61883->reserved0 = reserved0;
+}
+
+uint16_t avb_get_61883_reserved0(six1883_header *h61883)
+{
+ return h61883->reserved0;
+}
+
+void avb_set_61883_data_block_size(six1883_header *h61883, uint16_t data_block_size)
+{
+ h61883->data_block_size = data_block_size;
+}
+
+uint16_t avb_get_61883_data_block_size(six1883_header *h61883)
+{
+ return h61883->data_block_size;
+}
+
+void avb_set_61883_reserved1(six1883_header *h61883, uint16_t reserved1)
+{
+ h61883->reserved1 = reserved1;
+}
+
+uint16_t avb_get_61883_reserved1(six1883_header *h61883)
+{
+ return h61883->reserved1;
+}
+
+void avb_set_61883_source_packet_header(six1883_header *h61883, uint16_t source_packet_header)
+{
+ h61883->source_packet_header = source_packet_header;
+}
+
+uint16_t avb_get_61883_source_packet_header(six1883_header *h61883)
+{
+ return h61883->source_packet_header;
+}
+
+void avb_set_61883_quadlet_padding_count(six1883_header *h61883, uint16_t quadlet_padding_count)
+{
+ h61883->quadlet_padding_count = quadlet_padding_count;
+}
+
+uint16_t avb_get_61883_quadlet_padding_count(six1883_header *h61883)
+{
+ return h61883->quadlet_padding_count;
+}
+
+void avb_set_61883_fraction_number(six1883_header *h61883, uint16_t fraction_number)
+{
+ h61883->fraction_number = fraction_number;
+}
+
+uint16_t avb_get_61883_fraction_number(six1883_header *h61883)
+{
+ return h61883->fraction_number;
+}
+
+void avb_set_61883_data_block_continuity(six1883_header *h61883, uint16_t data_block_continuity)
+{
+ h61883->data_block_continuity = data_block_continuity;
+}
+
+uint16_t avb_get_61883_data_block_continuity(six1883_header *h61883)
+{
+ return h61883->data_block_continuity;
+}
+
+void avb_set_61883_format_id(six1883_header *h61883, uint16_t format_id)
+{
+ h61883->format_id = format_id;
+}
+
+uint16_t avb_get_61883_format_id(six1883_header *h61883)
+{
+ return h61883->format_id;
+}
+
+void avb_set_61883_eoh(six1883_header *h61883, uint16_t eoh)
+{
+ h61883->eoh = eoh;
+}
+
+uint16_t avb_get_61883_eoh(six1883_header *h61883)
+{
+ return h61883->eoh;
+}
+
+void avb_set_61883_format_dependent_field(six1883_header *h61883, uint16_t format_dependent_field)
+{
+ h61883->format_dependent_field = format_dependent_field;
+}
+
+uint16_t avb_get_61883_format_dependent_field(six1883_header *h61883)
+{
+ return h61883->format_dependent_field;
+}
+
+void avb_set_61883_syt(six1883_header *h61883, uint16_t syt)
+{
+ h61883->syt = syt;
+}
+
+uint16_t avb_get_61883_syt(six1883_header *h61883)
+{
+ return h61883->syt;
+}
+
+void * avb_create_packet(uint32_t payload_len)
+{
+ void *avb_packet = NULL;
+ uint32_t size;
+
+ size = sizeof(six1883_header);
+ size += sizeof(eth_header) + sizeof(seventeen22_header) + payload_len;
+
+ avb_packet = calloc(size, sizeof(uint8_t));
+ if (!avb_packet)
+ return NULL;
+
+ return avb_packet;
+}
+
+void avb_initialize_h1722_to_defaults(seventeen22_header *h1722)
+{
+ avb_set_1722_subtype(h1722, 0x0);
+ avb_set_1722_cd_indicator(h1722, 0x0);
+ avb_set_1722_timestamp_valid(h1722, 0x0);
+ avb_set_1722_gateway_valid(h1722, 0x0);
+ avb_set_1722_reserved0(h1722, 0x0);
+ avb_set_1722_sid_valid(h1722, 0x0);
+ avb_set_1722_reset(h1722, 0x0);
+ avb_set_1722_version(h1722, 0x0);
+ avb_set_1722_sid_valid(h1722, 0x0);
+ avb_set_1722_timestamp_uncertain(h1722, 0x0);
+ avb_set_1722_reserved1(h1722, 0x0);
+ avb_set_1722_timestamp(h1722, 0x0);
+ avb_set_1722_gateway_info(h1722, 0x0);
+ avb_set_1722_length(h1722, 0x0);
+}
+
+void avb_initialize_61883_to_defaults(six1883_header *h61883)
+{
+ avb_set_61883_packet_channel(h61883, 0x0);
+ avb_set_61883_format_tag(h61883, 0x0);
+ avb_set_61883_app_control(h61883, 0x0);
+ avb_set_61883_packet_tcode(h61883, 0x0);
+ avb_set_61883_source_id(h61883, 0x0);
+ avb_set_61883_reserved0(h61883, 0x0);
+ avb_set_61883_data_block_size(h61883, 0x0);
+ avb_set_61883_reserved1(h61883, 0x0);
+ avb_set_61883_source_packet_header(h61883, 0x0);
+ avb_set_61883_quadlet_padding_count(h61883, 0x0);
+ avb_set_61883_fraction_number(h61883, 0x0);
+ avb_set_61883_data_block_continuity(h61883, 0x0);
+ avb_set_61883_format_id(h61883, 0x0);
+ avb_set_61883_eoh(h61883, 0x0);
+ avb_set_61883_format_dependent_field(h61883, 0x0);
+ avb_set_61883_syt(h61883, 0x0);
+}
+
+int32_t avb_get_iface_mac_address(int8_t *iface, uint8_t *addr)
+{
+ struct ifreq ifreq;
+ int fd, ret;
+
+ /* Create a socket */
+ fd = socket(PF_PACKET, SOCK_RAW, htons(0x800));
+ if (fd < 0)
+ return -1;
+
+ memset(&ifreq, 0, sizeof(ifreq));
+
+ strncpy(ifreq.ifr_name, (const char*)iface, sizeof(ifreq.ifr_name));
+ ret = ioctl(fd, SIOCGIFHWADDR, &ifreq);
+ if (ret < 0) {
+ close(fd);
+ return -1;
+ }
+
+ memcpy(addr, ifreq.ifr_hwaddr.sa_data, ETH_ALEN);
+ close(fd);
+
+ return 0;
+}
+
+void avb_1722_set_eth_type(eth_header *eth_header) {
+
+ eth_header->h_protocol[0] = 0x22;
+ eth_header->h_protocol[1] = 0xf0;
+
+ return;
+}
+
+int32_t
+avb_eth_header_set_mac(eth_header *ethernet_header, uint8_t *addr, int8_t *iface)
+{
+ uint8_t source_mac[ETH_ALEN];
+
+ if (!addr || !iface)
+ return -EINVAL;
+
+ if (avb_get_iface_mac_address(iface, source_mac))
+ return -EINVAL;
+
+ memcpy(ethernet_header->h_dest, addr, ETH_ALEN);
+ memcpy(ethernet_header->h_source, source_mac, ETH_ALEN);
+
+ return 0;
+}
diff --git a/lib/avtp_pipeline/openavb_common/avb.h b/lib/avtp_pipeline/openavb_common/avb.h
new file mode 100644
index 00000000..a592290b
--- /dev/null
+++ b/lib/avtp_pipeline/openavb_common/avb.h
@@ -0,0 +1,210 @@
+ /*
+ * Copyright (c) <2013>, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef __AVBTP_H__
+#define __AVBTP_H__
+
+#include <inttypes.h>
+
+#include "igb.h"
+
+#define VALID 1
+#define INVALID 0
+
+#define MAC_ADDR_LEN 6
+
+#define IGB_BIND_NAMESZ 24
+
+#define SHM_SIZE 4*8 + sizeof(pthread_mutex_t) /* 3 - 64 bit and 2 - 32 bits */
+#define SHM_NAME "/ptp"
+
+#define MAX_SAMPLE_VALUE ((1U << ((sizeof(int32_t)*8)-1))-1)
+
+#define IEEE_61883_IIDC_SUBTYPE 0x0
+
+#define MRPD_PORT_DEFAULT 7500
+
+#define STREAM_ID_SIZE 8
+
+#define ETHER_TYPE_AVTP 0x22f0
+
+typedef struct __attribute__ ((packed)) {
+ uint64_t subtype:7;
+ uint64_t cd_indicator:1;
+ uint64_t timestamp_valid:1;
+ uint64_t gateway_valid:1;
+ uint64_t reserved0:1;
+ uint64_t reset:1;
+ uint64_t version:3;
+ uint64_t sid_valid:1;
+ uint64_t seq_number:8;
+ uint64_t timestamp_uncertain:1;
+ uint64_t reserved1:7;
+ uint64_t stream_id;
+ uint64_t timestamp:32;
+ uint64_t gateway_info:32;
+ uint64_t length:16;
+
+} seventeen22_header;
+
+/* 61883 CIP with SYT Field */
+typedef struct {
+ uint16_t packet_channel:6;
+ uint16_t format_tag:2;
+ uint16_t app_control:4;
+ uint16_t packet_tcode:4;
+ uint16_t source_id:6;
+ uint16_t reserved0:2;
+ uint16_t data_block_size:8;
+ uint16_t reserved1:2;
+ uint16_t source_packet_header:1;
+ uint16_t quadlet_padding_count:3;
+ uint16_t fraction_number:2;
+ uint16_t data_block_continuity:8;
+ uint16_t format_id:6;
+ uint16_t eoh:2;
+ uint16_t format_dependent_field:8;
+ uint16_t syt;
+} six1883_header;
+
+typedef struct {
+ uint8_t label;
+ uint8_t value[3];
+} six1883_sample;
+
+#define ETH_ALEN 6 /* Size of Ethernet address */
+
+typedef struct __attribute__ ((packed)) {
+ /* Destination MAC address. */
+ uint8_t h_dest [ETH_ALEN];
+ /* Destination MAC address. */
+ uint8_t h_source [ETH_ALEN];
+ /* Protocol ID. */
+ uint8_t h_protocol[2];
+} eth_header;
+
+typedef long double FrequencyRatio;
+
+typedef struct {
+ int64_t ml_phoffset;
+ int64_t ls_phoffset;
+ FrequencyRatio ml_freqoffset;
+ FrequencyRatio ls_freqoffset;
+ uint64_t local_time;
+} gPtpTimeData;
+
+#ifndef false
+typedef enum { false = 0, true = 1 } bool;
+#endif
+
+int pci_connect(device_t * igb_dev);
+
+int gptpscaling(gPtpTimeData * td, char *memory_offset_buffer);
+
+bool gptplocaltime(const gPtpTimeData * td, uint64_t* now_local);
+
+void gptpdeinit(int shm_fd, char *memory_offset_buffer);
+
+int gptpinit(int *shm_fd, char **memory_offset_buffer);
+
+void avb_set_1722_cd_indicator(seventeen22_header *h1722, uint64_t cd_indicator);
+uint64_t avb_get_1722_cd_indicator(seventeen22_header *h1722);
+void avb_set_1722_subtype(seventeen22_header *h1722, uint64_t subtype);
+uint64_t avb_get_1722_subtype(seventeen22_header *h1722);
+void avb_set_1722_sid_valid(seventeen22_header *h1722, uint64_t sid_valid);
+uint64_t avb_get_1722_sid_valid(seventeen22_header *h1722);
+void avb_set_1722_version(seventeen22_header *h1722, uint64_t version);
+uint64_t avb_get_1722_version(seventeen22_header *h1722);
+void avb_set_1722_reset(seventeen22_header *h1722, uint64_t reset);
+uint64_t avb_get_1722_reset(seventeen22_header *h1722);
+void avb_set_1722_reserved0(seventeen22_header *h1722, uint64_t reserved0);
+uint64_t avb_get_1722_reserved0(seventeen22_header *h1722);
+void avb_set_1722_reserved1(seventeen22_header *h1722, uint64_t reserved1);
+uint64_t avb_get_1722_reserved1(seventeen22_header *h1722);
+void avb_set_1722_timestamp_uncertain(seventeen22_header *h1722, uint64_t timestamp_uncertain);
+uint64_t avb_get_1722_timestamp_uncertain(seventeen22_header *h1722);
+void avb_set_1722_timestamp(seventeen22_header *h1722, uint64_t timestamp);
+uint64_t avb_get_1722_reset(seventeen22_header *h1722);
+void avb_set_1722_reserved0(seventeen22_header *h1722, uint64_t reserved0);
+uint64_t avb_get_1722_reserved0(seventeen22_header *h1722);
+void avb_set_1722_gateway_valid(seventeen22_header *h1722, uint64_t gateway_valid);
+uint64_t avb_get_1722_gateway_valid(seventeen22_header *h1722);
+void avb_set_1722_timestamp_valid(seventeen22_header *h1722, uint64_t timestamp_valid);
+uint64_t avb_get_1722_timestamp_valid(seventeen22_header *h1722);
+void avb_set_1722_reserved1(seventeen22_header *h1722, uint64_t reserved1);
+uint64_t avb_get_1722_reserved1(seventeen22_header *h1722);
+void avb_set_1722_timestamp_uncertain(seventeen22_header *h1722, uint64_t timestamp_uncertain);
+uint64_t avb_get_1722_timestamp_uncertain(seventeen22_header *h1722);
+void avb_set_1722_timestamp(seventeen22_header *h1722, uint64_t timestamp);
+uint64_t avb_get_1722_timestamp(seventeen22_header *h1722);
+void avb_set_1722_gateway_info(seventeen22_header *h1722, uint64_t gateway_info);
+uint64_t avb_get_1722_gateway_info(seventeen22_header *h1722);
+void avb_set_1722_length(seventeen22_header *h1722, uint64_t length);
+uint64_t avb_get_1722_length(seventeen22_header *h1722);
+void avb_set_1722_stream_id(seventeen22_header *h1722, uint64_t stream_id);
+uint64_t avb_get_1722_stream_id(seventeen22_header *h1722);
+void avb_set_1722_seq_number(seventeen22_header *h1722, uint64_t seq_number);
+uint64_t avb_get_1722_seq_number(seventeen22_header *h1722);
+
+void avb_set_61883_packet_channel(six1883_header *h61883, uint16_t packet_channel);
+uint16_t avb_get_61883_length(six1883_header *h61883);
+void avb_set_61883_format_tag(six1883_header *h61883, uint16_t format_tag);
+uint16_t avb_get_61883_format_tag(six1883_header *h61883);
+void avb_set_61883_app_control(six1883_header *h61883, uint16_t app_control);
+uint16_t avb_get_61883_app_control(six1883_header *h61883);
+void avb_set_61883_packet_tcode(six1883_header *h61883, uint16_t packet_tcode);
+uint16_t avb_get_61883_packet_tcode(six1883_header *h61883);
+void avb_set_61883_source_id(six1883_header *h61883, uint16_t source_id);
+uint16_t avb_get_61883_source_id(six1883_header *h61883);
+void avb_set_61883_reserved0(six1883_header *h61883, uint16_t reserved0);
+uint16_t avb_get_61883_reserved0(six1883_header *h61883);
+void avb_set_61883_data_block_size(six1883_header *h61883, uint16_t data_block_size);
+uint16_t avb_get_61883_data_block_size(six1883_header *h61883);
+void avb_set_61883_reserved1(six1883_header *h61883, uint16_t reserved1);
+uint16_t avb_get_61883_reserved1(six1883_header *h61883);
+void avb_set_61883_source_packet_header(six1883_header *h61883, uint16_t source_packet_header);
+uint16_t avb_get_61883_source_packet_header(six1883_header *h61883);
+void avb_set_61883_quadlet_padding_count(six1883_header *h61883, uint16_t quadlet_padding_count);
+uint16_t avb_get_61883_quadlet_padding_count(six1883_header *h61883);
+void avb_set_61883_fraction_number(six1883_header *h61883, uint16_t fraction_number);
+uint16_t avb_get_61883_fraction_number(six1883_header *h61883);
+void avb_set_61883_data_block_continuity(six1883_header *h61883, uint16_t data_block_continuity);
+uint16_t avb_get_61883_data_block_continuity(six1883_header *h61883);
+void avb_set_61883_format_id(six1883_header *h61883, uint16_t format_id);
+uint16_t avb_get_61883_format_id(six1883_header *h61883);
+void avb_set_61883_eoh(six1883_header *h61883, uint16_t eoh);
+uint16_t avb_get_61883_eoh(six1883_header *h61883);
+void avb_set_61883_format_dependent_field(six1883_header *h61883, uint16_t format_dependent_field);
+uint16_t avb_get_61883_format_dependent_field(six1883_header *h61883);
+void avb_set_61883_syt(six1883_header *h61883, uint16_t syt);
+uint16_t avb_get_61883_syt(six1883_header *h61883);
+
+void * avb_create_packet(uint32_t payload_len);
+
+void avb_initialize_h1722_to_defaults(seventeen22_header *h1722);
+
+void avb_initialize_61883_to_defaults(six1883_header *h61883);
+
+int32_t avb_get_iface_mac_address(int8_t *iface, uint8_t *addr);
+
+int32_t
+avb_eth_header_set_mac(eth_header *ethernet_header, uint8_t *addr, int8_t *iface);
+
+void avb_1722_set_eth_type(eth_header *eth_header);
+
+#endif /* __AVBTP_H__ */
diff --git a/lib/avtp_pipeline/openavb_common/mrp_client.c b/lib/avtp_pipeline/openavb_common/mrp_client.c
new file mode 100644
index 00000000..da1afba8
--- /dev/null
+++ b/lib/avtp_pipeline/openavb_common/mrp_client.c
@@ -0,0 +1,710 @@
+/******************************************************************************
+
+ Copyright (c) 2012, Intel Corporation
+ Copyright (c) 2014, Parrot SA
+ 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.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 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 "mrp_client.h"
+
+#define AVB_LOG_COMPONENT "MRP"
+#include "openavb_log.h"
+
+/* global variables */
+
+int control_socket = -1;
+
+volatile int halt_tx = 0;
+volatile int listeners = 0;
+volatile int mrp_okay;
+volatile int mrp_error = 0;;
+
+volatile int domain_a_valid = 0;
+int domain_class_a_id = 0;
+int domain_class_a_priority = 0;
+u_int16_t domain_class_a_vid = 0;
+
+volatile int domain_b_valid = 0;
+int domain_class_b_id = 0;
+int domain_class_b_priority = 0;
+u_int16_t domain_class_b_vid = 0;
+
+pthread_t monitor_thread;
+pthread_attr_t monitor_attr;
+unsigned char monitor_stream_id[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+/*
+ * private
+ */
+
+int send_mrp_msg(char *notify_data, int notify_len)
+{
+ struct sockaddr_in addr;
+ socklen_t addr_len;
+
+ if (control_socket == -1)
+ return -1;
+ if (notify_data == NULL)
+ return -1;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(MRPD_PORT_DEFAULT);
+ inet_aton("127.0.0.1", &addr.sin_addr);
+ addr_len = sizeof(addr);
+ return sendto(control_socket, notify_data, notify_len, 0,
+ (struct sockaddr *)&addr, addr_len);
+}
+
+int process_mrp_msg(char *buf, int buflen)
+{
+
+ /*
+ * 1st character indicates application
+ * [MVS] - MAC, VLAN or STREAM
+ */
+ unsigned int id;
+ unsigned int priority;
+ unsigned int vid;
+ unsigned int max_frame_size;
+ unsigned int max_interval_frames;
+ unsigned int priority_and_rank;
+ unsigned int latency;
+ int i, j, k;
+ 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");
+ break;
+ case 3:
+ AVB_LOG_DEBUG("with state readyfail");
+ break;
+ default:
+ AVB_LOGF_DEBUG("with state UNKNOWN (%d)", substate);
+ 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;
+ 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[k + 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 = k + 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;
+
+ 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[k+1] == 'J', dest_addr, max_frame_size, max_interval_frames, vid, latency);
+ break;
+ default:
+ return 0;
+ break;
+ }
+ break;
+ case '\0':
+ break;
+ }
+ return 0;
+}
+
+void *mrp_monitor_thread(void *arg)
+{
+ char *msgbuf;
+ struct sockaddr_in client_addr;
+ struct msghdr msg;
+ struct iovec iov;
+ int bytes = 0;
+ struct pollfd fds;
+ int rc;
+ (void) arg; /* unused */
+
+ msgbuf = (char *)malloc(MAX_MRPD_CMDSZ);
+ if (NULL == msgbuf)
+ return NULL;
+ while (!halt_tx) {
+ fds.fd = control_socket;
+ fds.events = POLLIN;
+ fds.revents = 0;
+ rc = poll(&fds, 1, 100);
+ if (rc < 0) {
+ free(msgbuf);
+ pthread_exit(NULL);
+ }
+ if (rc == 0)
+ continue;
+ if ((fds.revents & POLLIN) == 0) {
+ free(msgbuf);
+ pthread_exit(NULL);
+ }
+ memset(&msg, 0, sizeof(msg));
+ memset(&client_addr, 0, sizeof(client_addr));
+ memset(msgbuf, 0, MAX_MRPD_CMDSZ);
+ iov.iov_len = MAX_MRPD_CMDSZ;
+ iov.iov_base = msgbuf;
+ msg.msg_name = &client_addr;
+ msg.msg_namelen = sizeof(client_addr);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ bytes = recvmsg(control_socket, &msg, 0);
+ if (bytes < 0)
+ continue;
+ AVB_LOGF_VERBOSE("Msg: %s", msgbuf);
+ process_mrp_msg(msgbuf, bytes);
+ }
+ free(msgbuf);
+ pthread_exit(NULL);
+}
+
+/*
+ * public
+ */
+
+int mrp_connect(void)
+{
+ struct sockaddr_in addr;
+ int sock_fd = -1;
+ sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (sock_fd < 0)
+ goto out;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(MRPD_PORT_DEFAULT);
+ inet_aton("127.0.0.1", &addr.sin_addr);
+ memset(&addr, 0, sizeof(addr));
+ control_socket = sock_fd;
+ return 0;
+ out: if (sock_fd != -1)
+ close(sock_fd);
+ sock_fd = -1;
+ return -1;
+}
+
+int mrp_disconnect(void)
+{
+ char *msgbuf;
+ int rc;
+
+ msgbuf = malloc(1500);
+ if (NULL == msgbuf)
+ return -1;
+ memset(msgbuf, 0, 64);
+ sprintf(msgbuf, "BYE");
+ mrp_okay = 0;
+ rc = send_mrp_msg(msgbuf, 1500);
+ free(msgbuf);
+
+ if (rc != 1500)
+ return -1;
+ else
+ return 0;
+}
+
+int mrp_monitor(void)
+{
+ int rc;
+ rc = pthread_attr_init(&monitor_attr);
+ rc |= pthread_create(&monitor_thread, NULL, mrp_monitor_thread, NULL);
+ return rc;
+}
+
+int mrp_register_domain(int *class_id, int *priority, u_int16_t * vid)
+{
+ char *msgbuf;
+ int rc;
+
+ msgbuf = malloc(1500);
+ if (NULL == msgbuf)
+ return -1;
+ memset(msgbuf, 0, 1500);
+
+ sprintf(msgbuf, "S+D:C=%d,P=%d,V=%04x", *class_id, *priority, *vid);
+ mrp_okay = 0;
+ rc = send_mrp_msg(msgbuf, 1500);
+ free(msgbuf);
+
+ if (rc != 1500)
+ return -1;
+ else
+ return 0;
+}
+
+
+int
+mrp_advertise_stream(uint8_t * streamid,
+ uint8_t * destaddr,
+ u_int16_t vlan,
+ int pktsz, int interval, int priority, int latency)
+{
+ char *msgbuf;
+ int rc;
+
+ msgbuf = malloc(1500);
+ if (NULL == msgbuf)
+ return -1;
+ memset(msgbuf, 0, 1500);
+
+ sprintf(msgbuf, "S++:S=%02X%02X%02X%02X%02X%02X%02X%02X"
+ ",A=%02X%02X%02X%02X%02X%02X"
+ ",V=%04X"
+ ",Z=%d"
+ ",I=%d"
+ ",P=%d"
+ ",L=%d", streamid[0], streamid[1], streamid[2],
+ streamid[3], streamid[4], streamid[5], streamid[6],
+ streamid[7], destaddr[0], destaddr[1], destaddr[2],
+ destaddr[3], destaddr[4], destaddr[5], vlan, pktsz,
+ interval, priority << 5, latency);
+ mrp_okay = 0;
+ rc = send_mrp_msg(msgbuf, 1500);
+ free(msgbuf);
+
+ if (rc != 1500)
+ return -1;
+ else
+ return 0;
+}
+
+int
+mrp_unadvertise_stream(uint8_t * streamid,
+ uint8_t * destaddr,
+ u_int16_t vlan,
+ int pktsz, int interval, int priority, int latency)
+{
+ char *msgbuf;
+ int rc;
+ msgbuf = malloc(1500);
+ if (NULL == msgbuf)
+ return -1;
+ memset(msgbuf, 0, 1500);
+ sprintf(msgbuf, "S--:S=%02X%02X%02X%02X%02X%02X%02X%02X"
+ ",A=%02X%02X%02X%02X%02X%02X"
+ ",V=%04X"
+ ",Z=%d"
+ ",I=%d"
+ ",P=%d"
+ ",L=%d", streamid[0], streamid[1], streamid[2],
+ streamid[3], streamid[4], streamid[5], streamid[6],
+ streamid[7], destaddr[0], destaddr[1], destaddr[2],
+ destaddr[3], destaddr[4], destaddr[5], vlan, pktsz,
+ interval, priority << 5, latency);
+ mrp_okay = 0;
+ rc = send_mrp_msg(msgbuf, 1500);
+ free(msgbuf);
+
+ if (rc != 1500)
+ return -1;
+ else
+ return 0;
+}
+
+
+int mrp_await_listener(unsigned char *streamid)
+{
+ char *msgbuf;
+ int rc;
+
+ memcpy(monitor_stream_id, streamid, sizeof(monitor_stream_id));
+ msgbuf = malloc(1500);
+ if (NULL == msgbuf)
+ return -1;
+ memset(msgbuf, 0, 1500);
+ sprintf(msgbuf, "S??");
+ rc = send_mrp_msg(msgbuf, 1500);
+ free(msgbuf);
+ if (rc != 1500)
+ return -1;
+
+ /* either already there ... or need to wait ... */
+ while (!halt_tx && (listeners == 0))
+ usleep(20000);
+
+ return 0;
+}
+
+/*
+ * actually not used
+ */
+
+int mrp_get_domain(int *class_a_id, int *a_priority, u_int16_t * a_vid,
+ int *class_b_id, int *b_priority, u_int16_t * b_vid)
+{
+ char *msgbuf;
+ int ret;
+ int tries = 5;
+
+ /* we may not get a notification if we are joining late,
+ * so query for what is already there ...
+ */
+ msgbuf = malloc(1500);
+ if (NULL == msgbuf)
+ return -1;
+ memset(msgbuf, 0, 1500);
+ sprintf(msgbuf, "S??");
+ ret = send_mrp_msg(msgbuf, 1500);
+ free(msgbuf);
+ if (ret != 1500)
+ return -1;
+ while (!halt_tx && (domain_a_valid == 0) && (domain_b_valid == 0) && tries--) {
+ usleep(20000);
+ }
+ *class_a_id = 0;
+ *a_priority = 0;
+ *a_vid = 0;
+ *class_b_id = 0;
+ *b_priority = 0;
+ *b_vid = 0;
+ if (domain_a_valid) {
+ *class_a_id = domain_class_a_id;
+ *a_priority = domain_class_a_priority;
+ *a_vid = domain_class_a_vid;
+ }
+ if (domain_b_valid) {
+ *class_b_id = domain_class_b_id;
+ *b_priority = domain_class_b_priority;
+ *b_vid = domain_class_b_vid;
+ }
+ return domain_a_valid && domain_b_valid ? 0 : -1;
+}
+
+int mrp_join_vlan()
+{
+ char *msgbuf;
+ int rc;
+
+ msgbuf = malloc(1500);
+ if (NULL == msgbuf)
+ return -1;
+ memset(msgbuf, 0, 1500);
+ sprintf(msgbuf, "V++:I=0002");
+ rc = send_mrp_msg(msgbuf, 1500);
+ free(msgbuf);
+
+ if (rc != 1500)
+ return -1;
+ else
+ return 0;
+}
+
+int mrp_join_listener(uint8_t * streamid)
+{
+ char *msgbuf;
+ int rc;
+
+ msgbuf = malloc(1500);
+ if (NULL == msgbuf)
+ return -1;
+ memset(msgbuf, 0, 1500);
+ sprintf(msgbuf, "S+L:S=%02X%02X%02X%02X%02X%02X%02X%02X"
+ ",D=2", streamid[0], streamid[1], streamid[2], streamid[3],
+ streamid[4], streamid[5], streamid[6], streamid[7]);
+ mrp_okay = 0;
+ rc = send_mrp_msg(msgbuf, 1500);
+ free(msgbuf);
+
+ if (rc != 1500)
+ return -1;
+ else
+ return 0;
+}
+
+// TODO remove
+int recv_mrp_okay()
+{
+ while ((mrp_okay == 0) && (mrp_error == 0))
+ usleep(20000);
+ return 0;
+}
+
+int mrp_send_ready(uint8_t *stream_id)
+{
+ char *databuf;
+ int rc;
+
+ databuf = malloc(1500);
+ if (NULL == databuf)
+ return -1;
+ memset(databuf, 0, 1500);
+ sprintf(databuf, "S+L:L=%02x%02x%02x%02x%02x%02x%02x%02x, D=2",
+ stream_id[0], stream_id[1],
+ stream_id[2], stream_id[3],
+ stream_id[4], stream_id[5],
+ stream_id[6], stream_id[7]);
+ rc = send_mrp_msg(databuf, 1500);
+ free(databuf);
+
+ if (rc != 1500)
+ return -1;
+ else
+ return 0;
+}
+
+int mrp_send_leave(uint8_t *stream_id)
+{
+ char *databuf;
+ int rc;
+
+ databuf = malloc(1500);
+ if (NULL == databuf)
+ return -1;
+ memset(databuf, 0, 1500);
+ sprintf(databuf, "S-L:L=%02x%02x%02x%02x%02x%02x%02x%02x, D=3",
+ stream_id[0], stream_id[1],
+ stream_id[2], stream_id[3],
+ stream_id[4], stream_id[5],
+ stream_id[6], stream_id[7]);
+
+ rc = send_mrp_msg(databuf, 1500);
+ free(databuf);
+
+ if (rc != 1500)
+ return -1;
+ else
+ return 0;
+}
diff --git a/lib/avtp_pipeline/openavb_common/mrp_client.h b/lib/avtp_pipeline/openavb_common/mrp_client.h
new file mode 100644
index 00000000..d6106e9a
--- /dev/null
+++ b/lib/avtp_pipeline/openavb_common/mrp_client.h
@@ -0,0 +1,92 @@
+/******************************************************************************
+
+ Copyright (c) 2012, Intel Corporation
+ Copyright (c) 2014, Parrot SA
+ 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.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 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 _TALKER_MRP_CLIENT_H_
+#define _TALKER_MRP_CLIENT_H_
+
+/*
+ * simple_talker MRP client part
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <poll.h>
+
+#include "mrpd.h"
+#include "mrp.h"
+#include "msrp.h" // spurious dep daemons/mrpd/msrp.h:50:#define MSRP_LISTENER_ASKFAILED
+
+/* global variables */
+
+// TODO move these in a talker_context struct + init func
+
+extern volatile int halt_tx;
+extern volatile int listeners;
+extern volatile int mrp_error;
+
+extern volatile int domain_a_valid;
+extern int domain_class_a_id;
+extern int domain_class_a_priority;
+extern u_int16_t domain_class_a_vid;
+
+extern volatile int domain_b_valid;
+extern int domain_class_b_id;
+extern int domain_class_b_priority;
+extern u_int16_t domain_class_b_vid;
+
+extern void mrp_attach_cb(unsigned char streamid[8], int subtype);
+extern void mrp_register_cb(unsigned char streamid[8], int declType, unsigned char destaddr[6], unsigned int max_frame_size, unsigned int max_interval_frames, uint16_t vid, unsigned int latency);
+
+
+/* functions */
+
+int mrp_connect(void);
+int mrp_disconnect(void);
+int mrp_monitor(void);
+int mrp_register_domain(int *class_id, int *priority, u_int16_t *vid);
+int mrp_join_vlan(void);
+int mrp_advertise_stream(uint8_t * streamid, uint8_t * destaddr, u_int16_t vlan, int pktsz, int interval, int priority, int latency);
+int mrp_unadvertise_stream(uint8_t * streamid, uint8_t * destaddr, u_int16_t vlan, int pktsz, int interval, int priority, int latency);
+int mrp_await_listener(unsigned char *streamid);
+
+int mrp_get_domain(int *class_a_id, int *a_priority, u_int16_t * a_vid,
+ int *class_b_id, int *b_priority, u_int16_t * b_vid);
+
+int mrp_send_ready(uint8_t *stream_id);
+int mrp_send_leave(uint8_t *stream_id);
+
+#endif /* _TALKER_MRP_CLIENT_H_ */
diff --git a/lib/avtp_pipeline/platform/Linux/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/CMakeLists.txt
new file mode 100644
index 00000000..a6ecfd37
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/CMakeLists.txt
@@ -0,0 +1,333 @@
+cmake_minimum_required ( VERSION 2.6 )
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
+project ( AVB )
+
+# Some CMake voodoo to set the default build type
+IF(NOT CMAKE_BUILD_TYPE)
+ SET(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE)
+else ()
+ IF (NOT (("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
+ OR ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
+ OR ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
+ OR ("${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel")))
+ MESSAGE ( FATAL_ERROR "Unknown CMAKE_BUILD_TYPE; Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel")
+ ENDIF ()
+ENDIF()
+MESSAGE ("-- Build type is ${CMAKE_BUILD_TYPE}")
+
+# Set a define to signal build to source files
+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 RelWithDebInfo: "-O2 -g"
+# for Release: "-03 -DNDEBUG"
+# for MinSizeRel: "-0s -DNDEBUG"
+
+# point to AVB SRC directory
+set ( AVB_SRC_DIR ${CMAKE_SOURCE_DIR} )
+
+# point to HAL directory
+set ( AVB_HAL_DIR ${AVB_SRC_DIR}/platform/${OPENAVB_HAL} )
+
+# point to OSAL directory
+set ( AVB_OSAL_DIR ${AVB_SRC_DIR}/platform/${OPENAVB_OSAL} )
+
+# point to TCAL directory
+set ( AVB_TCAL_DIR ${AVB_SRC_DIR}/platform/platTCAL/${OPENAVB_TCAL} )
+
+# Directory to install binaries to
+set ( AVB_INSTALL_BIN_DIR ${CMAKE_BINARY_DIR}/bin )
+
+# Directory to install static libraries to
+set ( AVB_INSTALL_LIB_DIR ${CMAKE_BINARY_DIR}/lib )
+
+# Directory to install AVTP Interface module SDK to
+set ( SDK_INSTALL_SDK_INTF_MOD_DIR ${CMAKE_BINARY_DIR}/sdk_intf_mod )
+
+# Directory to install AVTP Interface module SDK to
+set ( SDK_INSTALL_SDK_MAP_MOD_DIR ${CMAKE_BINARY_DIR}/sdk_map_mod )
+
+# Directory to install EAVB SDK to
+set ( SDK_INSTALL_SDK_EAVB_DIR ${CMAKE_BINARY_DIR}/sdk_eavb )
+
+MESSAGE ("-- CMAKE_SOURCE_DIR : ${CMAKE_SOURCE_DIR}")
+MESSAGE ("-- AVB_SRC_DIR : ${AVB_SRC_DIR}")
+MESSAGE ("-- AVB_HAL_DIR : ${AVB_HAL_DIR}")
+MESSAGE ("-- AVB_OSAL_DIR : ${AVB_OSAL_DIR}")
+MESSAGE ("-- AVB_INSTALL_BIN_DIR : ${AVB_INSTALL_BIN_DIR}")
+MESSAGE ("-- AVB_INSTALL_LIB_DIR : ${AVB_INSTALL_LIB_DIR}")
+MESSAGE ("-- SDK_INSTALL_SDK_INTF_MOD_DIR : ${SDK_INSTALL_SDK_INTF_MOD_DIR}")
+MESSAGE ("-- SDK_INSTALL_SDK_MAP_MOD_DIR : ${SDK_INSTALL_SDK_MAP_MOD_DIR}")
+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" )
+
+# Set default visibility of symbols (requires GCC version > 4)
+set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden" )
+
+# Need this to use pthread attributes
+set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE" )
+
+# Increase ini parser's max line length
+set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DINI_MAX_LINE=1024" )
+
+# check Gstreamer version
+if ( GSTREAMER_1_0)
+set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGSTREAMER_1_0" )
+endif ()
+
+# Default feature flags
+if (NOT DEFINED AVB_FEATURE_FQTSS)
+ set ( AVB_FEATURE_FQTSS 1 )
+endif ()
+# include GStreamer interfaces if not defined
+if (NOT DEFINED AVB_FEATURE_GSTREAMER)
+ set ( AVB_FEATURE_GSTREAMER 1 )
+endif ()
+# Default Endpoint feature
+if (NOT DEFINED AVB_FEATURE_ENDPOINT)
+ set ( AVB_FEATURE_ENDPOINT 0 )
+endif ()
+
+
+# Export feature flags for sub-builds
+if (AVB_FEATURE_FQTSS)
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAVB_FEATURE_FQTSS=1" )
+endif ()
+if (AVB_FEATURE_GSTREAMER)
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAVB_FEATURE_GSTREAMER=1" )
+endif ()
+if (AVB_FEATURE_ENDPOINT)
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAVB_FEATURE_ENDPOINT=1" )
+endif ()
+
+#Export Platform defines
+if ( PLATFORM_DEFINE )
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D${PLATFORM_DEFINE}" )
+endif ()
+
+if (NOT DEFINED SDK_DOC_ONLY)
+ if ( NOT DEFINED CROSS_PREFIX )
+ MESSAGE ( "-- Native build for ${CMAKE_SYSTEM} on ${CMAKE_SYSTEM_PROCESSOR}" )
+ set ( ARCH x86 )
+ set ( LINUX_KERNEL_DIR /usr/src/linux-headers-${CMAKE_SYSTEM_VERSION} )
+ find_package(PkgConfig REQUIRED)
+ pkg_check_modules(GLIB_PKG glib-2.0)
+ if (AVB_FEATURE_GSTREAMER)
+ if ( GSTREAMER_1_0)
+ pkg_check_modules(GST_PKG gstreamer-app-1.0 gstreamer-rtp-1.0)
+ else ()
+ pkg_check_modules(GST_PKG gstreamer-app-0.10 gstreamer-rtp-0.10)
+ endif ()
+ endif()
+ find_package(ALSA REQUIRED)
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUBUNTU=1" )
+ else ()
+ message ( "-- Cross-compiling for " ${OPENAVB_PLATFORM} " (" ${CROSS_PREFIX} "gcc)" )
+ endif ()
+
+ if (NOT DEFINED ARCH)
+ MESSAGE ( FATAL_ERROR "Aborting: ARCH not set" )
+ endif ()
+ if (NOT DEFINED LINUX_KERNEL_DIR)
+ MESSAGE ( FATAL_ERROR "Aborting: LINUX_KERNEL_DIR not set" )
+ 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 ()
+ 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" )
+ endif()
+ endif ()
+ if (NOT DEFINED ALSA_INCLUDE_DIRS)
+ MESSAGE ( FATAL_ERROR "Aborting: alsa library not found" )
+ endif ()
+endif()
+
+# Add /usr/lib to library search path
+link_directories( ${SYSROOT}/usr/lib )
+link_directories ( ${PLATFORM_SPECIFIC_DIRECTORIES} )
+set ( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_SPECIFIC_LINKER_FLAGS}" )
+
+# Setup platform directories
+include_directories ( ${PLATFORM_INCLUDE_DIRECTORIES} )
+link_directories ( ${PLATFORM_LINK_DIRECTORIES} )
+
+find_library(TEMP NAMES ${PLATFORM_LINK_LIBRARIES} PATHS ${PLATFORM_LINK_DIRECTORIES} )
+set ( PLATFORM_LINK_LIBRARIES ${TEMP} )
+
+# Add our include directories
+#
+# TODO: CMakeLists.txt Cleanup
+# Many of the AVB_SRC_DIR directories listed below
+# need to be listed due to component A including
+# header from componet B which is dependent on
+# component C ...
+#
+# These should be cleaned up to limit the dependencies
+# across components.
+#
+include_directories(
+ ${AVB_TCAL_DIR}
+ ${AVB_HAL_DIR}
+ ${AVB_HAL_DIR}/mcr
+ ${AVB_OSAL_DIR}
+ ${AVB_OSAL_DIR}/include
+ ${AVB_OSAL_DIR}/fqtss/include
+ ${AVB_SRC_DIR}/include
+ ${AVB_OSAL_DIR}/avtp
+ ${AVB_OSAL_DIR}/tl
+ ${AVB_SRC_DIR}/avtp
+ ${AVB_SRC_DIR}/endpoint
+ ${AVB_SRC_DIR}/srp
+ ${AVB_SRC_DIR}/maap
+ ${AVB_SRC_DIR}/inih
+ ${AVB_SRC_DIR}/map_mjpeg
+ ${AVB_SRC_DIR}/map_mpeg2ts
+ ${AVB_SRC_DIR}/map_null
+ ${AVB_SRC_DIR}/map_pipe
+ ${AVB_SRC_DIR}/map_aaf_audio
+ ${AVB_SRC_DIR}/map_uncmp_audio
+ ${AVB_SRC_DIR}/map_ctrl
+ ${AVB_SRC_DIR}/map_h264
+ ${AVB_SRC_DIR}/intf_ctrl
+ ${AVB_SRC_DIR}/mcr
+ ${AVB_SRC_DIR}/mediaq
+ ${AVB_SRC_DIR}/rawsock
+ ${AVB_SRC_DIR}/qmgr
+ ${AVB_SRC_DIR}/tl
+ ${AVB_SRC_DIR}/util
+ ${AVB_OSAL_DIR}/endpoint
+ ${AVB_OSAL_DIR}/fqtss/qmgr
+ )
+
+# Need include and link directories for GLIB
+include_directories(${GLIB_PKG_INCLUDE_DIRS})
+link_directories(${GLIB_PKG_LIBRARY_DIRS})
+
+# AVB Core Library
+SET ( SRC_FILES "" )
+add_subdirectory ( avtp )
+add_subdirectory ( tl )
+add_subdirectory ( util )
+add_subdirectory ( mediaq )
+add_subdirectory ( inih )
+add_subdirectory ( rawsock )
+add_subdirectory ( qmgr )
+if (AVB_FEATURE_ENDPOINT)
+ add_subdirectory ( endpoint )
+ SET ( SRC_FILES ${SRC_FILES} ${AVB_OSAL_DIR}/openavb_osal_endpoint.c )
+else()
+ SET ( SRC_FILES ${SRC_FILES} ${AVB_OSAL_DIR}/openavb_osal.c )
+endif()
+SET ( SRC_FILES ${SRC_FILES} ${AVB_OSAL_DIR}/rawsock/openavb_rawsock.c )
+SET ( SRC_FILES ${SRC_FILES} ${AVB_OSAL_DIR}/rawsock/simple_rawsock.c )
+SET ( SRC_FILES ${SRC_FILES} ${AVB_OSAL_DIR}/rawsock/ring_rawsock.c )
+SET ( SRC_FILES ${SRC_FILES} ${AVB_OSAL_DIR}/rawsock/igb_rawsock.c )
+SET ( SRC_FILES ${SRC_FILES} ${AVB_OSAL_DIR}/openavb_time_osal.c )
+SET ( SRC_FILES ${SRC_FILES} ${AVB_HAL_DIR}/openavb_ether_hal.c )
+SET ( SRC_FILES ${SRC_FILES} ${AVB_HAL_DIR}/openavb_time_hal.c )
+SET ( SRC_FILES ${SRC_FILES} ${AVB_HAL_DIR}/mcr/openavb_mcr_hal.c )
+
+# OpenAVB Common (support) files
+SET ( SRC_FILES ${SRC_FILES} ${AVB_SRC_DIR}/openavb_common/avb.c )
+SET ( SRC_FILES ${SRC_FILES} ${AVB_SRC_DIR}/openavb_common/mrp_client.c )
+
+if ( AVB_FEATURE_PCAP )
+ find_package ( PCAP REQUIRED )
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAVB_FEATURE_PCAP" )
+ include_directories ( ${PCAP_INCLUDE_DIR} )
+ list ( APPEND SRC_FILES ${AVB_OSAL_DIR}/rawsock/pcap_rawsock.c )
+endif ()
+
+add_library ( avbTl ${SRC_FILES} )
+target_link_libraries ( avbTl dl )
+
+install ( TARGETS avbTl ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
+
+if ( AVB_FEATURE_PCAP )
+ target_link_libraries ( avbTl ${PCAP_LIBRARY} )
+endif ()
+
+# 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" )
+endif ()
+add_intf_mod_platform ( "intf_mpeg2ts_file" )
+add_intf_mod_platform ( "intf_wav_file" )
+
+# API documentation
+add_subdirectory ( documents )
+
+# 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_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} )
+
+# Copy additional installation files
+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} )
+
+
diff --git a/lib/avtp_pipeline/platform/Linux/avb_host/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/avb_host/CMakeLists.txt
new file mode 100644
index 00000000..1edf78ab
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avb_host/CMakeLists.txt
@@ -0,0 +1,86 @@
+include_directories(
+ ${AVB_OSAL_DIR}/tl
+ ${AVB_OSAL_DIR}/endpoint
+ ${AVB_SRC_DIR}/util
+ ${AVB_SRC_DIR}/tl
+ ${AVB_SRC_DIR}/srp
+ )
+
+# Rules to build the AVB host
+add_executable ( openavb_host openavb_host.c )
+target_link_libraries( openavb_host
+ map_ctrl
+ map_mjpeg
+ map_mpeg2ts
+ map_null
+ map_pipe
+ map_aaf_audio
+ map_uncmp_audio
+ map_h264
+ intf_ctrl
+ intf_echo
+ intf_logger
+ intf_null
+ intf_tonegen
+ intf_viewer
+ intf_alsa
+ intf_mpeg2ts_gst
+ intf_mjpeg_gst
+ intf_mpeg2ts_file
+ intf_wav_file
+ intf_h264_gst
+ avbTl
+ ${PLATFORM_LINK_LIBRARIES}
+ ${ALSA_LIBRARIES}
+ ${GSTRTP_PKG_LIBRARIES}
+ ${GLIB_PKG_LIBRARIES}
+ ${GST_PKG_LIBRARIES}
+ pthread
+ rt
+ dl
+ pci )
+
+
+# Rules to build the AVB harness
+add_executable ( openavb_harness openavb_harness.c )
+target_link_libraries( openavb_harness
+ map_ctrl
+ map_mjpeg
+ map_mpeg2ts
+ map_null
+ map_pipe
+ map_aaf_audio
+ map_uncmp_audio
+ map_h264
+ intf_ctrl
+ intf_echo
+ intf_logger
+ intf_null
+ intf_tonegen
+ intf_viewer
+ intf_alsa
+ intf_mpeg2ts_gst
+ intf_mjpeg_gst
+ intf_mpeg2ts_file
+ intf_wav_file
+ intf_h264_gst
+ avbTl
+ ${PLATFORM_LINK_LIBRARIES}
+ ${ALSA_LIBRARIES}
+ ${GSTRTP_PKG_LIBRARIES}
+ ${GLIB_PKG_LIBRARIES}
+ ${GST_PKG_LIBRARIES}
+ pthread
+ rt
+ dl
+ pci )
+
+# Install rules
+install ( TARGETS openavb_host RUNTIME DESTINATION ${AVB_INSTALL_BIN_DIR} )
+install ( TARGETS openavb_harness RUNTIME DESTINATION ${AVB_INSTALL_BIN_DIR} )
+
+if (AVB_FEATURE_GSTREAMER)
+include_directories( ${GLIB_PKG_INCLUDE_DIRS} ${GST_PKG_INCLUDE_DIRS} )
+target_link_libraries( openavb_host ${GLIB_PKG_LIBRARIES} ${GST_PKG_LIBRARIES} ${PLATFORM_LINK_LIBRARIES} )
+target_link_libraries( openavb_harness ${GLIB_PKG_LIBRARIES} ${GST_PKG_LIBRARIES} ${PLATFORM_LINK_LIBRARIES} )
+endif ()
diff --git a/lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c b/lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c
new file mode 100644
index 00000000..c999e628
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c
@@ -0,0 +1,543 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Talker listener test host implementation.
+*/
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <signal.h>
+#include <pthread.h>
+#include "openavb_tl_pub.h"
+#include "openavb_osal_pub.h"
+#include "openavb_plugin.h"
+#include "openavb_trace_pub.h"
+#ifdef AVB_FEATURE_GSTREAMER
+#include <gst/gst.h>
+#endif
+#include <inttypes.h>
+
+#define AVB_LOG_COMPONENT "TL Harness"
+#include "openavb_log_pub.h"
+
+bool bRunning = TRUE;
+
+// Platform indendent 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);
+extern bool openavbMapH264Initialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
+extern bool openavbMapMjpegInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
+extern bool openavbMapMpeg2tsInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
+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
+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);
+extern bool openavbIntfNullInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+extern bool openavbIntfToneGenInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+extern bool openavbIntfViewerInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+
+// Linux interface modules
+extern bool openavbIntfAlsaInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+extern bool openavbIntfMjpegGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+extern bool openavbIntfMpeg2tsFileInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+extern bool openavbIntfMpeg2tsGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+extern bool openavbIntfWavFileInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+extern bool openavbIntfH264RtpGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+
+
+
+/***********************************************
+ * Signal handler - used to respond to signals.
+ * Allows graceful cleanup.
+ */
+static void openavbTLSigHandler(int signal)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HOST);
+
+ if (signal == SIGINT) {
+ AVB_LOG_INFO("Host shutting down");
+ bRunning = FALSE;
+ }
+ else if (signal == SIGUSR1) {
+ AVB_LOG_DEBUG("Waking up streaming thread");
+ }
+ else {
+ AVB_LOG_ERROR("Unexpected signal");
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_HOST);
+}
+
+void openavbTlHarnessUsage(char *programName)
+{
+ printf(
+ "\n"
+ "Usage: %s [options] file...\n"
+ " -a val Override stream address in each configuration file.\n"
+ " -h Prints this message.\n"
+ " -i Enables interactive mode.\n"
+ " -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"
+ "\n"
+ "Examples:\n"
+ " %s talker.ini\n"
+ " Start 1 stream with data from the ini file.\n\n"
+ " %s talker1.ini talker2.ini\n"
+ " Start 2 streams with data from the ini files.\n\n"
+ " %s -I eth0 talker1.ini talker2.ini\n"
+ " Start 2 streams with data from the ini files, both talkers use eth0 interface.\n\n"
+ " %s -I eth0 talker1.ini talker2.ini listener1.ini,ifname=pcap:eth0\n"
+ " Start 3 streams with data from the ini files, talkers 1&2 use eth0 interface, listener1 use pcap:eth0.\n\n"
+ " %s listener.ini,stream_addr=84:7E:40:2C:8F:DE\n"
+ " Start 1 stream and override the sream_addr in the ini file.\n\n"
+ " %s -i -s 8 -a 84:7E:40:2C:8F:DE listener.ini\n"
+ " Work interactively with 8 streams overriding the stream_uid and stream_addr of each.\n\n"
+ ,
+ programName, programName, programName, programName, programName, programName, programName);
+}
+
+void openavbTlHarnessMenu()
+{
+ printf(
+ "\n"
+ " MENU OPTIONS\n"
+ " s Start all streams\n"
+ " t Stop all streams\n"
+ " l List streams\n"
+ " 0-99 Toggle the state of the numbered stream\n"
+ " m Display this menu\n"
+ " z Stats\n"
+ " x Exit\n"
+ );
+}
+
+
+/**********************************************
+ * main
+ */
+int main(int argc, char *argv[])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HOST);
+
+ // Command line vars
+ char *programName;
+ char *optStreamAddr = NULL;
+ bool optInteractive = FALSE;
+ int optStreamCount = 1;
+ bool optStreamCountSet = FALSE;
+ bool optDestAddrSet = FALSE;
+ U8 destAddr[ETH_ALEN] = {0x91, 0xe0, 0xf0, 0x00, 0xfe, 0x00};
+ char *optIfnameGlobal = NULL;
+
+ // Talker listener vars
+ int iniIdx = 0;
+ int iniCount = 0;
+ int tlCount = 0;
+ char **tlIniList = NULL;
+ tl_handle_t *tlHandleList = NULL;
+
+ // General vars
+ int i1, i2;
+
+ // Setup signal handler. Catch SIGINT and shutdown cleanly
+ struct sigaction sa;
+ sa.sa_handler = openavbTLSigHandler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0; // not SA_RESTART
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGUSR1, &sa, NULL);
+
+ registerStaticMapModule(openavbMapPipeInitialize);
+ registerStaticMapModule(openavbMapAVTPAudioInitialize);
+ registerStaticMapModule(openavbMapCtrlInitialize);
+ registerStaticMapModule(openavbMapH264Initialize);
+ registerStaticMapModule(openavbMapMjpegInitialize);
+ registerStaticMapModule(openavbMapMpeg2tsInitialize);
+ registerStaticMapModule(openavbMapNullInitialize);
+ registerStaticMapModule(openavbMapUncmpAudioInitialize);
+
+ registerStaticIntfModule(openavbIntfEchoInitialize);
+ registerStaticIntfModule(openavbIntfCtrlInitialize);
+ registerStaticIntfModule(openavbIntfLoggerInitialize);
+ registerStaticIntfModule(openavbIntfNullInitialize);
+ //registerStaticIntfModule(openavbIntfToneGenInitialize);
+ registerStaticIntfModule(openavbIntfViewerInitialize);
+ registerStaticIntfModule(openavbIntfAlsaInitialize);
+ registerStaticIntfModule(openavbIntfMjpegGstInitialize);
+ registerStaticIntfModule(openavbIntfMpeg2tsFileInitialize);
+ registerStaticIntfModule(openavbIntfMpeg2tsGstInitialize);
+ registerStaticIntfModule(openavbIntfWavFileInitialize);
+ registerStaticIntfModule(openavbIntfH264RtpGstInitialize);
+
+ // Process command line
+ programName = strrchr(argv[0], '/');
+ programName = programName ? programName + 1 : argv[0];
+
+ if (argc < 2) {
+ openavbTlHarnessUsage(programName);
+ exit(-1);
+ }
+
+ bool optDone = FALSE;
+ while (!optDone) {
+ int opt = getopt(argc, argv, "a:his:d:I:");
+ if (opt != EOF) {
+ switch (opt) {
+ case 'a':
+ optStreamAddr = strdup(optarg);
+ break;
+ case 'i':
+ optInteractive = TRUE;
+ break;
+ case 's':
+ optStreamCount = atoi(optarg);
+ optStreamCountSet = TRUE;
+ break;
+ case 'd':
+ optDestAddrSet = TRUE;
+ destAddr[5] = strtol(optarg, NULL, 0);
+ break;
+ case 'I':
+ optIfnameGlobal = strdup(optarg);
+ break;
+ case '?':
+ default:
+ openavbTlHarnessUsage(programName);
+ exit(-1);
+ }
+ }
+ else {
+ optDone = TRUE;
+ }
+ }
+
+ osalAVBInitialize(optIfnameGlobal);
+
+ // Setup the talker listener counts and lists
+ iniIdx = optind;
+ iniCount = argc - iniIdx;
+ tlCount = iniCount * optStreamCount;
+
+ tlIniList = calloc(1, sizeof(char *) * tlCount);
+ if (!tlIniList) {
+ AVB_LOG_ERROR("Unable to allocate ini list");
+ osalAVBFinalize();
+ exit(-1);
+ }
+
+ tlHandleList = calloc(1, sizeof(tl_handle_t) * tlCount);
+ if (!tlHandleList) {
+ AVB_LOG_ERROR("Unable to allocate handle list");
+ osalAVBFinalize();
+ exit(-1);
+ }
+
+ if (!openavbTLInitialize(tlCount)) {
+ AVB_LOG_ERROR("Unable to initialize talker listener library");
+ osalAVBFinalize();
+ exit(-1);
+ }
+
+ // Populate the ini file list
+ int tlIndex = 0;
+ for (i1 = 0; i1 < iniCount; i1++) {
+ char iniFile[1024];
+ char sStreamAddr[31] = "";
+ char sDestAddr[29] = "";
+
+ if (optStreamAddr) {
+ snprintf(sStreamAddr, sizeof(sStreamAddr), ",stream_addr=%s", optStreamAddr);
+ }
+
+ if (optDestAddrSet) {
+ snprintf(sDestAddr, sizeof(sDestAddr), ",dest_addr="ETH_FORMAT, ETH_OCTETS(destAddr));
+ }
+
+ if (!optStreamCountSet) {
+ snprintf(iniFile, sizeof(iniFile), "%s%s%s", argv[i1 + iniIdx], sDestAddr, sStreamAddr);
+ if (optIfnameGlobal && !strcasestr(iniFile, ",ifname=")) {
+ snprintf(iniFile + strlen(iniFile), sizeof(iniFile), ",ifname=%s", optIfnameGlobal);
+ }
+ tlIniList[tlIndex++] = strdup(iniFile);
+ }
+ else {
+ for (i2 = 0; i2 < optStreamCount; i2++) {
+ snprintf(iniFile, sizeof(iniFile), "%s%s%s,stream_uid=%d", argv[i1 + iniIdx], sDestAddr, sStreamAddr, tlIndex);
+ if (optIfnameGlobal && !strcasestr(iniFile, ",ifname=")) {
+ snprintf(iniFile + strlen(iniFile), sizeof(iniFile), ",ifname=%s", optIfnameGlobal);
+ }
+ tlIniList[tlIndex++] = strdup(iniFile);
+ if (optDestAddrSet) {
+ destAddr[5]++;
+ snprintf(sDestAddr, sizeof(sDestAddr), ",dest_addr="ETH_FORMAT, ETH_OCTETS(destAddr));
+ }
+ }
+ }
+ }
+
+#ifdef AVB_FEATURE_GSTREAMER
+ // If we're supporting the interface modules which use GStreamer,
+ // initialize GStreamer here to avoid errors.
+ gst_init(0, NULL);
+#endif
+
+ // Open all streams
+ for (i1 = 0; i1 < tlCount; i1++) {
+ printf("Opening: %s\n", tlIniList[i1]);
+ tlHandleList[i1] = openavbTLOpen();
+ }
+
+ // Parse ini and configure all streams
+ for (i1 = 0; i1 < tlCount; i1++) {
+ printf("Configuring: %s\n", tlIniList[i1]);
+ openavb_tl_cfg_t cfg;
+ openavb_tl_cfg_name_value_t NVCfg;
+
+ openavbTLInitCfg(&cfg);
+ memset(&NVCfg, 0, sizeof(NVCfg));
+
+ if (!openavbTLReadIniFileOsal(tlHandleList[i1], tlIniList[i1], &cfg, &NVCfg)) {
+ printf("Error reading ini file: %s\n", tlIniList[i1]);
+ osalAVBFinalize();
+ exit(-1);
+ }
+ if (!openavbTLConfigure(tlHandleList[i1], &cfg, &NVCfg)) {
+ printf("Error configuring: %s\n", tlIniList[i1]);
+ osalAVBFinalize();
+ exit(-1);
+ }
+
+ int i2;
+ for (i2 = 0; i2 < NVCfg.nLibCfgItems; i2++) {
+ free(NVCfg.libCfgNames[i2]);
+ free(NVCfg.libCfgValues[i2]);
+ }
+ }
+
+ if (!optInteractive) {
+ // Non-interactive mode
+ // Run the streams
+ for (i1 = 0; i1 < tlCount; i1++) {
+ printf("Starting: %s\n", tlIniList[i1]);
+ openavbTLRun(tlHandleList[i1]);
+ }
+
+ while (bRunning) {
+ sleep(1);
+ }
+
+ for (i1 = 0; i1 < tlCount; i1++) {
+ if (tlHandleList[i1] && openavbTLIsRunning(tlHandleList[i1])) {
+ printf("Stopping: %s\n", tlIniList[i1]);
+ openavbTLStop(tlHandleList[i1]);
+ }
+ }
+ }
+ else {
+ // Interactive mode
+
+ openavbTlHarnessMenu();
+ while (bRunning) {
+ char buf[16];
+ printf("> ");
+ if (fgets(buf, sizeof(buf), stdin) == NULL) {
+ openavbTlHarnessMenu();
+ continue;
+ }
+
+ switch (buf[0]) {
+ case 's':
+ // Start all streams
+ {
+ int i1;
+ for (i1 = 0; i1 < tlCount; i1++) {
+ if (tlHandleList[i1] && !openavbTLIsRunning(tlHandleList[i1])) {
+ printf("Starting: %s\n", tlIniList[i1]);
+ openavbTLRun(tlHandleList[i1]);
+ }
+ }
+ }
+ break;
+ case 't':
+ // Stop all streams
+ {
+ int i1;
+ for (i1 = 0; i1 < tlCount; i1++) {
+ if (tlHandleList[i1] && openavbTLIsRunning(tlHandleList[i1])) {
+ printf("Stopping: %s\n", tlIniList[i1]);
+ openavbTLStop(tlHandleList[i1]);
+ }
+ }
+ }
+ break;
+ case 'l':
+ // List all streams
+ {
+ int i1;
+ for (i1 = 0; i1 < tlCount; i1++) {
+ if (tlHandleList[i1] && openavbTLIsRunning(tlHandleList[i1])) {
+ printf("%02d: [Started] %s\n", i1, tlIniList[i1]);
+ }
+ else {
+ printf("%02d: [Stopped] %s\n", i1, tlIniList[i1]);
+ }
+ }
+ }
+ break;
+ case 'm':
+ // Display menu
+ openavbTlHarnessMenu();
+ break;
+ case 'z':
+ // Stats
+ {
+ int i1;
+ for (i1 = 0; i1 < tlCount; i1++) {
+ if (tlHandleList[i1] && openavbTLIsRunning(tlHandleList[i1])) {
+ printf("%02d: [Started] %s\n", i1, tlIniList[i1]);
+ if (openavbTLGetRole(tlHandleList[i1]) == AVB_ROLE_TALKER) {
+ printf(" Talker totals: calls=%" PRIu64 ", frames=%" PRIu64 ", late=%" PRIu64 ", bytes=%" PRIu64 "\n",
+ openavbTLStat(tlHandleList[i1], TL_STAT_TX_CALLS),
+ openavbTLStat(tlHandleList[i1], TL_STAT_TX_FRAMES),
+ openavbTLStat(tlHandleList[i1], TL_STAT_TX_LATE),
+ openavbTLStat(tlHandleList[i1], TL_STAT_TX_BYTES));
+ }
+ else if (openavbTLGetRole(tlHandleList[i1]) == AVB_ROLE_LISTENER) {
+ printf(" Listener totals: calls=%" PRIu64 ", frames=%" PRIu64 ", lost=%" PRIu64 ", bytes=%" PRIu64 "\n",
+ openavbTLStat(tlHandleList[i1], TL_STAT_RX_CALLS),
+ openavbTLStat(tlHandleList[i1], TL_STAT_RX_FRAMES),
+ openavbTLStat(tlHandleList[i1], TL_STAT_RX_LOST),
+ openavbTLStat(tlHandleList[i1], TL_STAT_RX_BYTES));
+ }
+ }
+ else {
+ printf("%02d: [Stopped] %s\n", i1, tlIniList[i1]);
+ }
+ }
+ }
+ break;
+ case 'x':
+ // Exit
+ {
+ int i1;
+ for (i1 = 0; i1 < tlCount; i1++) {
+ if (tlHandleList[i1] && openavbTLIsRunning(tlHandleList[i1])) {
+ printf("Stopping: %s\n", tlIniList[i1]);
+ openavbTLStop(tlHandleList[i1]);
+ }
+ }
+ bRunning = FALSE;
+ }
+ break;
+ default:
+ // Check for number
+ {
+ if (isdigit(buf[0])) {
+ int idx = atoi(buf);
+ if (idx < tlCount) {
+ if (tlHandleList[idx] && openavbTLIsRunning(tlHandleList[idx])) {
+ // Stop the stream
+ printf("Stopping: %s\n", tlIniList[idx]);
+ openavbTLStop(tlHandleList[idx]);
+ }
+ else {
+ // Start the stream
+ printf("Starting: %s\n", tlIniList[idx]);
+ openavbTLRun(tlHandleList[idx]);
+ }
+ }
+ else {
+ openavbTlHarnessMenu();
+ }
+ }
+ else {
+ openavbTlHarnessMenu();
+ }
+ }
+ break;
+ }
+
+ }
+ }
+
+ // Close the streams
+ for (i1 = 0; i1 < tlCount; i1++) {
+ if (tlHandleList[i1]) {
+ printf("Stopping: %s\n", tlIniList[i1]);
+
+ openavbTLClose(tlHandleList[i1]);
+
+ tlHandleList[i1] = NULL;
+ }
+ }
+
+ openavbTLCleanup();
+
+ for (i1 = 0; i1 < tlCount; i1++) {
+ if (tlIniList[i1]) {
+ free(tlIniList[i1]);
+ tlIniList[i1] = NULL;
+ }
+ }
+
+ if (tlIniList) {
+ free(tlIniList);
+ tlIniList = NULL;
+ }
+
+ if (tlHandleList) {
+ free(tlHandleList);
+ tlHandleList = NULL;
+ }
+
+ if (optStreamAddr) {
+ free(optStreamAddr);
+ optStreamAddr = NULL;
+ }
+
+#ifdef AVB_FEATURE_GSTREAMER
+ // If we're supporting the interface modules which use GStreamer,
+ // De-initialize GStreamer to clean up resources.
+ gst_deinit();
+#endif
+
+ osalAVBFinalize();
+ AVB_TRACE_EXIT(AVB_TRACE_HOST);
+ exit(0);
+}
diff --git a/lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c b/lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c
new file mode 100644
index 00000000..e1eec996
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c
@@ -0,0 +1,290 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Talker listener test host implementation.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include "openavb_tl_pub.h"
+#include "openavb_plugin.h"
+#include "openavb_trace_pub.h"
+#ifdef AVB_FEATURE_GSTREAMER
+#include <gst/gst.h>
+#endif
+
+#define AVB_LOG_COMPONENT "TL Host"
+#include "openavb_log_pub.h"
+
+bool bRunning = TRUE;
+
+// Platform indendent 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);
+extern bool openavbMapH264Initialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
+extern bool openavbMapMjpegInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
+extern bool openavbMapMpeg2tsInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
+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
+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);
+extern bool openavbIntfNullInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+extern bool openavbIntfToneGenInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+extern bool openavbIntfViewerInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+
+// Linux interface modules
+extern bool openavbIntfAlsaInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+extern bool openavbIntfMjpegGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+extern bool openavbIntfMpeg2tsFileInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+extern bool openavbIntfMpeg2tsGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+extern bool openavbIntfWavFileInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+extern bool openavbIntfH264RtpGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+
+/***********************************************
+ * Signal handler - used to respond to signals.
+ * Allows graceful cleanup.
+ */
+static void openavbTLSigHandler(int signal)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HOST);
+
+ if (signal == SIGINT) {
+ AVB_LOG_INFO("Host shutting down");
+ bRunning = FALSE;
+ }
+ else if (signal == SIGUSR1) {
+ AVB_LOG_DEBUG("Waking up streaming thread");
+ }
+ else {
+ AVB_LOG_ERROR("Unexpected signal");
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_HOST);
+}
+
+void openavbTlHostUsage(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"
+ "\n"
+ "Examples:\n"
+ " %s talker.ini\n"
+ " Start 1 stream with data from the ini file.\n\n"
+ " %s talker1.ini talker2.ini\n"
+ " Start 2 streams with data from the ini files.\n\n"
+ " %s -I eth0 talker1.ini talker2.ini\n"
+ " Start 2 streams with data from the ini files, both talkers use eth0 interface.\n\n"
+ " %s -I eth0 talker1.ini talker2.ini listener1.ini,ifname=pcap:eth0\n"
+ " Start 3 streams with data from the ini files, talkers 1&2 use eth0 interface, listener1 use pcap:eth0.\n\n"
+ ,
+ programName, programName, programName, programName, programName);
+}
+
+/**********************************************
+ * main
+ */
+int main(int argc, char *argv[])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HOST);
+
+ int iniIdx = 0;
+ char *programName;
+ char *optIfnameGlobal = NULL;
+
+ programName = strrchr(argv[0], '/');
+ programName = programName ? programName + 1 : argv[0];
+
+ if (argc < 2) {
+ openavbTlHostUsage(programName);
+ exit(-1);
+ }
+
+ tl_handle_t *tlHandleList = NULL;
+ int i1;
+
+ // Process command line
+ bool optDone = FALSE;
+ while (!optDone) {
+ int opt = getopt(argc, argv, "hI:");
+ if (opt != EOF) {
+ switch (opt) {
+ case 'I':
+ optIfnameGlobal = strdup(optarg);
+ break;
+ case 'h':
+ default:
+ openavbTlHostUsage(programName);
+ exit(-1);
+ }
+ }
+ else {
+ optDone = TRUE;
+ }
+ }
+
+ osalAVBInitialize(optIfnameGlobal);
+
+ iniIdx = optind;
+ U32 tlCount = argc - iniIdx;
+
+ if (!openavbTLInitialize(tlCount)) {
+ AVB_LOG_ERROR("Unable to initialize talker listener library");
+ osalAVBFinalize();
+ exit(-1);
+ }
+
+ // Setup signal handler
+ // We catch SIGINT and shutdown cleanly
+ bool err;
+ struct sigaction sa;
+ sa.sa_handler = openavbTLSigHandler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ err = sigaction(SIGINT, &sa, NULL);
+ if (err)
+ {
+ AVB_LOG_ERROR("Failed to setup SIGINT handler");
+ osalAVBFinalize();
+ exit(-1);
+ }
+ err = sigaction(SIGUSR1, &sa, NULL);
+ if (err)
+ {
+ AVB_LOG_ERROR("Failed to setup SIGUSR1 handler");
+ osalAVBFinalize();
+ exit(-1);
+ }
+
+ registerStaticMapModule(openavbMapPipeInitialize);
+ registerStaticMapModule(openavbMapAVTPAudioInitialize);
+ registerStaticMapModule(openavbMapCtrlInitialize);
+ registerStaticMapModule(openavbMapH264Initialize);
+ registerStaticMapModule(openavbMapMjpegInitialize);
+ registerStaticMapModule(openavbMapMpeg2tsInitialize);
+ registerStaticMapModule(openavbMapNullInitialize);
+ registerStaticMapModule(openavbMapUncmpAudioInitialize);
+
+ registerStaticIntfModule(openavbIntfEchoInitialize);
+ registerStaticIntfModule(openavbIntfCtrlInitialize);
+ registerStaticIntfModule(openavbIntfLoggerInitialize);
+ registerStaticIntfModule(openavbIntfNullInitialize);
+ //registerStaticIntfModule(openavbIntfToneGenInitialize);
+ registerStaticIntfModule(openavbIntfViewerInitialize);
+ registerStaticIntfModule(openavbIntfAlsaInitialize);
+ registerStaticIntfModule(openavbIntfMjpegGstInitialize);
+ registerStaticIntfModule(openavbIntfMpeg2tsFileInitialize);
+ registerStaticIntfModule(openavbIntfMpeg2tsGstInitialize);
+ registerStaticIntfModule(openavbIntfWavFileInitialize);
+ registerStaticIntfModule(openavbIntfH264RtpGstInitialize);
+
+ tlHandleList = calloc(1, sizeof(tl_handle_t) * tlCount);
+
+ // Open all streams
+ for (i1 = 0; i1 < tlCount; i1++) {
+ tlHandleList[i1] = openavbTLOpen();
+ }
+
+ // Parse ini and configure all streams
+ for (i1 = 0; i1 < tlCount; i1++) {
+ openavb_tl_cfg_t cfg;
+ openavb_tl_cfg_name_value_t NVCfg;
+ char iniFile[1024];
+
+ snprintf(iniFile, sizeof(iniFile), "%s", argv[i1 + iniIdx]);
+
+ if (optIfnameGlobal && !strcasestr(iniFile, ",ifname=")) {
+ snprintf(iniFile + strlen(iniFile), sizeof(iniFile), ",ifname=%s", optIfnameGlobal);
+ }
+
+ openavbTLInitCfg(&cfg);
+ memset(&NVCfg, 0, sizeof(NVCfg));
+
+ if (!openavbTLReadIniFileOsal(tlHandleList[i1], iniFile, &cfg, &NVCfg)) {
+ AVB_LOGF_ERROR("Error reading ini file: %s\n", argv[i1 + 1]);
+ osalAVBFinalize();
+ exit(-1);
+ }
+ if (!openavbTLConfigure(tlHandleList[i1], &cfg, &NVCfg)) {
+ AVB_LOGF_ERROR("Error configuring: %s\n", argv[i1 + 1]);
+ osalAVBFinalize();
+ exit(-1);
+ }
+
+ int i2;
+ for (i2 = 0; i2 < NVCfg.nLibCfgItems; i2++) {
+ free(NVCfg.libCfgNames[i2]);
+ free(NVCfg.libCfgValues[i2]);
+ }
+ }
+
+#ifdef AVB_FEATURE_GSTREAMER
+ // If we're supporting the interface modules which use GStreamer,
+ // initialize GStreamer here to avoid errors.
+ gst_init(0, NULL);
+#endif
+
+ for (i1 = 0; i1 < tlCount; i1++) {
+ openavbTLRun(tlHandleList[i1]);
+ }
+
+ while (bRunning) {
+ sleep(1);
+ }
+
+ for (i1 = 0; i1 < tlCount; i1++) {
+ openavbTLStop(tlHandleList[i1]);
+ }
+
+ for (i1 = 0; i1 < tlCount; i1++) {
+ openavbTLClose(tlHandleList[i1]);
+ }
+
+ openavbTLCleanup();
+
+#ifdef AVB_FEATURE_GSTREAMER
+ // If we're supporting the interface modules which use GStreamer,
+ // De-initialize GStreamer to clean up resources.
+ gst_deinit();
+#endif
+
+ osalAVBFinalize();
+
+ AVB_TRACE_EXIT(AVB_TRACE_HOST);
+ exit(0);
+}
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
new file mode 100644
index 00000000..227174c7
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avtp/openavb_avtp_time_osal.c
@@ -0,0 +1,34 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Avtp Time implementation
+*/
+
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/endpoint/CMakeLists.txt
new file mode 100644
index 00000000..139597f9
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c
new file mode 100644
index 00000000..d00e2380
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c
@@ -0,0 +1,224 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 .ini file for an enpoint and
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include "openavb_endpoint.h"
+#include "openavb_endpoint_cfg.h"
+#include "openavb_trace.h"
+#include "openavb_rawsock.h"
+#include "ini.h"
+
+#define AVB_LOG_COMPONENT "Endpoint"
+#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_endpoint_cfg_t *pCfg = (openavb_endpoint_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, IFNAMSIZ - 1);
+ memcpy(pCfg->ifmac, &ifinfo.mac, ETH_ALEN);
+ pCfg->ifindex = ifinfo.index;
+ pCfg->mtu = ifinfo.mtu;
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "link_kbit")) {
+ errno = 0;
+ pCfg->link_kbit = strtoul(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "nsr_kbit")) {
+ errno = 0;
+ pCfg->nsr_kbit = 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, "ptp"))
+ {
+ if (MATCH(name, "start_options")) {
+ pCfg->ptp_start_opts = strdup(value);
+ 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, "fqtss"))
+ {
+ if (MATCH(name, "mode")) {
+ errno = 0;
+ pCfg->fqtss_mode = 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, "srp"))
+ {
+ if (MATCH(name, "preconfigured")) {
+ errno = 0;
+ unsigned temp = strtoul(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0) {
+ valOK = TRUE;
+ if (temp == 1)
+ pCfg->noSrp = TRUE;
+ else
+ pCfg->noSrp = FALSE;
+ }
+ }
+ else if (MATCH(name, "gptp_asCapable_not_required")) {
+ errno = 0;
+ unsigned temp = strtoul(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0) {
+ valOK = TRUE;
+ if (temp == 1)
+ pCfg->bypassAsCapableCheck = TRUE;
+ else
+ pCfg->bypassAsCapableCheck = FALSE;
+ }
+ }
+ 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 openavbReadConfig(const char *ini_file, openavb_endpoint_cfg_t *pCfg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ // defaults - most are handled by setting everything to 0
+ memset(pCfg, 0, sizeof(openavb_endpoint_cfg_t));
+ pCfg->fqtss_mode = -1;
+
+ 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 openavbUnconfigure(openavb_endpoint_cfg_t *pCfg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ if (pCfg) {
+ if (pCfg->ptp_start_opts) {
+ free(pCfg->ptp_start_opts);
+ pCfg->ptp_start_opts = NULL;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+}
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.h b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.h
new file mode 100644
index 00000000..8cc989a5
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.h
@@ -0,0 +1,63 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_CONFIG_H
+#define AVB_ENDPOINT_CONFIG_H
+
+#include "openavb_types.h"
+#include "openavb_srp_api.h"
+#include "net/if.h"
+
+#define DEFAULT_INI_FILE "endpoint.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;
+} openavb_endpoint_cfg_t;
+
+int openavbReadConfig(const char *inifile, 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
new file mode 100644
index 00000000..bbc0e2a2
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_client_osal.c
@@ -0,0 +1,179 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_ENDPOINT_CLIENT_OSAL_C
+#define OPENAVB_ENDPOINT_CLIENT_OSAL_C
+
+static void socketClose(int h)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+ if (h != AVB_ENDPOINT_HANDLE_INVALID) {
+ close(h);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+}
+
+static bool openavbEptClntSendToServer(int h, openavbEndpointMessage_t *msg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ if (!msg || h == AVB_ENDPOINT_HANDLE_INVALID) {
+ AVB_LOG_ERROR("Client send: invalid argument passed");
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return FALSE;
+ }
+
+ ssize_t nWrite = write(h, msg, OPENAVB_ENDPOINT_MSG_LEN);
+ AVB_LOGF_VERBOSE("Sent message, len=%d, nWrite=%d", OPENAVB_ENDPOINT_MSG_LEN, nWrite);
+
+ if (nWrite < OPENAVB_ENDPOINT_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(h);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return TRUE;
+}
+
+int openavbEptClntOpenSrvrConnection(tl_state_t *pTLState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+ struct sockaddr_un server;
+ server.sun_family = AF_UNIX;
+ snprintf(server.sun_path, UNIX_PATH_MAX, AVB_ENDPOINT_UNIX_PATH);
+
+ int h = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (h < 0) {
+ AVB_LOGF_DEBUG("Failed to open socket: %s", strerror(errno));
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return AVB_ENDPOINT_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_ENDPOINT);
+ return AVB_ENDPOINT_HANDLE_INVALID;
+ }
+
+ AVB_LOG_DEBUG("connected to endpoint");
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return h;
+}
+
+void openavbEptClntCloseSrvrConnection(int h)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+ socketClose(h);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+}
+
+bool openavbEptClntService(int h, int timeout)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+ bool rc = FALSE;
+
+ if (h == AVB_ENDPOINT_HANDLE_INVALID) {
+ AVB_LOG_ERROR("Client service: invalid socket");
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return FALSE;
+ }
+
+ struct pollfd fds[1];
+ memset(fds, 0, sizeof(struct pollfd));
+ fds[0].fd = h;
+ 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_ENDPOINT);
+ return TRUE;
+ }
+ else if (pRet < 0) {
+ if (errno == EINTR) {
+ AVB_LOG_VERBOSE("Poll interrupted");
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ 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.
+ openavbEndpointMessage_t msgBuf;
+ memset(&msgBuf, 0, OPENAVB_ENDPOINT_MSG_LEN);
+ ssize_t nRead = read(h, &msgBuf, OPENAVB_ENDPOINT_MSG_LEN);
+
+ if (nRead < OPENAVB_ENDPOINT_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(h);
+ }
+ else {
+ // got a message
+ if (openavbEptClntReceiveFromServer(h, &msgBuf)) {
+ rc = TRUE;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid message received");
+ socketClose(h);
+ }
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return rc;
+}
+
+#endif // OPENAVB_ENDPOINT_CLIENT_OSAL_C
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.c
new file mode 100644
index 00000000..7eb3a17d
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.c
@@ -0,0 +1,577 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_endpoint_cfg.h"
+#include "openavb_srp.h"
+#include "openavb_maap.h"
+#include "mrp_client.h"
+#include "openavb_ether_hal.h"
+#include "openavb_list.h"
+
+#define AVB_LOG_COMPONENT "Endpoint"
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+// the following are from openavb_endpoint.c
+extern openavb_endpoint_cfg_t x_cfg;
+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)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+ 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;
+ }
+
+ // Set endpoint configuration
+ memset(&x_cfg, 0, sizeof(openavb_endpoint_cfg_t));
+ x_cfg.fqtss_mode = mode;
+ x_cfg.ifindex = ifindex;
+ if (ifname)
+ strncpy(x_cfg.ifname, ifname, sizeof(x_cfg.ifname));
+
+ igbGetMacAddr(x_cfg.ifmac);
+
+ x_cfg.mtu = 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) {
+ AVB_LOGF_ERROR("Failed to start endpoint thread: %s", strerror(err));
+ goto error;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return true;
+
+error:
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return false;
+}
+
+void stopEndpoint()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ endpointRunning = FALSE;
+ pthread_join(endpointServerHandle, NULL);
+
+ openavbUnconfigure(&x_cfg);
+
+ AVB_LOG_INFO("Shutting down");
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+}
+
+static void* endpointServerThread(void *arg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ while (endpointRunning) {
+ int err = avbEndpointLoop();
+ if (err) {
+ AVB_LOG_ERROR("Make sure that mrpd daemon is started.");
+ SLEEP(1);
+ }
+ }
+
+ 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
new file mode 100644
index 00000000..4f41f8d5
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.h
@@ -0,0 +1,62 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_ENDPOINT_H
+#define OSAL_ENDPOINT_H
+
+// should only be included from openavb_endpoint.h
+
+#include <linux/un.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <signal.h>
+
+typedef struct {
+ openavbEndpointMsgType_t type;
+ AVBStreamID_t streamID;
+ union {
+ // Client messages
+ openavbEndpointParams_TalkerRegister_t talkerRegister;
+ openavbEndpointParams_ListenerAttach_t listenerAttach;
+ openavbEndpointParams_ClientStop_t clientStop;
+ openavbEndpointParams_VersionRequest_t versionRequest;
+
+ // Server messages
+ openavbEndpointParams_TalkerCallback_t talkerCallback;
+ openavbEndpointParams_ListenerCallback_t listenerCallback;
+ openavbEndpointParams_VersionCallback_t versionCallback;
+ } params;
+} openavbEndpointMessage_t;
+
+
+bool startEndpoint(int mode, int ifindex, const char* ifname, unsigned mtu, unsigned link_kbit, unsigned nsr_kbit);
+void stopEndpoint();
+
+#endif // OSAL_ENDPOINT_H
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
new file mode 100644
index 00000000..c2a4125d
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_server_osal.c
@@ -0,0 +1,254 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_ENDPOINT_SERVER_OSAL_C
+#define OPENAVB_ENDPOINT_SERVER_OSAL_C
+
+#define AVB_ENDPOINT_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_ENDPOINT);
+
+ if (h < 0 || h >= POLL_FD_COUNT) {
+ AVB_LOG_ERROR("Closing socket; invalid handle");
+ }
+ else {
+ openavbEptSrvrCloseClientConnection(h);
+ close(fds[h].fd);
+ fds[h].fd = SOCK_INVALID;
+ fds[h].events = 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+}
+
+static bool openavbEptSrvrSendToClient(int h, openavbEndpointMessage_t *msg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ if (h < 0 || h >= POLL_FD_COUNT) {
+ AVB_LOG_ERROR("Sending message; invalid handle");
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return FALSE;
+ }
+ if (!msg) {
+ AVB_LOG_ERROR("Sending message; invalid argument passed");
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ 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_ENDPOINT_MSG_LEN);
+ AVB_LOGF_VERBOSE("Sent message, len=%d, nWrite=%d", OPENAVB_ENDPOINT_MSG_LEN, nWrite);
+ if (nWrite < OPENAVB_ENDPOINT_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_ENDPOINT);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return TRUE;
+}
+
+bool openavbEndpointServerOpen(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+ int i;
+
+ 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_ENDPOINT_UNIX_PATH);
+
+ 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 endpoint 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_ENDPOINT_LISTEN_FDS].fd = lsock;
+ fds[AVB_ENDPOINT_LISTEN_FDS].events = POLLIN;
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return TRUE;
+
+ error:
+ if (lsock >= 0) {
+ close(lsock);
+ lsock = -1;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return FALSE;
+}
+
+void openavbEptSrvrService(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+ 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_ENDPOINT_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);
+ }
+ }
+ }
+ else {
+ csock = fds[i].fd;
+ openavbEndpointMessage_t msgBuf;
+ memset(&msgBuf, 0, OPENAVB_ENDPOINT_MSG_LEN);
+ ssize_t nRead = read(csock, &msgBuf, OPENAVB_ENDPOINT_MSG_LEN);
+ AVB_LOGF_VERBOSE("Socket read h=%d,fd=%d: read=%d, expect=%d", i, csock, nRead, OPENAVB_ENDPOINT_MSG_LEN);
+
+ if (nRead < OPENAVB_ENDPOINT_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 (!openavbEptSrvrReceiveFromClient(i, &msgBuf)) {
+ AVB_LOG_ERROR("Failed to handle message");
+ socketClose(i);
+ }
+ }
+ }
+ }
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+}
+
+void openavbEndpointServerClose(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+ int i;
+ for (i = 0; i < POLL_FD_COUNT; i++) {
+ if (fds[i].fd != SOCK_INVALID) {
+ close(fds[i].fd);
+ }
+ }
+ 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));
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+}
+
+#endif // OPENAVB_ENDPOINT_SERVER_OSAL_C
diff --git a/lib/avtp_pipeline/platform/Linux/generic.cmake b/lib/avtp_pipeline/platform/Linux/generic.cmake
new file mode 100644
index 00000000..a81a99ef
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/generic.cmake
@@ -0,0 +1,17 @@
+# generic build settings
+# just builds linux version of stack on host machine
+
+# Label for messages / build configuration
+set ( OPENAVB_HAL "generic" )
+set ( OPENAVB_OSAL "Linux" )
+set ( OPENAVB_TCAL "GNU" )
+set ( OPENAVB_PLATFORM "${OPENAVB_HAL}-${OPENAVB_OSAL}" )
+
+# point to our "proxy" linux/ptp_clock.h include file
+# which includes /usr/include/linux/ptp_clock.h
+# and adding missing defines just to make everything compile
+include_directories ( platform/generic/include )
+
+set ( PLATFORM_DEFINE "AVB_DELAY_TWEAK_USEC=45" )
+
+set ( GSTREAMER_1_0 1 )
diff --git a/lib/avtp_pipeline/platform/Linux/gst_al/gst_al.h b/lib/avtp_pipeline/platform/Linux/gst_al/gst_al.h
new file mode 100644
index 00000000..d55284ae
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/gst_al/gst_al.h
@@ -0,0 +1,161 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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.
+*************************************************************************************************************/
+
+/**
+ * \brief - Gstreamer Abstraction Layer interface
+ * for handling different versions
+ * (currently 0.10 and 1.0)
+ */
+
+#include <gst/gst.h>
+#include <gst/app/gstappsink.h>
+#include <gst/app/gstappsrc.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+typedef GstFlowReturn (*GstAlCallback)(GstAppSink *sink, gpointer pv);
+
+/**
+ * \brief - Gstreamer Abstraction Layer buffer
+ */
+typedef struct _GstAlBuf
+{
+// public
+ gpointer m_dptr; //<! data pointer
+ guint m_dlen; //<! data length
+// private
+ GstBuffer *m_buffer; //<! gstreamer buffer
+#if GSTREAMER_1_0
+ GstSample *m_sample; //<! gstreamer sample
+ GstMemory *m_memory; //<! gstreamer memory
+ GstRTPBuffer m_rtpbuf; //<! gstreamer RTP buffer
+ GstMapInfo m_info; //<! gstreamer map info
+#endif
+}
+GstAlBuf;
+
+/** Gets buffer data pointer */
+#define GST_AL_BUF_DATA(buf) (buf->m_dptr)
+/** Gets buffer data length */
+#define GST_AL_BUF_SIZE(buf) (buf->m_dlen)
+
+#define GST_AL_BUFFER_TIMESTAMP(buf) GST_BUFFER_TIMESTAMP(buf->m_buffer)
+#define GST_AL_BUFFER_DURATION(buf) GST_BUFFER_DURATION(buf->m_buffer)
+
+/**
+ * \brief - sets a buffer callback
+ *
+ * \param cbfns - a pointer to a callbacks structure
+ * \param callback - a callback to set
+ */
+void gst_al_set_callback(GstAppSinkCallbacks *cbfns, GstAlCallback callback);
+/**
+ * \brief - pulls a buffer from a sink
+ *
+ * \param sink - a sink to pull a buffer from
+ *
+ * \return - a buffer taken from a sink
+ */
+GstAlBuf* gst_al_pull_buffer(GstAppSink *sink);
+/**
+ * \brief - pushes a buffer to source
+ *
+ * \param src - source to push a buffer to
+ */
+GstFlowReturn gst_al_push_buffer(GstAppSrc *src, GstAlBuf *buf);
+/**
+ * \brief - allocates a buffer
+ *
+ * \param len - length of a buffer
+ *
+ * \return - a newly allocated buffer
+ */
+GstAlBuf* gst_al_alloc_buffer(gint len);
+/**
+ * \brief - unrefs a buffer
+ *
+ * \param buf - a buffer to unref
+ */
+void gst_al_buffer_unref(GstAlBuf *buf);
+/**
+ * \brief - pulls a RTP buffer from sink
+ *
+ * \param sink - a sink to pull buffer from
+ *
+ * \return - a buffer taken from sink
+ */
+GstAlBuf* gst_al_pull_rtp_buffer(GstAppSink *sink);
+/**
+ * \brief - gets a RTP buffer marker
+ *
+ * \param buf - a RTP buffer
+ *
+ * \return - a RTP buffer marker
+ */
+gboolean gst_al_rtp_buffer_get_marker(GstAlBuf *buf);
+/**
+ * \brief - sets a RTP buffer marker
+ *
+ * \param buf - a RTP buffer
+ * \param mark - a marker
+ */
+void gst_al_rtp_buffer_set_marker(GstAlBuf *buf, gboolean mark);
+/**
+ * \brief - set a RTP buffer params
+ *
+ * \param buf - a RTP buffer
+ * \param ssrc - a ssrc param
+ * \param payload_type - a payload type param
+ * \param version - a version param
+ * \param sequence - a sequence param
+ */
+void gst_al_rtp_buffer_set_params(GstAlBuf *buf, gint ssrc,
+ gint payload_type, gint version, gint sequence);
+/**
+ * \brief - pushes a RTP buffer to source
+ *
+ * \param src - s source to push buffer to
+ */
+GstFlowReturn gst_al_push_rtp_buffer(GstAppSrc *src, GstAlBuf *buf);
+/**
+ * \brief - allocates a RTP buffer
+ *
+ * \param packet_len - length of a RTP buffer
+ * \param pad_len - pad length of a RTP buffer
+ * \param csrct_count - csrc count of a RTP buffer
+ *
+ * \return - a newly allocated RTP buffer
+ */
+GstAlBuf* gst_al_alloc_rtp_buffer(guint packet_len, guint8 pad_len, guint8 csrc_count);
+/**
+ * \brief - unrefs a RTP buffer
+ *
+ * \param buf - a RTP buffer to unref
+ */
+void gst_al_rtp_buffer_unref(GstAlBuf *buf);
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
new file mode 100644
index 00000000..86d7d475
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/gst_al/gst_al_01.c
@@ -0,0 +1,123 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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.
+*************************************************************************************************************/
+
+/*
+ * Gstreamer abstraction layer implementation
+ * for version 0.10
+ */
+
+#include "gst_al.h"
+
+void gst_al_set_callback(GstAppSinkCallbacks *cbfns, GstAlCallback callback)
+{
+ cbfns->new_buffer = callback;
+}
+
+GstAlBuf* gst_al_pull_buffer(GstAppSink *sink)
+{
+ GstAlBuf *buf = g_new(GstAlBuf,1);
+ buf->m_buffer = gst_app_sink_pull_buffer(sink);
+ buf->m_dptr = GST_BUFFER_DATA(buf->m_buffer);
+ buf->m_dlen = GST_BUFFER_SIZE(buf->m_buffer);
+ return buf;
+}
+
+GstAlBuf* gst_al_alloc_buffer(gint len)
+{
+ GstAlBuf *buf = g_new(GstAlBuf,1);
+ buf->m_buffer = gst_buffer_new_and_alloc(len);
+ buf->m_dptr = GST_BUFFER_DATA(buf->m_buffer);
+ buf->m_dlen = GST_BUFFER_SIZE(buf->m_buffer);
+ return buf;
+}
+
+GstFlowReturn gst_al_push_buffer(GstAppSrc *src, GstAlBuf *buf)
+{
+ GstFlowReturn gstret = gst_app_src_push_buffer(src, buf->m_buffer);
+ g_free(buf);
+ return gstret;
+}
+
+void gst_al_buffer_unref(GstAlBuf *buf)
+{
+ gst_buffer_unref(buf->m_buffer);
+ g_free(buf);
+}
+
+GstAlBuf* gst_al_pull_rtp_buffer(GstAppSink *sink)
+{
+ GstAlBuf *buf = g_new(GstAlBuf,1);
+ buf->m_buffer = gst_app_sink_pull_buffer(sink);
+ buf->m_dptr = gst_rtp_buffer_get_payload(buf->m_buffer);
+ buf->m_dlen = gst_rtp_buffer_get_payload_len(buf->m_buffer);
+ return buf;
+}
+
+gboolean gst_al_rtp_buffer_get_marker(GstAlBuf *buf)
+{
+ return gst_rtp_buffer_get_marker(buf->m_buffer);
+}
+
+void gst_al_rtp_buffer_set_marker(GstAlBuf *buf, gboolean mark)
+{
+ gst_rtp_buffer_set_marker(buf->m_buffer, mark);
+}
+
+void gst_al_rtp_buffer_set_params(GstAlBuf *buf, gint ssrc,
+ gint payload_type, gint version, gint sequence)
+{
+ GstBuffer *buffer = buf->m_buffer;
+ gst_rtp_buffer_set_ssrc(buffer, ssrc);
+ gst_rtp_buffer_set_payload_type(buffer, payload_type);
+ gst_rtp_buffer_set_version(buffer, version);
+ gst_rtp_buffer_set_seq(buffer, sequence);
+}
+
+GstFlowReturn gst_al_push_rtp_buffer(GstAppSrc *src, GstAlBuf *buf)
+{
+ GstFlowReturn gstret = gst_app_src_push_buffer(src, buf->m_buffer);
+ g_free(buf);
+ return gstret;
+}
+
+GstAlBuf* gst_al_alloc_rtp_buffer(guint payload_len, guint8 pad_len, guint8 csrc_count)
+{
+ GstAlBuf *buf = g_new(GstAlBuf,1);
+ buf->m_buffer = gst_rtp_buffer_new_allocate(payload_len, pad_len, csrc_count);
+ buf->m_dptr = gst_rtp_buffer_get_payload(buf->m_buffer);
+ buf->m_dlen = gst_rtp_buffer_get_payload_len(buf->m_buffer);
+ return buf;
+}
+
+void gst_al_rtp_buffer_unref(GstAlBuf *buf)
+{
+ gst_buffer_unref(buf->m_buffer);
+ g_free(buf);
+}
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
new file mode 100644
index 00000000..a3fa8a47
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/gst_al/gst_al_10.c
@@ -0,0 +1,211 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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.
+*************************************************************************************************************/
+
+/*
+ * Gstreamer abstraction layer implementation
+ * for version 1.0
+ */
+#include "gst_al.h"
+
+void gst_al_set_callback(GstAppSinkCallbacks *cbfns, GstAlCallback callback)
+{
+ cbfns->new_sample = callback;
+}
+
+GstAlBuf* gst_al_pull_buffer(GstAppSink *sink)
+{
+ GstAlBuf *buf = g_new0(GstAlBuf,1);
+ GstMemory *memory;
+ GstBuffer * buffer;
+ GstSample *sample = gst_app_sink_pull_sample(sink);
+ buf->m_sample = sample;
+ if(sample)
+ {
+ buffer = gst_sample_get_buffer(sample);
+ buf->m_buffer = buffer;
+ if(buffer)
+ {
+ memory = gst_buffer_get_memory(buffer, 0);
+ buf->m_memory = memory;
+ if(memory)
+ {
+ GstMapInfo *info = &buf->m_info;
+ if(gst_memory_map(memory, info, GST_MAP_READ))
+ {
+ buf->m_dptr = info->data;
+ buf->m_dlen = info->size;
+ goto pull_success;
+ }
+ gst_memory_unref(memory);
+ }
+ }
+ gst_sample_unref(sample);
+ }
+ g_free(buf);
+ buf = NULL;
+pull_success:
+ return buf;
+}
+
+GstAlBuf* gst_al_alloc_buffer(gint len)
+{
+ GstAlBuf *buf = g_new0(GstAlBuf,1);
+ GstMemory *memory;
+ GstBuffer *buffer = gst_buffer_new_and_alloc(len);
+ buf->m_buffer = buffer;
+ if(buffer)
+ {
+ memory = gst_buffer_get_memory(buffer, 0);
+ buf->m_memory = memory;
+ if(memory)
+ {
+ GstMapInfo *info = &buf->m_info;
+ if(TRUE == gst_memory_map(memory, info, GST_MAP_WRITE))
+ {
+ buf->m_dptr = info->data;
+ buf->m_dlen = info->size;
+ goto alloc_success;
+ }
+ gst_memory_unref(memory);
+ }
+ gst_buffer_unref(buffer);
+ }
+ g_free(buf);
+ buf = NULL;
+alloc_success:
+ return buf;
+}
+
+GstFlowReturn gst_al_push_buffer(GstAppSrc *src, GstAlBuf *buf)
+{
+ GstFlowReturn gstret = gst_app_src_push_buffer(src, buf->m_buffer);
+ gst_memory_unmap(buf->m_memory, &buf->m_info);
+ gst_memory_unref(buf->m_memory);
+ g_free(buf);
+ return gstret;
+}
+
+void gst_al_buffer_unref(GstAlBuf *buf)
+{
+ gst_memory_unmap(buf->m_memory, &buf->m_info);
+ gst_memory_unref(buf->m_memory);
+ gst_sample_unref(buf->m_sample);
+ g_free(buf);
+}
+
+GstAlBuf* gst_al_pull_rtp_buffer(GstAppSink *sink)
+{
+
+ GstAlBuf *buf = g_new0(GstAlBuf,1);
+ GstBuffer *buffer;
+ GstSample *sample = gst_app_sink_pull_sample(sink);
+ buf->m_sample = sample;
+
+ if(sample)
+ {
+ buffer = gst_sample_get_buffer(sample);
+ buf->m_buffer = buffer;
+
+ if(buffer)
+ {
+ GstRTPBuffer *rtpbuf = &buf->m_rtpbuf;
+ if( gst_rtp_buffer_map(buffer, GST_MAP_READ, rtpbuf))
+ {
+ buf->m_dptr = gst_rtp_buffer_get_payload(rtpbuf);
+ buf->m_dlen = gst_rtp_buffer_get_payload_len(rtpbuf);
+ goto pull_rtp_success;
+ }
+ }
+ gst_sample_unref(sample);
+ }
+ g_free(buf);
+ buf = NULL;
+pull_rtp_success:
+ return buf;
+}
+
+GstAlBuf* gst_al_alloc_rtp_buffer(guint payload_len,
+ guint8 pad_len, guint8 csrc_count)
+{
+ GstAlBuf *buf = g_new0(GstAlBuf, 1);
+ GstBuffer *buffer = gst_rtp_buffer_new_allocate(payload_len, pad_len, csrc_count);
+ buf->m_buffer = buffer;
+ if(buffer)
+ {
+ GstRTPBuffer *rtpbuf = &buf->m_rtpbuf;
+ if( gst_rtp_buffer_map(buffer, GST_MAP_WRITE, rtpbuf))
+ {
+ buf->m_dptr = gst_rtp_buffer_get_payload(rtpbuf);
+ buf->m_dlen = gst_rtp_buffer_get_payload_len(rtpbuf);
+ goto alloc_rtp_success;
+ }
+ gst_buffer_unref(buffer);
+ }
+ g_free(buf);
+ buf = NULL;
+alloc_rtp_success:
+ return buf;
+}
+
+gboolean gst_al_rtp_buffer_get_marker(GstAlBuf *buf)
+{
+ return gst_rtp_buffer_get_marker(&buf->m_rtpbuf);
+}
+
+void gst_al_rtp_buffer_set_marker(GstAlBuf *buf, gboolean mark)
+{
+ gst_rtp_buffer_set_marker(&buf->m_rtpbuf, mark);
+}
+
+void gst_al_rtp_buffer_set_params(GstAlBuf *buf, gint ssrc,
+ gint payload_type, gint version,
+ gint sequence)
+{
+ GstRTPBuffer *rtpbuf = &buf->m_rtpbuf;
+ gst_rtp_buffer_set_ssrc(rtpbuf, ssrc);
+ gst_rtp_buffer_set_payload_type(rtpbuf, payload_type);
+ gst_rtp_buffer_set_version(rtpbuf, version);
+ gst_rtp_buffer_set_seq(rtpbuf, sequence);
+}
+
+GstFlowReturn gst_al_push_rtp_buffer(GstAppSrc *src, GstAlBuf *buf)
+{
+ gst_rtp_buffer_unmap(&buf->m_rtpbuf);
+ GstFlowReturn gstret = gst_app_src_push_buffer(src, buf->m_buffer);
+ g_free(buf);
+ return gstret;
+}
+
+void gst_al_rtp_buffer_unref(GstAlBuf *buf)
+{
+ gst_rtp_buffer_unmap(&buf->m_rtpbuf);
+ gst_sample_unref(buf->m_sample);
+ g_free(buf);
+}
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/intf_alsa/CMakeLists.txt
new file mode 100644
index 00000000..4d4747f3
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/CMakeLists.txt
@@ -0,0 +1,10 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_OSAL_DIR}/intf_alsa/openavb_intf_alsa.c
+ PARENT_SCOPE
+)
+
+# Need include and link directories for ALSA
+SET (INTF_INCLUDE_DIR ${INTF_INCLUDE_DIR} ${ALSA_INCLUDE_DIRS} PARENT_SCOPE)
+SET (INTF_LIBRARY_DIR ${INTF_LIBRARY_DIR} ${ALSA_LIBRARY_DIRS} PARENT_SCOPE)
+SET (INTF_LIBRARY ${ALSA_LIBRARIES} pthread rt PARENT_SCOPE)
+
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
new file mode 100644
index 00000000..ffa339a5
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_file_talker.ini
@@ -0,0 +1,120 @@
+#####################################################################
+# General Talker configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = talker
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 2
+
+# dest_addr: destination multicast address for the stream.
+#
+# If using SRP and MAAP, dynamic destination addresses are generated
+# automatically by the talker and passed to the listner, and don't
+# need to be configured.
+#
+# Without MAAP, locally administered (static) addresses must be
+# configured. Thouse 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.
+#
+# When SRP is being used the static destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set (to the same value) in both the talker and listener.
+#
+# 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.
+#
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1000
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+#report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_aaf_audio.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapAVTPAudioInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+# map_nv_tx_rate: Transmit rate.
+# This must be set for the AAF audio mapping module.
+map_nv_tx_rate = 4000
+
+# map_nv_packing_factor: Multiple of how many packets of audio frames to place in a media queue item.
+map_nv_packing_factor = 32
+
+# map_nv_sparse_mode: if set to 0 put presentation time in each packet.
+# Set to 1 to use sparse mode - valid timestamp in every 8th packet.
+# Default value used (0) when commented.
+map_nv_sparse_mode = 0
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. 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.
+intf_lib = ./libopenavb_intf_wav_file.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfWavFileInitialize
+
+# intf_nv_file_name: The fully qualified file name.
+intf_nv_file_name = test.wav
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener.ini
new file mode 100644
index 00000000..b04ca608
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener.ini
@@ -0,0 +1,129 @@
+#####################################################################
+# Configuration for ALSA and the uncompressed audio mapping module
+#####################################################################
+
+#####################################################################
+# General Listener configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = listener
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 2
+
+# dest_addr: When SRP is being used the destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set in both side the talker and listener.
+# 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.
+# At this time they need to be locally administered and must be in the range
+# of 91:E0:F0:00:FE:00 - 91:E0:F0:00:FE:FF.
+# Typically :00 for the first stream, :01 for the second, etc.
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 50000
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+#report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_aaf_audio.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapAVTPAudioInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 32
+
+# map_nv_tx_rate: Transmit rate.
+# This must be set for the AAF audio mapping module.
+map_nv_tx_rate = 4000
+
+# map_nv_packing_factor: Multiple of how many packets of audio frames to place in a media queue item.
+# If sparse timestamping mode is enabled the listener should set here one of the possible
+# packing factors values to be sure that proper presentation time is put into media queue item.
+# Possible values are: 1, 2, 4, 8, 16, 24, 32, 40, 48, (+ 8)...
+map_nv_packing_factor = 32
+
+# map_nv_sparse_mode: if set to 0 presentation time should be
+# valid in each packet. Set to 1 to use sparse mode - presentation
+# time should be valid in every 8th packet.
+map_nv_sparse_mode = 0
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. 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.
+intf_lib = ./libopenavb_intf_alsa.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfAlsaInitialize
+
+# intf_nv_ignore_timestamp: If set the listener will ignore the timestamp on media queue items.
+# intf_nv_ignore_timestamp = 1
+
+# intf_nv_device_name: ALSA device name. Commonly "default" or "plug:dmix"
+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
+intf_nv_audio_rate = 48000
+
+# intf_nv_audio_bit_depth: Valid values that are supported by AAF are:
+# 8, 16, 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 = 2
+
+# intf_nv_allow_resampling: 0 = disable software resampling. 1 = allow software resampling. Default is disable.
+intf_nv_allow_resampling = 1
+
+# intf_nv_start_threshold_periods: The number of period to wait before starting playback. The larger the value to great
+# the latency. The small the number the great chance for a buffer underrun. A good range is 1 - 5.
+intf_nv_start_threshold_periods = 3
+
+# intf_nv_period_time: the number of microseconds which should be set to unify latency between different platforms.
+# 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
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
new file mode 100644
index 00000000..481dac65
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener_auto.ini
@@ -0,0 +1,129 @@
+#####################################################################
+# Configuration for ALSA and the uncompressed audio mapping module
+#####################################################################
+
+#####################################################################
+# General Listener configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = listener
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 2
+
+# dest_addr: When SRP is being used the destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set in both side the talker and listener.
+# 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.
+# At this time they need to be locally administered and must be in the range
+# of 91:E0:F0:00:FE:00 - 91:E0:F0:00:FE:FF.
+# Typically :00 for the first stream, :01 for the second, etc.
+dest_addr = 91:e0:f0:00:fe:01
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 2000
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+#report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_aaf_audio.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapAVTPAudioInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 32
+
+# map_nv_tx_rate: Transmit rate.
+# This must be set for the AAF audio mapping module.
+map_nv_tx_rate = 8000
+
+# map_nv_packing_factor: Multiple of how many packets of audio frames to place in a media queue item.
+# If sparse timestamping mode is enabled the listener should set here one of the possible
+# packing factors values to be sure that proper presentation time is put into media queue item.
+# Possible values are: 1, 2, 4, 8, 16, 24, 32, 40, 48, (+ 8)...
+map_nv_packing_factor = 32
+
+# map_nv_sparse_mode: if set to 0 presentation time should be
+# valid in each packet. Set to 1 to use sparse mode - presentation
+# time should be valid in every 8th packet.
+map_nv_sparse_mode = 0
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. 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.
+intf_lib = ./libopenavb_intf_alsa.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfAlsaInitialize
+
+# intf_nv_ignore_timestamp: If set the listener will ignore the timestamp on media queue items.
+# intf_nv_ignore_timestamp = 1
+
+# intf_nv_device_name: ALSA device name. Commonly "default" or "plug:dmix"
+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
+intf_nv_audio_rate = 48000
+
+# intf_nv_audio_bit_depth: Valid values that are supported by AAF are:
+# 8, 16, 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 = 2
+
+# intf_nv_allow_resampling: 0 = disable software resampling. 1 = allow software resampling. Default is disable.
+intf_nv_allow_resampling = 1
+
+# intf_nv_start_threshold_periods: The number of period to wait before starting playback. The larger the value to great
+# the latency. The small the number the great chance for a buffer underrun. A good range is 1 - 5.
+intf_nv_start_threshold_periods = 3
+
+# intf_nv_period_time: the number of microseconds which should be set to unify latency between different platforms.
+# 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
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_talker.ini
new file mode 100644
index 00000000..40bb3e38
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_talker.ini
@@ -0,0 +1,155 @@
+#####################################################################
+# General Talker configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = talker
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 2
+
+# dest_addr: destination multicast address for the stream.
+#
+# If using SRP and MAAP, dynamic destination addresses are generated
+# automatically by the talker and passed to the listner, and don't
+# need to be configured.
+#
+# Without MAAP, locally administered (static) addresses must be
+# configured. Thouse 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.
+#
+# When SRP is being used the static destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set (to the same value) in both the talker and listener.
+#
+# 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.
+#
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 50000
+
+# max_transmit_deficit_usec: Allows setting the maximum packet transmit rate deficit that will
+# be recovered when a talker falls behind. This is only used on a talker side. 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. Typically this value can be set to the expected buffer size (in usec) that listeners are
+# expected to be buffering. 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.
+max_transmit_deficit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+#report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_aaf_audio.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapAVTPAudioInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+# map_nv_tx_rate: Transmit rate.
+# This must be set for the simple audio mapping module.
+# The recommended values are:
+# For audio sample rates which are a multiple of 8000hz: 8000 for class A, 4000 for class B
+# For audio sample rates which are a multiple of 44100hz: 7350 for class A, 3675 for class B
+map_nv_tx_rate = 4000
+
+# map_nv_packing_factor: Each media queue item will hold data for this many packets
+map_nv_packing_factor = 32
+
+# map_nv_sparse_mode: if set to 0 put presentation time in each packet.
+# Set to 1 to use sparse mode - valid timestamp in every 8th packet.
+# Default value used (0) when commented.
+map_nv_sparse_mode = 0
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. 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.
+intf_lib = ./libopenavb_intf_alsa.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfAlsaInitialize
+
+# intf_nv_device_name: ALSA device name. Commonly "default" or "plug:dmix"
+# hw:CARD=Loopback,DEV=1
+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
+intf_nv_audio_rate = 48000
+
+# intf_nv_audio_bit_depth: Valid values that are supported by AAF are:
+# 8, 16, 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 = 2
+
+# intf_nv_allow_resampling: 0 = disable software resampling. 1 = allow software resampling. Default is disable.
+intf_nv_allow_resampling = 1
+
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_intf.md b/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_intf.md
new file mode 100644
index 00000000..cd97cf1a
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_intf.md
@@ -0,0 +1,50 @@
+ALSA interface {#alsa_intf}
+==============
+
+# Description
+
+ALSA interface module. An interface to connect AVTP streams to ALSA either as an audio source or sink.
+
+<br>
+# Interface module configuration parameters
+
+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
+
+<br>
+# Notes
+
+There are some parameters that have to be set during configuration of this
+interface module and before configuring mapping:
+* [AAF audio mapping](@ref aaf_audio_map)
+* [Uncompressed audio mapping](@ref uncmp_audio_map)
+
+These parameters can be set in either:
+* in the ini file (or available configuration system), so values will be parsed
+in the intf_cfg_cb function,
+* in the interface module initialization function where valid values can be
+assigned directly
+
+Values assigned in the intf_cfg_cb function will override any values set in the
+initialization function.
+
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_listener.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_listener.ini
new file mode 100644
index 00000000..944616d1
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_listener.ini
@@ -0,0 +1,145 @@
+#####################################################################
+# Configuration for ALSA and the uncompressed audio mapping module
+#####################################################################
+
+#####################################################################
+# General Listener configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = listener
+
+# 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
+stream_addr = 84:7E:40:2C:8F:DE
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: When SRP is being used the destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set in both side the talker and listener.
+# 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.
+# At this time they need to be locally administered and must be in the range
+# of 91:E0:F0:00:FE:00 - 91:E0:F0:00:FE:FF.
+# Typically :00 for the first stream, :01 for the second, etc.
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+#max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = A
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+raw_rx_buffers = 200
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_uncmp_audio.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapUncmpAudioInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 32
+
+# map_nv_tx_rate: Transmit rate.
+# This must be set for the uncompressed audio mapping module.
+map_nv_tx_rate = 8000
+
+# map_nv_packing_factor: Multiple of how many packets of audio frames to place in a media queue item.
+# Note: Typically when decreasing the map_nv_tx_rate the packing factor will also be decreased since
+# the number of frames per packet will be increasing.
+# The ALSA interface module writes entire media queue items to the ALSA APIs. ALSA is much happier with
+# larger blocks of writes otherwise buffer underruns can occur. Typically at least the number of frames greater
+# than a period size.
+map_nv_packing_factor = 32
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. 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.
+intf_lib = ./libopenavb_intf_alsa.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfAlsaInitialize
+
+# intf_nv_ignore_timestamp: If set the listener will ignore the timestamp on media queue items.
+# intf_nv_ignore_timestamp = 1
+
+# intf_nv_device_name: ALSA device name. Commonly "default" or "plug:dmix"
+intf_nv_device_name = default
+
+# intf_nv_audio_rate: Valid values that are supported by the Alsa, TI J5 and 61883-6 are: 32000, 44100, 48000, 88200 and 96000
+intf_nv_audio_rate = 48000
+
+# intf_nv_audio_bit_depth: Valid values that are supported by the Alsa, TI J5 and 61883-6 are: 16
+# Note: Typically 20 and 24 bit is not supported in ALSA
+intf_nv_audio_bit_depth = 16
+
+# intf_nv_audio_channels: Valid values that are supported by the Alsa, TI J5 and 61883-6 are: 1 - 8
+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
+
+# intf_nv_start_threshold_periods: The number of period to wait before starting playback. The larger the value to great
+# the latency. The small the number the great chance for a buffer underrun. A good range is 1 - 5.
+intf_nv_start_threshold_periods = 2
+
+# intf_nv_period_time: the number of microseconds which should be set to unify latency between different platforms.
+# 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
+
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_talker.ini
new file mode 100644
index 00000000..652b9704
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_talker.ini
@@ -0,0 +1,148 @@
+#####################################################################
+# Configuration for ALSA and the uncompressed audio mapping module
+#####################################################################
+
+#####################################################################
+# General Talker configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = talker
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: When SRP is being used the destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set in both side the talker and listener.
+# 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.
+# At this time they need to be locally administered and must be in the range
+# of 91:E0:F0:00:FE:00 - 91:E0:F0:00:FE:FF.
+# Typically :00 for the first stream, :01 for the second, etc.
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = A
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 2000
+
+# max_transmit_deficit_usec: Allows setting the maximum packet transmit rate deficit that will
+# be recovered when a talker falls behind. This is only used on a talker side. 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. Typically this value can be set to the expected buffer size (in usec) that listeners are
+# expected to be buffering. 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.
+max_transmit_deficit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 4
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_uncmp_audio.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapUncmpAudioInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+# map_nv_tx_rate: Transmit rate.
+# This must be set for the uncompressed audio mapping module.
+map_nv_tx_rate = 8000
+
+# map_nv_packing_factor: Multiple of how many packets of audio frames to place in a media queue item.
+# Note: Typically when decreasing the map_nv_tx_rate the packing factor will also be decreased since
+# the number of frames per packet will be increasing.
+map_nv_packing_factor = 32
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. 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.
+intf_lib = ./libopenavb_intf_alsa.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfAlsaInitialize
+
+# intf_nv_ignore_timestamp: If set the listener will ignore the timestamp on media queue items.
+# intf_nv_ignore_timestamp = 1
+
+# intf_nv_device_name: ALSA device name. Commonly "default" or "plug:dmix"
+intf_nv_device_name = default
+
+# intf_nv_audio_rate: Valid values that are supported by the Alsa, TI J5 and 61883-6 are: 32000, 44100, 48000, 88200 and 96000
+intf_nv_audio_rate = 48000
+
+# intf_nv_audio_bit_depth: Valid values that are supported by the Alsa, TI J5 and 61883-6 are: 16
+# Note: Typically 20 and 24 bit is not supported in ALSA
+intf_nv_audio_bit_depth = 16
+
+# intf_nv_audio_channels: Valid values that are supported by the Alsa, TI J5 and 61883-6 are: 1 - 8
+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
+
+
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
new file mode 100644
index 00000000..7685db93
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/openavb_intf_alsa.c
@@ -0,0 +1,1041 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : ALSA interface module.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "openavb_types_pub.h"
+#include "openavb_audio_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_map_uncmp_audio_pub.h"
+#include "openavb_map_aaf_audio_pub.h"
+#include "openavb_intf_pub.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.
+#include <alsa/asoundlib.h>
+
+#define PCM_DEVICE_NAME_DEFAULT "default"
+#define PCM_ACCESS_TYPE SND_PCM_ACCESS_RW_INTERLEAVED
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ // Ignore timestamp at listener.
+ bool ignoreTimestamp;
+
+ // ALSA Device name
+ char *pDeviceName;
+
+ // map_nv_audio_rate
+ avb_audio_rate_t audioRate;
+
+ // map_nv_audio_type
+ avb_audio_type_t audioType;
+
+ // map_nv_audio_bit_depth
+ avb_audio_bit_depth_t audioBitDepth;
+
+ // map_nv_audio_endian
+ avb_audio_endian_t audioEndian;
+
+ // map_nv_channels
+ avb_audio_channels_t audioChannels;
+
+ // map_nv_allow_resampling
+ bool allowResampling;
+
+ U32 startThresholdPeriods;
+
+ U32 periodTimeUsec;
+
+ /////////////
+ // Variable data
+ /////////////
+ // Handle for the PCM device
+ snd_pcm_t *pcmHandle;
+
+ // ALSA stream
+ snd_pcm_stream_t pcmStream;
+
+ // ALSA read/write interval
+ U32 intervalCounter;
+} pvt_data_t;
+
+
+static snd_pcm_format_t x_AVBAudioFormatToAlsaFormat(avb_audio_type_t type,
+ avb_audio_bit_depth_t bitDepth,
+ avb_audio_endian_t endian,
+ char const* pMediaQDataFormat)
+{
+ bool tight = FALSE;
+ if (bitDepth == AVB_AUDIO_BIT_DEPTH_24BIT) {
+ if (pMediaQDataFormat != NULL
+ && (strcmp(pMediaQDataFormat, MapAVTPAudioMediaQDataFormat) == 0
+ || strcmp(pMediaQDataFormat, MapUncmpAudioMediaQDataFormat) == 0)) {
+ tight = TRUE;
+ }
+ }
+
+ if (type == AVB_AUDIO_TYPE_FLOAT) {
+ switch (bitDepth) {
+ case AVB_AUDIO_BIT_DEPTH_32BIT:
+ if (endian == AVB_AUDIO_ENDIAN_BIG)
+ return SND_PCM_FORMAT_FLOAT_BE;
+ else
+ return SND_PCM_FORMAT_FLOAT_LE;
+ default:
+ AVB_LOGF_ERROR("Unsupported audio bit depth for float: %d", bitDepth);
+ break;
+ }
+ }
+ else if (type == AVB_AUDIO_TYPE_UINT) {
+ switch (bitDepth) {
+ case AVB_AUDIO_BIT_DEPTH_8BIT:
+ return SND_PCM_FORMAT_U8;
+ case AVB_AUDIO_BIT_DEPTH_16BIT:
+ if (endian == AVB_AUDIO_ENDIAN_BIG)
+ return SND_PCM_FORMAT_U16_BE;
+ else
+ return SND_PCM_FORMAT_U16_LE;
+ case AVB_AUDIO_BIT_DEPTH_20BIT:
+ if (endian == AVB_AUDIO_ENDIAN_BIG)
+ return SND_PCM_FORMAT_U20_3BE;
+ else
+ return SND_PCM_FORMAT_U20_3LE;
+ case AVB_AUDIO_BIT_DEPTH_24BIT:
+ if (tight) {
+ if (endian == AVB_AUDIO_ENDIAN_BIG)
+ return SND_PCM_FORMAT_U24_3BE;
+ else
+ return SND_PCM_FORMAT_U24_3LE;
+ }
+ else {
+ if (endian == AVB_AUDIO_ENDIAN_BIG)
+ return SND_PCM_FORMAT_U24_BE;
+ else
+ return SND_PCM_FORMAT_U24_LE;
+ }
+ case AVB_AUDIO_BIT_DEPTH_32BIT:
+ if (endian == AVB_AUDIO_ENDIAN_BIG)
+ return SND_PCM_FORMAT_U32_BE;
+ else
+ return SND_PCM_FORMAT_U32_LE;
+ case AVB_AUDIO_BIT_DEPTH_1BIT:
+ case AVB_AUDIO_BIT_DEPTH_48BIT:
+ case AVB_AUDIO_BIT_DEPTH_64BIT:
+ default:
+ AVB_LOGF_ERROR("Unsupported integer audio bit depth: %d", bitDepth);
+ break;
+ }
+ }
+ else {
+ // AVB_AUDIO_TYPE_INT
+ // or unspecified (defaults to signed int)
+ switch (bitDepth) {
+ case AVB_AUDIO_BIT_DEPTH_8BIT:
+ // 8bit samples don't worry about endianness,
+ // but default to unsigned instead of signed.
+ if (type == AVB_AUDIO_TYPE_INT)
+ return SND_PCM_FORMAT_S8;
+ else // default
+ return SND_PCM_FORMAT_U8;
+ case AVB_AUDIO_BIT_DEPTH_16BIT:
+ if (endian == AVB_AUDIO_ENDIAN_BIG)
+ return SND_PCM_FORMAT_S16_BE;
+ else
+ return SND_PCM_FORMAT_S16_LE;
+ case AVB_AUDIO_BIT_DEPTH_20BIT:
+ if (endian == AVB_AUDIO_ENDIAN_BIG)
+ return SND_PCM_FORMAT_S20_3BE;
+ else
+ return SND_PCM_FORMAT_S20_3LE;
+ case AVB_AUDIO_BIT_DEPTH_24BIT:
+ if (tight) {
+ if (endian == AVB_AUDIO_ENDIAN_BIG)
+ return SND_PCM_FORMAT_S24_3BE;
+ else
+ return SND_PCM_FORMAT_S24_3LE;
+ }
+ else {
+ if (endian == AVB_AUDIO_ENDIAN_BIG)
+ return SND_PCM_FORMAT_S24_BE;
+ else
+ return SND_PCM_FORMAT_S24_LE;
+ }
+ case AVB_AUDIO_BIT_DEPTH_32BIT:
+ if (endian == AVB_AUDIO_ENDIAN_BIG)
+ return SND_PCM_FORMAT_S32_BE;
+ else
+ return SND_PCM_FORMAT_S32_LE;
+ case AVB_AUDIO_BIT_DEPTH_1BIT:
+ case AVB_AUDIO_BIT_DEPTH_48BIT:
+ case AVB_AUDIO_BIT_DEPTH_64BIT:
+ default:
+ AVB_LOGF_ERROR("Unsupported audio bit depth: %d", bitDepth);
+ break;
+ }
+ }
+
+ return SND_PCM_FORMAT_UNKNOWN;
+}
+
+
+// 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)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ if (pMediaQ) {
+ char *pEnd;
+ long tmp;
+ U32 val;
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo;
+ pPubMapUncmpAudioInfo = (media_q_pub_map_uncmp_audio_info_t *)pMediaQ->pPubMapInfo;
+ if (!pPubMapUncmpAudioInfo) {
+ AVB_LOG_ERROR("Public map data for audio info not allocated.");
+ return;
+ }
+
+
+ if (strcmp(name, "intf_nv_ignore_timestamp") == 0) {
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1) {
+ pPvtData->ignoreTimestamp = (tmp == 1);
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_device_name") == 0) {
+ if (pPvtData->pDeviceName)
+ free(pPvtData->pDeviceName);
+ pPvtData->pDeviceName = strdup(value);
+ }
+
+ else if (strcmp(name, "intf_nv_audio_rate") == 0) {
+ val = strtol(value, &pEnd, 10);
+ // TODO: Should check for specific values
+ if (val >= AVB_AUDIO_RATE_8KHZ && val <= AVB_AUDIO_RATE_192KHZ) {
+ pPvtData->audioRate = val;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid audio rate configured for intf_nv_audio_rate.");
+ pPvtData->audioRate = AVB_AUDIO_RATE_44_1KHZ;
+ }
+
+ // Give the audio parameters to the mapping module.
+ if (pMediaQ->pMediaQDataFormat) {
+ if (strcmp(pMediaQ->pMediaQDataFormat, MapUncmpAudioMediaQDataFormat) == 0
+ || strcmp(pMediaQ->pMediaQDataFormat, MapAVTPAudioMediaQDataFormat) == 0) {
+ pPubMapUncmpAudioInfo->audioRate = pPvtData->audioRate;
+ }
+ //else if (pMediaQ->pMediaQDataFormat == MapSAFMediaQDataFormat) {
+ //}
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_audio_bit_depth") == 0) {
+ val = strtol(value, &pEnd, 10);
+ // 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;
+ }
+
+ // Give the audio parameters to the mapping module.
+ if (pMediaQ->pMediaQDataFormat) {
+ if (strcmp(pMediaQ->pMediaQDataFormat, MapUncmpAudioMediaQDataFormat) == 0
+ || strcmp(pMediaQ->pMediaQDataFormat, MapAVTPAudioMediaQDataFormat) == 0) {
+ pPubMapUncmpAudioInfo->audioBitDepth = pPvtData->audioBitDepth;
+ }
+ //else if (pMediaQ->pMediaQDataFormat == MapSAFMediaQDataFormat) {
+ //}
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_audio_type") == 0) {
+ if (strncasecmp(value, "float", 5) == 0)
+ pPvtData->audioType = AVB_AUDIO_TYPE_FLOAT;
+ else if (strncasecmp(value, "sign", 4) == 0
+ || strncasecmp(value, "int", 4) == 0)
+ pPvtData->audioType = AVB_AUDIO_TYPE_INT;
+ else if (strncasecmp(value, "unsign", 6) == 0
+ || strncasecmp(value, "uint", 4) == 0)
+ pPvtData->audioType = AVB_AUDIO_TYPE_UINT;
+ else {
+ AVB_LOG_ERROR("Invalid audio type configured for intf_nv_audio_type.");
+ pPvtData->audioType = AVB_AUDIO_TYPE_UNSPEC;
+ }
+
+ // Give the audio parameters to the mapping module.
+ if (pMediaQ->pMediaQDataFormat) {
+ if (strcmp(pMediaQ->pMediaQDataFormat, MapUncmpAudioMediaQDataFormat) == 0
+ || strcmp(pMediaQ->pMediaQDataFormat, MapAVTPAudioMediaQDataFormat) == 0) {
+ pPubMapUncmpAudioInfo->audioType = pPvtData->audioType;
+ }
+ //else if (pMediaQ->pMediaQDataFormat == MapSAFMediaQDataFormat) {
+ //}
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_audio_endian") == 0) {
+ if (strncasecmp(value, "big", 3) == 0)
+ pPvtData->audioEndian = AVB_AUDIO_ENDIAN_BIG;
+ else if (strncasecmp(value, "little", 6) == 0)
+ pPvtData->audioEndian = AVB_AUDIO_ENDIAN_LITTLE;
+ else {
+ AVB_LOG_ERROR("Invalid audio type configured for intf_nv_audio_endian.");
+ pPvtData->audioEndian = AVB_AUDIO_ENDIAN_UNSPEC;
+ }
+
+ // Give the audio parameters to the mapping module.
+ if (pMediaQ->pMediaQDataFormat) {
+ if (strcmp(pMediaQ->pMediaQDataFormat, MapUncmpAudioMediaQDataFormat) == 0
+ || strcmp(pMediaQ->pMediaQDataFormat, MapAVTPAudioMediaQDataFormat) == 0) {
+ pPubMapUncmpAudioInfo->audioEndian = pPvtData->audioEndian;
+ }
+ //else if (pMediaQ->pMediaQDataFormat == MapSAFMediaQDataFormat) {
+ //}
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_audio_channels") == 0) {
+ val = strtol(value, &pEnd, 10);
+ // TODO: Should check for specific values
+ if (val >= AVB_AUDIO_CHANNELS_1 && val <= AVB_AUDIO_CHANNELS_8) {
+ pPvtData->audioChannels = val;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid audio channels configured for intf_nv_audio_channels.");
+ pPvtData->audioChannels = AVB_AUDIO_CHANNELS_2;
+ }
+
+ // Give the audio parameters to the mapping module.
+ if (pMediaQ->pMediaQDataFormat) {
+ if (strcmp(pMediaQ->pMediaQDataFormat, MapUncmpAudioMediaQDataFormat) == 0
+ || strcmp(pMediaQ->pMediaQDataFormat, MapAVTPAudioMediaQDataFormat) == 0) {
+ pPubMapUncmpAudioInfo->audioChannels = pPvtData->audioChannels;
+ }
+ //else if (pMediaQ->pMediaQDataFormat == MapSAFMediaQDataFormat) {
+ //}
+ }
+
+ }
+
+ if (strcmp(name, "intf_nv_allow_resampling") == 0) {
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1) {
+ pPvtData->allowResampling = (tmp == 1);
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_start_threshold_periods") == 0) {
+ pPvtData->startThresholdPeriods = strtol(value, &pEnd, 10);
+ }
+
+ else if (strcmp(name, "intf_nv_period_time") == 0) {
+ pPvtData->periodTimeUsec = strtol(value, &pEnd, 10);
+ }
+
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfAlsaGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// 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)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ S32 rslt;
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ // Holds the hardware parameters
+ snd_pcm_hw_params_t *hwParams;
+
+ // Open the pcm device.
+ rslt = snd_pcm_open(&pPvtData->pcmHandle, pPvtData->pDeviceName, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
+
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_open error(): %s", snd_strerror(rslt));
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Allocate the parameter structure
+ rslt = snd_pcm_hw_params_malloc(&hwParams);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params_malloc error(): %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Initialize the hardware paramneters
+ 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));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Set if resampling allowed.
+ rslt = snd_pcm_hw_params_set_rate_resample(pPvtData->pcmHandle, hwParams, pPvtData->allowResampling);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params_set_rate_resample() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Set the access type
+ rslt = snd_pcm_hw_params_set_access(pPvtData->pcmHandle, hwParams, PCM_ACCESS_TYPE);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params_set_access() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Set the sample format
+ int fmt = x_AVBAudioFormatToAlsaFormat(pPvtData->audioType,
+ pPvtData->audioBitDepth,
+ pPvtData->audioEndian,
+ pMediaQ->pMediaQDataFormat);
+ rslt = snd_pcm_hw_params_set_format(pPvtData->pcmHandle, hwParams, fmt);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params_set_format() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Set the sample rate
+ U32 rate = pPvtData->audioRate;
+ rslt = snd_pcm_hw_params_set_rate_near(pPvtData->pcmHandle, hwParams, &rate, 0);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params_set_rate_near() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+ if (rate != pPvtData->audioRate) {
+ AVB_LOGF_ERROR("Could not set the exact rate. Requested: %u Using: %u", pPvtData->audioRate, rate);
+ }
+
+ // Set the number of channels
+ rslt = snd_pcm_hw_params_set_channels(pPvtData->pcmHandle, hwParams, pPvtData->audioChannels);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params_set_channels() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Give the hardware parameters to ALSA
+ rslt = snd_pcm_hw_params(pPvtData->pcmHandle, hwParams);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Free the hardware parameters
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+
+ // Get ready for playback
+ rslt = snd_pcm_prepare(pPvtData->pcmHandle);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_prepare() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Dump settings
+ snd_output_t* out;
+ snd_output_stdio_attach(&out, stderr, 0);
+ snd_pcm_dump(pPvtData->pcmHandle, out);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback will be called for each AVB transmit interval.
+bool openavbIntfAlsaTxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+
+ S32 rslt;
+
+ if (pMediaQ) {
+ media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo = pMediaQ->pPubMapInfo;
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ media_q_item_t *pMediaQItem = NULL;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ 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)
+ return TRUE;
+
+ pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ if (pMediaQItem->itemSize < pPubMapUncmpAudioInfo->itemSize) {
+ AVB_LOG_ERROR("Media queue item not large enough for samples");
+ }
+
+ 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));
+ }
+ 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;
+ }
+ else {
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ openavbMediaQHeadPush(pMediaQ);
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+ }
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE; // Media queue full
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+}
+
+// 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)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ S32 rslt;
+
+ // Holds the hardware parameters
+ snd_pcm_hw_params_t *hwParams;
+ snd_pcm_sw_params_t *swParams;
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ // Open the pcm device.
+ rslt = snd_pcm_open(&pPvtData->pcmHandle, pPvtData->pDeviceName, SND_PCM_STREAM_PLAYBACK, 0);
+
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_open error(): %s", snd_strerror(rslt));
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Allocate the parameter structure
+ rslt = snd_pcm_hw_params_malloc(&hwParams);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params_malloc error(): %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Initialize the hardware paramneters
+ 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));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Set if resampling allowed.
+ rslt = snd_pcm_hw_params_set_rate_resample(pPvtData->pcmHandle, hwParams, pPvtData->allowResampling);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params_set_rate_resample() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Set the access type
+ rslt = snd_pcm_hw_params_set_access(pPvtData->pcmHandle, hwParams, PCM_ACCESS_TYPE);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params_set_access() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Set the sample format
+ int fmt = x_AVBAudioFormatToAlsaFormat(pPvtData->audioType,
+ pPvtData->audioBitDepth,
+ pPvtData->audioEndian,
+ pMediaQ->pMediaQDataFormat);
+ rslt = snd_pcm_hw_params_set_format(pPvtData->pcmHandle, hwParams, fmt);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params_set_format() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Set the sample rate
+ U32 rate = pPvtData->audioRate;
+ rslt = snd_pcm_hw_params_set_rate_near(pPvtData->pcmHandle, hwParams, &rate, 0);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params_set_rate_near() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+ if (rate != pPvtData->audioRate) {
+ AVB_LOGF_ERROR("Could not set the exact rate. Requested: %u Using: %u", pPvtData->audioRate, rate);
+ }
+
+ // Set the number of channels
+ rslt = snd_pcm_hw_params_set_channels(pPvtData->pcmHandle, hwParams, pPvtData->audioChannels);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params_set_channels() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+
+ // Time based buffer and period setup
+ int dir;
+
+ unsigned int buffer_time = 500000; // ring buffer length in us
+ unsigned int period_time = pPvtData->periodTimeUsec; // period time in us
+ int period_event = 1; // produce poll event after each period
+ snd_pcm_uframes_t buffer_size;
+ snd_pcm_uframes_t period_size;
+ const unsigned int usec_round = 10000;
+ unsigned int max;
+
+ // Hard-coded buffer and period times were failing for 192KHz.
+ // Check for maximum buffer time and adjust ours down if necessary
+ rslt = snd_pcm_hw_params_get_buffer_time_max(hwParams, &max, &dir);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params_get_buffer_time_max() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+ else if (max < buffer_time) {
+ buffer_time = (max / usec_round) * usec_round;
+ }
+
+ // Check for maximum perioid 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));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+ else if (max < period_time) {
+ period_time = (max / usec_round) * usec_round;
+ }
+
+ rslt = snd_pcm_hw_params_set_buffer_time_near(pPvtData->pcmHandle, hwParams, &buffer_time, &dir);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params_set_buffer_time_near() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ rslt = snd_pcm_hw_params_get_buffer_size(hwParams, &buffer_size);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params_get_buffer_size() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ rslt = snd_pcm_hw_params_set_period_time_near(pPvtData->pcmHandle, hwParams, &period_time, &dir);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params_set_period_time_near() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+ pPvtData->periodTimeUsec = period_time;
+
+ rslt = snd_pcm_hw_params_get_period_size(hwParams, &period_size, &dir);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params_get_period_size() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Give the hardware parameters to ALSA
+ rslt = snd_pcm_hw_params(pPvtData->pcmHandle, hwParams);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_hw_params() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Free the hardware parameters
+ snd_pcm_hw_params_free(hwParams);
+ hwParams = NULL;
+
+
+ // Set software parameters
+
+ // Allocate the parameter structure
+ rslt = snd_pcm_sw_params_malloc(&swParams);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_sw_params_malloc error(): %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ rslt = snd_pcm_sw_params_current(pPvtData->pcmHandle, swParams);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_sw_params_current error(): %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ rslt = snd_pcm_sw_params_set_start_threshold(pPvtData->pcmHandle, swParams, period_size * pPvtData->startThresholdPeriods);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_sw_params_set_start_threshold error(): %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ rslt = snd_pcm_sw_params_set_avail_min(pPvtData->pcmHandle, swParams, period_event ? buffer_size : period_size);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_sw_params_set_avail_min error(): %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ rslt = snd_pcm_sw_params_set_period_event(pPvtData->pcmHandle, swParams, 1);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_sw_params_set_period_event error(): %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ rslt = snd_pcm_sw_params(pPvtData->pcmHandle, swParams);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_sw_params error(): %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Free the hardware parameters
+ snd_pcm_sw_params_free(swParams);
+ swParams = NULL;
+
+
+ // Get ready for playback
+ rslt = snd_pcm_prepare(pPvtData->pcmHandle);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_prepare() error: %s", snd_strerror(rslt));
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ // Dump settings
+ snd_output_t* out;
+ snd_output_stdio_attach(&out, stderr, 0);
+ snd_pcm_dump(pPvtData->pcmHandle, out);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback is called when acting as a listener.
+bool openavbIntfAlsaRxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+
+ if (pMediaQ) {
+ media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo = pMediaQ->pPubMapInfo;
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ bool moreItems = TRUE;
+
+ while (moreItems) {
+ media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, pPvtData->ignoreTimestamp);
+ if (pMediaQItem) {
+ if (pMediaQItem->dataLen) {
+ S32 rslt;
+
+ rslt = snd_pcm_writei(pPvtData->pcmHandle, pMediaQItem->pPubData, pPubMapUncmpAudioInfo->framesPerItem);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_writei: %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));
+ }
+ rslt = snd_pcm_writei(pPvtData->pcmHandle, pMediaQItem->pPubData, pPubMapUncmpAudioInfo->framesPerItem);
+ }
+ if (rslt != pPubMapUncmpAudioInfo->framesPerItem) {
+ AVB_LOGF_WARNING("Not all pcm data consumed written:%u consumed:%u", pMediaQItem->dataLen, rslt * pPubMapUncmpAudioInfo->audioChannels);
+ }
+
+ // DEBUG
+ // rslt = snd_pcm_avail(pPvtData->pcmHandle);
+ // AVB_LOGF_INFO("%d\n", rslt);
+
+ }
+ else {
+ }
+ openavbMediaQTailPull(pMediaQ);
+ }
+ else {
+ moreItems = FALSE;
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+}
+
+// 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)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ if (pPvtData->pcmHandle) {
+ snd_pcm_close(pPvtData->pcmHandle);
+ pPvtData->pcmHandle = NULL;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfAlsaGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ 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)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pMediaQ->pPvtIntfInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pPvtIntfInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for AVTP interface module.");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ pIntfCB->intf_cfg_cb = openavbIntfAlsaCfgCB;
+ pIntfCB->intf_gen_init_cb = openavbIntfAlsaGenInitCB;
+ pIntfCB->intf_tx_init_cb = openavbIntfAlsaTxInitCB;
+ pIntfCB->intf_tx_cb = openavbIntfAlsaTxCB;
+ pIntfCB->intf_rx_init_cb = openavbIntfAlsaRxInitCB;
+ pIntfCB->intf_rx_cb = openavbIntfAlsaRxCB;
+ pIntfCB->intf_end_cb = openavbIntfAlsaEndCB;
+ pIntfCB->intf_gen_end_cb = openavbIntfAlsaGenEndCB;
+
+ pPvtData->ignoreTimestamp = FALSE;
+ pPvtData->pDeviceName = strdup(PCM_DEVICE_NAME_DEFAULT);
+ pPvtData->allowResampling = TRUE;
+ pPvtData->intervalCounter = 0;
+ pPvtData->startThresholdPeriods = 2; // Default to 2 periods of frames as the start threshold
+ pPvtData->periodTimeUsec = 100000;
+
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/intf_h264_gst/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/CMakeLists.txt
new file mode 100644
index 00000000..e4840023
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/CMakeLists.txt
@@ -0,0 +1,23 @@
+IF (NOT GSTREAMER_1_0)
+ SET (SRC_FILES ${SRC_FILES}
+ ${AVB_OSAL_DIR}/intf_h264_gst/openavb_intf_h264_gst.c
+ ${AVB_OSAL_DIR}/gst_al/gst_al_01.c
+ PARENT_SCOPE
+ )
+ELSE ()
+ SET (SRC_FILES ${SRC_FILES}
+ ${AVB_OSAL_DIR}/intf_h264_gst/openavb_intf_h264_gst.c
+ ${AVB_OSAL_DIR}/gst_al/gst_al_10.c
+ PARENT_SCOPE
+ )
+ENDIF ()
+
+# Need include and link directories for GST
+SET (INTF_INCLUDE_DIR
+ ${INTF_INCLUDE_DIR} ${GLIB_PKG_INCLUDE_DIRS} ${GST_PKG_INCLUDE_DIRS}
+ ${AVB_OSAL_DIR}/gst_al
+ PARENT_SCOPE
+)
+SET (INTF_LIBRARY_DIR ${INTF_LIBRARY_DIR} PARENT_SCOPE)
+SET (INTF_LIBRARY ${GLIB_PKG_LIBRARIES} ${GST_PKG_LIBRARIES} ${GSTRTP_PKG_LIBRARIES} PARENT_SCOPE)
+
diff --git a/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_intf.md b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_intf.md
new file mode 100644
index 00000000..dd09fab6
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_intf.md
@@ -0,0 +1,18 @@
+H264 with GStreamer interface {#h264_gst_intf}
+=========================
+
+# Description
+
+H264 with gstreamer interface module.
+
+<br>
+# Interface module configuration parameters
+
+Name | Description
+--------------------------|---------------------------
+intf_nv_gst_pipeline |GStreamer pipeline that will be used
+intf_nv_async_rx |If set to 1 sets RX in async mode
+intf_nv_blocking_rx |If set to 1 switches gstreamer into blocking mode
+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.
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
new file mode 100644
index 00000000..9817900c
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_listener.ini
@@ -0,0 +1,106 @@
+#####################################################################
+# General Listener configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = listener
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 55
+
+# dest_addr: see description in talker.ini
+dest_addr = 91:e0:f0:00:fe:55
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+#max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 100
+
+# 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.
+raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+report_seconds = 1
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_h264.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapH264Initialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 200
+
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+intf_lib = ./libopenavb_intf_h264_gst.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfH264RtpGstInitialize
+
+# intf_nv_file_name: The fully qualified file name used both the talker and listener.
+#intf_nv_file_name = output.mjpeg
+
+# intf_nv_repeat: Continually repeat the file stream when running as a talker.
+#intf_nv_repeat = 0
+
+# intf_nv_ignore_timestamp: If set the listener will ignore the timestamp on media queue items.
+# intf_nv_ignore_timestamp = 1
+
+# gst 1.0 with libav
+#intf_nv_gst_pipeline = appsrc name=avbsrc ! application/x-rtp,media=video,clock-rate=90000,encoding-name=H264,payload=96,ssrc=5,clock-base=1,seqnum-base=1 ! rtph264depay ! h264parse ! avdec_h264 ! autovideosink sync=false
+
+# gst 0.1 with ffmpeg
+intf_nv_gst_pipeline = appsrc name=avbsrc ! application/x-rtp,media=video,clock-rate=90000,encoding-name=H264,payload=96,ssrc=5,clock-base=1,seqnum-base=1 ! rtph264depay ! h264parse ! ffdec_h264 ! autovideosink sync=false
+
+intf_nv_blocking_rx = 0
+intf_nv_async_rx = 0
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
new file mode 100644
index 00000000..87569675
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_talker.ini
@@ -0,0 +1,127 @@
+#####################################################################
+# General Talker configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = talker
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 55
+
+# dest_addr: destination multicast address for the stream.
+#
+# If using SRP and MAAP, dynamic destination addresses are generated
+# automatically by the talker and passed to the listner, and don't
+# need to be configured.
+#
+# Without MAAP, locally administered (static) addresses must be
+# configured. Thouse 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.
+#
+# When SRP is being used the static destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set (to the same value) in both the talker and listener.
+#
+# 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.
+#
+dest_addr = 91:e0:f0:00:fe:55
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 50000
+
+# max_transmit_deficit_usec: Allows setting the maximum packet transmit rate deficit that will
+# be recovered when a talker falls behind. This is only used on a talker side. 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. Typically this value can be set to the expected buffer size (in usec) that listeners are
+# expected to be buffering. 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.
+max_transmit_deficit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 100
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+report_seconds = 1
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_h264.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapH264Initialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+# map_nv_tx_rate: Transmit rate
+# If not set default of the talker class will be used.
+#map_nv_tx_rate = 2000
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. 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.
+intf_lib = ./libopenavb_intf_h264_gst.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfH264RtpGstInitialize
+
+intf_nv_gst_pipeline = filesrc location=/home/marcin/ser02.h264 ! video/x-h264 ! typefind ! h264parse ! rtph264pay ssrc=5 timestamp-offset=1 seqnum-offset=1 name=avbrtppay ! appsink name=avbsink
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
new file mode 100644
index 00000000..9a7f08fb
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/openavb_intf_h264_gst.c
@@ -0,0 +1,619 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 <stdio.h>
+#include <gst/gst.h>
+#include <gst/app/gstappsink.h>
+#include <gst/app/gstappsrc.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_intf_pub.h"
+#include "openavb_map_h264_pub.h"
+#include "gst_al.h"
+
+#define AVB_LOG_COMPONENT "H264 Interface"
+#include "openavb_log_pub.h"
+
+#define APPSINK_NAME "avbsink"
+#define APPSRC_NAME "avbsrc"
+#define RTP_PAYLOADER_NAME "avbrtppay"
+#define PACKETS_PER_RX_CALL 20
+
+#define NBUFS 256
+
+typedef struct pvt_data_t
+{
+ char *pPipelineStr;
+
+ bool ignoreTimestamp;
+
+ GstElement *pipe;
+ GstAppSink *appsink;
+ GstAppSrc *appsrc;
+
+ U32 bufwr;
+ U32 bufrd;
+ U32 seq;
+ GstAlBuf *rxBufs[NBUFS];
+ bool asyncRx;
+ bool blockingRx;
+
+ gint nWaiting;
+} pvt_data_t;
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbIntfH264RtpGstCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ if (!pMediaQ)
+ {
+ AVB_LOG_DEBUG("H264Rtp-gst cfgCB: no mediaQ!");
+ return;
+ }
+
+ char *pEnd;
+ long tmp;
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ pPvtData->asyncRx = FALSE;
+
+ if (strcmp(name, "intf_nv_gst_pipeline") == 0)
+ {
+ if (pPvtData->pPipelineStr)
+ {
+ free(pPvtData->pPipelineStr);
+ }
+ pPvtData->pPipelineStr = strdup(value);
+ }
+ else if (strcmp(name, "intf_nv_async_rx") == 0)
+ {
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1)
+ {
+ pPvtData->asyncRx = (tmp == 1);
+ }
+ }
+ else if (strcmp(name, "intf_nv_blocking_rx") == 0)
+ {
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1)
+ {
+ pPvtData->blockingRx = (tmp == 1);
+ }
+ }
+ else if (strcmp(name, "intf_nv_ignore_timestamp") == 0)
+ {
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1)
+ {
+ pPvtData->ignoreTimestamp = (tmp == 1);
+ }
+ }
+}
+
+void openavbIntfH264RtpGstGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ if (!pMediaQ)
+ {
+ AVB_LOG_DEBUG("H264Rtp-gst initCB: no mediaQ!");
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+static GstFlowReturn sinkNewBufferSample(GstAppSink *sink, gpointer pv)
+{
+ media_q_t *pMediaQ = (media_q_t *)pv;
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ g_atomic_int_add(&pPvtData->nWaiting, 1);
+
+ return GST_FLOW_OK;
+}
+
+static int openavbMediaQGetItemSize(media_q_t *pMediaQ)
+{
+ int itemSize = 1412;
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem)
+ {
+ itemSize = pMediaQItem->itemSize;
+ openavbMediaQHeadUnlock(pMediaQ);
+ }
+ else
+ {
+ AVB_LOG_ERROR("pMediaQ item NULL in getMediaQItemSize");
+ }
+
+ return itemSize;
+}
+
+static void createTxPipeline(media_q_t *pMediaQ)
+{
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ GError *error = NULL;
+ pPvtData->pipe = gst_parse_launch(pPvtData->pPipelineStr, &error);
+ if (error)
+ {
+ AVB_LOGF_ERROR("Unable to create pipeline: %s", error->message);
+ }
+
+ AVB_LOGF_INFO("Pipeline: %s", pPvtData->pPipelineStr);
+ pPvtData->appsink = GST_APP_SINK(gst_bin_get_by_name(GST_BIN(pPvtData->pipe), APPSINK_NAME));
+ if (!pPvtData->appsink)
+ {
+ AVB_LOG_ERROR("Failed to find appsink element");
+ }
+
+ // Setup callback function to handle new buffers delivered to sink
+ GstAppSinkCallbacks cbfns;
+ memset(&cbfns, 0, sizeof(GstAppSinkCallbacks));
+
+ gst_al_set_callback(&cbfns, sinkNewBufferSample);
+
+ gst_app_sink_set_callbacks(pPvtData->appsink, &cbfns, (gpointer)(pMediaQ), NULL);
+
+ //No limits for internal sink buffers. This may cause large memory consumption.
+ g_object_set(pPvtData->appsink, "max-buffers", 0, "drop", 0, NULL);
+
+ GstElement *rtpPayloader = gst_bin_get_by_name(GST_BIN(pPvtData->pipe), RTP_PAYLOADER_NAME);
+ if (rtpPayloader)
+ {
+ g_object_set(rtpPayloader, "mtu", openavbMediaQGetItemSize(pMediaQ), NULL);
+ gst_object_unref(rtpPayloader);
+ }
+ else
+ {
+ AVB_LOG_ERROR("Cannot set mtu on rtppayloader. Make sure that its name is avbrtppay in the pipeline.");
+ }
+
+ if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(pPvtData->pipe, GST_STATE_PLAYING)) {
+ AVB_LOG_ERROR("Failed to change pipeline state to PLAYING.");
+ }
+}
+
+static void destroyPipeline(media_q_t *pMediaQ)
+{
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ if (pPvtData->pipe)
+ {
+ gst_element_set_state(pPvtData->pipe, GST_STATE_NULL);
+ if (pPvtData->appsink)
+ {
+ gst_object_unref(pPvtData->appsink);
+ pPvtData->appsink = NULL;
+ }
+ if (pPvtData->appsrc)
+ {
+ gst_object_unref(pPvtData->appsrc);
+ pPvtData->appsrc = NULL;
+ }
+ gst_object_unref(pPvtData->pipe);
+ pPvtData->pipe = NULL;
+ }
+}
+
+// A call to this callback indicates that this interface module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbIntfH264RtpGstTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (!pMediaQ)
+ {
+ AVB_LOG_DEBUG("H264Rtp-gst txinit: no mediaQ!");
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ createTxPipeline(pMediaQ);
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+
+ return;
+}
+
+// This callback will be called for each AVB transmit interval. Commonly this will be
+// 4000 or 8000 times per second.
+bool openavbIntfH264RtpGstTxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+
+ if (!pMediaQ)
+ {
+ AVB_LOG_DEBUG("No MediaQ in H264RtpGstTxCB");
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ if (gst_app_sink_is_eos(GST_APP_SINK(pPvtData->appsink))) {
+ AVB_LOG_INFO("Rewinding stream...");
+ destroyPipeline(pMediaQ);
+ createTxPipeline(pMediaQ);
+ }
+
+ while (g_atomic_int_get(&pPvtData->nWaiting) > 0)
+ {
+ //Transmit data --BEGIN--
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem)
+ {
+ U32 paySize = 0;
+
+ GstAlBuf *txBuf = NULL;
+
+ txBuf = gst_al_pull_rtp_buffer(GST_APP_SINK(pPvtData->appsink));
+
+ if (!txBuf)
+ {
+ pMediaQItem->dataLen = 0;
+ openavbMediaQHeadUnlock(pMediaQ);
+ AVB_LOG_ERROR("Gstreamer buffer pull problem");
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return FALSE;
+ }
+
+ g_atomic_int_add(&pPvtData->nWaiting, -1);
+ paySize = GST_AL_BUF_SIZE(txBuf);
+
+ if(paySize > pMediaQItem->itemSize){
+
+ AVB_LOGF_ERROR("PaySize (%d) exceeds pMediaQItem itemSize (%d).", paySize, pMediaQItem->itemSize);
+
+ pMediaQItem->dataLen = 0;
+ openavbMediaQHeadUnlock(pMediaQ);
+ gst_al_rtp_buffer_unref(txBuf);
+
+ return FALSE;
+ }
+
+ pMediaQItem->dataLen = paySize;
+ memcpy(pMediaQItem->pPubData, GST_AL_BUF_DATA(txBuf), paySize);
+ if (gst_al_rtp_buffer_get_marker(txBuf))
+ {
+ ((media_q_item_map_h264_pub_data_t *)pMediaQItem->pPubMapData)->lastPacket = TRUE;
+ }
+ else
+ {
+ ((media_q_item_map_h264_pub_data_t *)pMediaQItem->pPubMapData)->lastPacket = FALSE;
+ }
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ openavbMediaQHeadPush(pMediaQ);
+
+ gst_al_rtp_buffer_unref(txBuf);
+ }
+ else
+ {
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ //AVB_LOG_INFO("MediaQ full");
+ return FALSE; // Media queue full
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+}
+
+// Async stuff...
+static pthread_t asyncRxThread;
+static pthread_mutex_t asyncRxMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t asyncReadMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t asyncReadCond = PTHREAD_COND_INITIALIZER;
+#define LOCK() pthread_mutex_lock(&asyncRxMutex)
+#define UNLOCK() pthread_mutex_unlock(&asyncRxMutex)
+static bool bAsyncRXStreaming;
+static media_q_t *pAsyncRxMediaQ;
+//static media_q_item_t *pAsyncRxMediaQItem;
+//static bool bAsyncRXDoneWithItem;
+
+static void *openavbIntfH264RtpGstRxThreadfn(void *pv)
+{
+ pvt_data_t *pPvtData;
+
+ if (!pAsyncRxMediaQ)
+ {
+ AVB_LOG_ERROR("No async mediaQ");
+ return 0;
+ }
+ pPvtData = pAsyncRxMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("No async RX private data.");
+ return 0;
+ }
+
+ bAsyncRXStreaming = TRUE;
+ while (bAsyncRXStreaming)
+ {
+ U32 bufwr = pPvtData->bufwr;
+ U32 bufrd = pPvtData->bufrd;
+ if (bufwr == bufrd)
+ {
+ pthread_mutex_lock(&asyncReadMutex);
+ pthread_cond_wait(&asyncReadCond, &asyncReadMutex);
+ pthread_mutex_unlock(&asyncReadMutex);
+ }
+ else if(bufwr > bufrd)
+ {
+ GstAlBuf *rxBuf = pPvtData->rxBufs[pPvtData->bufrd%NBUFS];
+ if (rxBuf)
+ {
+ pPvtData->rxBufs[pPvtData->bufrd%NBUFS] = NULL;
+ __sync_fetch_and_add(&pPvtData->bufrd, 1);
+ GstFlowReturn ret = gst_al_push_rtp_buffer(GST_APP_SRC(pPvtData->appsrc), rxBuf);
+
+ if (ret != GST_FLOW_OK)
+ {
+ AVB_LOGF_ERROR("Pushing buffer to appsrc failed with code %d", ret);
+ }
+ }
+ else
+ {
+ AVB_LOGF_INFO("The Buf %x %d skipped, OO!!", rxBuf, bufrd);
+ }
+ }
+ else
+ {
+ AVB_LOGF_INFO("There is a BUG as bufwr=%d < bufrd=%d", bufwr, bufrd);
+ }
+ }
+ return 0;
+}
+// A call to this callback indicates that this interface module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbIntfH264RtpGstRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_LOG_DEBUG("Rx Init callback.");
+ if (!pMediaQ)
+ {
+ AVB_LOG_DEBUG("No MediaQ in H264RtpGstRxInitCB");
+ return;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ GError *error = NULL;
+ pPvtData->pipe = gst_parse_launch(pPvtData->pPipelineStr, &error);
+ if (error)
+ {
+ AVB_LOGF_ERROR("Unable to create pipeline: %s", error->message);
+ }
+
+ AVB_LOGF_INFO("Pipeline: %s", pPvtData->pPipelineStr);
+ pPvtData->appsrc = GST_APP_SRC(gst_bin_get_by_name(GST_BIN(pPvtData->pipe), APPSRC_NAME));
+ if (!pPvtData->appsrc)
+ {
+ AVB_LOG_ERROR("Failed to find appsrc element");
+ }
+
+ // caps can be set from pipeline
+ if (pPvtData->blockingRx)
+ {
+ AVB_LOG_DEBUG("Switching gstreamer into blocking mode");
+ g_object_set(pPvtData->appsrc, "block", 1, NULL); // and now we have to do async rx :)
+ }
+
+ //FIXME: Check if state change was successful
+ gst_element_set_state(pPvtData->pipe, GST_STATE_PLAYING);
+
+ pPvtData->seq = 1;
+
+ if (pPvtData->asyncRx)
+ {
+ pAsyncRxMediaQ = pMediaQ;
+ int err = pthread_mutex_init(&asyncRxMutex, 0);
+ if (err)
+ AVB_LOG_ERROR("Mutex init failed");
+ pthread_attr_t attr;
+ struct sched_param param;
+ pthread_attr_init(&attr);
+ pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
+ param.sched_priority = 0;
+ pthread_attr_setschedparam(&attr, &param);
+ pthread_create(&asyncRxThread, &attr, openavbIntfH264RtpGstRxThreadfn, NULL);
+ }
+}
+
+// This callback is called when acting as a listener.
+bool openavbIntfH264RtpGstRxCB(media_q_t *pMediaQ)
+{
+ if (!pMediaQ)
+ {
+ AVB_LOG_DEBUG("RxCB: no mediaQ!");
+ return TRUE;
+ }
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ bool moreSourcePackets = TRUE;
+
+ while (moreSourcePackets)
+ {
+ media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, pPvtData->ignoreTimestamp);
+ // there are no packets available or they are from the future
+ if (!pMediaQItem)
+ {
+ moreSourcePackets = FALSE;
+ continue;
+ }
+ if (!pMediaQItem->dataLen)
+ {
+ AVB_LOG_DEBUG("No dataLen");
+ openavbMediaQTailPull(pMediaQ);
+ continue;
+ }
+ if (pPvtData->asyncRx)
+ {
+ U32 bufwr = pPvtData->bufwr;
+ U32 bufrd = pPvtData->bufrd;
+ U32 mdif = bufwr - bufrd;
+ if (mdif >= NBUFS)
+ {
+ openavbMediaQTailPull(pMediaQ);
+ AVB_LOGF_INFO("Rx async queue full, dropping (%lu - %lu = %lu)", bufwr, bufrd, mdif);
+ moreSourcePackets = FALSE;
+ continue;
+ }
+ }
+ GstAlBuf *rxBuf = gst_al_alloc_rtp_buffer(pMediaQItem->dataLen, 0,0);
+
+ if (!rxBuf)
+ {
+ AVB_LOG_ERROR("gst_rtp_buffer_allocate failed!");
+ openavbMediaQTailUnlock(pMediaQ);
+ return FALSE;
+ }
+ memcpy(GST_AL_BUF_DATA(rxBuf), pMediaQItem->pPubData, pMediaQItem->dataLen);
+
+ GST_AL_BUFFER_TIMESTAMP(rxBuf) = GST_CLOCK_TIME_NONE;
+ GST_AL_BUFFER_DURATION(rxBuf) = GST_CLOCK_TIME_NONE;
+ if ( ((media_q_item_map_h264_pub_data_t *)pMediaQItem->pPubMapData)->lastPacket )
+ {
+ gst_al_rtp_buffer_set_marker(rxBuf,TRUE);
+ }
+
+ gst_al_rtp_buffer_set_params(rxBuf, 5, 96, 2, pPvtData->seq++);
+
+ if (pPvtData->asyncRx)
+ {
+ pPvtData->rxBufs[pPvtData->bufwr%NBUFS] = rxBuf;
+ __sync_fetch_and_add(&pPvtData->bufwr, 1);
+ pthread_mutex_lock(&asyncReadMutex);
+ pthread_cond_signal(&asyncReadCond);
+ pthread_mutex_unlock(&asyncReadMutex);
+ }
+ else
+ {
+ // appsrc manages this buffer at this point
+ GstFlowReturn ret = gst_al_push_rtp_buffer(GST_APP_SRC(pPvtData->appsrc), rxBuf);
+ if (ret != GST_FLOW_OK)
+ {
+ AVB_LOGF_ERROR("Pushing buffer to appsrc failed with code %d", ret);
+ }
+ }
+ openavbMediaQTailPull(pMediaQ);
+ }
+ return TRUE;
+}
+
+// This callback will be called when the interface needs to be closed. All shutdown should
+// occur in this function.
+void openavbIntfH264RtpGstEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ bAsyncRXStreaming = FALSE;
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+ destroyPipeline(pMediaQ);
+ if (pPvtData->asyncRx)
+ {
+ pthread_mutex_lock(&asyncReadMutex);
+ pthread_cond_signal(&asyncReadCond);
+ pthread_mutex_unlock(&asyncReadMutex);
+ pthread_join(asyncRxThread, NULL);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfH264RtpGstGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ 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)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (!pMediaQ)
+ {
+ AVB_LOG_DEBUG("H264Rtp-gst GstInitialize: no mediaQ!");
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+ }
+
+ pMediaQ->pPvtIntfInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ pIntfCB->intf_cfg_cb = openavbIntfH264RtpGstCfgCB;
+ pIntfCB->intf_gen_init_cb = openavbIntfH264RtpGstGenInitCB;
+ pIntfCB->intf_tx_init_cb = openavbIntfH264RtpGstTxInitCB;
+ pIntfCB->intf_tx_cb = openavbIntfH264RtpGstTxCB;
+ pIntfCB->intf_rx_init_cb = openavbIntfH264RtpGstRxInitCB;
+ pIntfCB->intf_rx_cb = openavbIntfH264RtpGstRxCB;
+ pIntfCB->intf_end_cb = openavbIntfH264RtpGstEndCB;
+ pIntfCB->intf_gen_end_cb = openavbIntfH264RtpGstGenEndCB;
+
+ pPvtData->ignoreTimestamp = FALSE;
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/CMakeLists.txt
new file mode 100644
index 00000000..4419ff26
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/CMakeLists.txt
@@ -0,0 +1,23 @@
+IF (NOT GSTREAMER_1_0)
+ SET (SRC_FILES ${SRC_FILES}
+ ${AVB_OSAL_DIR}/intf_mjpeg_gst/openavb_intf_mjpeg_gst.c
+ ${AVB_OSAL_DIR}/gst_al/gst_al_01.c
+ PARENT_SCOPE
+ )
+ELSE ()
+ SET (SRC_FILES ${SRC_FILES}
+ ${AVB_OSAL_DIR}/intf_mjpeg_gst/openavb_intf_mjpeg_gst.c
+ ${AVB_OSAL_DIR}/gst_al/gst_al_10.c
+ PARENT_SCOPE
+ )
+ENDIF ()
+
+# Need include and link directories for GST
+SET (INTF_INCLUDE_DIR
+ ${INTF_INCLUDE_DIR} ${GLIB_PKG_INCLUDE_DIRS} ${GST_PKG_INCLUDE_DIRS}
+ ${AVB_OSAL_DIR}/gst_al
+ PARENT_SCOPE
+)
+SET (INTF_LIBRARY_DIR ${INTF_LIBRARY_DIR} PARENT_SCOPE)
+SET (INTF_LIBRARY ${GLIB_PKG_LIBRARIES} ${GST_PKG_LIBRARIES} ${GSTRTP_PKG_LIBRARIES} PARENT_SCOPE)
+
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_camera_intf.md b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_camera_intf.md
new file mode 100644
index 00000000..b50e8f50
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_camera_intf.md
@@ -0,0 +1,18 @@
+MJPEG GStreamer interface {#mjpeg_gst_intf}
+=========================
+
+# Description
+
+MJPEG gstreamer interface module.
+
+<br>
+# Interface module configuration parameters
+
+Name | Description
+--------------------------|---------------------------
+intf_nv_gst_pipeline |GStreamer pipeline that will be used
+intf_nv_async_rx |If set to 1 sets RX in async mode
+intf_nv_blocking_rx |If set to 1 switches gstreamer into blocking mode
+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.
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
new file mode 100644
index 00000000..80b742ca
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_listener.ini
@@ -0,0 +1,110 @@
+#####################################################################
+# General Listener configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = listener
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: see description in talker.ini
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+#max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+#sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+#max_transit_usec = 2000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_mjpeg.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapMjpegInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+intf_lib = ./libopenavb_intf_mjpeg_gst.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfMjpegGstInitialize
+
+# intf_nv_file_name: The fully qualified file name used both the talker and listener.
+intf_nv_file_name = output.mjpeg
+
+# intf_nv_repeat: Continually repeat the file stream when running as a talker.
+intf_nv_repeat = 0
+
+# intf_nv_ignore_timestamp: If set the listener will ignore the timestamp on media queue items.
+#intf_nv_ignore_timestamp = 1
+
+# gst 0.1
+intf_nv_gst_pipeline = appsrc name=avbsrc ! application/x-rtp,media=video,clock-rate=90000,encoding-name=JPEG,payload=96,ssrc=5,clock-base=1,seqnum-base=1 ! rtpjpegdepay ! jpegdec ! ffmpegcolorspace ! autovideosink
+
+# gst 1.0
+#intf_nv_gst_pipeline = appsrc name=avbsrc ! application/x-rtp,media=video,clock-rate=90000,encoding-name=JPEG,payload=96,ssrc=5,clock-base=1,seqnum-base=1 ! rtpjpegdepay ! jpegdec ! autovideosink
+
+intf_nv_blocking_rx = 1
+intf_nv_async_rx = 1
+
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
new file mode 100644
index 00000000..05b8223e
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_talker.ini
@@ -0,0 +1,136 @@
+#####################################################################
+# General Talker configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = talker
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: destination multicast address for the stream.
+#
+# If using SRP and MAAP, dynamic destination addresses are generated
+# automatically by the talker and passed to the listner, and don't
+# need to be configured.
+#
+# Without MAAP, locally administered (static) addresses must be
+# configured. Thouse 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.
+#
+# When SRP is being used the static destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set (to the same value) in both the talker and listener.
+#
+# 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.
+#
+dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = A
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 2000
+
+# max_transmit_deficit_usec: Allows setting the maximum packet transmit rate deficit that will
+# be recovered when a talker falls behind. This is only used on a talker side. 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. Typically this value can be set to the expected buffer size (in usec) that listeners are
+# expected to be buffering. 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.
+max_transmit_deficit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_mjpeg.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapMjpegInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+# map_nv_tx_rate: Transmit rate
+# If not set default of the talker class will be used.
+#map_nv_tx_rate = 2000
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. 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.
+intf_lib = ./libopenavb_intf_mjpeg_gst.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfMjpegGstInitialize
+
+# gst 0.1
+#intf_nv_gst_pipeline = v4l2src ! "image/jpeg" ! rtpjpegpay ssrc=5 timestamp-offset=1 seqnum-offset=1 ! appsink name=avbsink
+intf_nv_gst_pipeline = v4l2src ! video/x-raw-yuv,width=640,height=480 ! jpegenc ! rtpjpegpay ssrc=5 timestamp-offset=1 seqnum-offset=1 ! appsink name=avbsink
+
+# gst 1.0
+#intf_nv_gst_pipeline = v4l2src ! video/x-raw,width=640,height=480 ! jpegenc ! rtpjpegpay ssrc=5 timestamp-offset=1 seqnum-offset=1 ! appsink name=avbsink
+#intf_nv_gst_pipeline = videotestsrc ! video/x-raw,width=640,height=480 ! jpegenc ! rtpjpegpay ssrc=5 timestamp-offset=1 seqnum-offset=1 ! appsink name=avbsink
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
new file mode 100644
index 00000000..52ee0a3e
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/openavb_intf_mjpeg_gst.c
@@ -0,0 +1,575 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : MJPEG File interface module.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <gst/gst.h>
+#include <gst/app/gstappsink.h>
+#include <gst/app/gstappsrc.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_intf_pub.h"
+#include "openavb_map_mjpeg_pub.h"
+#include "gst_al.h"
+
+#define AVB_LOG_COMPONENT "MJPEG Interface"
+#include "openavb_log_pub.h"
+
+#define APPSINK_NAME "avbsink"
+#define APPSRC_NAME "avbsrc"
+#define PACKETS_PER_RX_CALL 20
+
+#define NBUFS 256
+
+typedef struct pvt_data_t
+{
+ char *pPipelineStr;
+
+ bool ignoreTimestamp;
+
+ GstElement *pipe;
+ GstElement *appsink;
+ GstElement *appsrc;
+
+ U32 bufwr;
+ U32 bufrd;
+ U32 seq;
+ GstAlBuf *rxBufs[NBUFS];
+ bool asyncRx;
+ bool blockingRx;
+
+ bool get_avtp_timestamp; /*<! this flag indicates whether
+ an avtp timestamp should be taken */
+ U32 frame_timestamp; /*<! this is a timestamp of a video frame */
+} pvt_data_t;
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbIntfMjpegGstCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ if (!pMediaQ)
+ {
+ AVB_LOG_DEBUG("mjpeg-gst cfgCB: no mediaQ!");
+ return;
+ }
+
+ char *pEnd;
+ long tmp;
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ pPvtData->asyncRx = FALSE;
+
+ if (strcmp(name, "intf_nv_gst_pipeline") == 0)
+ {
+ if (pPvtData->pPipelineStr)
+ {
+ free(pPvtData->pPipelineStr);
+ }
+ pPvtData->pPipelineStr = strdup(value);
+ }
+ else if (strcmp(name, "intf_nv_async_rx") == 0)
+ {
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1)
+ {
+ pPvtData->asyncRx = (tmp == 1);
+ }
+ }
+ else if (strcmp(name, "intf_nv_blocking_rx") == 0)
+ {
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1)
+ {
+ pPvtData->blockingRx = (tmp == 1);
+ }
+ }
+ else if (strcmp(name, "intf_nv_ignore_timestamp") == 0)
+ {
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1)
+ {
+ pPvtData->ignoreTimestamp = (tmp == 1);
+ }
+ }
+}
+
+void openavbIntfMjpegGstGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ if (!pMediaQ)
+ {
+ AVB_LOG_DEBUG("mjpeg-gst initCB: no mediaQ!");
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// A call to this callback indicates that this interface module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbIntfMjpegGstTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (!pMediaQ)
+ {
+ AVB_LOG_DEBUG("mjpeg-gst txinit: no mediaQ!");
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ GError *error = NULL;
+ pPvtData->pipe = gst_parse_launch(pPvtData->pPipelineStr, &error);
+ if (error)
+ {
+ AVB_LOGF_ERROR("Unable to create pipeline: %s", error->message);
+ }
+
+ AVB_LOGF_INFO("Pipeline: %s", pPvtData->pPipelineStr);
+ pPvtData->appsink = gst_bin_get_by_name(GST_BIN(pPvtData->pipe), APPSINK_NAME);
+ if (!pPvtData->appsink)
+ {
+ AVB_LOG_ERROR("Failed to find appsink element");
+ }
+ //No limits for internal sink buffers. This may cause large memory consumption.
+ g_object_set(pPvtData->appsink, "max-buffers", 0, "drop", 0, NULL);
+ //FIXME: Check if state change was successful
+ gst_element_set_state(pPvtData->pipe, GST_STATE_PLAYING);
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+
+ return;
+}
+
+// This callback will be called for each AVB transmit interval. Commonly this will be
+// 4000 or 8000 times per second.
+bool openavbIntfMjpegGstTxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+
+ if (!pMediaQ)
+ {
+ AVB_LOG_DEBUG("No MediaQ in MjpegGstTxCB");
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ U32 paySize = 0;
+
+ GstAlBuf *txBuf = NULL;
+
+ txBuf = gst_al_pull_rtp_buffer(GST_APP_SINK(pPvtData->appsink));
+
+ if (!txBuf)
+ {
+ AVB_LOG_ERROR("Gstreamer buffer pull problem");
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return FALSE;
+ }
+
+ paySize = GST_AL_BUF_SIZE(txBuf);
+
+ //Transmit data --BEGIN--
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem)
+ {
+ pMediaQItem->dataLen = paySize;
+ memcpy(pMediaQItem->pPubData, GST_AL_BUF_DATA(txBuf), paySize);
+ if (gst_al_rtp_buffer_get_marker(txBuf))
+ {
+ ((media_q_item_map_mjpeg_pub_data_t *)pMediaQItem->pPubMapData)->lastFragment = TRUE;
+ // next time get avtp timestamp
+ pPvtData->get_avtp_timestamp = TRUE;
+ }
+ else
+ {
+ // it means this is a new bunch of fragments
+ // only first timestamp need to be taken
+ if(pPvtData->get_avtp_timestamp)
+ {
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ pPvtData->get_avtp_timestamp = FALSE;
+ }
+ ((media_q_item_map_mjpeg_pub_data_t *)pMediaQItem->pPubMapData)->lastFragment = FALSE;
+ }
+ openavbMediaQHeadPush(pMediaQ);
+
+ gst_al_rtp_buffer_unref(txBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+ }
+ else
+ {
+ gst_al_rtp_buffer_unref(txBuf);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ AVB_LOG_INFO("GStreamer returned NULL buffer, pipeline stopped");
+ return FALSE; // Media queue full
+ }
+ // never here....
+ openavbMediaQHeadUnlock(pMediaQ);
+ pMediaQItem->dataLen = 0;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+}
+
+// Async stuff...
+static pthread_t asyncRxThread;
+static pthread_mutex_t asyncRxMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t asyncReadMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t asyncReadCond = PTHREAD_COND_INITIALIZER;
+#define LOCK() pthread_mutex_lock(&asyncRxMutex)
+#define UNLOCK() pthread_mutex_unlock(&asyncRxMutex)
+static bool bAsyncRXStreaming;
+static media_q_t *pAsyncRxMediaQ;
+//static media_q_item_t *pAsyncRxMediaQItem;
+//static bool bAsyncRXDoneWithItem;
+
+static void *openavbIntfMjpegGstRxThreadfn(void *pv)
+{
+ pvt_data_t *pPvtData;
+
+ if (!pAsyncRxMediaQ)
+ {
+ AVB_LOG_ERROR("No async mediaQ");
+ return 0;
+ }
+ pPvtData = pAsyncRxMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("No async RX private data.");
+ return 0;
+ }
+
+ bAsyncRXStreaming = TRUE;
+ while (bAsyncRXStreaming)
+ {
+ U32 bufwr = pPvtData->bufwr;
+ U32 bufrd = pPvtData->bufrd;
+ if (bufwr == bufrd)
+ {
+ pthread_mutex_lock(&asyncReadMutex);
+ pthread_cond_wait(&asyncReadCond, &asyncReadMutex);
+ pthread_mutex_unlock(&asyncReadMutex);
+ }
+ else if(bufwr > bufrd)
+ {
+ GstAlBuf *rxBuf = pPvtData->rxBufs[pPvtData->bufrd%NBUFS];
+ if (rxBuf)
+ {
+ pPvtData->rxBufs[pPvtData->bufrd%NBUFS] = NULL;
+ __sync_fetch_and_add(&pPvtData->bufrd, 1);
+ GstFlowReturn ret = gst_al_push_rtp_buffer(GST_APP_SRC(pPvtData->appsrc), rxBuf);
+
+ if (ret != GST_FLOW_OK)
+ {
+ AVB_LOGF_ERROR("Pushing buffer to appsrc failed with code %d", ret);
+ }
+ }
+ else
+ {
+ AVB_LOGF_INFO("The Buf %x %d skipped, OO!!", rxBuf, bufrd);
+ }
+ }
+ else
+ {
+ AVB_LOGF_INFO("There is a BUG as bufwr=%d < bufrd=%d", bufwr, bufrd);
+ }
+ }
+ return 0;
+}
+// A call to this callback indicates that this interface module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbIntfMjpegGstRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_LOG_DEBUG("Rx Init callback.");
+ if (!pMediaQ)
+ {
+ AVB_LOG_DEBUG("No MediaQ in MjpegGstRxInitCB");
+ return;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ GError *error = NULL;
+ pPvtData->pipe = gst_parse_launch(pPvtData->pPipelineStr, &error);
+ if (error)
+ {
+ AVB_LOGF_ERROR("Unable to create pipeline: %s", error->message);
+ }
+
+ AVB_LOGF_INFO("Pipeline: %s", pPvtData->pPipelineStr);
+ pPvtData->appsrc = gst_bin_get_by_name(GST_BIN(pPvtData->pipe), APPSRC_NAME);
+ if (!pPvtData->appsrc)
+ {
+ AVB_LOG_ERROR("Failed to find appsrc element");
+ }
+
+ // caps can be set from pipeline
+ if (pPvtData->blockingRx)
+ {
+ AVB_LOG_DEBUG("Switching gstreamer into blocking mode");
+ g_object_set(pPvtData->appsrc, "block", 1, NULL); // and now we have to do async rx :)
+ }
+
+ //FIXME: Check if state change was successful
+ gst_element_set_state(pPvtData->pipe, GST_STATE_PLAYING);
+
+ pPvtData->seq = 1;
+
+ if (pPvtData->asyncRx)
+ {
+ pAsyncRxMediaQ = pMediaQ;
+ int err = pthread_mutex_init(&asyncRxMutex, 0);
+ if (err)
+ AVB_LOG_ERROR("Mutex init failed");
+ pthread_attr_t attr;
+ struct sched_param param;
+ pthread_attr_init(&attr);
+ pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
+ param.sched_priority = 0;
+ pthread_attr_setschedparam(&attr, &param);
+ pthread_create(&asyncRxThread, &attr, openavbIntfMjpegGstRxThreadfn, NULL);
+ }
+}
+
+// This callback is called when acting as a listener.
+bool openavbIntfMjpegGstRxCB(media_q_t *pMediaQ)
+{
+ if (!pMediaQ)
+ {
+ AVB_LOG_DEBUG("RxCB: no mediaQ!");
+ return TRUE;
+ }
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ bool moreSourcePackets = TRUE;
+
+ while (moreSourcePackets)
+ {
+ media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, pPvtData->ignoreTimestamp);
+ // there are no packets available or they are from the future
+ if (!pMediaQItem)
+ {
+ moreSourcePackets = FALSE;
+ continue;
+ }
+ if (!pMediaQItem->dataLen)
+ {
+ AVB_LOG_DEBUG("No dataLen");
+ openavbMediaQTailPull(pMediaQ);
+ continue;
+ }
+ if (pPvtData->asyncRx)
+ {
+ U32 bufwr = pPvtData->bufwr;
+ U32 bufrd = pPvtData->bufrd;
+ U32 mdif = bufwr - bufrd;
+ if (mdif >= NBUFS)
+ {
+ openavbMediaQTailPull(pMediaQ);
+ AVB_LOGF_INFO("Rx async queue full, dropping (%lu - %lu = %lu)", bufwr, bufrd, mdif);
+ moreSourcePackets = FALSE;
+ continue;
+ }
+ }
+ GstAlBuf *rxBuf = gst_al_alloc_rtp_buffer(pMediaQItem->dataLen, 0,0);
+
+ if (!rxBuf)
+ {
+ AVB_LOG_ERROR("gst_rtp_buffer_allocate failed!");
+ openavbMediaQTailUnlock(pMediaQ);
+ return FALSE;
+ }
+ memcpy(GST_AL_BUF_DATA(rxBuf), pMediaQItem->pPubData, pMediaQItem->dataLen);
+
+ GST_AL_BUFFER_TIMESTAMP(rxBuf) = GST_CLOCK_TIME_NONE;
+ GST_AL_BUFFER_DURATION(rxBuf) = GST_CLOCK_TIME_NONE;
+
+ if ( ((media_q_item_map_mjpeg_pub_data_t *)pMediaQItem->pPubMapData)->lastFragment )
+ {
+ pPvtData->get_avtp_timestamp = TRUE;
+ gst_al_rtp_buffer_set_marker(rxBuf,TRUE);
+ }
+ else
+ {
+ if(pPvtData->get_avtp_timestamp)
+ {
+ pPvtData->frame_timestamp = openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime);
+ pPvtData->get_avtp_timestamp = FALSE;
+ }
+ else
+ {
+ U32 fragment_timestamp = openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime);
+ // all fragments should have the same timestamp
+ if(pPvtData->frame_timestamp != fragment_timestamp)
+ {
+ AVB_LOGF_ERROR("Mapping is wrong. Fragment timestamp should be %lu instead of %lu",
+ pPvtData->frame_timestamp, fragment_timestamp);
+ }
+ }
+ }
+
+ gst_al_rtp_buffer_set_params(rxBuf, 5, 96, 2, pPvtData->seq++);
+
+ if (pPvtData->asyncRx)
+ {
+ pPvtData->rxBufs[pPvtData->bufwr%NBUFS] = rxBuf;
+ __sync_fetch_and_add(&pPvtData->bufwr, 1);
+ pthread_mutex_lock(&asyncReadMutex);
+ pthread_cond_signal(&asyncReadCond);
+ pthread_mutex_unlock(&asyncReadMutex);
+ }
+ else
+ {
+ // appsrc manages this buffer at this point
+ GstFlowReturn ret = gst_al_push_rtp_buffer(GST_APP_SRC(pPvtData->appsrc), rxBuf);
+ if (ret != GST_FLOW_OK)
+ {
+ AVB_LOGF_ERROR("Pushing buffer to appsrc failed with code %d", ret);
+ }
+ }
+ openavbMediaQTailPull(pMediaQ);
+ }
+ return TRUE;
+}
+
+// This callback will be called when the interface needs to be closed. All shutdown should
+// occur in this function.
+void openavbIntfMjpegGstEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ bAsyncRXStreaming = FALSE;
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+ if (pPvtData->pipe)
+ {
+ gst_element_set_state(pPvtData->pipe, GST_STATE_NULL);
+ if (pPvtData->appsink)
+ {
+ gst_object_unref(pPvtData->appsink);
+ pPvtData->appsink = NULL;
+ }
+ if (pPvtData->appsrc)
+ {
+ gst_object_unref(pPvtData->appsrc);
+ pPvtData->appsrc = NULL;
+ }
+ gst_object_unref(pPvtData->pipe);
+ pPvtData->pipe = NULL;
+ }
+ if (pPvtData->asyncRx)
+ {
+ pthread_mutex_lock(&asyncReadMutex);
+ pthread_cond_signal(&asyncReadCond);
+ pthread_mutex_unlock(&asyncReadMutex);
+ pthread_join(asyncRxThread, NULL);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfMjpegGstGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Main initialization entry point into the interface module
+extern DLL_EXPORT bool openavbIntfMjpegGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (!pMediaQ)
+ {
+ AVB_LOG_DEBUG("mjpeg-gst GstInitialize: no mediaQ!");
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+ }
+
+ pMediaQ->pPvtIntfInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ pPvtData->get_avtp_timestamp = TRUE;
+
+ pIntfCB->intf_cfg_cb = openavbIntfMjpegGstCfgCB;
+ pIntfCB->intf_gen_init_cb = openavbIntfMjpegGstGenInitCB;
+ pIntfCB->intf_tx_init_cb = openavbIntfMjpegGstTxInitCB;
+ pIntfCB->intf_tx_cb = openavbIntfMjpegGstTxCB;
+ pIntfCB->intf_rx_init_cb = openavbIntfMjpegGstRxInitCB;
+ pIntfCB->intf_rx_cb = openavbIntfMjpegGstRxCB;
+ pIntfCB->intf_end_cb = openavbIntfMjpegGstEndCB;
+ pIntfCB->intf_gen_end_cb = openavbIntfMjpegGstGenEndCB;
+
+ pPvtData->ignoreTimestamp = FALSE;
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/CMakeLists.txt
new file mode 100644
index 00000000..35bad67a
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/CMakeLists.txt
@@ -0,0 +1,4 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_OSAL_DIR}/intf_mpeg2ts_file/openavb_intf_mpeg2ts_file.c
+ PARENT_SCOPE
+)
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_intf.md b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_intf.md
new file mode 100644
index 00000000..ad17f7bd
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_intf.md
@@ -0,0 +1,50 @@
+MPEG2TS file interface {#mpeg2ts_file_intf}
+=======================
+
+# Description
+
+Mpeg2 TS File interface module.
+Computation of TS packet duration copied from Live555 application
+(www.live555.com).
+
+<br>
+# Interface module configuration parameters
+
+Name | Description
+--------------------------|---------------------------
+intf_nv_file_name |The fully qualified file name. Used on **talker** \
+ and on **listener** side
+intf_nv_repeat |If set to 1 it will continually repeat the file \
+ stream when running as a talker
+intf_nv_repeat_seconds |Delay in seconds which will be skipped when repeating
+intf_nv_enable_proper_bitrate_streaming|Setting to 1 will enable tracking of \
+ the bitrate
+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.
+
+<br>
+# Notes
+
+Additionally the @ref openavb_intf_cb_t::intf_get_src_bitrate_cb callback function
+can be used to calculate the maximum bitrate of the source.
+
+**Note**: To make those calculations
+**intf_nv_enable_proper_bitrate_streaming** has to be enabled.
+
+If this callback is registered (not NULL) it will trigger several actions:
+* calculated maximum bitrate will be passed to the maping module via the
+function @ref openavb_map_cb_t::map_set_src_bitrate_cb
+* callback @ref openavb_map_cb_t::map_get_max_interval_frames_cb will be
+called to calculate the **maximum interval frames**
+* **maximum frame size** is calculated by calling
+@ref openavb_map_cb_t::map_max_data_size_cb.
+
+If this callback function is not registered (is NULL), values taken from
+the configuration file for **maximum frame size** and **maximum interval frames**
+will be used for calculations.
+
+**maximum frame size** and **maximum interval frames** values are used by
+* SRP to calculate bandwidth,
+* FQTSS to calculate queueing discipline parameters.
+
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
new file mode 100644
index 00000000..eb76cb7d
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_listener.ini
@@ -0,0 +1,100 @@
+#####################################################################
+# General Listener configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = listener
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: see description in talker.ini
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+#max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+#sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+#max_transit_usec = 2000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_mpeg2ts.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapMpeg2tsInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+intf_lib = ./libopenavb_intf_mpeg2ts_file.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfMpeg2tsFileInitialize
+
+# intf_nv_file_name: The fully qualified file name used both the talker and listener.
+intf_nv_file_name = output.ts
+
+# intf_nv_repeat: Continually repeat the file stream when running as a talker.
+intf_nv_repeat = 0
+
+# intf_nv_ignore_timestamp: If set the listener will ignore the timestamp on media queue items.
+#intf_nv_ignore_timestamp = 1
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
new file mode 100644
index 00000000..c4f595a0
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_talker.ini
@@ -0,0 +1,142 @@
+#####################################################################
+# General Talker configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = talker
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: destination multicast address for the stream.
+#
+# If using SRP and MAAP, dynamic destination addresses are generated
+# automatically by the talker and passed to the listner, and don't
+# need to be configured.
+#
+# Without MAAP, locally administered (static) addresses must be
+# configured. Thouse 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.
+#
+# When SRP is being used the static destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set (to the same value) in both the talker and listener.
+#
+# 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.
+#
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+#sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 2000
+
+# max_transmit_deficit_usec: Allows setting the maximum packet transmit rate deficit that will
+# be recovered when a talker falls behind. This is only used on a talker side. 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. Typically this value can be set to the expected buffer size (in usec) that listeners are
+# expected to be buffering. 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.
+max_transmit_deficit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_mpeg2ts.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapMpeg2tsInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+# map_nv_tx_rate: Transmit rate
+# If not set default of the talker class will be used.
+#map_nv_tx_rate = 2000
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. 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.
+intf_lib = ./libopenavb_intf_mpeg2ts_file.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfMpeg2tsFileInitialize
+
+# intf_nv_file_name: The fully qualified file name used both the talker and listener.
+#intf_nv_file_name = input.ts
+intf_nv_file_name = hbo_trailer_6ksd_converted.ts
+
+# intf_nv_repeat: Continually repeat the file stream when running as a talker.
+intf_nv_repeat = 0
+
+
+
+
+
+
+
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
new file mode 100644
index 00000000..b44ee9e1
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/openavb_intf_mpeg2ts_file.c
@@ -0,0 +1,706 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Mpeg2 TS File interface module.
+* Computation of TS packet duration copied
+* from Live555 application (www.live555.com).
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_intf_pub.h"
+
+#define AVB_LOG_COMPONENT "MPEG2TS Interface"
+#include "openavb_log_pub.h"
+
+#define PCR_PERIOD_VARIATION_RATIO 0.5
+#define TIME_ADJUSTMENT_FACTOR 0.8
+#define MAX_PLAYOUT_BUFFER_DURATION 0.1 // (seconds)
+#define NEW_DURATION_WEIGHT 0.5
+#define MAX_TABLE_PIDS 100
+#define F27_MHZ 27000000.0
+#define F90_KHZ 90000.0
+
+struct PIDStatus {
+ double firstClock, lastClock, firstRealTime, lastRealTime;
+ unsigned long long lastPacketNum;
+ int used;
+ int pid;
+};
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ // intf_nv_file_name: The fully qualified file name used both the talker and listener.
+ // NULL means use stdin/stdout
+ char *pFileName;
+
+ // intf_nv_repeat: Continually repeat the file stream when running
+ bool repeat;
+
+ // Delay repeating the video until this many seconds have passed
+ int repeatSeconds;
+
+ // Ignore timestamp at listener.
+ bool ignoreTimestamp;
+
+ /////////////
+ // Variable data
+ /////////////
+ FILE *pFile;
+
+ // Talker variables for tracking rewind
+ struct timespec startTime;
+ int nRepeatCount;
+ int nBuffersSent;
+
+ // Talker variables for tracking bitrate
+ unsigned int maxBitrate;
+ int enableBitrateTracking;
+ double nextTransmitTime;
+ double fTSPacketCount;
+ double fTSPCRCount;
+ double fTSPacketDurationEstimate;
+ struct PIDStatus *fPIDStatusTable;
+
+} pvt_data_t;
+
+double openavbIntfMpeg2tsFileComputeDuration(pvt_data_t* pPvtData, unsigned char* pkts, unsigned int length);
+
+int pidTableFindOrCreatePid(struct PIDStatus *table, const unsigned int pid)
+{
+ int idx = -1;
+ int i = 0;
+ for (i = 0; i < MAX_TABLE_PIDS; ++i)
+ {
+ if (pid == table[i].pid)
+ {
+ idx = i;
+ break;
+ }
+ }
+ if (-1 == idx) /* create */
+ {
+ /* find free slot */
+ for (i = 0; i < MAX_TABLE_PIDS; ++i)
+ {
+ if (0 == table[i].used)
+ {
+ table[i].pid = pid;
+ idx = i;
+ break;
+ }
+ }
+ }
+
+ return idx;
+}
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbIntfMpeg2tsFileCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ char *pEnd;
+ unsigned long tmp;
+ bool nameOK = TRUE, valueOK = FALSE;
+
+ if (strcmp(name, "intf_nv_file_name") == 0) {
+ if (pPvtData->pFileName)
+ free(pPvtData->pFileName);
+ pPvtData->pFileName = strdup(value);
+ valueOK = TRUE;
+ }
+
+ else if (strcmp(name, "intf_nv_repeat") == 0) {
+ tmp = strtoul(value, &pEnd, 10);
+ if (*pEnd == '\0' && pEnd != value && (tmp == 0 || tmp == 1)) {
+ pPvtData->repeat = (tmp == 1);
+ valueOK = TRUE;
+ }
+ }
+ else if (strcmp(name, "intf_nv_repeat_seconds") == 0) {
+ tmp = strtoul(value, &pEnd, 10);
+ if (*pEnd == '\0' && pEnd != value) {
+ pPvtData->repeatSeconds = tmp;
+ valueOK = TRUE;
+ }
+ }
+ else if (strcmp(name, "intf_nv_ignore_timestamp") == 0) {
+ tmp = strtoul(value, &pEnd, 10);
+ if (*pEnd == '\0' && pEnd != value && (tmp == 0 || tmp == 1)) {
+ pPvtData->ignoreTimestamp = (tmp == 1);
+ valueOK = TRUE;
+ }
+ }
+ else if (strcmp(name, "intf_nv_enable_proper_bitrate_streaming") == 0) {
+ tmp = strtoul(value, &pEnd, 10);
+ if (*pEnd == '\0' && pEnd != value && (tmp == 0 || tmp == 1)) {
+ pPvtData->enableBitrateTracking = (tmp == 1);
+ valueOK = TRUE;
+ }
+ }
+ else {
+ AVB_LOGF_WARNING("Unknown configuration item: %s", name);
+ nameOK = FALSE;
+ }
+
+ if (nameOK && !valueOK) {
+ AVB_LOGF_WARNING("Bad value for configuration item: %s = %s", name, value);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+#define MPEGTS_SYNC_BYTE (0x47)
+static void sync_scan(FILE* input)
+{
+ unsigned char byte = 0;
+ while (1 == fread(&byte, 1, 1, input)) {
+ if (MPEGTS_SYNC_BYTE == byte) {
+ fseek(input, -1, SEEK_CUR);
+ break;
+ }
+ }
+}
+
+#define TS_PACKETS 1
+static unsigned int openavbComputeFileBitrate(char *fileName, media_q_t *pMediaQ)
+{
+ double max_bitrate = 0;
+ FILE *input = fopen(fileName, "rb");
+ if (input != NULL) {
+ unsigned char* packets = (unsigned char *) malloc(188*TS_PACKETS);
+ double fTSPCRCount = 0;
+ struct PIDStatus *fPIDStatusTable = (struct PIDStatus*) calloc(MAX_TABLE_PIDS, sizeof(struct PIDStatus));
+ double fTSPacketCount = 0;
+ int i = 0;
+ for(i = 0; i < MAX_TABLE_PIDS; ++i)
+ {
+ fPIDStatusTable[i].pid = -1;
+ fPIDStatusTable[i].used = 0;
+ }
+ sync_scan(input);
+ while((TS_PACKETS * 188) == fread((void *)packets, 1, 188*TS_PACKETS, input))
+ {
+ unsigned char* pkt;
+ for (pkt = packets; pkt < &(packets[TS_PACKETS*188]); pkt += 188)
+ {
+ fTSPacketCount++;
+
+ unsigned char const adaptation_field_control = (pkt[3]&0x30)>>4;
+ if (adaptation_field_control != 2 && adaptation_field_control != 3) continue;
+ // there's no adaptation_field
+
+ unsigned char const adaptation_field_length = pkt[4];
+ if (adaptation_field_length == 0) continue;
+
+ unsigned char const pcrFlag = pkt[5]&0x10;
+ if (pcrFlag == 0) continue; // no PCR
+
+ unsigned char const discontinuity_indicator = pkt[5]&0x80;
+ // There's a PCR. Get it.
+ ++fTSPCRCount;
+ unsigned int pcrBaseHigh = (pkt[6]<<24)|(pkt[7]<<16)|(pkt[8]<<8)|pkt[9];
+ double fClock = pcrBaseHigh/(F90_KHZ/2);
+ if ((pkt[10]&0x80) != 0) fClock += 1/F90_KHZ; // add in low-bit (if set)
+ unsigned short pcrExt = ((pkt[10]&0x01)<<8) | pkt[11];
+ fClock += pcrExt/F27_MHZ;
+
+ unsigned pid = ((pkt[1]&0x1F)<<8) | pkt[2];
+ int idx = pidTableFindOrCreatePid(fPIDStatusTable, pid);
+ if (!fPIDStatusTable[idx].used) {
+ // We're seeing this PID's PCR for the first time:
+ fPIDStatusTable[idx].used = 1;
+ fPIDStatusTable[idx].firstClock = fClock;
+ fPIDStatusTable[idx].lastClock = fClock;
+ fPIDStatusTable[idx].lastPacketNum = fTSPacketCount;
+ }
+ else {
+ if (discontinuity_indicator == 0) {
+ double duration = fClock - fPIDStatusTable[idx].lastClock;
+ if (duration > 0) {
+ double data = (fTSPacketCount - fPIDStatusTable[idx].lastPacketNum) * 188 * 8;
+ double bitrate = data / duration;
+ if (bitrate > max_bitrate)
+ max_bitrate = bitrate;
+ }
+ fPIDStatusTable[idx].lastClock = fClock;
+ if (duration > 0)
+ fPIDStatusTable[idx].lastPacketNum = fTSPacketCount;
+ }
+ else {
+ fPIDStatusTable[idx].firstClock = fClock;
+ fPIDStatusTable[idx].lastPacketNum = fTSPacketCount;
+ }
+ }
+ }
+ }
+ fclose(input);
+ free(fPIDStatusTable);
+ free(packets);
+ }
+
+ return (unsigned int)max_bitrate;
+}
+
+
+void openavbIntfMpeg2tsFileGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+unsigned int openavbIntMpeg2tsGetSrcBitrate(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ if (((pvt_data_t *)pMediaQ->pPvtIntfInfo)->enableBitrateTracking)
+ ((pvt_data_t *)pMediaQ->pPvtIntfInfo)->maxBitrate = openavbComputeFileBitrate(((pvt_data_t*)pMediaQ->pPvtIntfInfo)->pFileName, pMediaQ);
+ else
+ ((pvt_data_t *)pMediaQ->pPvtIntfInfo)->maxBitrate = 0;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+
+ return ((pvt_data_t *)pMediaQ->pPvtIntfInfo)->maxBitrate;
+}
+// A call to this callback indicates that this interface module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbIntfMpeg2tsFileTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ pPvtData->nRepeatCount = 0;
+ pPvtData->nBuffersSent = 0;
+
+ if (!pPvtData->pFileName) {
+ AVB_LOG_INFO("using stdin");
+ pPvtData->pFileName = strdup("stdin");
+ pPvtData->pFile = stdin;
+ }
+ else {
+ pPvtData->pFile = fopen(pPvtData->pFileName, "rb");
+ if (!pPvtData->pFile) {
+ AVB_LOGF_ERROR("Unable to open input file: %s", pPvtData->pFileName);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback will be called for each AVB transmit interval. Commonly this will be
+// 4000 or 8000 times per second.
+bool openavbIntfMpeg2tsFileTxCB(media_q_t *pMediaQ)
+{
+ media_q_item_t *pMediaQItem = NULL;
+ bool retval = FALSE;
+
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ if (!pPvtData->pFile) {
+ // input already closed
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE;
+ }
+
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ double nowSeconds = 0;
+ if (pPvtData->enableBitrateTracking) {
+ nowSeconds = (double)now.tv_sec + (double)now.tv_nsec / NANOSECONDS_PER_SECOND;
+
+ if (nowSeconds < pPvtData->nextTransmitTime)
+ {
+ return FALSE;
+ }
+ }
+
+ // handle end-of-file
+ if (feof(pPvtData->pFile)) {
+ if (pPvtData->pFileName && pPvtData->repeat) {
+ if (pPvtData->nRepeatCount < 2)
+ ; // No delay for first few rewinds - want to buffer some data for restarts
+ else if (pPvtData->repeatSeconds > (now.tv_sec - pPvtData->startTime.tv_sec)
+ || (pPvtData->repeatSeconds == (now.tv_sec - pPvtData->startTime.tv_sec)
+ && (now.tv_nsec >= pPvtData->startTime.tv_nsec))) {
+ // don't rewind, yet
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE;
+ }
+
+ AVB_LOGF_INFO("EOF, rewinding input file: %s", pPvtData->pFileName);
+ fseek(pPvtData->pFile, 0, 0);
+
+ pPvtData->nRepeatCount++;
+ pPvtData->nBuffersSent = 0;
+
+ if (pPvtData->enableBitrateTracking) {
+ // clear PCR infos here, PID hashtable, packet duration estimate
+ pPvtData->fTSPacketDurationEstimate = 0;
+ pPvtData->fTSPacketCount = 0;
+ pPvtData->fTSPCRCount = 0;
+ {
+ int i = 0;
+ for (i = 0; i < MAX_TABLE_PIDS; ++i)
+ {
+ pPvtData->fPIDStatusTable[i].used = 0;
+ pPvtData->fPIDStatusTable[i].pid = -1;
+ }
+ }
+ }
+ }
+ else {
+ AVB_LOGF_INFO("EOF, closing input file: %s", pPvtData->pFileName);
+ fclose(pPvtData->pFile);
+ pPvtData->pFile = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE;
+ }
+ }
+
+ pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (!pMediaQItem) {
+ IF_LOG_INTERVAL(1000) AVB_LOG_ERROR("Media queue full");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return FALSE; // Media queue full
+ }
+
+ size_t result = fread(pMediaQItem->pPubData, 1, pMediaQItem->itemSize, pPvtData->pFile);
+ if (result == 0) {
+ int e = ferror(pPvtData->pFile);
+ if (e != 0) {
+ AVB_LOGF_ERROR("Error reading file: %s, %s", pPvtData->pFileName, strerror(e));
+ fclose(pPvtData->pFile);
+ pPvtData->pFile = NULL;
+ }
+ pMediaQItem->dataLen = 0;
+ openavbMediaQHeadUnlock(pMediaQ);
+ }
+ else {
+ pMediaQItem->dataLen = result;
+ if (pPvtData->enableBitrateTracking) {
+ pPvtData->nextTransmitTime = nowSeconds + openavbIntfMpeg2tsFileComputeDuration(pPvtData,(unsigned char*) pMediaQItem->pPubData, pMediaQItem->dataLen);
+ }
+ openavbMediaQHeadPush(pMediaQ);
+ retval = TRUE;
+
+ if (pPvtData->nBuffersSent++ == 0) {
+ pPvtData->startTime = now;
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return retval;
+}
+
+double openavbIntfMpeg2tsFileComputeDuration(pvt_data_t* pPvtData, unsigned char* pkts, unsigned int length)
+{
+ int offset = 0;
+ unsigned char *pkt = NULL;
+
+ while(pkts[offset] != 0x47)
+ ++offset;
+
+ for (pkt = &pkts[offset]; pkt <= &(pkts[length-188]); pkt += 188)
+ {
+ struct timespec tvNow;
+ clock_gettime(CLOCK_MONOTONIC, &tvNow);
+
+
+ double timeNow = tvNow.tv_sec + tvNow.tv_nsec/NANOSECONDS_PER_SECOND;
+
+ pPvtData->fTSPacketCount++;
+
+ unsigned char const adaptation_field_control = (pkt[3]&0x30)>>4;
+ if (adaptation_field_control != 2 && adaptation_field_control != 3) continue;
+ // there's no adaptation_field
+
+ unsigned char const adaptation_field_length = pkt[4];
+ if (adaptation_field_length == 0) continue;
+
+ unsigned char const discontinuity_indicator = pkt[5]&0x80;
+ unsigned char const pcrFlag = pkt[5]&0x10;
+ if (pcrFlag == 0) continue; // no PCR
+
+ // There's a PCR. Get it, and the PID:
+ ++(pPvtData->fTSPCRCount);
+ unsigned int pcrBaseHigh = (pkt[6]<<24)|(pkt[7]<<16)|(pkt[8]<<8)|pkt[9];
+ double fClock = pcrBaseHigh/(F90_KHZ/2);
+ if ((pkt[10]&0x80) != 0) fClock += 1/F90_KHZ; // add in low-bit (if set)
+ unsigned short pcrExt = ((pkt[10]&0x01)<<8) | pkt[11];
+ fClock += pcrExt/F27_MHZ;
+
+ unsigned pid = ((pkt[1]&0x1F)<<8) | pkt[2];
+ int idx = pidTableFindOrCreatePid(pPvtData->fPIDStatusTable, pid);
+ if (!pPvtData->fPIDStatusTable[idx].used) {
+ // We're seeing this PID's PCR for the first time:
+ pPvtData->fPIDStatusTable[idx].used = 1;
+ pPvtData->fPIDStatusTable[idx].firstClock = fClock;
+ pPvtData->fPIDStatusTable[idx].lastClock = fClock;
+ pPvtData->fPIDStatusTable[idx].firstRealTime = timeNow;
+ pPvtData->fPIDStatusTable[idx].lastRealTime = timeNow;
+ pPvtData->fPIDStatusTable[idx].lastPacketNum = 0;
+ AVB_LOGF_VERBOSE("PID 0x%x, FIRST PCR 0x%08x+%d:%03x == %f @ %f, pkt #%lu\n", pid, pcrBaseHigh, pkt[10]>>7, pcrExt, fClock, timeNow, pPvtData->fTSPacketCount);
+ } else {
+ // We've seen this PID's PCR before; update our per-packet duration estimate:
+ double packetsSinceLast = (pPvtData->fTSPacketCount -pPvtData->fPIDStatusTable[idx].lastPacketNum);
+ // it's "int64_t" because some compilers can't convert "u_int64_t" -> "double"
+ double durationPerPacket = (fClock - pPvtData->fPIDStatusTable[idx].lastClock)/packetsSinceLast;
+ // Hack (suggested by "Romain"): Don't update our estimate if this PCR appeared unusually quickly.
+ // (This can produce more accurate estimates for wildly VBR streams.)
+ double meanPCRPeriod = 0.0;
+ if (pPvtData->fTSPCRCount > 0) {
+ double tsPacketCount = (double)(long long) pPvtData->fTSPacketCount;
+ double tsPCRCount = (double)(long long)pPvtData->fTSPCRCount;
+ meanPCRPeriod = tsPacketCount/tsPCRCount;
+ if (packetsSinceLast < meanPCRPeriod*PCR_PERIOD_VARIATION_RATIO) continue ;
+ }
+
+ if (pPvtData->fTSPacketDurationEstimate == 0.0) { // we've just started
+ pPvtData->fTSPacketDurationEstimate = durationPerPacket;
+ } else if (discontinuity_indicator == 0 && durationPerPacket >= 0.0) {
+ pPvtData->fTSPacketDurationEstimate= durationPerPacket*NEW_DURATION_WEIGHT + pPvtData->fTSPacketDurationEstimate*(1-NEW_DURATION_WEIGHT);
+
+ // Also adjust the duration estimate to try to ensure that the transmission
+ // rate matches the playout rate:
+
+ double transmitDuration = timeNow - pPvtData->fPIDStatusTable[idx].firstRealTime;
+ double playoutDuration = fClock - pPvtData->fPIDStatusTable[idx].firstClock;
+ if (transmitDuration > playoutDuration) {
+ pPvtData->fTSPacketDurationEstimate *= TIME_ADJUSTMENT_FACTOR; // reduce estimate
+ } else if (transmitDuration + MAX_PLAYOUT_BUFFER_DURATION < playoutDuration) {
+ pPvtData->fTSPacketDurationEstimate /= TIME_ADJUSTMENT_FACTOR; // increase estimate
+ }
+ } else {
+ // the PCR has a discontinuity from its previous value; don't use it now,
+ // but reset our PCR and real-time values to compensate:
+ pPvtData->fPIDStatusTable[idx].firstClock = fClock;
+ pPvtData->fPIDStatusTable[idx].firstRealTime = timeNow;
+ }
+ AVB_LOGF_VERBOSE("PID 0x%x, PCKT_CNT %lu PCR 0x%08x+%d:%03x == %f @ %f (diffs %f @ %f), pkt #%lu, discon %d => this duration %f, new estimate %f, mean PCR period=%f\n",
+ pid, pPvtData->fTSPacketCount, pcrBaseHigh, pkt[10]>>7, pcrExt, fClock, timeNow, fClock - pPvtData->fPIDStatusTable[idx].firstClock, timeNow - pPvtData->fPIDStatusTable[idx].firstRealTime, pPvtData->fTSPacketCount, discontinuity_indicator != 0, durationPerPacket, pPvtData->fTSPacketDurationEstimate, meanPCRPeriod );
+ }
+ pPvtData->fPIDStatusTable[idx].lastClock = fClock;
+ pPvtData->fPIDStatusTable[idx].lastRealTime = timeNow;
+ pPvtData->fPIDStatusTable[idx].lastPacketNum = pPvtData->fTSPacketCount;
+ }
+
+ return pPvtData->fTSPacketDurationEstimate * ((length - offset) / 188);
+}
+
+// A call to this callback indicates that this interface module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbIntfMpeg2tsFileRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ if (!pPvtData->pFileName) {
+ AVB_LOG_INFO("Using stdout");
+ pPvtData->pFileName = strdup("stdout");
+ pPvtData->pFile = stdout;
+ }
+ else {
+ pPvtData->pFile = fopen(pPvtData->pFileName, "wb");
+ if (!pPvtData->pFile) {
+ AVB_LOGF_ERROR("Unable to open output file: %s", pPvtData->pFileName);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback is called when acting as a listener.
+bool openavbIntfMpeg2tsFileRxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ bool moreData = TRUE;
+ size_t written;
+
+ while (moreData) {
+ media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, pPvtData->ignoreTimestamp);
+ if (pMediaQItem) {
+ while (pPvtData->pFile && pMediaQItem->dataLen > 0) {
+ written = fwrite(pMediaQItem->pPubData, 1, pMediaQItem->dataLen, pPvtData->pFile);
+ if (written == 0) {
+ int e = ferror(pPvtData->pFile);
+ AVB_LOGF_ERROR("Error writing file: %s, %s", pPvtData->pFileName, strerror(e));
+ fclose(pPvtData->pFile);
+ pPvtData->pFile = NULL;
+ }
+ else {
+ pMediaQItem->dataLen -= written;
+ }
+ }
+ openavbMediaQTailPull(pMediaQ);
+ }
+ else {
+ moreData = FALSE;
+ }
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+}
+
+// This callback will be called when the interface needs to be closed. All shutdown should
+// occur in this function.
+void openavbIntfMpeg2tsFileEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ if (pPvtData->pFile) {
+ fclose(pPvtData->pFile);
+ pPvtData->pFile = NULL;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfMpeg2tsFileGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ if (pPvtData->pFileName) {
+ free(pPvtData->pFileName);
+ pPvtData->pFileName = NULL;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Main initialization entry point into the interface module
+extern DLL_EXPORT bool openavbIntfMpeg2tsFileInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ int i = 0;
+ pMediaQ->pPvtIntfInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pPvtIntfInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for AVTP interface module.");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ pIntfCB->intf_cfg_cb = openavbIntfMpeg2tsFileCfgCB;
+ pIntfCB->intf_gen_init_cb = openavbIntfMpeg2tsFileGenInitCB;
+ pIntfCB->intf_tx_init_cb = openavbIntfMpeg2tsFileTxInitCB;
+ pIntfCB->intf_tx_cb = openavbIntfMpeg2tsFileTxCB;
+ pIntfCB->intf_rx_init_cb = openavbIntfMpeg2tsFileRxInitCB;
+ pIntfCB->intf_rx_cb = openavbIntfMpeg2tsFileRxCB;
+ pIntfCB->intf_end_cb = openavbIntfMpeg2tsFileEndCB;
+ pIntfCB->intf_gen_end_cb = openavbIntfMpeg2tsFileGenEndCB;
+ pIntfCB->intf_get_src_bitrate_cb = openavbIntMpeg2tsGetSrcBitrate;
+
+ pPvtData->ignoreTimestamp = FALSE;
+
+ pPvtData->fPIDStatusTable = (struct PIDStatus*) calloc(MAX_TABLE_PIDS, sizeof(struct PIDStatus));
+
+ if (NULL == pPvtData->fPIDStatusTable) {
+ AVB_LOG_ERROR("Unable to allocate memory for PID status table.");
+ return FALSE;
+ }
+
+ for (i = 0; i < MAX_TABLE_PIDS; ++i)
+ {
+ pPvtData->fPIDStatusTable[i].pid = -1;
+ }
+ pPvtData->enableBitrateTracking = 1;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/CMakeLists.txt
new file mode 100644
index 00000000..298a909b
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/CMakeLists.txt
@@ -0,0 +1,22 @@
+IF (NOT GSTREAMER_1_0)
+ SET (SRC_FILES ${SRC_FILES}
+ ${AVB_OSAL_DIR}/intf_mpeg2ts_gst/openavb_intf_mpeg2ts_gst.c
+ ${AVB_OSAL_DIR}/gst_al/gst_al_01.c
+ PARENT_SCOPE
+ )
+ELSE ()
+ SET (SRC_FILES ${SRC_FILES}
+ ${AVB_OSAL_DIR}/intf_mpeg2ts_gst/openavb_intf_mpeg2ts_gst.c
+ ${AVB_OSAL_DIR}/gst_al/gst_al_10.c
+ PARENT_SCOPE
+ )
+ENDIF ()
+
+# Need include and link directories for gstreamer
+SET (INTF_INCLUDE_DIR
+ ${INTF_INCLUDE_DIR} ${GLIB_PKG_INCLUDE_DIRS} ${GST_PKG_INCLUDE_DIRS}
+ ${AVB_OSAL_DIR}/gst_al
+ PARENT_SCOPE
+)
+SET (INTF_LIBRARY_DIR ${INTF_LIBRARY_DIR} PARENT_SCOPE)
+SET (INTF_LIBRARY ${GLIB_PKG_LIBRARIES} ${GST_PKG_LIBRARIES} PARENT_SCOPE)
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_intf.md b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_intf.md
new file mode 100644
index 00000000..61a1a260
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_intf.md
@@ -0,0 +1,16 @@
+MPEG2TS GStreamer interface {#mpeg2ts_gst_intf}
+============================
+
+# Description
+
+Mpeg2 TS GStreamer interface module.
+
+<br>
+# Interface module configuration parameters
+
+Name | Description
+--------------------------|---------------------------
+intf_nv_gst_pipeline |GStreamer pipeline to be used
+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.
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
new file mode 100644
index 00000000..bf7ef6b7
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_listener.ini
@@ -0,0 +1,119 @@
+#####################################################################
+# General Listener configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = listener
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: When SRP is being used the destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set in both side the talker and listener.
+# 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.
+# At this time they need to be locally administered and must be in the range
+# of 91:E0:F0:00:FE:00 - 91:E0:F0:00:FE:FF.
+# Typically :00 for the first stream, :01 for the second, etc.
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+#max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+#sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+#max_transit_usec = 2000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_mpeg2ts.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapMpeg2tsInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+intf_lib = ./libopenavb_intf_mpeg2ts_gst.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfMpeg2tsGstInitialize
+
+# intf_nv_file_name: The fully qualified file name used both the talker and listener.
+intf_nv_file_name = output.ts
+
+# intf_nv_repeat: Continually repeat the file stream when running as a talker.
+#intf_nv_repeat = 0
+
+# intf_nv_ignore_timestamp: If set the listener will ignore the timestamp on media queue items.
+# intf_nv_ignore_timestamp = 1
+
+#gstreamer pipeline
+
+# gst 0.1
+intf_nv_gst_pipeline = appsrc name=avbsrc ! queue ! mpegtsdemux ! h264parse ! ffdec_h264 ! autovideosink
+
+# gst 1.0
+#intf_nv_gst_pipeline = appsrc name=avbsrc ! queue ! tsdemux ! h264parse ! avdec_h264 ! autovideosink
+
+# alternate pipe to test that file is transferred
+#intf_nv_gst_pipeline = appsrc name=avbsrc ! filesink location=/dev/shm/listen.ts
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
new file mode 100644
index 00000000..fa48e7a3
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_talker.ini
@@ -0,0 +1,129 @@
+#####################################################################
+# General Talker configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = talker
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: When SRP is being used the destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set in both side the talker and listener.
+# 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.
+# At this time they need to be locally administered and must be in the range
+# of 91:E0:F0:00:FE:00 - 91:E0:F0:00:FE:FF.
+# Typically :00 for the first stream, :01 for the second, etc.
+dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+#sr_class = B
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 2000
+
+# max_transmit_deficit_usec: Allows setting the maximum packet transmit rate deficit that will
+# be recovered when a talker falls behind. This is only used on a talker side. 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. Typically this value can be set to the expected buffer size (in usec) that listeners are
+# expected to be buffering. 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.
+max_transmit_deficit_usec = 50000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_mpeg2ts.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapMpeg2tsInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+# map_nv_tx_rate: Transmit rate
+# If not set default of the talker class will be used.
+#map_nv_tx_rate = 2000
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. 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.
+intf_lib = ./libopenavb_intf_mpeg2ts_gst.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfMpeg2tsGstInitialize
+
+# intf_nv_file_name: The fully qualified file name used both the talker and listener.
+#intf_nv_file_name = input.ts
+#intf_nv_file_name = hbo_trailer_6ksd_converted.ts
+
+# intf_nv_repeat: Continually repeat the file stream when running as a talker.
+#intf_nv_repeat = 0
+
+#gstreamer pipeline
+intf_nv_gst_pipeline = v4l2src ! video/x-raw-yuv,width=320,height=240 ! ffmpegcolorspace ! omx_h264enc ! queue ! h264parse ! mpegtsmux m2ts_mode=true ! appsink name=avbsink
+
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
new file mode 100644
index 00000000..0c12af20
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/openavb_intf_mpeg2ts_gst.c
@@ -0,0 +1,605 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Mpeg2 TS Gstreamer interface module.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <gst/gst.h>
+#include <gst/app/gstappsink.h>
+#include <gst/app/gstappsrc.h>
+#include "openavb_types_pub.h"
+#include "openavb_log_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_intf_pub.h"
+#include "gst_al.h"
+
+#define APPSINK_NAME "avbsink"
+#define APPSRC_NAME "avbsrc"
+
+typedef struct
+{
+ /////////////
+ // Config data
+ /////////////
+ char *pPipelineStr;
+
+ bool ignoreTimestamp;
+
+ /////////////
+ // Variable data
+ /////////////
+ GstElement *pipe;
+ GstBus *bus;
+ GstAppSink *appsink;
+ GstAppSrc *appsrc;
+
+ // talker: number of gstreamer buffers waiting to be pulled
+ gint nWaiting;
+ // listener: whether gstreamer wants more pushed data now
+ bool srcPaused;
+
+} pvt_data_t;
+
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbIntfMpeg2tsGstCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+
+ if (pMediaQ)
+ {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ char *pEnd;
+ unsigned long tmp;
+ bool nameOK = TRUE, valueOK = FALSE;
+
+ if (strcmp(name, "intf_nv_gst_pipeline") == 0)
+ {
+ if (pPvtData->pPipelineStr)
+ free(pPvtData->pPipelineStr);
+ pPvtData->pPipelineStr = strdup(value);
+ valueOK = (value != NULL && strlen(value) > 0);
+ }
+ else if (strcmp(name, "intf_nv_ignore_timestamp") == 0)
+ {
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && pEnd != value && (tmp == 0 || tmp == 1))
+ {
+ pPvtData->ignoreTimestamp = (tmp == 1);
+ valueOK = TRUE;
+ }
+ }
+ else
+ {
+ AVB_LOGF_WARNING("Unknown configuration item: %s", name);
+ nameOK = FALSE;
+ }
+
+ if (nameOK && !valueOK)
+ {
+ AVB_LOGF_WARNING("Bad value for configuration item: %s = %s", name, value);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+}
+
+void openavbIntfMpeg2tsGstGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+}
+
+static gboolean
+bus_message(GstBus *bus, GstMessage *message, void *pv)
+{
+ switch (GST_MESSAGE_TYPE(message))
+ {
+ case GST_MESSAGE_ERROR:
+ {
+ GError *err = NULL;
+ gchar *dbg_info = NULL;
+
+ gst_message_parse_error(message, &err, &dbg_info);
+ AVB_LOGF_ERROR("GStreamer ERROR message from element %s: %s",
+ GST_OBJECT_NAME(message->src),
+ err->message);
+ AVB_LOGF_ERROR("Additional info: %s\n", (dbg_info) ? dbg_info : "none");
+ g_error_free(err);
+ g_free(dbg_info);
+ break;
+ }
+ case GST_MESSAGE_WARNING:
+ {
+ GError *err = NULL;
+ gchar *dbg_info = NULL;
+
+ gst_message_parse_warning(message, &err, &dbg_info);
+ AVB_LOGF_WARNING("GStreamer WARNING message from element %s: %s",
+ GST_OBJECT_NAME(message->src),
+ err->message);
+ AVB_LOGF_WARNING("Additional info: %s\n", (dbg_info) ? dbg_info : "none");
+ g_error_free(err);
+ g_free(dbg_info);
+ break;
+ }
+ case GST_MESSAGE_INFO:
+ {
+ GError *err = NULL;
+ gchar *dbg_info = NULL;
+
+ gst_message_parse_info(message, &err, &dbg_info);
+ AVB_LOGF_ERROR("GStreamer INFO message from element %s: %s",
+ GST_OBJECT_NAME(message->src),
+ err->message);
+ AVB_LOGF_ERROR("Additional info: %s\n", (dbg_info) ? dbg_info : "none");
+ g_error_free(err);
+ g_free(dbg_info);
+ break;
+ }
+ case GST_MESSAGE_STATE_CHANGED:
+ {
+ GstState old_state, new_state;
+ gst_message_parse_state_changed(message, &old_state, &new_state, NULL);
+ AVB_LOGF_DEBUG("Element %s changed state from %s to %s",
+ GST_OBJECT_NAME(message->src),
+ gst_element_state_get_name(old_state),
+ gst_element_state_get_name(new_state));
+ break;
+ }
+ case GST_MESSAGE_STREAM_STATUS:
+ {
+ // not so valuable
+ break;
+ }
+ case GST_MESSAGE_EOS:
+ AVB_LOG_INFO("EOS received");
+ break;
+ default:
+ AVB_LOGF_INFO("GStreamer '%s' message from element %s",
+ gst_message_type_get_name(GST_MESSAGE_TYPE(message)),
+ GST_OBJECT_NAME(message->src));
+ break;
+ }
+
+ return TRUE;
+}
+
+// This callback triggers when appsrc needs data.
+static void srcStartFeed (GstAppSrc *source, guint size, gpointer pv)
+{
+ media_q_t *pMediaQ = (media_q_t *)pv;
+ assert(pMediaQ);
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ assert(pPvtData);
+ if (pPvtData->srcPaused)
+ {
+// AVB_LOG_INFO("Restart");
+ pPvtData->srcPaused = FALSE;
+ }
+}
+
+// This callback triggers when appsrc has enough data and we can stop sending.
+static void srcStopFeed (GstAppSrc *source, gpointer pv)
+{
+ media_q_t *pMediaQ = (media_q_t *)pv;
+ assert(pMediaQ);
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ assert(pPvtData);
+// AVB_LOG_INFO("Pause");
+ pPvtData->srcPaused = TRUE;
+}
+
+static GstFlowReturn sinkNewBufferSample(GstAppSink *sink, gpointer pv)
+{
+ assert(pv);
+ media_q_t *pMediaQ = (media_q_t *)pv;
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ assert(pPvtData);
+
+ g_atomic_int_add(&pPvtData->nWaiting, 1);
+
+ return GST_FLOW_OK;
+}
+
+// A call to this callback indicates that this interface module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbIntfMpeg2tsGstTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+
+ if (pMediaQ)
+ {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ pPvtData->pipe = (GstElement*)NULL;
+ pPvtData->appsink = (GstAppSink*)NULL;
+ pPvtData->appsrc = (GstAppSrc*)NULL;
+ pPvtData->bus = (GstBus*)NULL;
+ pPvtData->nWaiting = 0;
+
+ GError *error = NULL;
+ pPvtData->pipe = gst_parse_launch(pPvtData->pPipelineStr, &error);
+ if (error)
+ {
+ AVB_LOGF_ERROR("Error creating pipeline: %s", error->message);
+ return;
+ }
+
+ AVB_LOGF_INFO("Pipeline: %s", pPvtData->pPipelineStr);
+ pPvtData->appsink = GST_APP_SINK(gst_bin_get_by_name(GST_BIN(pPvtData->pipe), APPSINK_NAME));
+ if (!pPvtData->appsink)
+ {
+ AVB_LOG_ERROR("Failed to find appsink element");
+ return;
+ }
+
+ // create bus
+ pPvtData->bus = gst_pipeline_get_bus(GST_PIPELINE(pPvtData->pipe));
+ if (!pPvtData->bus)
+ {
+ AVB_LOG_ERROR("Failed to create bus");
+ return;
+ }
+
+ /* add callback for bus messages */
+ gst_bus_add_watch(pPvtData->bus, (GstBusFunc)bus_message, pMediaQ);
+
+ // Setup callback function to handle new buffers delivered to sink
+ GstAppSinkCallbacks cbfns;
+ memset(&cbfns, 0, sizeof(GstAppSinkCallbacks));
+
+ gst_al_set_callback(&cbfns, sinkNewBufferSample);
+
+ gst_app_sink_set_callbacks(pPvtData->appsink, &cbfns, (gpointer)(pMediaQ), NULL);
+
+ // Set most capabilities in pipeline (config), not code
+
+ // Don't drop buffers
+ g_object_set(pPvtData->appsink, "drop", 0, NULL);
+
+ // Start playing
+ gst_element_set_state(pPvtData->pipe, GST_STATE_PLAYING);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+}
+
+bool openavbIntfMpeg2tsGstTxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+
+ if (!pMediaQ)
+ {
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ if (!pPvtData->appsink)
+ {
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+ }
+
+ media_q_item_t *pMediaQItem;
+ GstAlBuf *txBuf;
+
+ while (g_atomic_int_get(&pPvtData->nWaiting) > 0)
+ {
+
+ // Get a mediaQItem to hold the buffered data
+ pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (!pMediaQItem)
+ {
+ IF_LOG_INTERVAL(1000) AVB_LOG_ERROR("Media queue full");
+ break;
+ }
+
+ /* Retrieve the buffer
+ */
+ txBuf = gst_al_pull_buffer(pPvtData->appsink);
+
+ if (txBuf)
+ {
+ g_atomic_int_add(&pPvtData->nWaiting, -1);
+ if ( GST_AL_BUF_SIZE(txBuf) > pMediaQItem->itemSize )
+ {
+ AVB_LOGF_ERROR("GStreamer buffer too large (size=%d) for mediaQ item (dataLen=%d)",
+ GST_AL_BUF_SIZE(txBuf), pMediaQItem->itemSize);
+ pMediaQItem->dataLen = 0;
+ openavbMediaQHeadUnlock(pMediaQ);
+ }
+ else
+ {
+ memcpy(pMediaQItem->pPubData, GST_AL_BUF_DATA(txBuf), GST_AL_BUF_SIZE(txBuf));
+ pMediaQItem->dataLen = GST_AL_BUF_SIZE(txBuf);
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ openavbMediaQHeadPush(pMediaQ);
+ }
+ gst_al_buffer_unref(txBuf);
+ }
+ else
+ {
+ AVB_LOG_ERROR("GStreamer buffer pull failed");
+ // assume the pipeline is empty
+ g_atomic_int_set(&pPvtData->nWaiting, 0);
+ // abandon the mediaq item
+ pMediaQItem->dataLen = 0;
+ openavbMediaQHeadUnlock(pMediaQ);
+ // and get out
+ break;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+}
+
+
+// A call to this callback indicates that this interface module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbIntfMpeg2tsGstRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+
+ if (pMediaQ)
+ {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ pPvtData->pipe = (GstElement*)NULL;
+ pPvtData->appsink = (GstAppSink*)NULL;
+ pPvtData->appsrc = (GstAppSrc*)NULL;
+ pPvtData->bus = (GstBus*)NULL;
+ pPvtData->srcPaused = FALSE;
+
+ GError *error = NULL;
+ pPvtData->pipe = gst_parse_launch(pPvtData->pPipelineStr, &error);
+ if (error)
+ {
+ AVB_LOGF_ERROR("Error creating pipeline: %s", error->message);
+ return;
+ }
+
+ AVB_LOGF_INFO("Pipeline: %s", pPvtData->pPipelineStr);
+ pPvtData->appsrc = GST_APP_SRC(gst_bin_get_by_name(GST_BIN(pPvtData->pipe), APPSRC_NAME));
+ if (!pPvtData->appsrc)
+ {
+ AVB_LOG_ERROR("Failed to find appsrc element");
+ return;
+ }
+
+ // Make appsrc non-blocking
+ g_object_set(G_OBJECT(pPvtData->appsrc), "block", FALSE, NULL);
+
+ // create bus
+ pPvtData->bus = gst_pipeline_get_bus(GST_PIPELINE(pPvtData->pipe));
+ if (!pPvtData->bus)
+ {
+ AVB_LOG_ERROR("Failed to create bus");
+ return;
+ }
+
+ /* add callback for bus messages */
+ gst_bus_add_watch(pPvtData->bus, (GstBusFunc)bus_message, pMediaQ);
+
+ // Setup callback function to handle request from src to pause/start data flow
+ GstAppSrcCallbacks cbfns;
+ memset(&cbfns, 0, sizeof(GstAppSrcCallbacks));
+ cbfns.enough_data = srcStopFeed;
+ cbfns.need_data = srcStartFeed;
+ gst_app_src_set_callbacks(pPvtData->appsrc, &cbfns, (gpointer)(pMediaQ), NULL);
+
+ // Set most capabilities in pipeline (config), not code
+
+ // Don't block
+ g_object_set(pPvtData->appsrc, "block", 0, NULL);
+
+ // PLAY
+ gst_element_set_state(pPvtData->pipe, GST_STATE_PLAYING);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+}
+
+// This callback is called when acting as a listener.
+bool openavbIntfMpeg2tsGstRxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+
+ if (!pMediaQ)
+ {
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+ if (!pPvtData->appsrc)
+ {
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+ }
+
+ bool moreData = TRUE;
+ bool retval = TRUE;
+
+ while (moreData)
+ {
+ media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, pPvtData->ignoreTimestamp);
+ if (pMediaQItem)
+ {
+ unsigned long len = pMediaQItem->dataLen;
+ if (len > 0)
+ {
+ GstAlBuf *rxBuf = gst_al_alloc_buffer(len);
+
+ if (rxBuf)
+ {
+ GST_AL_BUFFER_TIMESTAMP(rxBuf) = GST_CLOCK_TIME_NONE;
+ GST_AL_BUFFER_DURATION(rxBuf) = GST_CLOCK_TIME_NONE;
+
+ memcpy(GST_AL_BUF_DATA(rxBuf), pMediaQItem->pPubData, GST_AL_BUF_SIZE(rxBuf));
+
+ GstFlowReturn gstret = gst_al_push_buffer(GST_APP_SRC(pPvtData->appsrc), rxBuf);
+ if (gstret != GST_FLOW_OK)
+ {
+ AVB_LOGF_ERROR("Pushing buffer to gstreamer failed: %d", gstret);
+ retval = moreData = FALSE;
+ }
+ }
+ else
+ {
+ AVB_LOG_ERROR("Failed to get gstreamer buffer");
+ retval = moreData = FALSE;
+ }
+ }
+ openavbMediaQTailPull(pMediaQ);
+ }
+ else
+ {
+ moreData = FALSE;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return retval;
+}
+
+// This callback will be called when the interface needs to be closed. All shutdown should
+// occur in this function.
+void openavbIntfMpeg2tsGstEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+
+ if (pMediaQ)
+ {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ if (pPvtData->pipe)
+ {
+ gst_element_set_state(GST_ELEMENT(pPvtData->pipe), GST_STATE_NULL);
+ if (pPvtData->bus)
+ {
+ gst_object_unref(pPvtData->bus);
+ pPvtData->bus = NULL;
+ }
+ if (pPvtData->appsink)
+ {
+ gst_object_unref(pPvtData->appsink);
+ pPvtData->appsink = NULL;
+ }
+ if (pPvtData->appsrc)
+ {
+ gst_object_unref(pPvtData->appsrc);
+ pPvtData->appsrc = NULL;
+ }
+ gst_object_unref(pPvtData->pipe);
+ pPvtData->pipe = NULL;
+ }
+ }
+
+ // Media Queue destroy cleans up all of our allocated data.
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+}
+
+void openavbIntfMpeg2tsGstGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Main initialization entry point into the interface module
+extern DLL_EXPORT bool openavbIntfMpeg2tsGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ)
+ {
+ pMediaQ->pPvtIntfInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pPvtIntfInfo)
+ {
+ AVB_LOG_ERROR("Unable to allocate memory for AVTP interface module.");
+ return FALSE;
+ }
+
+ //pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ pIntfCB->intf_cfg_cb = openavbIntfMpeg2tsGstCfgCB;
+ pIntfCB->intf_gen_init_cb = openavbIntfMpeg2tsGstGenInitCB;
+ pIntfCB->intf_tx_init_cb = openavbIntfMpeg2tsGstTxInitCB;
+ pIntfCB->intf_tx_cb = openavbIntfMpeg2tsGstTxCB;
+ pIntfCB->intf_rx_init_cb = openavbIntfMpeg2tsGstRxInitCB;
+ pIntfCB->intf_rx_cb = openavbIntfMpeg2tsGstRxCB;
+ pIntfCB->intf_end_cb = openavbIntfMpeg2tsGstEndCB;
+ pIntfCB->intf_gen_end_cb = openavbIntfMpeg2tsGstGenEndCB;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/intf_wav_file/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/intf_wav_file/CMakeLists.txt
new file mode 100644
index 00000000..8ca81a8a
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_wav_file/CMakeLists.txt
@@ -0,0 +1,9 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_OSAL_DIR}/intf_wav_file/openavb_intf_wav_file.c
+ PARENT_SCOPE
+)
+
+# Need include and link directories
+SET (INTF_INCLUDE_DIR ${INTF_INCLUDE_DIR} PARENT_SCOPE)
+SET (INTF_LIBRARY_DIR ${INTF_LIBRARY_DIR} PARENT_SCOPE)
+SET (INTF_LIBRARY ${INTF_LIBRARY} PARENT_SCOPE)
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
new file mode 100644
index 00000000..c038c95c
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_wav_file/openavb_intf_wav_file.c
@@ -0,0 +1,698 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : 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>
+#include <string.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_map_uncmp_audio_pub.h"
+#include "openavb_map_aaf_audio_pub.h"
+#include "openavb_intf_pub.h"
+
+#define AVB_LOG_COMPONENT "Wav File Interface"
+#include "openavb_log_pub.h"
+
+typedef struct {
+ // RIFF Chunk descriptor
+ U8 chunkID[4]; // "RIFF"
+ U32 chunkSize;
+ U8 format[4]; // "WAVE"
+
+ // FMT Sub Chuck
+ U8 subChunk1ID[4]; // "fmt "
+ U32 subChunk1Size;
+ U16 audioFormat; // 1 = PCM
+ U16 numberChannels;
+ U32 sampleRate;
+ U32 byteRate;
+ U16 blockAlign;
+ U16 bitsPerSample;
+
+ // Data Sub Chunk
+ U8 subChunk2ID[4]; // "data"
+ U32 subChunk2Size;
+
+} wav_file_header_t;
+
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ // intf_nv_file_name: The fully qualified file name used both the talker and listener.
+ char *pFileName;
+
+ /////////////
+ // Variable data
+ /////////////
+ FILE *pFile;
+
+ // ALSA read/write interval
+ U32 intervalCounter;
+
+ // map_nv_audio_rate
+ avb_audio_rate_t audioRate;
+
+ // map_nv_audio_bit_depth
+ avb_audio_bit_depth_t audioBitDepth;
+
+ // map_nv_channels
+ avb_audio_channels_t audioChannels;
+
+ // map_nv_audio_endian
+ avb_audio_endian_t audioEndian;
+
+ // intf_nv_number_of_data_bytes
+ U32 numberOfDataBytes;
+
+} pvt_data_t;
+
+// fread that (mostly) ignores return value - to silence compiler warnings
+static inline void ifread(void *ptr, size_t size, size_t num, FILE *stream)
+{
+ if (fread(ptr, size, num, stream) != num) {
+ AVB_LOG_DEBUG("Error reading file");
+ }
+}
+
+static inline void ifwrite(void *ptr, size_t size, size_t num, FILE *stream)
+{
+ if (fwrite(ptr, size, num, stream) != num) {
+ AVB_LOG_DEBUG("Error writting to file");
+ }
+}
+
+static void x_parseWaveFile(media_q_t *pMediaQ)
+{
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ if (!pPvtData->pFileName) {
+ AVB_LOG_ERROR("Input file name not found.");
+ return;
+ }
+
+ pPvtData->pFile = fopen(pPvtData->pFileName, "rb");
+ if (!pPvtData->pFile) {
+ AVB_LOGF_ERROR("Unable to open input file: %s", pPvtData->pFileName);
+ return;
+ }
+
+ // Check if wav file format is valid and of a supported type.
+ wav_file_header_t wavFileHeader;
+
+ // RIFF Chunk
+ ifread(wavFileHeader.chunkID, sizeof(wavFileHeader.chunkID), 1, pPvtData->pFile);
+ ifread(&wavFileHeader.chunkSize, sizeof(wavFileHeader.chunkSize), 1, pPvtData->pFile);
+ ifread(wavFileHeader.format, sizeof(wavFileHeader.format), 1, pPvtData->pFile);
+
+ // FMT sub Chunk
+ ifread(wavFileHeader.subChunk1ID, sizeof(wavFileHeader.subChunk1ID), 1, pPvtData->pFile);
+ ifread(&wavFileHeader.subChunk1Size, sizeof(wavFileHeader.subChunk1Size), 1, pPvtData->pFile);
+ ifread(&wavFileHeader.audioFormat, sizeof(wavFileHeader.audioFormat), 1, pPvtData->pFile);
+ ifread(&wavFileHeader.numberChannels, sizeof(wavFileHeader.numberChannels), 1, pPvtData->pFile);
+ ifread(&wavFileHeader.sampleRate, sizeof(wavFileHeader.sampleRate), 1, pPvtData->pFile);
+ ifread(&wavFileHeader.byteRate, sizeof(wavFileHeader.byteRate), 1, pPvtData->pFile);
+ ifread(&wavFileHeader.blockAlign, sizeof(wavFileHeader.blockAlign), 1, pPvtData->pFile);
+ ifread(&wavFileHeader.bitsPerSample, sizeof(wavFileHeader.bitsPerSample), 1, pPvtData->pFile);
+
+ // Data sub Chunk
+ ifread(wavFileHeader.subChunk2ID, sizeof(wavFileHeader.subChunk2ID), 1, pPvtData->pFile);
+ ifread(&wavFileHeader.subChunk2Size, sizeof(wavFileHeader.subChunk2Size), 1, pPvtData->pFile);
+
+ AVB_LOGF_INFO("Number of data bytes:%d", wavFileHeader.subChunk2Size);
+
+ // Make sure wav file format is supported
+ if (memcmp(wavFileHeader.chunkID, "RIFF", 4) != 0) {
+ AVB_LOGF_ERROR("%s does not appear to be a supported wav file.", pPvtData->pFileName);
+ fclose(pPvtData->pFile);
+ pPvtData->pFile = NULL;
+ return;
+ }
+
+ if (memcmp(wavFileHeader.format, "WAVE", 4) != 0) {
+ AVB_LOGF_ERROR("%s does not appear to be a supported wav file.", pPvtData->pFileName);
+ fclose(pPvtData->pFile);
+ pPvtData->pFile = NULL;
+ return;
+ }
+
+ if (memcmp(wavFileHeader.subChunk1ID, "fmt ", 4) != 0) {
+ AVB_LOGF_ERROR("%s does not appear to be a supported wav file.", pPvtData->pFileName);
+ fclose(pPvtData->pFile);
+ pPvtData->pFile = NULL;
+ return;
+ }
+
+ if (memcmp(wavFileHeader.subChunk2ID, "data", 4) != 0) {
+ AVB_LOGF_ERROR("%s does not appear to be a supported wav file.", pPvtData->pFileName);
+ fclose(pPvtData->pFile);
+ pPvtData->pFile = NULL;
+ return;
+ }
+
+ if (wavFileHeader.audioFormat != 1) {
+ AVB_LOGF_ERROR("%s does not appear to be a supported wav file.", pPvtData->pFileName);
+ fclose(pPvtData->pFile);
+ pPvtData->pFile = NULL;
+ return;
+ }
+
+ // Give the audio parameters to the mapping module.
+ if (pMediaQ->pMediaQDataFormat) {
+ if (strcmp(pMediaQ->pMediaQDataFormat, MapUncmpAudioMediaQDataFormat) == 0
+ || strcmp(pMediaQ->pMediaQDataFormat, MapAVTPAudioMediaQDataFormat) == 0) {
+ media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo;
+ pPubMapUncmpAudioInfo = (media_q_pub_map_uncmp_audio_info_t *)pMediaQ->pPubMapInfo;
+ pPubMapUncmpAudioInfo->audioRate = wavFileHeader.sampleRate;
+ pPubMapUncmpAudioInfo->audioBitDepth = wavFileHeader.bitsPerSample;
+ pPubMapUncmpAudioInfo->audioChannels = wavFileHeader.numberChannels;
+ pPubMapUncmpAudioInfo->audioEndian = pPvtData->audioEndian;
+
+ AVB_LOGF_INFO("Wav file - Rate:%d Bits:%d Channels:%d", pPubMapUncmpAudioInfo->audioRate, pPubMapUncmpAudioInfo->audioBitDepth, pPubMapUncmpAudioInfo->audioChannels);
+ }
+ else {
+ AVB_LOG_ERROR("MediaQ mapping format not supported in this interface module.");
+ }
+ }
+ else {
+ AVB_LOG_ERROR("MediaQ mapping format not defined.");
+ }
+ }
+}
+
+static void passParamToMapModule(media_q_t *pMediaQ)
+{
+ if (pMediaQ) {
+ media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo = (media_q_pub_map_uncmp_audio_info_t *)pMediaQ->pPubMapInfo;
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ if (!pPubMapUncmpAudioInfo) {
+ AVB_LOG_ERROR("Public interface module data not allocated.");
+ return;
+ }
+
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ if (pMediaQ->pMediaQDataFormat) {
+ if (strcmp(pMediaQ->pMediaQDataFormat, MapUncmpAudioMediaQDataFormat) == 0
+ || strcmp(pMediaQ->pMediaQDataFormat, MapAVTPAudioMediaQDataFormat) == 0) {
+ pPubMapUncmpAudioInfo->audioRate = pPvtData->audioRate;
+ pPubMapUncmpAudioInfo->audioBitDepth = pPvtData->audioBitDepth;
+ pPubMapUncmpAudioInfo->audioChannels = pPvtData->audioChannels;
+ pPubMapUncmpAudioInfo->audioEndian = pPvtData->audioEndian;
+ }
+ }
+ }
+}
+
+// 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
+// sample in reverse order back into the buffer
+static void convertEndianness(uint8_t *pData, U32 dataLen, U32 sampleSize)
+{
+ U32 sampleByteIndex = sampleSize;
+ U32 itemIndex, readIndex = 0;
+ U8 itemData[dataLen];
+ for (itemIndex = 0; itemIndex < dataLen; itemIndex++) {
+ sampleByteIndex--;
+ itemData[itemIndex] = *(pData + readIndex + sampleByteIndex);
+ if (sampleByteIndex == 0) {
+ sampleByteIndex = sampleSize;
+ readIndex = itemIndex + 1;
+ }
+ }
+ memcpy(pData, itemData, dataLen);
+}
+#endif
+
+
+#define SWAPU16(x) (((x) >> 8) | ((x) << 8))
+#define SWAPU32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | ((x) << 24))
+static void convertEndianness(uint8_t *pData, U32 dataLen, U32 sampleSize)
+{
+ if (sampleSize == 2) {
+ int i1;
+ int cnt = dataLen >> 1; // 2 bytes at a time
+ U16 *pData16 = (U16 *)pData;
+ for (i1 = 0; i1 < cnt; i1++) {
+ *pData16 = SWAPU16(*pData16);
+ pData16++;
+ }
+ }
+ else if (sampleSize == 4) {
+ int i1;
+ int cnt = dataLen >> 1; // 2 bytes at a time
+ U32 *pData32 = (U32 *)pData;
+ for (i1 = 0; i1 < cnt; i1++) {
+ *pData32 = SWAPU32(*pData32);
+ pData32++;
+ }
+ }
+}
+
+// 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)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ char *pEnd;
+ U32 val;
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ if (strcmp(name, "intf_nv_file_name") == 0) {
+ if (pPvtData->pFileName) {
+ free(pPvtData->pFileName);
+ }
+ pPvtData->pFileName = strdup(value);
+ x_parseWaveFile(pMediaQ);
+ }
+ else if (strcmp(name, "intf_nv_file_name_rx") == 0) {
+ if (pPvtData->pFileName) {
+ free(pPvtData->pFileName);
+ }
+ pPvtData->pFileName = strdup(value);
+ passParamToMapModule(pMediaQ);
+ }
+ else if (strcmp(name, "intf_nv_audio_rate") == 0) {
+ val = strtol(value, &pEnd, 10);
+ if (val >= AVB_AUDIO_RATE_8KHZ && val <= AVB_AUDIO_RATE_192KHZ) {
+ pPvtData->audioRate = val;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid audio rate configured for intf_nv_audio_rate.");
+ pPvtData->audioRate = AVB_AUDIO_RATE_44_1KHZ;
+ }
+ }
+ else if (strcmp(name, "intf_nv_audio_bit_depth") == 0) {
+ val = strtol(value, &pEnd, 10);
+ 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;
+ }
+ }
+ else if (strcmp(name, "intf_nv_audio_channels") == 0) {
+ val = strtol(value, &pEnd, 10);
+ if (val >= AVB_AUDIO_CHANNELS_1 && val <= AVB_AUDIO_CHANNELS_8) {
+ pPvtData->audioChannels = val;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid audio channels configured for intf_nv_audio_channels.");
+ pPvtData->audioChannels = AVB_AUDIO_CHANNELS_2;
+ }
+ }
+ else if (strcmp(name, "intf_nv_number_of_data_bytes") == 0) {
+ val = strtol(value, &pEnd, 10);
+ if (val > 0) {
+ pPvtData->numberOfDataBytes = val;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid number of data bytes for intf_nv_number_of_data_bytes.");
+ }
+ }
+ else if (strcmp(name, "intf_nv_audio_endian") == 0) {
+ if (strncasecmp(value, "big", 3) == 0) {
+ pPvtData->audioEndian = AVB_AUDIO_ENDIAN_BIG;
+ AVB_LOG_INFO("Forced audio samples endian conversion: little <-> big");
+ }
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfWavFileGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ if (strcmp(pMediaQ->pMediaQDataFormat, MapAVTPAudioMediaQDataFormat) == 0) {
+ // WAV files are little-endian, AAF (SAF) need big-endian
+ pPvtData->audioEndian = AVB_AUDIO_ENDIAN_BIG;
+ }
+ else {
+ pPvtData->audioEndian = AVB_AUDIO_ENDIAN_LITTLE;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// 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)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ // U8 b;
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ if (!pPvtData->pFile) {
+ pPvtData->pFile = fopen(pPvtData->pFileName, "rb");
+ if (!pPvtData->pFile) {
+ AVB_LOGF_ERROR("Unable to open input file: %s", pPvtData->pFileName);
+ return;
+ }
+ }
+
+ if (pPvtData->pFile) {
+ // Seek to start of data for our only supported wav file format.
+ fseek(pPvtData->pFile, 44, 0);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback will be called for each AVB transmit interval. Commonly this will be
+// 4000 or 8000 times per second.
+bool openavbIntfWavFileTxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ if (pMediaQ) {
+ media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo = pMediaQ->pPubMapInfo;
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ media_q_item_t *pMediaQItem = NULL;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ 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;
+
+ pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ if (pMediaQItem->itemSize < pPubMapUncmpAudioInfo->itemSize) {
+ AVB_LOG_ERROR("Media queue item not large enough for samples");
+ }
+
+ if (pPvtData->pFile) {
+
+ U32 bytesRead = fread(pMediaQItem->pPubData, 1, pPubMapUncmpAudioInfo->itemSize, pPvtData->pFile);
+
+ if (bytesRead < pPubMapUncmpAudioInfo->itemSize) {
+ // Pad reminder of item with anything we didn't read because of end of file.
+ memset(pMediaQItem->pPubData + bytesRead, 0x00, pPubMapUncmpAudioInfo->itemSize - bytesRead);
+
+ // Repeat wav file. Seek to start of data for our only supported wav file format.
+ fseek(pPvtData->pFile, 44, 0);
+ }
+ pMediaQItem->dataLen = pPubMapUncmpAudioInfo->itemSize;
+
+ if (pPvtData->audioEndian == AVB_AUDIO_ENDIAN_BIG) {
+ convertEndianness((uint8_t *)pMediaQItem->pPubData, pMediaQItem->dataLen, pPubMapUncmpAudioInfo->itemSampleSizeBytes);
+ }
+
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ openavbMediaQHeadPush(pMediaQ);
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+ }
+ else {
+ openavbMediaQHeadUnlock(pMediaQ);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE; // No File handle
+ }
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE; // Media queue full
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+}
+
+// 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)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ struct stat buf;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ if (!pPvtData->pFileName) {
+ AVB_LOG_ERROR("Output wav file not provided in ini");
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ }
+ else if (stat(pPvtData->pFileName, &buf) == 0) {
+ AVB_LOGF_ERROR("Will not open output file: %s file exists", pPvtData->pFileName);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+ else {
+ AVB_LOGF_INFO("Creating output wav file: %s", pPvtData->pFileName);
+ pPvtData->pFile = fopen(pPvtData->pFileName, "wb");
+ if (!pPvtData->pFile) {
+ AVB_LOGF_ERROR("Unable to open output wav file: %s", pPvtData->pFileName);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return;
+ }
+ wav_file_header_t wavFileHeader;
+ memcpy(wavFileHeader.chunkID, "RIFF", sizeof(wavFileHeader.chunkID));
+ memcpy(wavFileHeader.format, "WAVE", sizeof(wavFileHeader.format));
+ memcpy(wavFileHeader.subChunk1ID, "fmt ", sizeof(wavFileHeader.subChunk1ID));
+ wavFileHeader.subChunk1Size = 0x10;
+ wavFileHeader.audioFormat = 0x01;
+ wavFileHeader.numberChannels = pPvtData->audioChannels;
+ wavFileHeader.sampleRate = pPvtData->audioRate;
+ wavFileHeader.bitsPerSample = pPvtData->audioBitDepth;
+ wavFileHeader.byteRate = wavFileHeader.sampleRate * wavFileHeader.numberChannels * wavFileHeader.bitsPerSample/8;
+ wavFileHeader.blockAlign = wavFileHeader.numberChannels * wavFileHeader.bitsPerSample/8;
+ memcpy(wavFileHeader.subChunk2ID, "data", sizeof(wavFileHeader.subChunk2ID));
+ wavFileHeader.subChunk2Size = pPvtData->numberOfDataBytes;
+ wavFileHeader.chunkSize = 4 + (8 + wavFileHeader.subChunk1Size) + (8 + wavFileHeader.subChunk2Size);
+
+ ifwrite(&wavFileHeader.chunkID, sizeof(wavFileHeader.chunkID), 1, pPvtData->pFile);
+ ifwrite(&wavFileHeader.chunkSize, sizeof(wavFileHeader.chunkSize), 1, pPvtData->pFile);
+ ifwrite(wavFileHeader.format, sizeof(wavFileHeader.format), 1, pPvtData->pFile);
+ ifwrite(&wavFileHeader.subChunk1ID, sizeof(wavFileHeader.subChunk1ID), 1, pPvtData->pFile);
+ ifwrite(&wavFileHeader.subChunk1Size, sizeof(wavFileHeader.subChunk1Size), 1, pPvtData->pFile);
+ ifwrite(&wavFileHeader.audioFormat, sizeof(wavFileHeader.audioFormat), 1, pPvtData->pFile);
+ ifwrite(&wavFileHeader.numberChannels, sizeof(wavFileHeader.numberChannels), 1, pPvtData->pFile);
+ ifwrite(&wavFileHeader.sampleRate, sizeof(wavFileHeader.sampleRate), 1, pPvtData->pFile);
+ ifwrite(&wavFileHeader.byteRate, sizeof(wavFileHeader.byteRate), 1, pPvtData->pFile);
+ ifwrite(&wavFileHeader.blockAlign, sizeof(wavFileHeader.blockAlign), 1, pPvtData->pFile);
+ ifwrite(&wavFileHeader.bitsPerSample, sizeof(wavFileHeader.bitsPerSample), 1, pPvtData->pFile);
+ ifwrite(wavFileHeader.subChunk2ID, sizeof(wavFileHeader.subChunk2ID), 1, pPvtData->pFile);
+ ifwrite(&wavFileHeader.subChunk2Size, sizeof(wavFileHeader.subChunk2Size), 1, pPvtData->pFile);
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback is called when acting as a listener.
+bool openavbIntfWavFileRxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo = pMediaQ->pPubMapInfo;
+
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ 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 (pPvtData->pFile && pMediaQItem->dataLen > 0) {
+ if (expectedNumberOfDataReceived == FALSE) {
+ if ((numOfStoredDataBytes + pMediaQItem->dataLen ) > pPvtData->numberOfDataBytes) {
+ pMediaQItem->dataLen = pPvtData->numberOfDataBytes - numOfStoredDataBytes;
+ expectedNumberOfDataReceived = TRUE;
+ }
+ }
+ if (pPvtData->audioEndian == AVB_AUDIO_ENDIAN_BIG) {
+ convertEndianness((uint8_t *)pMediaQItem->pPubData, pMediaQItem->dataLen, pPubMapUncmpAudioInfo->itemSampleSizeBytes);
+ }
+ written = fwrite(pMediaQItem->pPubData, 1, pMediaQItem->dataLen, pPvtData->pFile);
+ if (written != pMediaQItem->dataLen) {
+ int e = ferror(pPvtData->pFile);
+ AVB_LOGF_ERROR("Error writing file: %s, %s", pPvtData->pFileName, strerror(e));
+ fclose(pPvtData->pFile);
+ pPvtData->pFile = NULL;
+ }
+ else {
+ pMediaQItem->dataLen = 0;
+ numOfStoredDataBytes += written;
+ if (expectedNumberOfDataReceived == TRUE) {
+ fileReady = TRUE;
+ AVB_LOG_INFO("Wav file ready.");
+ }
+ }
+ }
+ openavbMediaQTailPull(pMediaQ);
+ }
+ else {
+ moreData = FALSE;
+ }
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+}
+
+// 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)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ if (pPvtData->pFile) {
+ fclose(pPvtData->pFile);
+ pPvtData->pFile = NULL;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfWavFileGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ if (pPvtData->pFileName) {
+ free(pPvtData->pFileName);
+ pPvtData->pFileName = NULL;
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Main initialization entry point into the interface module
+extern DLL_EXPORT bool openavbIntfWavFileInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pMediaQ->pPvtIntfInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pPvtIntfInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for AVTP interface module.");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ pIntfCB->intf_cfg_cb = openavbIntfWavFileCfgCB;
+ pIntfCB->intf_gen_init_cb = openavbIntfWavFileGenInitCB;
+ pIntfCB->intf_tx_init_cb = openavbIntfWavFileTxInitCB;
+ pIntfCB->intf_tx_cb = openavbIntfWavFileTxCB;
+ pIntfCB->intf_rx_init_cb = openavbIntfWavFileRxInitCB;
+ pIntfCB->intf_rx_cb = openavbIntfWavFileRxCB;
+ pIntfCB->intf_end_cb = openavbIntfWavFileEndCB;
+ pIntfCB->intf_gen_end_cb = openavbIntfWavFileGenEndCB;
+ pPvtData->audioEndian = AVB_AUDIO_ENDIAN_LITTLE; //wave file default
+
+ pPvtData->intervalCounter = 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_intf.md b/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_intf.md
new file mode 100644
index 00000000..3d409d3d
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_intf.md
@@ -0,0 +1,45 @@
+WAV file interface {#wav_file_intf}
+==================
+
+# Description
+
+WAV file interface module.
+
+This interface module is narrowly focused to read a common wav file format
+and send the data samples to mapping modules.
+
+<br>
+# Interface module configuration parameters
+
+Name | Description
+--------------------------|---------------------------
+intf_nv_file_name |Name of the file to be read
+intf_nv_file_name_rx |Name of wav file where received data will be stored
+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_number_of_data_bytes|Size of sample data counted in bytes. This size \
+ should be equal to Subchunk2Size field in wav file\
+ to be transferred. The data is printed out by \
+ talker when started (INFO: Number of data bytes)
+
+<br>
+# Notes
+
+There are some parameters that have to be set during configuration of this
+interface module and before configuring mapping:
+* [AAF audio mapping](@ref aaf_audio_map)
+* [Uncompressed audio mapping](@ref uncmp_audio_map)
+
+These parameters can be set in either:
+* in the ini file (or available configuration system), so values will be parsed
+in the intf_cfg_cb function,
+* in the interface module initialization function where valid values can be
+assigned directly
+
+Values assigned in the intf_cfg_cb function will override any values set in the
+initialization function.
+
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
new file mode 100644
index 00000000..f1b6d595
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_listener.ini
@@ -0,0 +1,112 @@
+#####################################################################
+# General wav file listener configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = listener
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: When SRP is being used the destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set in both side the talker and listener.
+# 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.
+# At this time they need to be locally administered and must be in the range
+# of 91:E0:F0:00:FE:00 - 91:E0:F0:00:FE:FF.
+# Typically :00 for the first stream, :01 for the second, etc.
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+#max_interval_frames = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 50000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_uncmp_audio.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapUncmpAudioInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 400
+
+# map_nv_tx_rate: Transmit rate.
+# This must be set for the uncompressed audio mapping module.
+map_nv_tx_rate = 8000
+
+# map_nv_packing_factor: Multiple of how many packets of audio frames to place in a media queue item.
+# Note: Typically when decreasing the map_nv_tx_rate the packing factor will also be decreased since
+# the number of frames per packet will be increasing.
+map_nv_packing_factor = 256
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. 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.
+intf_lib = ./libopenavb_intf_wav_file.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfWavFileInitialize
+
+# intf_nv_ignore_timestamp: If set the listener will ignore the timestamp on media queue items.
+# intf_nv_ignore_timestamp = 1
+
+# intf_nv_audio_rate: Audio sample rate, must be consistenet with wav file sample rate
+intf_nv_audio_rate = 48000
+
+# intf_nv_audio_bit_depth: must be consistenet with wav file bit depth
+intf_nv_audio_bit_depth = 16
+
+# intf_nv_audio_channels: must be consistenet with wav file audio channels
+intf_nv_audio_channels = 1
+
+#intf_nv_number_of_data_bytes: Size of sample data counted in bytes. This field should be equal to Subchunk2Size field
+#in wav file to be transferred. This data is printed out by talker when started with wav interface.
+# see: INFO: Number of data bytes:
+intf_nv_number_of_data_bytes = 9600
+
+#intf_nv_file_name_rx: Name of wav file where received data will be stored. Finally it should be the same as
+#original wav file transferred by talker.
+intf_nv_file_name_rx = wavfileout.wav
+
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
new file mode 100644
index 00000000..ead3bbfc
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_talker.ini
@@ -0,0 +1,128 @@
+#####################################################################
+# General Talker configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = talker
+
+# 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
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: destination multicast address for the stream.
+#
+# If using SRP and MAAP, dynamic destination addresses are generated
+# automatically by the talker and passed to the listner, and don't
+# need to be configured.
+#
+# Without MAAP, locally administered (static) addresses must be
+# configured. Thouse 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.
+#
+# When SRP is being used the static destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set (to the same value) in both the talker and listener.
+#
+# 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.
+#
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = A
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# 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
+# max transit time.
+max_transit_usec = 2000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# 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). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# 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_tx_buffers = 1
+
+# 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.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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 = ./libopenavb_map_uncmp_audio.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapUncmpAudioInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+# map_nv_tx_rate: Transmit rate.
+# This must be set for the uncompressed audio mapping module.
+map_nv_tx_rate = 8000
+
+# map_nv_packing_factor: Multiple of how many packets of audio frames to place in a media queue item.
+# Note: Typically when decreasing the map_nv_tx_rate the packing factor will also be decreased since
+# the number of frames per packet will be increasing.
+map_nv_packing_factor = 32
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. 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. 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.
+intf_lib = ./libopenavb_intf_wav_file.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfWavFileInitialize
+
+# intf_nv_file_name: The fully qualified file name.
+intf_nv_file_name = song1.wav
+
+
+
+
+
+
+
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_ether_osal.c b/lib/avtp_pipeline/platform/Linux/openavb_ether_osal.c
new file mode 100644
index 00000000..95239bf0
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_ether_osal.c
@@ -0,0 +1,39 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_ether_osal.h"
+
+// MAC address is retrieved differently for Linux
+bool osalGetMacAddr(U8 *macAddr)
+{
+ return TRUE;
+}
+
+
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_ether_osal.h b/lib/avtp_pipeline/platform/Linux/openavb_ether_osal.h
new file mode 100644
index 00000000..a75d2ac6
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_ether_osal.h
@@ -0,0 +1,40 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_ETHER_OSAL_H
+#define OPENAVB_ETHER_OSAL_H 1
+
+#include "openavb_types_base.h"
+#include "openavb_osal.h"
+
+struct ether_addr* ether_aton_r(const char *asc, struct ether_addr *addr);
+bool osalGetMacAddr(U8 *macAddr);
+
+#endif // OPENAVB_ETHER_OSAL_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
new file mode 100644
index 00000000..36a3171f
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal.h
@@ -0,0 +1,169 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_OS_SERVICES_OSAL_H
+#define _OPENAVB_OS_SERVICES_OSAL_H
+
+#include "openavb_hal.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>
+
+#include "openavb_tasks.h"
+
+#define EXTERN_DLL_EXPORT extern DLL_EXPORT
+
+#ifndef PTHREAD_MUTEX_RECURSIVE
+#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
+#endif
+
+#include "openavb_osal_pub.h"
+
+// Uncomment to use manual data alignment adjustments. Not needed for Linux
+//#define DATA_ALIGNMENT_ADJUSTMENT 1
+
+// Many socket implementations support a minimum timeout of 1ms (value 1000 here).
+#define RAWSOCK_MIN_TIMEOUT_USEC 1
+
+#define SLEEP(sec) sleep(sec)
+#define SLEEP_MSEC(mSec) usleep(mSec * 1000)
+#define SLEEP_NSEC(nSec) usleep(nSec)
+#define SLEEP_UNTIL_NSEC(nSec) xSleepUntilNSec(nSec)
+inline static void xSleepUntilNSec(U64 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_CHECK_ERROR(threadhandle, message, error) \
+ do { \
+ error=FALSE; \
+ if (threadhandle##_ThreadData.err != 0) \
+ { \
+ AVB_LOGF_ERROR("Thread error: %s code:", 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 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_TIMEDWAIT(sem, timeoutMSec, err) \
+{ \
+ struct timespec timeout; \
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &timeout); \
+ openavbTimeTimespecAddUsec(&timeout, timeoutMSec * MICROSECONDS_PER_MSEC); \
+ err = sem_timedwait(&sem, &timeout); \
+}
+#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_LOG_ERR(err) if (0 != err) AVB_LOGF_ERROR("Semaphore error code: %d", err);
+
+
+typedef struct
+{
+ char *libName;
+ char *funcName;
+ void *libHandle;
+} link_lib_t;
+
+#define LINK_LIB(library) \
+link_lib_t library
+
+#endif // _OPENAVB_OS_SERVICES_OSAL_H
+
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
new file mode 100644
index 00000000..fe235104
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal_pub.h
@@ -0,0 +1,109 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_OS_SERVICES_OSAL_PUB_H
+#define _OPENAVB_OS_SERVICES_OSAL_PUB_H
+
+#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"
+
+#define INLINE_VARIABLE_NUM_OF_ARGUMENTS inline // must be okay of gcc
+
+#include <netinet/ether.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <math.h>
+
+
+#define STD_LOG stderr
+
+#define NEWLINE "\n"
+
+#define SIN(rad) sin(rad)
+
+#define THREAD_SELF() pthread_self()
+#define GET_PID() getpid()
+
+
+// Funky struct to hold a configurable ethernet address (MAC).
+// The "mac" pointer is null if no config value was supplied,
+// and points to the configured value if one was
+typedef struct {
+ struct ether_addr buffer;
+ struct ether_addr *mac;
+} cfg_mac_t;
+
+#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) AVB_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)
+
+
+// pthread_mutexattr_t mta;
+// pthread_mutexattr_init(&mta);
+// pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE);
+// pthread_mutex_init(&maapMutex, &mta);
+
+#if defined __BYTE_ORDER && defined __BIG_ENDIAN && defined __LITTLE_ENDIAN
+#if __BYTE_ORDER == __BIG_ENDIAN
+# define ntohll(x) (x)
+# define htonll(x) (x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+# define ntohll(x) __bswap_64 (x)
+# define htonll(x) __bswap_64 (x)
+#else
+# error
+#endif
+#else
+# error
+#endif
+
+#endif // _OPENAVB_OS_SERVICES_OSAL_PUB_H
+
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_osal.c b/lib/avtp_pipeline/platform/Linux/openavb_osal.c
new file mode 100644
index 00000000..ba960ff6
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal.c
@@ -0,0 +1,55 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_ether_hal.h"
+#include "openavb_osal.h"
+#include "openavb_qmgr.h"
+
+#define AVB_LOG_COMPONENT "osal"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+extern DLL_EXPORT bool osalAVBInitialize(const char* ifname)
+{
+ avbLogInit();
+ osalAVBTimeInit();
+ openavbQmgrInitialize(FQTSS_MODE_HW_CLASS, 0, ifname, 0, 0, 0);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool osalAVBFinalize(void)
+{
+ openavbQmgrFinalize();
+ osalAVBTimeClose();
+ avbLogExit();
+ return TRUE;
+}
+
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_osal.h b/lib/avtp_pipeline/platform/Linux/openavb_osal.h
new file mode 100644
index 00000000..dc1e4463
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal.h
@@ -0,0 +1,41 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_OSAL_H
+#define _OPENAVB_OSAL_H
+
+#include "openavb_hal.h"
+#include "openavb_os_services_osal.h"
+#include "openavb_tasks.h"
+#include "openavb_osal_pub.h"
+
+
+#endif // _OPENAVB_OSAL_H
+
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c b/lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c
new file mode 100644
index 00000000..593155f4
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c
@@ -0,0 +1,56 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_ether_hal.h"
+#include "openavb_osal.h"
+#include "openavb_qmgr.h"
+#include "openavb_endpoint.h"
+
+#define AVB_LOG_COMPONENT "osal"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+extern DLL_EXPORT bool osalAVBInitialize(const char* ifname)
+{
+ avbLogInit();
+ osalAVBTimeInit();
+ startEndpoint(FQTSS_MODE_HW_CLASS, 0, ifname, 0, 0, 0);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool osalAVBFinalize(void)
+{
+ stopEndpoint();
+ osalAVBTimeClose();
+ avbLogExit();
+ return TRUE;
+}
+
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h b/lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h
new file mode 100644
index 00000000..0cae719d
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h
@@ -0,0 +1,44 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_OSAL_PUB_H
+#define _OPENAVB_OSAL_PUB_H
+
+// TODO_OPENAVB - Is this needed still?
+#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_os_services_osal_pub.h"
+
+bool osalAVBInitialize(const char *ifname);
+
+bool osalAVBFinalize(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
new file mode 100644
index 00000000..bd4e925f
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_poll_osal.h
@@ -0,0 +1,77 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_POLL_OSAL_H___
+#define __OPENAVB_POLL_OSAL_H___
+
+
+#include "openavb_platform.h"
+
+#define OPENAVB_POLLFD_TYPE struct pollfd
+
+#define OPENAVB_DECLARE_POLL_RET int ret
+
+#define OPENAVB_POLL(CNT) \
+ { \
+ int i; \
+ for (i = 0; i < CNT; i++) { \
+ pfd[i].revents = 0; \
+ } \
+ } \
+ ret = poll(pfd, CNT, 500); \
+ if (ret > 0)
+
+#define OPENAVB_POLLIN(X) (pfd[X].revents & POLLIN)
+#define OPENAVB_POLLERR(X) (pfd[X].revents & POLLERR)
+#define OPENAVB_POLLIN_OR_ERR(X) (pfd[X].revents & (POLLIN | POLLERR))
+
+#define OPENAVB_READPFD(X) \
+ { \
+ uint64_t nExpire; \
+ int ret = read(pfd[X].fd, &nExpire, sizeof(uint64_t)); \
+ if (ret != sizeof(uint64_t)) { \
+ AVB_LOGF_WARNING("timerfd read failed (%s)", strerror(errno)); \
+ } \
+ } \
+
+#define OPENAVB_CHECK_LOG_POLL_RESULT \
+ if (ret < 0) { \
+ if (errno == EAGAIN) { \
+ AVB_LOG_STATUS("EAGAIN polling receieve socket"); \
+ continue; \
+ } \
+ if (errno != EINTR) { \
+ AVB_LOGF_ERROR("Error polling receive socket: %s", strerror(errno)); \
+ } \
+ }
+
+
+#endif // __OPENAVB_POLL_OSAL_H___
+
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_tasks.h b/lib/avtp_pipeline/platform/Linux/openavb_tasks.h
new file mode 100644
index 00000000..d456b4f9
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_tasks.h
@@ -0,0 +1,106 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 _EAVBTASKS_H
+#define _EAVBTASKS_H
+
+#define THREAD_STACK_SIZE 65536
+
+///////////////////////////
+// Platform code Tasks values
+///////////////////////////
+
+///////////////////////////
+// Common code Tasks values
+///////////////////////////
+
+//task rcvThread. SRP
+#define rcvThread_THREAD_STK_SIZE 32768
+
+//task txThread. SRP
+#define txThread_THREAD_STK_SIZE 32768
+
+//task maapThread
+#define maapThread_THREAD_STK_SIZE 16384
+
+//task loggingThread
+#define loggingThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
+//task TLThread Used for both Talker and Listener threads
+#define TLThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
+//task TalkerThread
+#define talkerThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
+//task ListenerThread
+#define listenerThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
+//task openavbAecpSMEntityModelEntityThread
+#define openavbAecpSMEntityModelEntityThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
+//task openavbAdpSmAdvertiseEntityThread
+#define openavbAdpSmAdvertiseEntityThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
+//task openavbAcmpSmListenerThread
+#define openavbAcmpSmListenerThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
+//task openavbAecpMessageRxThread
+#define openavbAecpMessageRxThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
+//task openavbAdpMessageRxThread
+#define openavbAdpMessageRxThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
+//task openavbAdpSmAdvertiseInterfaceThread
+#define openavbAdpSmAdvertiseInterfaceThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
+//task openavbAcmpMessageRxThread
+#define openavbAcmpMessageRxThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
+//task openavbAcmpSmTalkerThread
+#define openavbAcmpSmTalkerThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
+//task openavbAcmpSmTalkerThread
+#define openavbAcmpSmTalkerThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#endif // _EAVBTASKS_H
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_time_osal.c b/lib/avtp_pipeline/platform/Linux/openavb_time_osal.c
new file mode 100644
index 00000000..832f4bc1
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_time_osal.c
@@ -0,0 +1,207 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 "igb.h"
+#include "avb.h"
+
+#include "openavb_platform.h"
+#include "openavb_time_osal.h"
+#include "openavb_time_hal.h"
+#include "openavb_trace.h"
+
+#define AVB_LOG_COMPONENT "osalTime"
+#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)
+
+static bool bInitialized = FALSE;
+static int gIgbShmFd = -1;
+static char *gIgbMmap = NULL;
+gPtpTimeData gPtpTD;
+
+static bool x_timeInit(void) {
+ AVB_TRACE_ENTRY(AVB_TRACE_TIME);
+
+ if (!halTimeInitialize()) {
+ AVB_LOG_ERROR("HAL Time Init failed");
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+ }
+
+ if (!gptpinit(&gIgbShmFd, &gIgbMmap)) {
+ AVB_LOG_ERROR("GPTP init failed");
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+ }
+
+ if (!gptpscaling(&gPtpTD, gIgbMmap)) {
+ AVB_LOG_ERROR("GPTP scaling failed");
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+ }
+
+ AVB_LOGF_INFO("local_time = %llu", gPtpTD.local_time);
+ AVB_LOGF_INFO("ml_phoffset = %lld, ls_phoffset = %lld", gPtpTD.ml_phoffset, gPtpTD.ls_phoffset);
+ AVB_LOGF_INFO("ml_freqffset = %Lf, ls_freqoffset = %Lf", gPtpTD.ml_freqoffset, gPtpTD.ls_freqoffset);
+
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return TRUE;
+}
+
+static bool x_getPTPTime(U64 *timeNsec) {
+ AVB_TRACE_ENTRY(AVB_TRACE_TIME);
+
+ if (!gptpscaling(&gPtpTD, gIgbMmap)) {
+ AVB_LOG_ERROR("GPTP scaling failed");
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+ }
+
+ uint64_t now_local;
+ uint64_t update_8021as;
+ int64_t delta_8021as;
+ int64_t delta_local;
+
+ if (gptplocaltime(&gPtpTD, &now_local)) {
+ update_8021as = gPtpTD.local_time - gPtpTD.ml_phoffset;
+ delta_local = now_local - gPtpTD.local_time;
+ delta_8021as = gPtpTD.ml_freqoffset * delta_local;
+ *timeNsec = update_8021as + delta_8021as;
+
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return TRUE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+}
+
+bool osalAVBTimeInit(void) {
+ AVB_TRACE_ENTRY(AVB_TRACE_TIME);
+
+ LOCK();
+ if (!bInitialized) {
+ if (x_timeInit())
+ bInitialized = TRUE;
+ }
+ UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return TRUE;
+}
+
+bool osalAVBTimeClose(void) {
+ AVB_TRACE_ENTRY(AVB_TRACE_TIME);
+
+ gptpdeinit(gIgbShmFd, gIgbMmap);
+
+ halTimeFinalize();
+
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return TRUE;
+}
+
+bool osalClockGettime(openavb_clockId_t openavbClockId, struct timespec *getTime) {
+ AVB_TRACE_ENTRY(AVB_TRACE_TIME);
+
+ if (openavbClockId < OPENAVB_CLOCK_WALLTIME) {
+ clockid_t clockId = CLOCK_MONOTONIC;
+ switch (openavbClockId) {
+ case OPENAVB_CLOCK_REALTIME:
+ clockId = CLOCK_REALTIME;
+ break;
+ case OPENAVB_CLOCK_MONOTONIC:
+ clockId = CLOCK_MONOTONIC;
+ break;
+ case OPENAVB_TIMER_CLOCK:
+ clockId = CLOCK_MONOTONIC;
+ break;
+ case OPENAVB_CLOCK_WALLTIME:
+ break;
+ }
+ if (!clock_gettime(clockId, getTime)) return TRUE;
+ }
+ else if (openavbClockId == OPENAVB_CLOCK_WALLTIME) {
+ U64 timeNsec;
+ if (!x_getPTPTime(&timeNsec)) {
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+ }
+ getTime->tv_sec = timeNsec / NANOSECONDS_PER_SECOND;
+ getTime->tv_nsec = timeNsec % NANOSECONDS_PER_SECOND;
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return TRUE;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+}
+
+bool osalClockGettime64(openavb_clockId_t openavbClockId, U64 *timeNsec) {
+ if (openavbClockId < OPENAVB_CLOCK_WALLTIME) {
+ clockid_t clockId = CLOCK_MONOTONIC;
+ switch (openavbClockId) {
+ case OPENAVB_CLOCK_REALTIME:
+ clockId = CLOCK_REALTIME;
+ break;
+ case OPENAVB_CLOCK_MONOTONIC:
+ clockId = CLOCK_MONOTONIC;
+ break;
+ case OPENAVB_TIMER_CLOCK:
+ clockId = CLOCK_MONOTONIC;
+ break;
+ case OPENAVB_CLOCK_WALLTIME:
+ break;
+ }
+ struct timespec getTime;
+ if (!clock_gettime(clockId, &getTime)) {
+ *timeNsec = ((U64)getTime.tv_sec * (U64)NANOSECONDS_PER_SECOND) + (U64)getTime.tv_nsec;
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return TRUE;
+ }
+ }
+ else if (openavbClockId == OPENAVB_CLOCK_WALLTIME) {
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return x_getPTPTime(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
new file mode 100644
index 00000000..3fa07afd
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_time_osal.h
@@ -0,0 +1,36 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_TIME_OSAL_H
+#define _OPENAVB_TIME_OSAL_H
+
+#include "openavb_time_osal_pub.h"
+
+#endif // _OPENAVB_TIME_OSAL_H
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_time_osal_pub.h b/lib/avtp_pipeline/platform/Linux/openavb_time_osal_pub.h
new file mode 100644
index 00000000..1f2c243f
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_time_osal_pub.h
@@ -0,0 +1,69 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_TIME_OSAL_PUB_H
+#define _OPENAVB_TIME_OSAL_PUB_H
+
+// timer Macros
+#include <sys/timerfd.h>
+#include <time.h>
+
+#define AVB_TIME_INIT() osalAVBTimeInit()
+#define AVB_TIME_CLOSE() osalAVBTimeClose()
+
+#define TIMERFD_CREATE(arg1, arg2) timerfd_create(arg1, arg2)
+#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()
+typedef enum {
+ OPENAVB_CLOCK_REALTIME,
+ OPENAVB_CLOCK_MONOTONIC,
+ OPENAVB_TIMER_CLOCK,
+ OPENAVB_CLOCK_WALLTIME
+} openavb_clockId_t;
+
+#define CLOCK_GETTIME(arg1, arg2) osalClockGettime(arg1, arg2)
+#define CLOCK_GETTIME64(arg1, arg2) osalClockGettime64(arg1, arg2)
+
+// Initialize the AVB Time system for client usage
+bool osalAVBTimeInit(void);
+
+// Close the AVB Time system for client usage
+bool osalAVBTimeClose(void);
+
+// Gets current time. Returns 0 on success otherwise -1
+bool osalClockGettime(openavb_clockId_t openavbClockId, struct timespec *getTime);
+
+// Gets current time as U64 nSec. Returns 0 on success otherwise -1
+bool osalClockGettime64(openavb_clockId_t openavbClockId, U64 *timeNsec);
+
+
+#endif // _OPENAVB_TIME_OSAL_PUB_H
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/avtp_rx.c b/lib/avtp_pipeline/platform/Linux/rawsock/avtp_rx.c
new file mode 100644
index 00000000..e451fab9
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/avtp_rx.c
@@ -0,0 +1,227 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 <stdio.h>
+#include <ctype.h>
+#include <glib.h>
+#include "openavb_rawsock.h"
+#include "openavb_avtp.h"
+#ifdef UBUNTU
+static int ethertype = ETHERTYPE_AVTP;
+#else
+static int ethertype = ETHERTYPE_8021Q;
+#endif
+
+#define MAX_NUM_FRAMES 10
+
+static bool bRunning = TRUE;
+
+static char* interface = NULL;
+
+#define NUM_STREAMS 256
+#define REPORT_SECONDS 10
+
+static GOptionEntry entries[] =
+{
+ { "interface", 'i', 0, G_OPTION_ARG_STRING, &interface, "network interface", "NAME" },
+ { NULL }
+};
+
+int timespec_cmp(struct timespec *a, struct timespec *b)
+{
+ if (a->tv_sec > b->tv_sec)
+ return 1;
+ else if (a->tv_sec < b->tv_sec)
+ return -1;
+ else {
+ if (a->tv_nsec > b->tv_nsec)
+ return 1;
+ else if (a->tv_nsec < b->tv_nsec)
+ return -1;
+ }
+ return 0;
+}
+
+void dumpAscii(U8 *pFrame, int i, int *j)
+{
+ char c;
+
+ printf(" ");
+
+ while (*j <= i) {
+ c = pFrame[*j];
+ *j += 1;
+ if (!isprint(c) || isspace(c))
+ c = '.';
+ printf("%c", c);
+ }
+}
+
+void dumpFrameContent(U8 *pFrame, U32 len)
+{
+ int i = 0, j = 0;
+ while (TRUE) {
+ if (i % 16 == 0) {
+ if (i != 0 ) {
+ // end of line stuff
+ dumpAscii(pFrame, (i < len ? i : len), &j);
+ printf("\n");
+
+ if (i >= len)
+ break;
+ }
+ if (i+1 < len) {
+ // start of line stuff
+ printf("0x%4.4d: ", i);
+ }
+ }
+ else if (i % 2 == 0) {
+ printf(" ");
+ }
+
+ if (i >= len)
+ printf(" ");
+ else
+ printf("%2.2x", pFrame[i]);
+
+ i += 1;
+ }
+}
+
+void dumpFrame(U8 *pFrame, U32 len, hdr_info_t *hdr)
+{
+ printf("Frame received, ethertype=0x%x len=%u\n", hdr->ethertype, len);
+ printf("src: %s\n", ether_ntoa((const struct ether_addr*)hdr->shost));
+ printf("dst: %s\n", ether_ntoa((const struct ether_addr*)hdr->dhost));
+ if (hdr->vlan) {
+ printf("VLAN pcp=%u, vid=%u\n", (unsigned)hdr->vlan_pcp, hdr->vlan_vid);
+ }
+ dumpFrameContent(pFrame, len);
+ printf("\n");
+}
+
+int main(int argc, char* argv[])
+{
+ GError *error = NULL;
+ GOptionContext *context;
+
+ context = g_option_context_new("- rawsock listenr");
+ g_option_context_add_main_entries(context, entries, NULL);
+ if (!g_option_context_parse(context, &argc, &argv, &error))
+ {
+ printf("error: %s\n", error->message);
+ exit(1);
+ }
+
+ if (interface == NULL) {
+ printf("error: must specify network interface\n");
+ exit(2);
+ }
+
+ void* rs = openavbRawsockOpen(interface, TRUE, FALSE, ethertype, 0, MAX_NUM_FRAMES);
+ if (!rs) {
+ printf("error: failed to open raw socket (are you root?)\n");
+ exit(3);
+ }
+
+ hdr_info_t hdr;
+ U8 *pBuf, *pFrame, tmp8;
+ U32 offset, len;
+ U16 uid, i;
+
+ long nTotal = 0, nRecv[NUM_STREAMS];
+ for (i = 0; i < NUM_STREAMS; i++)
+ nRecv[i] = 0;
+
+ struct timespec now, report;
+ clock_gettime(CLOCK_MONOTONIC, &report);
+ report.tv_sec += REPORT_SECONDS;
+
+ while (bRunning) {
+ pBuf = openavbRawsockGetRxFrame(rs, 1000, &offset, &len);
+ if (pBuf) {
+ pFrame = pBuf + offset;
+
+ offset = openavbRawsockRxParseHdr(rs, pBuf, &hdr);
+ if ((int)offset < 0) {
+ printf("error parsing frame header");
+ }
+ else {
+#ifndef UBUNTU
+ if (hdr.ethertype == ETHERTYPE_8021Q) {
+ // Oh! Need to look past the VLAN tag
+ U16 vlan_bits = ntohs(*(U16 *)(pFrame + offset));
+ hdr.vlan = TRUE;
+ hdr.vlan_vid = vlan_bits & 0x0FFF;
+ hdr.vlan_pcp = (vlan_bits >> 13) & 0x0007;
+ offset += 2;
+ hdr.ethertype = ntohs(*(U16 *)(pFrame + offset));
+ offset += 2;
+ }
+#endif
+
+ if (hdr.ethertype == ETHERTYPE_AVTP) {
+ //dumpFrame(pFrame + offset, len - offset, &hdr);
+
+ // Look for stream data frames
+ // (ignore control frames, including MAAP)
+ tmp8 = *(pFrame + offset);
+ if ((tmp8 & 0x80) == 0) {
+ // Find the unique ID in the streamID
+ uid = htons(*(U16*)(pFrame + offset + 10));
+ if (uid < NUM_STREAMS)
+ nRecv[uid]++;
+ nTotal++;
+ }
+ }
+ }
+
+ openavbRawsockRelRxFrame(rs, pBuf);
+ }
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ if (timespec_cmp(&now, &report) >= 0) {
+ printf("total=%ld\t", nTotal);
+ nTotal = 0;
+ for (i = 0; i < NUM_STREAMS-1; i++) {
+ if (nRecv[i] > 0) {
+ printf("%d=%ld\t", i, nRecv[i]);
+ nRecv[i] = 0;
+ }
+ }
+ printf("\n");
+ report.tv_sec += REPORT_SECONDS;
+ }
+ }
+
+ openavbRawsockClose(rs);
+ return 0;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.c b/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.c
new file mode 100644
index 00000000..4c702634
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.c
@@ -0,0 +1,276 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 "igb_rawsock.h"
+#include "pcap_rawsock.h"
+#include "simple_rawsock.h"
+#include "avb.h"
+#include "openavb_ether_hal.h"
+#include "avb_sched.h"
+
+#include "openavb_trace.h"
+
+#define AVB_LOG_COMPONENT "Raw Socket"
+#include "openavb_log.h"
+
+#if IGB_LAUNCHTIME_ENABLED
+// needed for gptplocaltime()
+extern gPtpTimeData gPtpTD;
+#endif
+
+void *igbRawsockOpen(igb_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);
+
+ if (rx_mode) {
+ if (!pcapRawsockOpen((pcap_rawsock_t*)rawsock, ifname, rx_mode,
+ false, ethertype, frame_size, num_frames))
+ {
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+ rawsock->base.txMode = tx_mode;
+ } else {
+ rawsock->handle = 0;
+ rawsock->base.rxMode = rx_mode;
+ rawsock->base.txMode = tx_mode;
+ rawsock->base.ethertype = ethertype;
+
+ // 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;
+ }
+ }
+
+ if (tx_mode) {
+ // Deal with frame size.
+ if (frame_size == 0) {
+ // use interface MTU as max frames size, if none specified
+ rawsock->base.frameSize = IGB_MTU;
+ }
+ else if (frame_size > IGB_MTU) {
+ AVB_LOGF_ERROR("Creating rawsock; requested frame size exceeds %d", IGB_MTU);
+ igbRawsockClose(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ } else {
+ rawsock->base.frameSize = frame_size;
+ }
+
+ // IGB setup
+ rawsock->igb_dev = igbAcquireDevice();
+
+ // select class B queue by default
+ rawsock->queue = 1;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return rawsock;
+}
+
+void igbRawsockClose(void *pvRawsock)
+{
+ igb_rawsock_t *rawsock = (igb_rawsock_t*)pvRawsock;
+
+ if (rawsock->igb_dev) {
+ igbReleaseDevice(rawsock->igb_dev);
+ }
+
+ pcapRawsockClose((pcap_rawsock_t*)rawsock);
+}
+
+bool igbRawsockTxSetMark(void *pvRawsock, int mark)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+
+ igb_rawsock_t *rawsock = (igb_rawsock_t*)pvRawsock;
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Setting TX mark; invalid argument passed");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ int fwmarkClass = TC_AVB_MARK_CLASS(mark);
+
+ if (fwmarkClass == SR_CLASS_A) {
+ rawsock->queue = 0;
+ } else if (fwmarkClass == SR_CLASS_B) {
+ rawsock->queue = 1;
+ } else {
+ AVB_LOGF_ERROR("fwmarkClass %d is not proper SR_CLASS", fwmarkClass);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return TRUE;
+}
+
+// Get a buffer from the ring to use for TX
+U8 *igbRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+
+ igb_rawsock_t *rawsock = (igb_rawsock_t*)pvRawsock;
+
+ if (!VALID_TX_RAWSOCK(rawsock) || len == NULL) {
+ AVB_LOG_ERROR("Getting TX frame; bad arguments");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+
+ U8 *ret = NULL;
+ int bBufferBusyReported = 0;
+
+ do {
+ rawsock->tx_packet = igbGetTxPacket(rawsock->igb_dev);
+ if (!rawsock->tx_packet && blocking) {
+ if (0 == bBufferBusyReported) {
+ if (!rawsock->txOutOfBuffer) {
+ AVB_LOGF_DEBUG("Getting TX frame (%p): TX buffer busy", rawsock);
+ }
+ ++rawsock->txOutOfBuffer;
+ ++rawsock->txOutOfBufferCyclic;
+ } else if (1 == bBufferBusyReported) {
+ AVB_LOGF_DEBUG("Getting TX frame (%p): TX buffer busy after usleep(10) verify if there are any late frames", rawsock);
+ }
+ ++bBufferBusyReported;
+ usleep(10);
+ }
+ } while (!rawsock->tx_packet && blocking);
+
+ if (rawsock->tx_packet) {
+ *len = rawsock->base.frameSize;
+ ret = rawsock->tx_packet->vaddr;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return ret;
+}
+
+// Release a TX frame, without marking it as ready to send
+bool igbRawsockRelTxFrame(void *pvRawsock, U8 *pBuffer)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ igb_rawsock_t *rawsock = (igb_rawsock_t*)pvRawsock;
+ if (!VALID_TX_RAWSOCK(rawsock) || pBuffer == NULL) {
+ AVB_LOG_ERROR("Releasing TX frame; invalid argument");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ igbRelTxPacket(rawsock->igb_dev, rawsock->queue, rawsock->tx_packet);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return TRUE;
+}
+
+// Release a TX frame, and mark it as ready to send
+bool igbRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ igb_rawsock_t *rawsock = (igb_rawsock_t*)pvRawsock;
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Send; invalid argument");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return -1;
+ }
+
+ int err;
+
+ rawsock->tx_packet->len = len;
+
+#if IGB_LAUNCHTIME_ENABLED
+ gptplocaltime(&gPtpTD, &rawsock->tx_packet->attime);
+#endif
+
+ err = igb_xmit(rawsock->igb_dev, rawsock->queue, rawsock->tx_packet);
+ if (err) {
+ AVB_LOGF_ERROR("igb_xmit failed: %s", strerror(err));
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return !err;
+}
+
+// Send all packets that are ready (i.e. tell kernel to send them)
+int igbRawsockSend(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+
+ // igbRawsock sends frames in igbRawsockTxFrameReady
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return 1;
+}
+
+int igbRawsockTxBufLevel(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ igb_rawsock_t *rawsock = (igb_rawsock_t*)pvRawsock;
+
+ int nInUse = igbTxBufLevel(rawsock->igb_dev);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return nInUse;
+}
+
+unsigned long igbRawsockGetTXOutOfBuffers(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ unsigned long counter = 0;
+ igb_rawsock_t *rawsock = (igb_rawsock_t*)pvRawsock;
+
+ if(VALID_TX_RAWSOCK(rawsock)) {
+ counter = rawsock->txOutOfBuffer;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return counter;
+}
+
+unsigned long igbRawsockGetTXOutOfBuffersCyclic(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ unsigned long counter = 0;
+ igb_rawsock_t *rawsock = (igb_rawsock_t*)pvRawsock;
+
+ if(VALID_TX_RAWSOCK(rawsock)) {
+ counter = rawsock->txOutOfBufferCyclic;
+ rawsock->txOutOfBufferCyclic = 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return counter;
+}
+
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.h b/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.h
new file mode 100644
index 00000000..efea97a9
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.h
@@ -0,0 +1,67 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 IGB_RAWSOCK_H
+#define IGB_RAWSOCK_H
+
+#include "rawsock_impl.h"
+#include <pcap/pcap.h>
+#include "igb.h"
+
+typedef struct {
+ base_rawsock_t base;
+ pcap_t *handle;
+ device_t *igb_dev;
+ struct igb_packet *tx_packet;
+ int queue;
+ unsigned long txOutOfBuffer;
+ unsigned long txOutOfBufferCyclic;
+} igb_rawsock_t;
+
+void *igbRawsockOpen(igb_rawsock_t* rawsock, const char *ifname, bool rx_mode, bool tx_mode, U16 ethertype, U32 frame_size, U32 num_frames);
+
+void igbRawsockClose(void *pvRawsock);
+
+bool igbRawsockTxSetMark(void *pvRawsock, int mark);
+
+U8 *igbRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len);
+
+bool igbRawsockRelTxFrame(void *pvRawsock, U8 *pBuffer);
+
+bool igbRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len);
+
+int igbRawsockSend(void *pvRawsock);
+
+int igbRawsockTxBufLevel(void *pvRawsock);
+
+unsigned long igbRawsockGetTXOutOfBuffers(void *pvRawsock);
+
+unsigned long igbRawsockGetTXOutOfBuffersCyclic(void *pvRawsock);
+
+#endif
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock.c b/lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock.c
new file mode 100644
index 00000000..52376abf
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock.c
@@ -0,0 +1,215 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_rawsock.h"
+#include <malloc.h>
+#include "simple_rawsock.h"
+#include "ring_rawsock.h"
+
+#define IGB
+
+#if AVB_FEATURE_PCAP
+#include "pcap_rawsock.h"
+#include "igb_rawsock.h"
+#endif
+
+#include "openavb_trace.h"
+
+#define AVB_LOG_COMPONENT "Raw Socket"
+#include "openavb_log.h"
+
+
+// Get information about an interface
+bool openavbCheckInterface(const char *ifname_uri, if_info_t *info)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+
+ const char* ifname = ifname_uri;
+ char proto[IF_NAMESIZE] = {0};
+ char *colon = strchr(ifname_uri, ':');
+ if (colon) {
+ ifname = colon + 1;
+ strncpy(proto, ifname_uri, colon - ifname_uri);
+ }
+
+ AVB_LOGF_DEBUG("%s ifname_uri %s ifname %s proto %s", __func__, ifname_uri, ifname, proto);
+
+ bool ret = simpleAvbCheckInterface(ifname, info);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return ret;
+}
+
+// Open a rawsock for TX or RX
+void *openavbRawsockOpen(const char *ifname_uri, bool rx_mode, bool tx_mode, U16 ethertype, U32 frame_size, U32 num_frames)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+
+ const char* ifname = ifname_uri;
+ char proto[IF_NAMESIZE] = "igb";
+ char *colon = strchr(ifname_uri, ':');
+ if (colon) {
+ ifname = colon + 1;
+ strncpy(proto, ifname_uri, colon - ifname_uri);
+ }
+
+ AVB_LOGF_DEBUG("%s ifname_uri %s ifname %s proto %s", __func__, ifname_uri, ifname, proto);
+
+ void *pvRawsock = NULL;
+
+ if (strcmp(proto, "ring") == 0) {
+
+ AVB_LOG_INFO("Using *ring* buffer implementation");
+
+ // allocate memory for rawsock object
+ ring_rawsock_t *rawsock = calloc(1, sizeof(ring_rawsock_t));
+ if (!rawsock) {
+ AVB_LOG_ERROR("Creating rawsock; malloc failed");
+ return NULL;
+ }
+
+ // fill virtual functions table
+ rawsock_cb_t *cb = &rawsock->base.cb;
+ cb->close = ringRawsockClose;
+ cb->getTxFrame = ringRawsockGetTxFrame;
+ cb->txSetMark = simpleRawsockTxSetMark;
+ cb->txSetHdr = simpleRawsockTxSetHdr;
+ cb->txFillHdr = baseRawsockTxFillHdr;
+ cb->relTxFrame = ringRawsockRelTxFrame;
+ cb->txFrameReady = ringRawsockTxFrameReady;
+ cb->send = ringRawsockSend;
+ cb->txBufLevel = ringRawsockTxBufLevel;
+ cb->rxBufLevel = ringRawsockRxBufLevel;
+ cb->getRxFrame = ringRawsockGetRxFrame;
+ cb->rxParseHdr = ringRawsockRxParseHdr;
+ cb->relRxFrame = ringRawsockRelRxFrame;
+ cb->rxMulticast = simpleRawsockRxMulticast;
+ cb->getSocket = simpleRawsockGetSocket;
+ cb->getAddr = baseRawsockGetAddr;
+ cb->getTXOutOfBuffers = ringRawsockGetTXOutOfBuffers;
+ cb->getTXOutOfBuffersCyclic = ringRawsockGetTXOutOfBuffersCyclic;
+
+ // call constructor
+ pvRawsock = ringRawsockOpen(rawsock, ifname, rx_mode, tx_mode, ethertype, frame_size, num_frames);
+
+ } else if (strcmp(proto, "simple") == 0) {
+
+ AVB_LOG_INFO("Using *simple* implementation");
+
+ // allocate memory for rawsock object
+ simple_rawsock_t *rawsock = calloc(1, sizeof(simple_rawsock_t));
+ if (!rawsock) {
+ AVB_LOG_ERROR("Creating rawsock; malloc failed");
+ return NULL;
+ }
+
+ // fill virtual functions table
+ rawsock_cb_t *cb = &rawsock->base.cb;
+ cb->close = simpleRawsockClose;
+ cb->getTxFrame = simpleRawsockGetTxFrame;
+ cb->txSetMark = simpleRawsockTxSetMark;
+ cb->txSetHdr = simpleRawsockTxSetHdr;
+ cb->txFillHdr = baseRawsockTxFillHdr;
+ cb->txFrameReady = simpleRawsockTxFrameReady;
+ cb->getRxFrame = simpleRawsockGetRxFrame;
+ cb->rxParseHdr = simpleRawsockRxParseHdr;
+ cb->rxMulticast = simpleRawsockRxMulticast;
+ cb->getSocket = simpleRawsockGetSocket;
+ cb->getAddr = baseRawsockGetAddr;
+
+ // call constructor
+ pvRawsock = simpleRawsockOpen(rawsock, ifname, rx_mode, tx_mode, ethertype, frame_size, num_frames);
+#if AVB_FEATURE_PCAP
+ } else if (strcmp(proto, "pcap") == 0) {
+
+ AVB_LOG_INFO("Using *pcap* implementation");
+
+ // allocate memory for rawsock object
+ pcap_rawsock_t *rawsock = calloc(1, sizeof(pcap_rawsock_t));
+ if (!rawsock) {
+ AVB_LOG_ERROR("Creating rawsock; malloc failed");
+ return NULL;
+ }
+
+ // fill virtual functions table
+ rawsock_cb_t *cb = &rawsock->base.cb;
+ cb->close = pcapRawsockClose;
+ cb->getTxFrame = pcapRawsockGetTxFrame;
+ cb->txSetHdr = baseRawsockTxSetHdr;
+ cb->txFillHdr = baseRawsockTxFillHdr;
+ cb->txFrameReady = pcapRawsockTxFrameReady;
+ cb->getRxFrame = pcapRawsockGetRxFrame;
+ cb->rxParseHdr = simpleRawsockRxParseHdr;
+ cb->rxMulticast = pcapRawsockRxMulticast;
+ cb->getAddr = baseRawsockGetAddr;
+
+ // call constructor
+ pvRawsock = pcapRawsockOpen(rawsock, ifname, rx_mode, tx_mode, ethertype, frame_size, num_frames);
+#ifdef IGB
+ } else if (strcmp(proto, "igb") == 0) {
+
+ AVB_LOG_INFO("Using *igb* implementation");
+
+ // allocate memory for rawsock object
+ igb_rawsock_t *rawsock = calloc(1, sizeof(igb_rawsock_t));
+ if (!rawsock) {
+ AVB_LOG_ERROR("Creating rawsock; malloc failed");
+ return NULL;
+ }
+
+ // fill virtual functions table
+ rawsock_cb_t *cb = &rawsock->base.cb;
+ cb->close = igbRawsockClose;
+ cb->getTxFrame = igbRawsockGetTxFrame;
+ cb->relTxFrame = igbRawsockRelTxFrame;
+ cb->txSetHdr = baseRawsockTxSetHdr;
+ cb->txSetMark = igbRawsockTxSetMark;
+ cb->txFillHdr = baseRawsockTxFillHdr;
+ cb->txFrameReady = igbRawsockTxFrameReady;
+ cb->send = igbRawsockSend;
+ cb->txBufLevel = igbRawsockTxBufLevel;
+ cb->getRxFrame = pcapRawsockGetRxFrame;
+ cb->rxParseHdr = simpleRawsockRxParseHdr;
+ cb->rxMulticast = pcapRawsockRxMulticast;
+ cb->getAddr = baseRawsockGetAddr;
+ cb->getTXOutOfBuffers = igbRawsockGetTXOutOfBuffers;
+ cb->getTXOutOfBuffersCyclic = igbRawsockGetTXOutOfBuffersCyclic;
+
+ // call constructor
+ pvRawsock = igbRawsockOpen((igb_rawsock_t*)rawsock, ifname, rx_mode, tx_mode, ethertype, frame_size, num_frames);
+#endif
+#endif
+ } else {
+ AVB_LOGF_ERROR("Unknown proto %s specified.", proto);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return pvRawsock;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.c b/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.c
new file mode 100644
index 00000000..c1c302a8
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.c
@@ -0,0 +1,185 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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.
+*************************************************************************************************************/
+
+/*
+ * Rawsock implemenation which uses libpcap for receiving and transmitting packets.
+*/
+#include "pcap_rawsock.h"
+#include "simple_rawsock.h"
+#include "openavb_trace.h"
+
+#define AVB_LOG_COMPONENT "Raw Socket"
+#include "openavb_log.h"
+
+// 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)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+
+ AVB_LOGF_DEBUG("Open, rx=%d, tx=%d, ethertype=%x size=%d, num=%d", rx_mode, tx_mode, ethertype, frame_size, num_frames);
+
+ if (tx_mode) {
+ AVB_LOG_ERROR("pcap rawsock transmit mode will bypass FQTSS");
+ }
+
+ rawsock->handle = 0;
+ rawsock->base.rxMode = rx_mode;
+ rawsock->base.txMode = tx_mode;
+ rawsock->base.frameSize = frame_size;
+ rawsock->base.ethertype = ethertype;
+
+ // 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;
+ }
+ else if (rawsock->base.frameSize > rawsock->base.ifInfo.mtu) {
+ AVB_LOG_ERROR("Creating raswsock; 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);
+ if (!rawsock->handle) {
+ AVB_LOGF_ERROR("Cannot open device %s: %s", ifname, errbuf);
+ free(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return rawsock;
+}
+
+void pcapRawsockClose(void *pvRawsock)
+{
+ pcap_rawsock_t *rawsock = (pcap_rawsock_t*)pvRawsock;
+
+ if (rawsock) {
+ if (rawsock->handle)
+ pcap_close(rawsock->handle);
+ free(rawsock);
+ }
+}
+
+U8 *pcapRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len)
+{
+ pcap_rawsock_t *rawsock = (pcap_rawsock_t*)pvRawsock;
+
+ if (rawsock) {
+ *len = rawsock->base.frameSize;
+ return rawsock->txBuffer;
+ }
+
+ return false;
+}
+
+bool pcapRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len)
+{
+ pcap_rawsock_t *rawsock = (pcap_rawsock_t*)pvRawsock;
+ int ret = -1;
+
+ if (rawsock) {
+ ret = pcap_sendpacket(rawsock->handle, pBuffer, len);
+ if (ret == -1) {
+ AVB_LOGF_ERROR("pcap_sendpacket failed: %s", pcap_geterr(rawsock->handle));
+ }
+
+ }
+ return ret == 0;
+}
+
+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;
+ const u_char *packet = 0;
+ int ret;
+
+ if (rawsock) {
+ ret = pcap_next_ex(rawsock->handle, &header, &packet);
+ switch(ret) {
+ case 1:
+ *offset = 0;
+ *len = header->caplen;
+ return (U8*)packet;
+ case -1:
+ AVB_LOGF_ERROR("pcap_next_ex failed: %s", pcap_geterr(rawsock->handle));
+ break;
+ case 0:
+ // timeout;
+ break;
+ case -2:
+ // no packets to be read from savefile
+ // this should not happend
+ break;
+ default:
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+// Setup the rawsock to receive multicast packets
+bool pcapRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[ETH_ALEN])
+{
+ pcap_rawsock_t *rawsock = (pcap_rawsock_t*)pvRawsock;
+
+ 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]);
+
+ AVB_LOGF_DEBUG("%s %d %s", __func__, (int)add_membership, filter_exp);
+
+ if (pcap_compile(rawsock->handle, &comp_filter_exp, filter_exp, 0, PCAP_NETMASK_UNKNOWN) < 0) {
+ AVB_LOGF_ERROR("Could not parse filter %s: %s", filter_exp, pcap_geterr(rawsock->handle));
+ return false;
+ }
+
+ if (pcap_setfilter(rawsock->handle, &comp_filter_exp) < 0) {
+ AVB_LOGF_ERROR("Could not install filter %s: %s", filter_exp, pcap_geterr(rawsock->handle));
+ return false;
+ }
+
+ return true;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.h b/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.h
new file mode 100644
index 00000000..ed8e7943
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.h
@@ -0,0 +1,55 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 PCAP_RAWSOCK_H
+#define PCAP_RAWSOCK_H
+
+#include "rawsock_impl.h"
+#include <pcap/pcap.h>
+
+typedef struct {
+ base_rawsock_t base;
+ pcap_t* handle;
+ U8 txBuffer[1518];
+} 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);
+
+void pcapRawsockClose(void *pvRawsock);
+
+U8 *pcapRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len);
+
+bool pcapRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len);
+
+U8 *pcapRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len);
+
+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
new file mode 100644
index 00000000..4fa4682f
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_rx.c
@@ -0,0 +1,194 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 <stdio.h>
+#include <ctype.h>
+#include <glib.h>
+#include "./openavb_rawsock.h"
+
+// Common usage with VTAG 0x8100: ./rawsock_rx -i eth0 -t 33024 -d 1 -s 1
+// Common usage without VTAG 0x22F0: ./rawsock_rx -i eth0 -t 8944 -d 1 -s 1
+
+#define MAX_NUM_FRAMES 10
+#define TIMESPEC_TO_NSEC(ts) (((uint64_t)ts.tv_sec * (uint64_t)NANOSECONDS_PER_SECOND) + (uint64_t)ts.tv_nsec)
+
+static bool bRunning = TRUE;
+
+static char* interface = NULL;
+static int ethertype = -1;
+static char* macaddr_s = NULL;
+static int dumpFlag = 0;
+static int reportSec = 1;
+
+static GOptionEntry entries[] =
+{
+ { "interface", 'i', 0, G_OPTION_ARG_STRING, &interface, "network interface", "NAME" },
+ { "ethertype", 't', 0, G_OPTION_ARG_INT, &ethertype, "ethernet protocol", "NUM" },
+ { "mac", 'a', 0, G_OPTION_ARG_STRING, &macaddr_s, "MAC address", "MAC" },
+ { "dump", 'd', 0, G_OPTION_ARG_INT, &dumpFlag, "Dump packets (1=yes, 0=no)", "DUMP" },
+ { "rptsec", 's', 0, G_OPTION_ARG_INT, &reportSec, "report interval in seconds", "RPTSEC" },
+ { NULL }
+};
+
+void dumpAscii(U8 *pFrame, int i, int *j)
+{
+ char c;
+
+ printf(" ");
+
+ while (*j <= i) {
+ c = pFrame[*j];
+ *j += 1;
+ if (!isprint(c) || isspace(c))
+ c = '.';
+ printf("%c", c);
+ }
+}
+
+void dumpFrameContent(U8 *pFrame, U32 len)
+{
+ int i = 0, j = 0;
+ while (TRUE) {
+ if (i % 16 == 0) {
+ if (i != 0 ) {
+ // end of line stuff
+ dumpAscii(pFrame, (i < len ? i : len), &j);
+ printf("\n");
+
+ if (i >= len)
+ break;
+ }
+ if (i+1 < len) {
+ // start of line stuff
+ printf("0x%4.4d: ", i);
+ }
+ }
+ else if (i % 2 == 0) {
+ printf(" ");
+ }
+
+ if (i >= len)
+ printf(" ");
+ else
+ printf("%2.2x", pFrame[i]);
+
+ i += 1;
+ }
+}
+
+void dumpFrame(U8 *pFrame, U32 len, hdr_info_t *hdr)
+{
+ printf("Frame received, ethertype=0x%x len=%u\n", hdr->ethertype, len);
+ printf("src: %s\n", ether_ntoa((const struct ether_addr*)hdr->shost));
+ printf("dst: %s\n", ether_ntoa((const struct ether_addr*)hdr->dhost));
+ if (hdr->vlan) {
+ printf("VLAN pcp=%u, vid=%u\n", (unsigned)hdr->vlan_pcp, hdr->vlan_vid);
+ }
+ dumpFrameContent(pFrame, len);
+ printf("\n");
+}
+
+int main(int argc, char* argv[])
+{
+ GError *error = NULL;
+ GOptionContext *context;
+ //U8 *macaddr;
+ struct ether_addr *macaddr;
+
+ context = g_option_context_new("- rawsock listenr");
+ g_option_context_add_main_entries(context, entries, NULL);
+ if (!g_option_context_parse(context, &argc, &argv, &error))
+ {
+ printf("error: %s\n", error->message);
+ exit(1);
+ }
+
+ if (interface == NULL || ethertype == -1) {
+ printf("error: must specify network interface and ethertype\n");
+ exit(2);
+ }
+
+ void* rs = openavbRawsockOpen(interface, TRUE, FALSE, ethertype, 0, MAX_NUM_FRAMES);
+ if (!rs) {
+ printf("error: failed to open raw socket (are you root?)\n");
+ exit(3);
+ }
+
+ if (macaddr_s) {
+ macaddr = ether_aton(macaddr_s);
+ if (macaddr) {
+ // if (openavbRawsockRxMulticast(rs, TRUE, macaddr) == FALSE) {
+ if (openavbRawsockRxMulticast(rs, TRUE, macaddr->ether_addr_octet) == FALSE) {
+ printf("error: failed to add multicast mac address\n");
+ exit(4);
+ }
+ }
+ else
+ printf("warning: failed to convert multicast mac address\n");
+ }
+
+ U8 *pBuf, *pFrame;
+ U32 offset, len;
+ hdr_info_t hdr;
+
+ struct timespec now;
+ static U32 packetCnt = 0;
+ static U64 nextReportInterval = 0;
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ nextReportInterval = TIMESPEC_TO_NSEC(now) + (NANOSECONDS_PER_SECOND * reportSec);
+
+ while (bRunning) {
+ pBuf = openavbRawsockGetRxFrame(rs, OPENAVB_RAWSOCK_BLOCK, &offset, &len);
+ pFrame = pBuf + offset;
+ openavbRawsockRxParseHdr(rs, pBuf, &hdr);
+ if (dumpFlag) {
+ dumpFrame(pFrame, len, &hdr);
+ }
+ openavbRawsockRelRxFrame(rs, pBuf);
+
+ packetCnt++;
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ U64 nowNSec = TIMESPEC_TO_NSEC(now);;
+
+ if (reportSec > 0) {
+ if (nowNSec > nextReportInterval) {
+ printf("RX Packets: %d\n", packetCnt);
+ packetCnt = 0;
+ nextReportInterval = nowNSec + (NANOSECONDS_PER_SECOND * reportSec);
+ }
+ }
+ }
+
+ openavbRawsockClose(rs);
+ return 0;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_tx.c b/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_tx.c
new file mode 100644
index 00000000..e01b5998
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_tx.c
@@ -0,0 +1,219 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <glib.h>
+#include "./openavb_rawsock.h"
+
+//Common usage: ./rawsock_tx -i eth0 -t 8944 -r 8000 -s 1 -c 1 -m 1 -l 100
+
+#define MAX_NUM_FRAMES 100
+#define NANOSECONDS_PER_SECOND (1000000000ULL)
+#define TIMESPEC_TO_NSEC(ts) (((uint64_t)ts.tv_sec * (uint64_t)NANOSECONDS_PER_SECOND) + (uint64_t)ts.tv_nsec)
+
+#define RAWSOCK_TX_MODE_FILL (0)
+#define RAWSOCK_TX_MODE_SEQ (1)
+
+static char* interface = NULL;
+static int ethertype = -1;
+static int txlen = 64;
+static int txRate = 8000;
+static int chunkSize = 1;
+static int reportSec = 1;
+static int mode = RAWSOCK_TX_MODE_FILL;
+
+static GOptionEntry entries[] =
+{
+ { "interface", 'i', 0, G_OPTION_ARG_STRING, &interface, "network interface", "NAME" },
+ { "ethertype", 't', 0, G_OPTION_ARG_INT, &ethertype, "ethernet protocol", "NUM" },
+ { "length", 'l', 0, G_OPTION_ARG_INT, &txlen, "frame length", "LEN" },
+ { "rate", 'r', 0, G_OPTION_ARG_INT, &txRate, "tx rate", "RATE" },
+ { "chunk", 'c', 0, G_OPTION_ARG_INT, &chunkSize, "Chunk size", "CHUNKSIZE" },
+ { "rptsec", 's', 0, G_OPTION_ARG_INT, &reportSec, "report interval in seconds", "RPTSEC" },
+ { "mode", 'm', 0, G_OPTION_ARG_INT, &mode, "mode: 0 = fill, 1 = sequence number", "MODE" },
+ { NULL }
+};
+
+void dumpAscii(U8 *pFrame, int i, int *j)
+{
+ char c;
+
+ printf(" ");
+
+ while (*j <= i) {
+ c = pFrame[*j];
+ *j += 1;
+ if (!isprint(c) || isspace(c))
+ c = '.';
+ printf("%c", c);
+ }
+}
+
+void dumpFrameContent(U8 *pFrame, U32 len)
+{
+ int i = 0, j = 0;
+ while (TRUE) {
+ if (i % 16 == 0) {
+ if (i != 0 ) {
+ // end of line stuff
+ dumpAscii(pFrame, (i < len ? i : len), &j);
+ printf("\n");
+
+ if (i >= len)
+ break;
+ }
+ if (i+1 < len) {
+ // start of line stuff
+ printf("0x%4.4d: ", i);
+ }
+ }
+ else if (i % 2 == 0) {
+ printf(" ");
+ }
+
+ if (i >= len)
+ printf(" ");
+ else
+ printf("%2.2x", pFrame[i]);
+
+ i += 1;
+ }
+}
+
+void dumpFrame(U8 *pFrame, U32 len, hdr_info_t *hdr)
+{
+ printf("Frame received, ethertype=0x%x len=%u\n", hdr->ethertype, len);
+ printf("src: %s\n", ether_ntoa((const struct ether_addr*)hdr->shost));
+ printf("dst: %s\n", ether_ntoa((const struct ether_addr*)hdr->dhost));
+ if (hdr->vlan) {
+ printf("VLAN pcp=%u, vid=%u\n", (unsigned)hdr->vlan_pcp, hdr->vlan_vid);
+ }
+ dumpFrameContent(pFrame, len);
+ printf("\n");
+}
+
+int main(int argc, char* argv[])
+{
+ GError *error = NULL;
+ GOptionContext *context;
+
+ context = g_option_context_new("- rawsock listenr");
+ g_option_context_add_main_entries(context, entries, NULL);
+ if (!g_option_context_parse(context, &argc, &argv, &error))
+ {
+ printf("error: %s\n", error->message);
+ exit(1);
+ }
+
+ if (interface == NULL || ethertype < 0) {
+ printf("error: must specify network interface and ethertype\n");
+ exit(2);
+ }
+
+ void* rs = openavbRawsockOpen(interface, FALSE, TRUE, ethertype, 0, MAX_NUM_FRAMES);
+ if (!rs) {
+ printf("error: failed to open raw socket (are you root?)\n");
+ exit(3);
+ }
+
+ U8 *pBuf, *pData;
+ U32 buflen, hdrlen, datalen;
+ hdr_info_t hdr;
+
+ memset(&hdr, 0, sizeof(hdr_info_t));
+ openavbRawsockTxSetHdr(rs, &hdr);
+
+ struct timespec now;
+ static U64 packetIntervalNSec = 0;
+ static U64 nextCycleNSec = 0;
+ static U32 packetCnt = 0;
+ static U64 nextReportInterval = 0;
+
+ packetIntervalNSec = NANOSECONDS_PER_SECOND / txRate;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ nextCycleNSec = TIMESPEC_TO_NSEC(now);
+ nextReportInterval = TIMESPEC_TO_NSEC(now) + (NANOSECONDS_PER_SECOND * reportSec);
+
+ while (1) {
+ pBuf = (U8*)openavbRawsockGetTxFrame(rs, TRUE, &buflen);
+ if (!pBuf) {
+ printf("failed to get TX frame buffer\n");
+ exit(4);
+ }
+
+ if (buflen < txlen || txlen == -1)
+ txlen = buflen;
+
+ openavbRawsockTxFillHdr(rs, pBuf, &hdrlen);
+ pData = pBuf + hdrlen;
+ datalen = txlen - hdrlen;
+
+ if (mode == RAWSOCK_TX_MODE_FILL) {
+ int i;
+ for (i=0; i<datalen; i++)
+ pData[i] = (i & 0xff);
+ }
+ else { // RAWSOCK_TX_MODE_sEQ
+ static unsigned char seq = 0;
+ pData[0] = 0x7F; // Experimental subtype
+ pData[1] = 0x00;
+ pData[2] = seq++;
+ txlen = hdrlen + 3;
+ }
+
+ openavbRawsockTxFrameReady(rs, pBuf, txlen);
+
+ packetCnt++;
+
+ if ((packetCnt % chunkSize) == 0) {
+ openavbRawsockSend(rs);
+ }
+
+ nextCycleNSec += packetIntervalNSec;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ U64 nowNSec = TIMESPEC_TO_NSEC(now);;
+
+ if (nowNSec > nextReportInterval) {
+ printf("TX Packets: %d\n", packetCnt);
+ packetCnt = 0;
+ nextReportInterval = nowNSec + (NANOSECONDS_PER_SECOND * reportSec);
+ }
+
+ if (nowNSec < nextCycleNSec) {
+ usleep((nextCycleNSec - nowNSec) / 1000);
+ }
+ }
+
+ openavbRawsockClose(rs);
+ return 0;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.c b/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.c
new file mode 100644
index 00000000..a8f09ba2
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.c
@@ -0,0 +1,680 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 "ring_rawsock.h"
+#include "simple_rawsock.h"
+#include <linux/if_packet.h>
+
+#include "openavb_trace.h"
+
+#define AVB_LOG_COMPONENT "Raw Socket"
+#include "openavb_log.h"
+
+
+// Open a rawsock for TX or RX
+void* ringRawsockOpen(ring_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);
+
+ rawsock->pMem = (void*)(-1);
+
+ if (!simpleRawsockOpen((simple_rawsock_t*)rawsock, ifname, rx_mode,
+ tx_mode, ethertype, frame_size, num_frames))
+ {
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+
+ // Use version 2 headers for the MMAP packet stuff - avoids 32/64
+ // bit problems, gives nanosecond timestamps, and allows rx of vlan id
+ int val = TPACKET_V2;
+ if (setsockopt(rawsock->sock, SOL_PACKET, PACKET_VERSION, &val, sizeof(val)) < 0) {
+ AVB_LOGF_ERROR("Creating rawsock; get PACKET_VERSION: %s", strerror(errno));
+ ringRawsockClose(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+
+ // Get the size of the headers in the ring
+ unsigned len = sizeof(val);
+ if (getsockopt(rawsock->sock, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) {
+ AVB_LOGF_ERROR("Creating rawsock; get PACKET_HDRLEN: %s", strerror(errno));
+ ringRawsockClose(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+ rawsock->bufHdrSize = TPACKET_ALIGN(val);
+
+ if (rawsock->base.rxMode) {
+ rawsock->bufHdrSize = rawsock->bufHdrSize + TPACKET_ALIGN(sizeof(struct sockaddr_ll));
+ }
+ rawsock->bufferSize = rawsock->base.frameSize + rawsock->bufHdrSize;
+ rawsock->frameCount = num_frames;
+ AVB_LOGF_DEBUG("frameSize=%d, bufHdrSize=%d(%d+%d) bufferSize=%d, frameCount=%d",
+ rawsock->base.frameSize, rawsock->bufHdrSize, val, sizeof(struct sockaddr_ll),
+ rawsock->bufferSize, rawsock->frameCount);
+
+ // Get number of bytes in a memory page. The blocks we ask for
+ // must be a multiple of pagesize. (Actually, it should be
+ // (pagesize * 2^N) to avoid wasting memory.)
+ int pagesize = getpagesize();
+ rawsock->blockSize = pagesize * 4;
+ AVB_LOGF_DEBUG("pagesize=%d blockSize=%d", pagesize, rawsock->blockSize);
+
+ // Calculate number of buffers and frames based on blocks
+ int buffersPerBlock = rawsock->blockSize / rawsock->bufferSize;
+ rawsock->blockCount = rawsock->frameCount / buffersPerBlock + 1;
+ rawsock->frameCount = buffersPerBlock * rawsock->blockCount;
+
+ AVB_LOGF_DEBUG("frameCount=%d, buffersPerBlock=%d, blockCount=%d",
+ rawsock->frameCount, buffersPerBlock, rawsock->blockCount);
+
+ // Fill in the kernel structure with our calculated values
+ struct tpacket_req s_packet_req;
+ memset(&s_packet_req, 0, sizeof(s_packet_req));
+ s_packet_req.tp_block_size = rawsock->blockSize;
+ s_packet_req.tp_frame_size = rawsock->bufferSize;
+ s_packet_req.tp_block_nr = rawsock->blockCount;
+ s_packet_req.tp_frame_nr = rawsock->frameCount;
+
+ // Ask the kernel to create the TX_RING or RX_RING
+ if (rawsock->base.txMode) {
+ if (setsockopt(rawsock->sock, SOL_PACKET, PACKET_TX_RING,
+ (char*)&s_packet_req, sizeof(s_packet_req)) < 0) {
+ AVB_LOGF_ERROR("Creating rawsock; TX_RING: %s", strerror(errno));
+ ringRawsockClose(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+ AVB_LOGF_DEBUG("PACKET_%s_RING OK", "TX");
+ }
+ else {
+ if (setsockopt(rawsock->sock, SOL_PACKET, PACKET_RX_RING,
+ (char*)&s_packet_req, sizeof(s_packet_req)) < 0) {
+ AVB_LOGF_ERROR("Creating rawsock, RX_RING: %s", strerror(errno));
+ ringRawsockClose(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+ AVB_LOGF_DEBUG("PACKET_%s_RING OK", "TX");
+ }
+
+ // Call MMAP to get access to the memory used for the ring
+ rawsock->memSize = rawsock->blockCount * rawsock->blockSize;
+ AVB_LOGF_DEBUG("memSize=%d (%d, %d), sock=%d",
+ rawsock->memSize,
+ rawsock->blockCount,
+ rawsock->blockSize,
+ rawsock->sock);
+ rawsock->pMem = mmap((void*)0, rawsock->memSize, PROT_READ|PROT_WRITE, MAP_SHARED, rawsock->sock, (off_t)0);
+ if (rawsock->pMem == (void*)(-1)) {
+ AVB_LOGF_ERROR("Creating rawsock; MMAP: %s", strerror(errno));
+ ringRawsockClose(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+ AVB_LOGF_DEBUG("mmap: %p", rawsock->pMem);
+
+ // Initialize the memory
+ memset(rawsock->pMem, 0, rawsock->memSize);
+
+ // Initialize the state of the ring
+ rawsock->blockIndex = 0;
+ rawsock->bufferIndex = 0;
+ rawsock->buffersOut = 0;
+ rawsock->buffersReady = 0;
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return rawsock;
+}
+
+// Close the rawsock
+void ringRawsockClose(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock;
+
+ if (rawsock) {
+ // free ring memory
+ if (rawsock->pMem != (void*)(-1)) {
+ munmap(rawsock->pMem, rawsock->memSize);
+ rawsock->pMem = (void*)(-1);
+ }
+
+ simpleRawsockClose(pvRawsock);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+}
+
+// Get a buffer from the ring to use for TX
+U8* ringRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock;
+
+ // Displays only warning when buffer busy after second try
+ int bBufferBusyReported = 0;
+
+
+ if (!VALID_TX_RAWSOCK(rawsock) || len == NULL) {
+ 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;
+ }
+
+ // Get pointer to next framebuf.
+ volatile struct tpacket2_hdr *pHdr =
+ (struct tpacket2_hdr*)(rawsock->pMem
+ + (rawsock->blockIndex * rawsock->blockSize)
+ + (rawsock->bufferIndex * rawsock->bufferSize));
+ // 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",
+ rawsock->blockIndex, rawsock->bufferIndex, rawsock->buffersOut,
+ pHdr, pBuffer);
+
+ // Check if buffer ready for user
+ // In send mode, we want to see TP_STATUS_AVAILABLE
+ while (pHdr->tp_status != TP_STATUS_AVAILABLE)
+ {
+ switch (pHdr->tp_status) {
+ case TP_STATUS_SEND_REQUEST:
+ case TP_STATUS_SENDING:
+ if (blocking) {
+#if 0
+// We should be able to poll on the socket to wait for the buffer to
+// be ready, but it doesn't work (at least on 2.6.37).
+// Keep this code, because it may work on newer kernels
+ // poll until tx buffer is ready
+ struct pollfd pfd;
+ pfd.fd = rawsock->sock;
+ pfd.events = POLLWRNORM;
+ pfd.revents = 0;
+ int ret = poll(&pfd, 1, -1);
+ if (ret < 0 && errno != EINTR) {
+ AVB_LOGF_DEBUG("getting TX frame; poll failed: %s", strerror(errno));
+ }
+#else
+ // Can't poll, so sleep instead to avoid tight loop
+ if(0 == bBufferBusyReported) {
+ if(!rawsock->txOutOfBuffer) {
+ // Display this info only once just to let know that something like this happened
+ AVB_LOGF_INFO("Getting TX frame (sock=%d): TX buffer busy", rawsock->sock);
+ }
+
+ ++rawsock->txOutOfBuffer;
+ ++rawsock->txOutOfBufferCyclic;
+ } else if(1 == bBufferBusyReported) {
+ //Display this warning if buffer was busy more than once because it might influence late/lost
+ AVB_LOGF_WARNING("Getting TX frame (sock=%d): TX buffer busy after usleep(50) verify if there are any lost/late frames", rawsock->sock);
+ }
+
+ ++bBufferBusyReported;
+
+ usleep(50);
+#endif
+ }
+ else {
+ AVB_LOG_DEBUG("Non-blocking, return NULL");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+ break;
+ case TP_STATUS_WRONG_FORMAT:
+ default:
+ pHdr->tp_status = TP_STATUS_AVAILABLE;
+ break;
+ }
+ }
+
+ // Remind client how big the frame buffer is
+ if (len)
+ *len = rawsock->base.frameSize;
+
+ // increment indexes to point to next buffer
+ if (++(rawsock->bufferIndex) >= (rawsock->frameCount/rawsock->blockCount)) {
+ rawsock->bufferIndex = 0;
+ if (++(rawsock->blockIndex) >= rawsock->blockCount) {
+ rawsock->blockIndex = 0;
+ }
+ }
+
+ // increment the count of buffers held by client
+ rawsock->buffersOut += 1;
+
+ // warn if too many are out
+ if (rawsock->buffersOut >= (rawsock->frameCount * 4)/5) {
+ AVB_LOGF_WARNING("Getting TX frame; consider increasing buffers: count=%d, out=%d",
+ rawsock->frameCount, rawsock->buffersOut);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return (U8*)pBuffer;
+}
+
+// Release a TX frame, without marking it as ready to send
+bool ringRawsockRelTxFrame(void *pvRawsock, U8 *pBuffer)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock;
+ if (!VALID_TX_RAWSOCK(rawsock) || pBuffer == NULL) {
+ AVB_LOG_ERROR("Releasing TX frame; invalid argument");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ volatile struct tpacket2_hdr *pHdr = (struct tpacket2_hdr*)(pBuffer - rawsock->bufHdrSize);
+ AVB_LOGF_VERBOSE("pBuffer=%p, pHdr=%p", pBuffer, pHdr);
+
+ pHdr->tp_len = 0;
+ pHdr->tp_status = TP_STATUS_KERNEL;
+ rawsock->buffersOut -= 1;
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return TRUE;
+}
+
+// Release a TX frame, and mark it as ready to send
+bool ringRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock;
+
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Marking TX frame ready; invalid argument");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ volatile struct tpacket2_hdr *pHdr = (struct tpacket2_hdr*)(pBuffer - rawsock->bufHdrSize);
+ AVB_LOGF_VERBOSE("pBuffer=%p, pHdr=%p szFrame=%d, len=%d", pBuffer, pHdr, rawsock->base.frameSize, len);
+
+ assert(len <= rawsock->bufferSize);
+ pHdr->tp_len = len;
+ pHdr->tp_status = TP_STATUS_SEND_REQUEST;
+ rawsock->buffersReady += 1;
+
+ if (rawsock->buffersReady >= rawsock->frameCount) {
+ AVB_LOG_WARNING("All buffers in ready/unsent state, calling send");
+ ringRawsockSend(pvRawsock);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return TRUE;
+}
+
+// Send all packets that are ready (i.e. tell kernel to send them)
+int ringRawsockSend(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock;
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Send; invalid argument");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return -1;
+ }
+
+ // Linux does something dumb to wait for frames to be sent.
+ // Without MSG_DONTWAIT, CPU usage is bad.
+ int flags = MSG_DONTWAIT;
+ int sent = send(rawsock->sock, NULL, 0, flags);
+ if (errno == EINTR) {
+ // ignore
+ }
+ else if (sent < 0) {
+ AVB_LOGF_ERROR("Send failed: %s", strerror(errno));
+ assert(0);
+ }
+ else {
+ AVB_LOGF_VERBOSE("Sent %d bytes, %d frames", sent, rawsock->buffersReady);
+ rawsock->buffersOut -= rawsock->buffersReady;
+ rawsock->buffersReady = 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return sent;
+}
+
+// Count used TX buffers in ring
+int ringRawsockTxBufLevel(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock;
+
+ int buffersPerBlock = rawsock->blockSize / rawsock->bufferSize;
+
+ int iBlock, iBuffer, nInUse = 0;
+ volatile struct tpacket2_hdr *pHdr;
+
+ if (!VALID_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("getting buffer level; invalid arguments");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ for (iBlock = 0; iBlock < rawsock->blockCount; iBlock++) {
+ for (iBuffer = 0; iBuffer < buffersPerBlock; iBuffer++) {
+
+ pHdr = (struct tpacket2_hdr*)(rawsock->pMem
+ + (iBlock * rawsock->blockSize)
+ + (iBuffer * rawsock->bufferSize));
+
+ if (rawsock->base.txMode) {
+ if (pHdr->tp_status == TP_STATUS_SEND_REQUEST
+ || pHdr->tp_status == TP_STATUS_SENDING)
+ nInUse++;
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return nInUse;
+}
+
+
+// Count used TX buffers in ring
+int ringRawsockRxBufLevel(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock;
+
+ int buffersPerBlock = rawsock->blockSize / rawsock->bufferSize;
+
+ int iBlock, iBuffer, nInUse = 0;
+ volatile struct tpacket2_hdr *pHdr;
+
+ if (!VALID_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("getting buffer level; invalid arguments");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ for (iBlock = 0; iBlock < rawsock->blockCount; iBlock++) {
+ for (iBuffer = 0; iBuffer < buffersPerBlock; iBuffer++) {
+
+ pHdr = (struct tpacket2_hdr*)(rawsock->pMem
+ + (iBlock * rawsock->blockSize)
+ + (iBuffer * rawsock->bufferSize));
+
+ if (!rawsock->base.txMode) {
+ if (pHdr->tp_status & TP_STATUS_USER)
+ nInUse++;
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return nInUse;
+}
+
+// Get a RX frame
+U8* ringRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ ring_rawsock_t *rawsock = (ring_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;
+ }
+ if (rawsock->buffersOut >= rawsock->frameCount) {
+ AVB_LOG_ERROR("Too many RX buffers in use");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+
+ // Get pointer to active buffer in ring
+ volatile struct tpacket2_hdr *pHdr =
+ (struct tpacket2_hdr*)(rawsock->pMem
+ + (rawsock->blockIndex * rawsock->blockSize)
+ + (rawsock->bufferIndex * rawsock->bufferSize));
+ volatile U8 *pBuffer = (U8*)pHdr + rawsock->bufHdrSize;
+
+ AVB_LOGF_VERBOSE("block=%d, buffer=%d, out=%d, pHdr=%p, pBuffer=%p",
+ rawsock->blockIndex, rawsock->bufferIndex, rawsock->buffersOut,
+ pHdr, pBuffer);
+
+ // Check if buffer ready for user
+ // In receive mode, we want TP_STATUS_USER flag set
+ if ((pHdr->tp_status & TP_STATUS_USER) == 0)
+ {
+ struct timespec ts, *pts = NULL;
+ struct pollfd pfd;
+
+ // Use poll to wait for "ready to read" condition
+
+ // Poll even if our timeout is 0 - to catch the case where
+ // kernel is writing to the wrong slot (see below.)
+ if (timeout != OPENAVB_RAWSOCK_BLOCK) {
+ ts.tv_sec = timeout / MICROSECONDS_PER_SECOND;
+ ts.tv_nsec = (timeout % MICROSECONDS_PER_SECOND) * NANOSECONDS_PER_USEC;
+ pts = &ts;
+ }
+
+ pfd.fd = rawsock->sock;
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+
+ int ret = ppoll(&pfd, 1, pts, NULL);
+ if (ret < 0) {
+ if (errno != EINTR) {
+ AVB_LOGF_ERROR("Getting RX frame; poll failed: %s", strerror(errno));
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+ if ((pfd.revents & POLLIN) == 0) {
+ // timeout
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+
+ if ((pHdr->tp_status & TP_STATUS_USER) == 0) {
+ // Hmmm, this is unexpected. poll indicated that the
+ // socket was ready to read, but the slot in the TX ring
+ // that we're looking for the kernel to fill isn't filled.
+
+ // If there aren't any RX buffers held by the application,
+ // we can try to fix this sticky situation...
+ if (rawsock->buffersOut == 0) {
+ // Scan forward through the RX ring, and look for a
+ // buffer that's ready for us to read. The kernel has
+ // a bad habit of not starting at the beginning of the
+ // ring when the listener process is restarted.
+ int nSkipped = 0;
+ while((pHdr->tp_status & TP_STATUS_USER) == 0) {
+ // Move to next slot in ring.
+ // (Increment buffer/block indexes)
+ if (++(rawsock->bufferIndex) >= (rawsock->frameCount/rawsock->blockCount)) {
+ rawsock->bufferIndex = 0;
+ if (++(rawsock->blockIndex) >= rawsock->blockCount) {
+ rawsock->blockIndex = 0;
+ }
+ }
+
+ // Adjust pHdr, pBuffer to point to the new slot
+ pHdr = (struct tpacket2_hdr*)(rawsock->pMem
+ + (rawsock->blockIndex * rawsock->blockSize)
+ + (rawsock->bufferIndex * rawsock->bufferSize));
+ pBuffer = (U8*)pHdr + rawsock->bufHdrSize;
+
+ // If we've scanned all the way around the ring, bail out.
+ if (++nSkipped > rawsock->frameCount) {
+ AVB_LOG_WARNING("Getting RX frame; no frame after poll");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+ }
+
+ // We found a slot that's ready. Hopefully, we're good now.
+ AVB_LOGF_WARNING("Getting RX frame; skipped %d empty slots (rawsock=%p)", nSkipped, rawsock);
+ }
+ else {
+ AVB_LOG_WARNING("Getting RX frame; no frame after poll");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+ }
+ }
+
+ AVB_LOGF_VERBOSE("Buffer status=0x%4.4lx", (unsigned long)pHdr->tp_status);
+ if (pHdr->tp_status & TP_STATUS_COPY) {
+ AVB_LOG_WARNING("Frame too big for receive buffer");
+ }
+
+ // Check the "losing" flag. That indicates that the ring is full,
+ // and the kernel had to toss some frames. There is no "winning" flag.
+ if ((pHdr->tp_status & TP_STATUS_LOSING)) {
+ if (!rawsock->bLosing) {
+ AVB_LOG_WARNING("Getting RX frame; mmap buffers full");
+ rawsock->bLosing = TRUE;
+ }
+ }
+ else {
+ rawsock->bLosing = FALSE;
+ }
+
+ // increment indexes for next time
+ if (++(rawsock->bufferIndex) >= (rawsock->frameCount/rawsock->blockCount)) {
+ rawsock->bufferIndex = 0;
+ if (++(rawsock->blockIndex) >= rawsock->blockCount) {
+ rawsock->blockIndex = 0;
+ }
+ }
+
+ // Remember that the client has another buffer
+ rawsock->buffersOut += 1;
+
+ if (pHdr->tp_snaplen < pHdr->tp_len) {
+ IF_LOG_INTERVAL(1000) AVB_LOGF_WARNING("Getting RX frame; partial frame ignored (len %d, snaplen %d)", pHdr->tp_len, pHdr->tp_snaplen);
+ ringRawsockRelRxFrame(rawsock, (U8*)pBuffer);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+
+ // Return pointer to the buffer and length
+ *offset = pHdr->tp_mac - rawsock->bufHdrSize;
+ *len = pHdr->tp_snaplen;
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return (U8*)pBuffer;
+}
+
+// Parse the ethernet frame header. Returns length of header, or -1 for failure
+int ringRawsockRxParseHdr(void *pvRawsock, U8 *pBuffer, hdr_info_t *pInfo)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock;
+ int hdrLen;
+ if (!VALID_RX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Parsing Ethernet headers; invalid arguments");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return -1;
+ }
+
+ volatile struct tpacket2_hdr *pHdr = (struct tpacket2_hdr*)(pBuffer - rawsock->bufHdrSize);
+ AVB_LOGF_VERBOSE("pBuffer=%p, pHdr=%p", pBuffer, pHdr);
+
+ memset(pInfo, 0, sizeof(hdr_info_t));
+
+ eth_hdr_t *pNoTag = (eth_hdr_t*)((U8*)pHdr + pHdr->tp_mac);
+ hdrLen = pHdr->tp_net - pHdr->tp_mac;
+ pInfo->shost = pNoTag->shost;
+ pInfo->dhost = pNoTag->dhost;
+ pInfo->ethertype = ntohs(pNoTag->ethertype);
+
+ if (pInfo->ethertype == ETHERTYPE_8021Q) {
+ pInfo->vlan = TRUE;
+ pInfo->vlan_vid = pHdr->tp_vlan_tci & 0x0FFF;
+ pInfo->vlan_pcp = (pHdr->tp_vlan_tci >> 13) & 0x0007;
+ pInfo->ethertype = ntohs(*(U16*)( ((U8*)(&pNoTag->ethertype)) + 4));
+ hdrLen += 4;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return hdrLen;
+}
+
+// Release a RX frame held by the client
+bool ringRawsockRelRxFrame(void *pvRawsock, U8 *pBuffer)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock;
+
+ if (!VALID_RX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Releasing RX frame; invalid arguments");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ volatile struct tpacket2_hdr *pHdr = (struct tpacket2_hdr*)(pBuffer - rawsock->bufHdrSize);
+ AVB_LOGF_VERBOSE("pBuffer=%p, pHdr=%p", pBuffer, pHdr);
+
+ pHdr->tp_status = TP_STATUS_KERNEL;
+ rawsock->buffersOut -= 1;
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return TRUE;
+}
+
+unsigned long ringRawsockGetTXOutOfBuffers(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ unsigned long counter = 0;
+ ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock;
+
+ if(VALID_TX_RAWSOCK(rawsock)) {
+ counter = rawsock->txOutOfBuffer;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return counter;
+}
+
+unsigned long ringRawsockGetTXOutOfBuffersCyclic(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ unsigned long counter = 0;
+ ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock;
+
+ if(VALID_TX_RAWSOCK(rawsock)) {
+ counter = rawsock->txOutOfBufferCyclic;
+ rawsock->txOutOfBufferCyclic = 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return counter;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.h b/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.h
new file mode 100644
index 00000000..92117f84
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.h
@@ -0,0 +1,115 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 RING_RAWSOCK_H
+#define RING_RAWSOCK_H
+
+#include "rawsock_impl.h"
+
+// State information for raw socket
+//
+typedef struct {
+ base_rawsock_t base;
+
+ // the underlying socket
+ int sock;
+
+ // number of frames that the ring can hold
+ int frameCount;
+
+ // size of the header prepended to each frame buffer
+ int bufHdrSize;
+ // size of the frame buffer (frameSize + bufHdrSize)
+ int bufferSize;
+
+ // memory for ring is allocated in blocks by kernel
+ int blockSize;
+ int blockCount;
+
+ // the memory for the ring
+ size_t memSize;
+ U8 *pMem;
+
+ // Active slot in the ring - tracked by
+ // block and buffer within that block.
+ int blockIndex, bufferIndex;
+
+ // Number of buffers held by client
+ int buffersOut;
+ // Buffers marked ready, but not yet sent
+ int buffersReady;
+
+ // Are we losing RX packets?
+ bool bLosing;
+
+ // Number of TX buffers we experienced problems with
+ unsigned long txOutOfBuffer;
+ // Number of TX buffers we experienced problems with from the time when last stats being displayed
+ unsigned long txOutOfBufferCyclic;
+} ring_rawsock_t;
+
+// Open a rawsock for TX or RX
+void* ringRawsockOpen(ring_rawsock_t *rawsock, const char *ifname, bool rx_mode, bool tx_mode, U16 ethertype, U32 frame_size, U32 num_frames);
+
+// Close the rawsock
+void ringRawsockClose(void *pvRawsock);
+
+// Get a buffer from the ring to use for TX
+U8* ringRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len);
+
+// Release a TX frame, without marking it as ready to send
+bool ringRawsockRelTxFrame(void *pvRawsock, U8 *pBuffer);
+
+// Release a TX frame, and mark it as ready to send
+bool ringRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len);
+
+// Send all packets that are ready (i.e. tell kernel to send them)
+int ringRawsockSend(void *pvRawsock);
+
+// Count used TX buffers in ring
+int ringRawsockTxBufLevel(void *pvRawsock);
+
+// Count used TX buffers in ring
+int ringRawsockRxBufLevel(void *pvRawsock);
+
+// Get a RX frame
+U8* ringRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len);
+
+// Parse the ethernet frame header. Returns length of header, or -1 for failure
+int ringRawsockRxParseHdr(void *pvRawsock, U8 *pBuffer, hdr_info_t *pInfo);
+
+// Release a RX frame held by the client
+bool ringRawsockRelRxFrame(void *pvRawsock, U8 *pBuffer);
+
+unsigned long ringRawsockGetTXOutOfBuffers(void *pvRawsock);
+
+unsigned long ringRawsockGetTXOutOfBuffersCyclic(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
new file mode 100644
index 00000000..257ce2cc
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.c
@@ -0,0 +1,467 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 "simple_rawsock.h"
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/if_packet.h>
+#include <linux/filter.h>
+
+#include "openavb_trace.h"
+
+#define AVB_LOG_COMPONENT "Raw Socket"
+#include "openavb_log.h"
+
+// Get information about an interface
+bool simpleAvbCheckInterface(const char *ifname, if_info_t *info)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+
+ if (!ifname || !info) {
+ AVB_LOG_ERROR("Checking interface; invalid arguments");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return FALSE;
+ }
+
+ // zap the result struct
+ memset(info, 0, sizeof(if_info_t));
+
+ AVB_LOGF_DEBUG("ifname=%s", ifname);
+ strncpy(info->name, ifname, IFNAMSIZ - 1);
+
+ // open a throw-away socket - used for our ioctls
+ int sk = socket(AF_INET, SOCK_STREAM, 0);
+ if (sk == -1) {
+ AVB_LOGF_ERROR("Checking interface; socket open failed: %s", strerror(errno));
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return FALSE;
+ }
+
+ // set the name of the interface in the ioctl request struct
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(struct ifreq));
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
+
+ // First check if the interface is up
+ // (also proves that the interface exists!)
+ int r = ioctl(sk, SIOCGIFFLAGS, &ifr);
+ if (r != 0) {
+ AVB_LOGF_ERROR("Checking interface; ioctl(SIOCGIFFLAGS) failed: %s", strerror(errno));
+ close(sk);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return FALSE;
+ }
+
+ if (!(ifr.ifr_flags&IFF_UP)) {
+ AVB_LOGF_ERROR("Checking interface; interface is not up: %s", ifname);
+ close(sk);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return FALSE;
+ }
+
+ // get index for interface
+ r = ioctl(sk, SIOCGIFINDEX, &ifr);
+ if (r != 0) {
+ AVB_LOGF_ERROR("Checking interface; ioctl(SIOCGIFINDEX) failed: %s", strerror(errno));
+ close(sk);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return FALSE;
+ }
+ info->index = ifr.ifr_ifindex;
+
+ // get the MAC address for the interface
+ r = ioctl(sk, SIOCGIFHWADDR, &ifr);
+ if (r != 0) {
+ AVB_LOGF_ERROR("Checking interface; ioctl(SIOCGIFHWADDR) failed: %s", strerror(errno));
+ close(sk);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return FALSE;
+ }
+ memcpy(&info->mac.ether_addr_octet, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ // get the MTU for the interface
+ r = ioctl(sk, SIOCGIFMTU, &ifr);
+ if (r != 0) {
+ AVB_LOGF_ERROR("Checking interface; ioctl(SIOCGIFMTU) failed: %s", strerror(errno));
+ close(sk);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return FALSE;
+ }
+ info->mtu = ifr.ifr_mtu;
+
+ // close the temporary socket
+ close(sk);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return TRUE;
+}
+
+// Open a rawsock for TX or RX
+void* simpleRawsockOpen(simple_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, rx=%d, tx=%d, ethertype=%x size=%d, num=%d", rx_mode, tx_mode, ethertype, frame_size, num_frames);
+
+ rawsock->sock = -1;
+ rawsock->base.rxMode = rx_mode;
+ rawsock->base.txMode = tx_mode;
+ rawsock->base.frameSize = frame_size;
+ rawsock->base.ethertype = ethertype;
+
+ // 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;
+ }
+ else if (rawsock->base.frameSize > rawsock->base.ifInfo.mtu) {
+ 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);
+
+ // 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));
+ simpleRawsockClose(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");
+ simpleRawsockClose(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));
+ simpleRawsockClose(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return rawsock;
+}
+
+// Close the rawsock
+void simpleRawsockClose(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ simple_rawsock_t *rawsock = (simple_rawsock_t*)pvRawsock;
+
+ if (rawsock) {
+ // close the socket
+ if (rawsock->sock != -1) {
+ close(rawsock->sock);
+ rawsock->sock = -1;
+ }
+ // free the state struct
+ free(rawsock);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+}
+
+// Get a buffer from the ring to use for TX
+U8* simpleRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ simple_rawsock_t *rawsock = (simple_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->txBuffer;
+
+ // 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 simpleRawsockTxSetMark(void *pvRawsock, int mark)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ simple_rawsock_t *rawsock = (simple_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 simpleRawsockTxSetHdr(void *pvRawsock, hdr_info_t *pHdr)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ simple_rawsock_t *rawsock = (simple_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("stcRawsockTxSetHdr; 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, and send it
+bool simpleRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ simple_rawsock_t *rawsock = (simple_rawsock_t*)pvRawsock;
+
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Marking TX frame ready; invalid argument");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ int flags = MSG_DONTWAIT;
+ send(rawsock->sock, pBuffer, len, flags);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return TRUE;
+}
+
+// Get a RX frame
+U8* simpleRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ simple_rawsock_t *rawsock = (simple_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;
+ }
+// if (rawsock->buffersOut >= rawsock->frameCount) {
+// 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 == -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;
+}
+
+// Parse the ethernet frame header. Returns length of header, or -1 for failure
+int simpleRawsockRxParseHdr(void *pvRawsock, U8 *pBuffer, hdr_info_t *pInfo)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+
+ 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);
+ int hdrLen = sizeof(eth_hdr_t);
+
+ if (pInfo->ethertype == ETHERTYPE_8021Q) {
+ pInfo->vlan = TRUE;
+ // TODO extract vlan_vid and vlan_pcp
+ hdrLen += 4;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return hdrLen;
+}
+
+// Setup the rawsock to receive multicast packets
+bool simpleRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[ETH_ALEN])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+
+ simple_rawsock_t *rawsock = (simple_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 simpleRawsockGetSocket(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ simple_rawsock_t *rawsock = (simple_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/simple_rawsock.h b/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.h
new file mode 100644
index 00000000..dacbceed
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.h
@@ -0,0 +1,85 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 SIMPLE_RAWSOCK_H
+#define SIMPLE_RAWSOCK_H
+
+#include "rawsock_impl.h"
+
+// State information for raw socket
+//
+typedef struct {
+ base_rawsock_t base;
+
+ // the underlying socket
+ int sock;
+
+ // buffer for sending frames
+ U8 txBuffer[1518];
+
+ // buffer for receiving frames
+ U8 rxBuffer[1518];
+} simple_rawsock_t;
+
+bool simpleAvbCheckInterface(const char *ifname, if_info_t *info);
+
+// Open a rawsock for TX or RX
+void* simpleRawsockOpen(simple_rawsock_t *rawsock, const char *ifname, bool rx_mode, bool tx_mode, U16 ethertype, U32 frame_size, U32 num_frames);
+
+// Close the rawsock
+void simpleRawsockClose(void *pvRawsock);
+
+// Get a buffer from the simple to use for TX
+U8* simpleRawsockGetTxFrame(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 simpleRawsockTxSetMark(void *pvRawsock, int mark);
+
+// Pre-set the ethernet header information that will be used on TX frames
+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);
+
+// Get a RX frame
+U8* simpleRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len);
+
+// Parse the ethernet frame header. Returns length of header, or -1 for failure
+int simpleRawsockRxParseHdr(void *pvRawsock, U8 *pBuffer, hdr_info_t *pInfo);
+
+// Setup the rawsock to receive multicast packets
+bool simpleRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[ETH_ALEN]);
+
+// Get the socket used for this rawsock; can be used for poll/select
+int simpleRawsockGetSocket(void *pvRawsock);
+
+#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
new file mode 100644
index 00000000..44d5b1c4
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c
@@ -0,0 +1,443 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 <unistd.h>
+#include <pthread.h>
+#include <signal.h>
+#include <dlfcn.h>
+#include "ini.h"
+
+#include "openavb_platform.h"
+
+#include "openavb_osal.h"
+#include "openavb_intf_pub.h"
+#include "openavb_map_pub.h"
+#include "openavb_trace.h"
+#include "openavb_rawsock.h"
+#include "openavb_mediaq.h"
+#include "openavb_tl.h"
+
+#define AVB_LOG_COMPONENT "Talker / Listener"
+#include "openavb_log.h"
+
+#define MATCH(A, B)(strcasecmp((A), (B)) == 0)
+#define MATCH_LEFT(A, B, C)(strncasecmp((A), (B), (C)) == 0)
+
+typedef struct {
+ tl_state_t *pTLState;
+ openavb_tl_cfg_t *pCfg;
+ openavb_tl_cfg_name_value_t *pNVCfg;
+} parse_ini_data_t;
+
+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 bool openMapLib(tl_state_t *pTLState)
+{
+// OpenAVB using static mapping plugins therefore don't attempt to open a library
+#if 0
+ // Opening library
+ if (pTLState->mapLib.libName) {
+ AVB_LOGF_INFO("Attempting to open library: %s", pTLState->mapLib.libName);
+ pTLState->mapLib.libHandle = dlopen(pTLState->mapLib.libName, RTLD_LAZY);
+ if (!pTLState->mapLib.libHandle) {
+ AVB_LOG_ERROR("Unable to open the mapping library.");
+ return FALSE;
+ }
+ }
+#endif
+
+ // Looking up function entry
+ if (!pTLState->mapLib.funcName) {
+ AVB_LOG_ERROR("Mapping initialize function not set.");
+ return FALSE;
+ }
+
+ char *error;
+ AVB_LOGF_INFO("Looking up symbol for function: %s", pTLState->mapLib.funcName);
+ if (pTLState->mapLib.libHandle) {
+ pTLState->cfg.pMapInitFn = dlsym(pTLState->mapLib.libHandle, pTLState->mapLib.funcName);
+ }
+ else {
+ pTLState->cfg.pMapInitFn = dlsym(RTLD_DEFAULT, pTLState->mapLib.funcName);
+ }
+ if ((error = dlerror()) != NULL) {
+ AVB_LOGF_ERROR("Mapping initialize function lookup error: %s.", error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool openIntfLib(tl_state_t *pTLState)
+{
+// OpenAVB using static interface plugins therefore don't attempt to open a library
+#if 0
+ // Opening library
+ if (pTLState->intfLib.libName) {
+ AVB_LOGF_INFO("Attempting to open library: %s", pTLState->intfLib.libName);
+ pTLState->intfLib.libHandle = dlopen(pTLState->intfLib.libName, RTLD_LAZY);
+ if (!pTLState->intfLib.libHandle) {
+ AVB_LOG_ERROR("Unable to open the interface library.");
+ return FALSE;
+ }
+ }
+#endif
+
+ // Looking up function entry
+ if (!pTLState->intfLib.funcName) {
+ AVB_LOG_ERROR("Interface initialize function not set.");
+ return FALSE;
+ }
+
+ char *error;
+ AVB_LOGF_INFO("Looking up symbol for function: %s", pTLState->intfLib.funcName);
+ if (pTLState->intfLib.libHandle) {
+ pTLState->cfg.pIntfInitFn = dlsym(pTLState->intfLib.libHandle, pTLState->intfLib.funcName);
+ }
+ else {
+ pTLState->cfg.pIntfInitFn = dlsym(RTLD_DEFAULT, pTLState->intfLib.funcName);
+ }
+ if ((error = dlerror()) != NULL) {
+ AVB_LOGF_ERROR("Interface initialize function lookup error: %s.", error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// callback function - called for each name/value pair by ini parsing library
+static int openavbTLCfgCallback(void *user, const char *tlSection, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ parse_ini_data_t *pParseIniData = (parse_ini_data_t *)user;
+ openavb_tl_cfg_t *pCfg = pParseIniData->pCfg;
+ openavb_tl_cfg_name_value_t *pNVCfg = pParseIniData->pNVCfg;
+ tl_state_t *pTLState = pParseIniData->pTLState;
+
+ AVB_LOGF_DEBUG("name=[%s] value=[%s]", name, value);
+
+ bool valOK = FALSE;
+ char *pEnd;
+ int i;
+
+ 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, "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, "ifname")) {
+ if_info_t ifinfo;
+ if (openavbCheckInterface(value, &ifinfo)) {
+ strncpy(pCfg->ifname, value, IFNAMSIZ - 1);
+ valOK = TRUE;
+ }
+ }
+
+ else if (MATCH(name, "map_lib")) {
+ if (pTLState->mapLib.libName)
+ free(pTLState->mapLib.libName);
+ pTLState->mapLib.libName = strdup(value);
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "map_fn")) {
+ if (pTLState->mapLib.funcName)
+ free(pTLState->mapLib.funcName);
+ pTLState->mapLib.funcName = strdup(value);
+ valOK = TRUE;
+ }
+
+ else if (MATCH(name, "intf_lib")) {
+ if (pTLState->intfLib.libName)
+ free(pTLState->intfLib.libName);
+ pTLState->intfLib.libName = strdup(value);
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "intf_fn")) {
+ if (pTLState->intfLib.funcName)
+ free(pTLState->intfLib.funcName);
+ pTLState->intfLib.funcName = strdup(value);
+ valOK = TRUE;
+ }
+
+ else if (MATCH_LEFT(name, "intf_nv_", 8)
+ || MATCH_LEFT(name, "map_nv_", 7)) {
+ // Need to save the interface and mapping module configuration
+ // until later (after those libraries are loaded.)
+
+ // check if this setting replaces an earlier one
+ for (i = 0; i < pNVCfg->nLibCfgItems; i++) {
+ if (MATCH(name, pNVCfg->libCfgNames[i])) {
+ if (pNVCfg->libCfgValues[i])
+ free(pNVCfg->libCfgValues[i]);
+ pNVCfg->libCfgValues[i] = strdup(value);
+ valOK = TRUE;
+ }
+ }
+ if (i >= pNVCfg->nLibCfgItems) {
+ // is a new name/value
+ if (i >= MAX_LIB_CFG_ITEMS) {
+ AVB_LOG_ERROR("Too many INI settings for interface/mapping modules");
+ }
+ else {
+ pNVCfg->libCfgNames[i] = strdup(name);
+ pNVCfg->libCfgValues[i] = strdup(value);
+ pNVCfg->nLibCfgItems++;
+ valOK = TRUE;
+ }
+ }
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: name=%s", name);
+ return 0;
+ }
+
+ if (!valOK) {
+ // bad value
+ AVB_LOGF_ERROR("Invalid value: name=%s, value=%s", name, value);
+ return 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+
+ return 1; // OK
+}
+
+bool openavbTLThreadFnOsal(tl_state_t *pTLState)
+{
+ return TRUE;
+}
+
+
+
+
+
+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);
+
+ parse_ini_data_t parseIniData;
+ parseIniData.pTLState = (tl_state_t *)TLhandle;
+ parseIniData.pCfg = pCfg;
+ parseIniData.pNVCfg = pNVCfg;
+
+ int result = ini_parse(fileName, openavbTLCfgCallback, &parseIniData);
+ if (result < 0) {
+ AVB_LOGF_ERROR("Couldn't parse INI file: %s", fileName);
+ return FALSE;
+ }
+ if (result > 0) {
+ AVB_LOGF_ERROR("Error in INI file: %s, line %d", fileName, result);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TRUE;
+}
+
+
+bool openavbTLOpenLinkLibsOsal(tl_state_t *pTLState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!pTLState->cfg.pMapInitFn) {
+ if (!openMapLib(pTLState)) {
+ return FALSE;
+ }
+ }
+
+ if (!pTLState->cfg.pIntfInitFn) {
+ if (!openIntfLib(pTLState)) {
+ return FALSE;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TRUE;
+}
+
+bool openavbTLCloseLinkLibsOsal(tl_state_t *pTLState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (pTLState->mapLib.libHandle)
+ dlclose(pTLState->mapLib.libHandle);
+ if (pTLState->intfLib.libHandle)
+ dlclose(pTLState->intfLib.libHandle);
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TRUE;
+}
+
+
diff --git a/lib/avtp_pipeline/platform/Linux/x86_i210_linux.cmake b/lib/avtp_pipeline/platform/Linux/x86_i210_linux.cmake
new file mode 100644
index 00000000..ae9ce67a
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/x86_i210_linux.cmake
@@ -0,0 +1,33 @@
+# and another kernel sources
+#set ( LINUX_KERNEL_DIR "/usr/src/kernel" )
+
+# build configuration
+set ( OPENAVB_HAL "x86_i210" )
+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/x86_i210/include
+ ${CMAKE_SOURCE_DIR}/../igb
+ ${CMAKE_SOURCE_DIR}/openavb_common
+ ${CMAKE_SOURCE_DIR}/../../daemons/common
+ ${CMAKE_SOURCE_DIR}/../../daemons/mrpd
+)
+
+set ( PLATFORM_LINK_DIRECTORIES
+ ${CMAKE_SOURCE_DIR}/../igb
+)
+
+set ( PLATFORM_LINK_LIBRARIES
+ igb
+)
+
+
+# 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/include/linux/ptp_clock.h b/lib/avtp_pipeline/platform/generic/include/linux/ptp_clock.h
new file mode 100644
index 00000000..b829d8dd
--- /dev/null
+++ b/lib/avtp_pipeline/platform/generic/include/linux/ptp_clock.h
@@ -0,0 +1,29 @@
+#ifndef _OPENAVB_GENERIC_LINUX_PTP_CLOCK_H
+#define _OPENAVB_GENERIC_LINUX_PTP_CLOCK_H
+
+#include "/usr/include/linux/ptp_clock.h"
+
+#ifndef ptpas_offset_request
+
+#warning "Adding missing PTP declarations, it is just to make everything compile, AVB stack will not work properly."
+
+struct ptpas_offset_request {
+ unsigned long long syncReceiptTime;
+ unsigned long long syncReceiptLocalTime;
+ unsigned int gmRateRatioPPB; // gmRateRatio in ppb
+ unsigned int gmSeqNumber; // an indication of the combination of clockID and clockIndex
+};
+
+struct ptpas_get_wallclock {
+ long tv_sec; /* seconds */
+ long tv_nsec; /* nanoseconds */
+ unsigned int gmRateRatioPPB; // gmRateRatio in ppm
+ unsigned int gmSeqNumber; // an indication of the combination of clockID and clockIndex
+};
+
+#define PTPAS_SET_OFFSET _IOW(PTP_CLK_MAGIC, 6, struct ptpas_offset_request)
+#define PTPAS_GET_WALLCLOCK _IOR(PTP_CLK_MAGIC, 7, struct ptpas_get_wallclock)
+
+#endif
+
+#endif // _OPENAVB_GENERIC_LINUX_PTP_CLOCK_H
diff --git a/lib/avtp_pipeline/platform/generic/openavb_hal.h b/lib/avtp_pipeline/platform/generic/openavb_hal.h
new file mode 100644
index 00000000..e48711eb
--- /dev/null
+++ b/lib/avtp_pipeline/platform/generic/openavb_hal.h
@@ -0,0 +1,37 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_HAL_H
+#define _OPENAVB_HAL_H
+
+// halPushMCR() API not defined
+#define HAL_PUSH_MCR(mcrTimeStampPtr) FALSE
+
+#endif // _OPENAVB_HAL_H
diff --git a/lib/avtp_pipeline/platform/platHAL/readme.txt b/lib/avtp_pipeline/platform/platHAL/readme.txt
new file mode 100644
index 00000000..52b2d136
--- /dev/null
+++ b/lib/avtp_pipeline/platform/platHAL/readme.txt
@@ -0,0 +1 @@
+Consider migration of HAL implements into this folder. \ No newline at end of file
diff --git a/lib/avtp_pipeline/platform/platOSAL/readme.txt b/lib/avtp_pipeline/platform/platOSAL/readme.txt
new file mode 100644
index 00000000..af269fcb
--- /dev/null
+++ b/lib/avtp_pipeline/platform/platOSAL/readme.txt
@@ -0,0 +1 @@
+Consider migration of OSAL implements into this folder. \ No newline at end of file
diff --git a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.c b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.c
new file mode 100644
index 00000000..deb113b9
--- /dev/null
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.c
@@ -0,0 +1,39 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 <malloc.h>
+
+void tcalGetHeapInfo(unsigned int *ttlMallocHeap, unsigned int *freeMallocHeap)
+{
+ struct mallinfo minfo = mallinfo();
+
+ *ttlMallocHeap = (minfo.arena + minfo.fordblks);
+ *freeMallocHeap = minfo.fordblks;
+}
diff --git a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.h b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.h
new file mode 100644
index 00000000..046ab971
--- /dev/null
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.h
@@ -0,0 +1,37 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_MEM_TCAL_H
+#define OPENAVB_MEM_TCAL_H 1
+
+void tcalGetHeapInfo(unsigned int *ttlMallocHeap, unsigned int *freeMallocHeap);
+
+#endif // OPENAVB_MEM_TCAL_H
+
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
new file mode 100644
index 00000000..b6d3b239
--- /dev/null
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal_pub.h
@@ -0,0 +1,38 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_MEM_TCAL_PUB_H
+#define OPENAVB_MEM_TCAL_PUB_H 1
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#endif // OPENAVB_MEM_TCAL_PUB_H
+
diff --git a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_tcal_pub.h b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_tcal_pub.h
new file mode 100644
index 00000000..f3bb489b
--- /dev/null
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_tcal_pub.h
@@ -0,0 +1,38 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_TCAL_PUB_H
+#define OPENAVB_TCAL_PUB_H 1
+
+// Logging Extra Newline. Some platforms libraries require an extra newline
+static const bool OPENAVB_TCAL_LOG_EXTRA_NEWLINE = TRUE;
+
+#endif // OPENAVB_TCAL_PUB_H
+
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
new file mode 100644
index 00000000..4afe007e
--- /dev/null
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_time_tcal_pub.h
@@ -0,0 +1,49 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_TIME_TCAL_PUB_H
+#define _OPENAVB_TIME_TCAL_PUB_H
+
+#if PROVIDED_BY_PLATFORM
+typedef int clockid_t;
+#endif
+
+#if PROVIDED_BY_PLATFORM
+struct timespec {
+ long tv_sec; /* seconds */
+ long tv_nsec; /* nanoseconds */
+};
+struct itimerspec {
+ struct timespec it_interval; /* timer period */
+ struct timespec it_value; /* timer expiration */
+};
+#endif
+
+#endif // _OPENAVB_TIME_TCAL_PUB_H
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
new file mode 100644
index 00000000..5f4da71e
--- /dev/null
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_types_base_tcal_pub.h
@@ -0,0 +1,40 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 AVB_TYPES_BASE_TCAL_PUB_H
+#define AVB_TYPES_BASE_TCAL_PUB_H 1
+
+#define OPENAVB_PRAGMA(arg) _Pragma(#arg)
+
+#define OPENAVB_CODE_FUNCTION_PRI
+#define OPENAVB_CODE_MODULE_PRI
+#define OPENAVB_DATA_PRI
+
+#endif // AVB_TYPES_BASE_TCAL_PUB_H
diff --git a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_warnings_tcal.h b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_warnings_tcal.h
new file mode 100644
index 00000000..637910a2
--- /dev/null
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_warnings_tcal.h
@@ -0,0 +1,37 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_WARNINGS_TCAL_H
+#define OPENAVB_WARNINGS_TCAL_H 1
+
+#define OPENAVB_SUPPRESS_WARNING_UNREACHABLE_CODE()
+
+#endif // OPENAVB_WARNINGS_TCAL_H
+
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
new file mode 100644
index 00000000..460cf50e
--- /dev/null
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/rawsock/openavb_rawsock_tcal.h
@@ -0,0 +1,59 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_RAWSOCK_TCAL_H
+#define OPENAVB_RAWSOCK_TCAL_H 1
+
+
+// Ethernet header
+typedef struct {
+ U8 dhost[ETH_ALEN];
+ U8 shost[ETH_ALEN];
+ uint16_t ethertype;
+}
+__attribute__ ((__packed__)) eth_hdr_t;
+
+// VLAN tag
+typedef struct {
+ uint16_t tpip;
+ uint16_t bits;
+}
+__attribute__ ((__packed__)) vlan_tag_t;
+
+// Ethernet header w/VLAN tag
+typedef struct {
+ U8 dhost[ETH_ALEN];
+ U8 shost[ETH_ALEN];
+ vlan_tag_t vlan;
+ uint16_t ethertype;
+}
+__attribute__ ((__packed__)) eth_vlan_hdr_t;
+
+#endif // OPENAVB_RAWSOCK_TCAL_H
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
new file mode 100644
index 00000000..5dee1f6f
--- /dev/null
+++ b/lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.c
@@ -0,0 +1,62 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 "MCR"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+#include "openavb_mcr_hal.h"
+
+
+bool halInitMCR(U32 packetRate, U32 pushInterval, U32 timestampInterval, U32 recoveryInterval)
+{
+ return TRUE;
+}
+
+bool halCloseMCR(void)
+{
+ return TRUE;
+}
+
+bool halPushMCR(void)
+{
+ return TRUE;
+}
+
+void halAdjustMCRNSec(S32 adjNSec)
+{
+}
+
+void halAdjustMCRGranularityNSec(U32 adjGranularityNSec)
+{
+}
+
+
+
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
new file mode 100644
index 00000000..a458b262
--- /dev/null
+++ b/lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.h
@@ -0,0 +1,37 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_MCR_HAL_H
+#define OPENAVB_MCR_HAL_H
+
+#include "openavb_platform.h"
+#include "openavb_mcr_hal_pub.h"
+
+#endif // OPENAVB_MCR_HAL_H
diff --git a/lib/avtp_pipeline/platform/x86_i210/openavb_ether_hal.c b/lib/avtp_pipeline/platform/x86_i210/openavb_ether_hal.c
new file mode 100644
index 00000000..fd57e263
--- /dev/null
+++ b/lib/avtp_pipeline/platform/x86_i210/openavb_ether_hal.c
@@ -0,0 +1,283 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_ether_hal.h"
+#include "openavb_osal.h"
+#include "avb.h"
+#include "igb.h"
+
+#define AVB_LOG_COMPONENT "HAL Ethernet"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+#include "openavb_trace.h"
+
+
+static pthread_mutex_t gIgbDeviceMutex = PTHREAD_MUTEX_INITIALIZER;
+#define LOCK() pthread_mutex_lock(&gIgbDeviceMutex)
+#define UNLOCK() pthread_mutex_unlock(&gIgbDeviceMutex)
+
+static struct igb_dma_alloc g_pages[IGB_PAGES];
+static struct igb_packet *g_free_packets;
+
+static device_t *igb_dev = NULL;
+static int igb_dev_users = 0; // time uses it
+
+static int g_totalBuffers = 0;
+static int g_usedBuffers = -1;
+
+static int count_packets(struct igb_packet *packet)
+{
+ int count=0;
+ while (packet) {
+ count++;
+ packet = packet->next;
+ }
+ return count;
+}
+
+static struct igb_packet* alloc_page(device_t* dev, struct igb_dma_alloc *a_page)
+{
+ int err = igb_dma_malloc_page(dev, a_page);
+ if (err) {
+ AVB_LOGF_ERROR("igb_dma_malloc_page failed: %s", strerror(err));
+ return NULL;
+ }
+
+ struct igb_packet *free_packets;
+ struct igb_packet a_packet;
+
+ a_packet.dmatime = a_packet.attime = a_packet.flags = 0;
+ a_packet.map.paddr = a_page->dma_paddr;
+ a_packet.map.mmap_size = a_page->mmap_size;
+ a_packet.offset = 0;
+ a_packet.vaddr = a_page->dma_vaddr + a_packet.offset;
+ a_packet.len = IGB_MTU;
+ a_packet.next = NULL;
+
+ free_packets = NULL;
+
+ /* divide the dma page into buffers for packets */
+ int i;
+ for (i = 0; i < a_page->mmap_size / IGB_MTU; i++) {
+ struct igb_packet *tmp_packet = malloc(sizeof(struct igb_packet));
+ if (!tmp_packet) {
+ AVB_LOG_ERROR("failed to allocate igb_packet memory!");
+ return false;
+ }
+ *tmp_packet = a_packet;
+ tmp_packet->offset = (i * IGB_MTU);
+ tmp_packet->vaddr += tmp_packet->offset;
+ tmp_packet->next = free_packets;
+ memset(tmp_packet->vaddr, 0, IGB_MTU);
+ free_packets = tmp_packet;
+ }
+ return free_packets;
+}
+
+device_t *igbAcquireDevice()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HAL_ETHER);
+
+ LOCK();
+ if (!igb_dev) {
+ device_t *tmp_dev = malloc(sizeof(device_t));
+ if (!tmp_dev) {
+ AVB_LOGF_ERROR("Cannot allocate memory for device: %s", strerror(errno));
+ goto unlock;
+ }
+
+ int err = pci_connect(tmp_dev);
+ if (err) {
+ AVB_LOGF_ERROR("connect failed (%s) - are you running as root?", strerror(err));
+ goto unlock;
+ }
+
+ err = igb_init(tmp_dev);
+ if (err) {
+ AVB_LOGF_ERROR("init failed (%s) - is the driver really loaded?", strerror(err));
+ igb_detach(tmp_dev);
+ goto unlock;
+ }
+
+
+ int i;
+ for (i = 0; i < IGB_PAGES; i++) {
+ struct igb_packet* free_packets = alloc_page(tmp_dev, &g_pages[i]);
+ if (!g_free_packets) {
+ g_free_packets = free_packets;
+ } else {
+ struct igb_packet* last_packet = g_free_packets;
+ while (last_packet->next) {
+ last_packet = last_packet->next;
+ }
+ last_packet->next = free_packets;
+ }
+ }
+
+ g_totalBuffers = count_packets(g_free_packets);
+
+ AVB_LOGF_INFO("TX buffers: %d", g_totalBuffers);
+
+ igbControlLaunchTime(tmp_dev, IGB_LAUNCHTIME_ENABLED);
+
+ AVB_LOGF_INFO("IGB launch time feature is %s", IGB_LAUNCHTIME_ENABLED ? "ENABLED" : "DISABLED");
+
+ igb_dev = tmp_dev;
+unlock:
+ if (!igb_dev)
+ free(tmp_dev);
+ }
+
+ if (igb_dev) {
+ igb_dev_users += 1;
+ AVB_LOGF_DEBUG("igb_dev_users %d", igb_dev_users);
+ }
+ UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+ return igb_dev;
+}
+
+void igbReleaseDevice(device_t* dev)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HAL_ETHER);
+
+ LOCK();
+
+ igb_dev_users -= 1;
+ AVB_LOGF_DEBUG("igb_dev_users %d", igb_dev_users);
+
+ if (igb_dev && igb_dev_users <= 0) {
+ int i;
+ for (i = 0; i < IGB_PAGES; i++)
+ igb_dma_free_page(igb_dev, &g_pages[i]);
+
+ igb_detach(igb_dev);
+ free(igb_dev);
+ igb_dev = NULL;
+ }
+
+ UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+}
+
+struct igb_packet *igbGetTxPacket(device_t* dev)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HAL_ETHER);
+
+ LOCK();
+
+ struct igb_packet* tx_packet = g_free_packets;
+
+ if (!tx_packet) {
+ struct igb_packet *cleaned_packets;
+ igb_clean(dev, &cleaned_packets);
+ while (cleaned_packets) {
+ struct igb_packet *tmp_packet = cleaned_packets;
+ cleaned_packets = cleaned_packets->next;
+ tmp_packet->next = g_free_packets;
+ g_free_packets = tmp_packet;
+ }
+ tx_packet = g_free_packets;
+
+ g_usedBuffers = g_totalBuffers - count_packets(g_free_packets);
+ }
+
+ if (tx_packet) {
+ g_free_packets = tx_packet->next;
+ }
+
+ UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+ return tx_packet;
+}
+
+void igbRelTxPacket(device_t* dev, int queue, struct igb_packet *tx_packet)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HAL_ETHER);
+
+ LOCK();
+
+ tx_packet->next = g_free_packets;
+ g_free_packets = tx_packet;
+
+ UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+}
+
+int igbTxBufLevel(device_t *dev)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HAL_ETHER);
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+ return g_usedBuffers;
+}
+
+bool igbGetMacAddr(U8 mac_addr[ETH_ALEN])
+{
+ int err = igb_get_mac_addr(igb_dev, mac_addr);
+ if (err) {
+ AVB_LOGF_ERROR("igb_get_mac_addr() failed: %s", strerror(err));
+ }
+ return !err;
+}
+
+bool igbControlLaunchTime(device_t *dev, int enable)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HAL_ETHER);
+
+ const uint32_t E1000_TQAVCTRL = 0x03570;
+ const uint32_t E1000_TQAVCTRL_LAUNCH_VALID = 0x00000200;
+
+ int err;
+ uint32_t regVal;
+
+ err = igb_lock(dev);
+ if (err)
+ goto error;
+
+ igb_readreg(dev, E1000_TQAVCTRL, &regVal);
+
+ if (enable)
+ regVal |= E1000_TQAVCTRL_LAUNCH_VALID;
+ else
+ regVal &= ~E1000_TQAVCTRL_LAUNCH_VALID;
+
+ igb_writereg(dev, E1000_TQAVCTRL, regVal);
+
+ err = igb_unlock(dev);
+
+error:
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+ return !err;
+}
+
diff --git a/lib/avtp_pipeline/platform/x86_i210/openavb_ether_hal.h b/lib/avtp_pipeline/platform/x86_i210/openavb_ether_hal.h
new file mode 100644
index 00000000..2ccc9db8
--- /dev/null
+++ b/lib/avtp_pipeline/platform/x86_i210/openavb_ether_hal.h
@@ -0,0 +1,60 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 HAL_ETHER_H
+#define HAL_ETHER_H 1
+
+#include "openavb_platform.h"
+#include "openavb_types_base.h"
+
+#include "igb.h"
+
+#define IGB_MTU 1522
+
+// how many pages to alloc for tx buffers (2 frames fit in one page)
+#define IGB_PAGES 20
+
+#define IGB_LAUNCHTIME_ENABLED 0
+
+device_t *igbAcquireDevice();
+
+void igbReleaseDevice(device_t *igb_dev);
+
+struct igb_packet *igbGetTxPacket(device_t* dev);
+
+void igbRelTxPacket(device_t* dev, int queue, struct igb_packet *tx_packet);
+
+int igbTxBufLevel(device_t *dev);
+
+bool igbGetMacAddr(U8 mac_addr[ETH_ALEN]);
+
+bool igbControlLaunchTime(device_t *dev, int enable);
+
+#endif // HAL_ETHER_H
diff --git a/lib/avtp_pipeline/platform/x86_i210/openavb_hal.h b/lib/avtp_pipeline/platform/x86_i210/openavb_hal.h
new file mode 100644
index 00000000..58d077a0
--- /dev/null
+++ b/lib/avtp_pipeline/platform/x86_i210/openavb_hal.h
@@ -0,0 +1,38 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_HAL_H
+#define _OPENAVB_HAL_H
+
+// Note this remains for backwards compatabilty with older prots. See openavb_mcr_hall_pub.h for newer APIs
+// halPushMCR() API not defined
+#define HAL_PUSH_MCR(mcrTimeStampPtr) FALSE
+
+#endif // _OPENAVB_HAL_H
diff --git a/lib/avtp_pipeline/platform/x86_i210/openavb_time_hal.c b/lib/avtp_pipeline/platform/x86_i210/openavb_time_hal.c
new file mode 100644
index 00000000..1a07a4bb
--- /dev/null
+++ b/lib/avtp_pipeline/platform/x86_i210/openavb_time_hal.c
@@ -0,0 +1,72 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_time_hal.h"
+#include "openavb_ether_hal.h"
+
+#include "openavb_trace.h"
+
+#define AVB_LOG_COMPONENT "halTime"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+static device_t *igb_dev = NULL;
+
+bool halTimeInitialize(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TIME);
+ igb_dev = igbAcquireDevice();
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return TRUE;
+}
+
+bool halTimeFinalize(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TIME);
+ igbReleaseDevice(igb_dev);
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return TRUE;
+}
+
+bool halTimeGetLocaltime(U64 *localTime64)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TIME);
+
+ if (igb_get_wallclock(igb_dev, localTime64, NULL ) > 0) {
+ IF_LOG_INTERVAL(1000) AVB_LOG_ERROR("Failed to get wallclock time");
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return TRUE;
+}
+
diff --git a/lib/avtp_pipeline/platform/x86_i210/openavb_time_hal.h b/lib/avtp_pipeline/platform/x86_i210/openavb_time_hal.h
new file mode 100644
index 00000000..9bd04048
--- /dev/null
+++ b/lib/avtp_pipeline/platform/x86_i210/openavb_time_hal.h
@@ -0,0 +1,38 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_TIME_HAL_H
+#define _OPENAVB_TIME_HAL_H
+
+bool halTimeInitialize(void);
+bool halTimeFinalize(void);
+bool halTimeGetLocaltime(U64 *localTime64);
+
+#endif // _OPENAVB_TIME_HAL_H
diff --git a/lib/avtp_pipeline/qmgr/CMakeLists.txt b/lib/avtp_pipeline/qmgr/CMakeLists.txt
new file mode 100644
index 00000000..ab919273
--- /dev/null
+++ b/lib/avtp_pipeline/qmgr/CMakeLists.txt
@@ -0,0 +1,5 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/qmgr/openavb_qmgr.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/qmgr/openavb_qmgr.c b/lib/avtp_pipeline/qmgr/openavb_qmgr.c
new file mode 100644
index 00000000..1dbd1db8
--- /dev/null
+++ b/lib/avtp_pipeline/qmgr/openavb_qmgr.c
@@ -0,0 +1,303 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : AVB Queue Manager
+ */
+
+#include <openavb_types.h>
+#include "openavb_ether_hal.h"
+#define AVB_LOG_COMPONENT "QMGR"
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
+#include "openavb_log.h"
+#include "openavb_trace.h"
+
+#include "openavb_qmgr.h"
+#include "avb_sched.h"
+#include "openavb_ether_hal.h"
+
+#define AVB_DEFAULT_QDISC_MODE AVB_SHAPER_HWQ_PER_CLASS
+
+// We have a singleton Qmgr, so we use file-static data here
+
+// Qdisc configuration
+typedef struct {
+ device_t *igb_dev;
+ int mode;
+ int ifindex;
+ char ifname[IFNAMSIZ];
+ U32 linkKbit;
+ U32 nsrKbit;
+ U32 linkMTU;
+ int ref;
+} qdisc_data_t;
+
+static qdisc_data_t qdisc_data;
+
+// We do get accessed from multiple threads, so need a mutex
+pthread_mutex_t qmgr_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+#define LOCK() pthread_mutex_lock(&qmgr_mutex)
+#define UNLOCK() pthread_mutex_unlock(&qmgr_mutex)
+
+// Information for each SR class
+typedef struct {
+ unsigned classBytesPerSec;
+} qmgrClass_t;
+
+// Information for each active stream
+typedef struct {
+ unsigned streamBytesPerSec;
+ unsigned classRate;
+ unsigned maxIntervalFrames;
+ unsigned maxFrameSize;
+} qmgrStream_t;
+
+// Arrays to hold info for classes and streams
+static qmgrClass_t qmgr_classes[MAX_AVB_SR_CLASSES];
+static qmgrStream_t qmgr_streams[MAX_AVB_STREAMS];
+
+// Make sure that the scheme we're using to encode the class/stream
+// into the fwmark will work! (we encode class and stream into 16-bits)
+#if MAX_AVB_STREAMS_PER_CLASS > (1 << TC_AVB_CLASS_SHIFT)
+#error MAX_AVB_STREAMS_PER_CLASS too large for FWMARK encoding
+#endif
+
+static bool setupHWQueue(int nClass, unsigned classBytesPerSec)
+{
+ int err = 0;
+ U32 class_a_bytes_per_sec, class_b_bytes_per_sec;
+
+ AVB_TRACE_ENTRY(AVB_TRACE_QUEUE_MANAGER);
+
+ if (nClass == SR_CLASS_A) {
+ class_a_bytes_per_sec = 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_b_bytes_per_sec = classBytesPerSec;
+ }
+
+ 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));
+
+ AVB_TRACE_EXIT(AVB_TRACE_QUEUE_MANAGER);
+ return !err;
+}
+
+/* Add a stream.
+ *
+ * nClass = index of class (A, B, etc.)
+ * classRate = class observation interval (8000, 4000, etc.)
+ * maxIntervalFrames = frames per interval
+ * maxFrameSize = max size of frames
+ *
+ */
+U16 openavbQmgrAddStream(SRClassIdx_t nClass, unsigned classRate, unsigned maxIntervalFrames, unsigned maxFrameSize)
+{
+ unsigned fullFrameSize = maxFrameSize + OPENAVB_AVTP_ETHER_FRAME_OVERHEAD;
+ unsigned long streamBytesPerSec = fullFrameSize * maxIntervalFrames * classRate;
+ int idx, nStream;
+ U16 fwmark = INVALID_FWMARK;
+
+ AVB_TRACE_ENTRY(AVB_TRACE_QUEUE_MANAGER);
+ LOCK();
+
+ AVB_LOGF_DEBUG("Adding stream; class=%d, rate=%u frames=%u, size=%u(%u), bytes/sec=%lu",
+ nClass, classRate, maxIntervalFrames, maxFrameSize,
+ fullFrameSize, streamBytesPerSec);
+
+ if ((int)nClass < 0 || nClass >= MAX_AVB_SR_CLASSES || streamBytesPerSec == 0) {
+ AVB_LOG_ERROR("Adding stream; invalid argument");
+ }
+ else {
+ // Find an unused stream in the appropriate SR class
+ for (nStream = 0, idx = nClass * MAX_AVB_STREAMS_PER_CLASS; nStream < MAX_AVB_STREAMS_PER_CLASS; nStream++, idx++) {
+ if (0 == qmgr_streams[idx].streamBytesPerSec) {
+ fwmark = TC_AVB_MARK(nClass, nStream);
+ break;
+ }
+ }
+
+ if (fwmark == INVALID_FWMARK) {
+ AVB_LOGF_ERROR("Adding stream; too many streams in class %d", nClass);
+ } else {
+
+ if (qdisc_data.mode != AVB_SHAPER_DISABLED) {
+ if (!setupHWQueue(nClass, qmgr_classes[nClass].classBytesPerSec + streamBytesPerSec)) {
+ fwmark = INVALID_FWMARK;
+ }
+ }
+
+ if (fwmark != INVALID_FWMARK) {
+ // good to go - update stream
+ qmgr_streams[idx].streamBytesPerSec = streamBytesPerSec;
+ qmgr_streams[idx].classRate = classRate;
+ qmgr_streams[idx].maxIntervalFrames = maxIntervalFrames;
+ qmgr_streams[idx].maxFrameSize = maxFrameSize;
+ // and class
+ qmgr_classes[nClass].classBytesPerSec += streamBytesPerSec;
+
+ AVB_LOGF_DEBUG("Added stream; classBPS=%u, streamBPS=%u", qmgr_classes[nClass].classBytesPerSec, qmgr_streams[idx].streamBytesPerSec);
+ }
+ }
+ }
+
+ UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_QUEUE_MANAGER);
+ return fwmark;
+}
+
+
+void openavbQmgrRemoveStream(U16 fwmark)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_QUEUE_MANAGER);
+
+ if (fwmark == INVALID_FWMARK) {
+ AVB_LOG_ERROR("Removing stream; invalid argument");
+ AVB_TRACE_EXIT(AVB_TRACE_QUEUE_MANAGER);
+ return;
+ }
+
+ int nClass = TC_AVB_MARK_CLASS(fwmark);
+ int nStream = TC_AVB_MARK_STREAM(fwmark);
+ int idx = nClass * MAX_AVB_STREAMS_PER_CLASS + nStream;
+
+ LOCK();
+
+ if (nStream < 0
+ || nStream >= MAX_AVB_STREAMS
+ || nClass < 0
+ || nClass >= MAX_AVB_SR_CLASSES
+ || qmgr_streams[idx].streamBytesPerSec == 0)
+ {
+ // something is wrong
+ AVB_LOG_ERROR("Removing stream; invalid argument or data");
+ }
+ else {
+ if (qdisc_data.mode != AVB_SHAPER_DISABLED) {
+ setupHWQueue(nClass, qmgr_classes[nClass].classBytesPerSec - qmgr_streams[idx].streamBytesPerSec);
+ }
+
+ // 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);
+ // and stream
+ memset(&qmgr_streams[idx], 0, sizeof(qmgrStream_t));
+ }
+
+ UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_QUEUE_MANAGER);
+}
+
+bool openavbQmgrInitialize(int mode, int ifindex, const char* ifname, unsigned mtu, unsigned link_kbit, unsigned nsr_kbit)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_QUEUE_MANAGER);
+ bool ret = FALSE;
+
+// if (!ifname || mtu == 0 || link_kbit == 0 || nsr_kbit == 0) {
+// AVB_LOG_ERROR("Initializing QMgr; invalid argument");
+// return FALSE;
+// }
+
+ LOCK();
+
+ if (qdisc_data.ref++ > 0) {
+ AVB_LOG_DEBUG("Already initialized");
+
+ UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_QUEUE_MANAGER);
+ return TRUE;
+ }
+
+ if (mode >= 0)
+ qdisc_data.mode = mode;
+ else
+ qdisc_data.mode = AVB_DEFAULT_QDISC_MODE;
+
+
+ AVB_LOGF_DEBUG("Initializing QMgr; mode=%d, idx=%d, mtu=%u, link_kbit=%u, nsr_kbit=%u",
+ qdisc_data.mode, ifindex, mtu, link_kbit, nsr_kbit);
+
+ if ( qdisc_data.mode != AVB_SHAPER_DISABLED
+ && (qdisc_data.igb_dev = igbAcquireDevice()) == 0)
+ {
+ AVB_LOG_ERROR("Initializing QMgr; unable to acquire igb device");
+ }
+ else
+ {
+ // Initialize data for classes and streams
+ memset(qmgr_classes, 0, sizeof(qmgr_classes));
+ memset(qmgr_streams, 0, sizeof(qmgr_streams));
+
+ // Save the configuration
+ if (ifname)
+ strncpy(qdisc_data.ifname, ifname, IFNAMSIZ - 1);
+ qdisc_data.ifindex = ifindex;
+ qdisc_data.linkKbit = link_kbit;
+ qdisc_data.linkMTU = mtu;
+ qdisc_data.nsrKbit = nsr_kbit;
+
+ if (qdisc_data.mode == AVB_SHAPER_DISABLED) {
+ ret = TRUE;
+ } else {
+ ret = TRUE;
+ // igb device aquired, nothing more to do
+ }
+ }
+
+ UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_QUEUE_MANAGER);
+ return ret;
+}
+
+void openavbQmgrFinalize(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_QUEUE_MANAGER);
+ LOCK();
+
+ if (--qdisc_data.ref == 0 && qdisc_data.mode != AVB_SHAPER_DISABLED) {
+ int nClass;
+ for (nClass = SR_CLASS_A; nClass < MAX_AVB_SR_CLASSES; nClass++) {
+ int nStream, idx;
+ for (nStream = 0, idx = nClass * MAX_AVB_STREAMS_PER_CLASS; nStream < MAX_AVB_STREAMS_PER_CLASS; nStream++, idx++) {
+ if (qmgr_streams[idx].streamBytesPerSec) {
+ U16 fwmark = TC_AVB_MARK(nClass, nStream);
+ openavbQmgrRemoveStream(fwmark);
+ }
+ }
+ }
+ igbReleaseDevice(qdisc_data.igb_dev);
+ qdisc_data.igb_dev = NULL;
+ }
+
+ UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_QUEUE_MANAGER);
+}
diff --git a/lib/avtp_pipeline/qmgr/openavb_qmgr.h b/lib/avtp_pipeline/qmgr/openavb_qmgr.h
new file mode 100644
index 00000000..8e67257d
--- /dev/null
+++ b/lib/avtp_pipeline/qmgr/openavb_qmgr.h
@@ -0,0 +1,95 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : The AVB Queue Manager sets up Linux network packet
+ * scheduling, so that transmitted Ethernet frames for an AVB stream
+ * are sent according to their SRP reservation.
+ */
+
+#ifndef AVB_QMGR_H
+#define AVB_QMGR_H 1
+
+#include "openavb_types.h"
+
+#define INVALID_FWMARK (U16)(-1)
+#define DEFAULT_FWMARK (U16)(1)
+
+#define FQTSS_MODE_DISABLED 0
+#define FQTSS_MODE_DROP_ALL 1
+#define FQTSS_MODE_ALL_NONSR 2
+#define FQTSS_MODE_DROP_SR 3
+#define FQTSS_MODE_SW 4
+#define FQTSS_MODE_HW_CLASS 5
+
+#ifdef AVB_FEATURE_FQTSS
+
+bool openavbQmgrInitialize(int mode,
+ int ifindex,
+ const char* ifname,
+ unsigned mtu,
+ unsigned link_kbit,
+ unsigned nsr_kbit);
+
+void openavbQmgrFinalize();
+
+U16 openavbQmgrAddStream(SRClassIdx_t nClass,
+ unsigned classRate,
+ unsigned maxIntervalFrames,
+ unsigned maxFrameSize);
+
+void openavbQmgrRemoveStream(U16 fwmark);
+
+#else
+/* Dummy versions to use if FQTSS is compiled out
+ */
+inline bool openavbQmgrInitialize(int mode,
+ int ifindex,
+ const char* ifname,
+ unsigned mtu,
+ unsigned link_kbit,
+ unsigned nsr_kbit)
+{ return TRUE; }
+
+inline void openavbQmgrFinalize()
+{}
+
+inline U16 openavbQmgrAddStream(SRClassIdx_t nClass,
+ unsigned classRate,
+ unsigned maxIntervalFrames,
+ unsigned maxFrameSize)
+{ return DEFAULT_FWMARK; }
+
+inline void openavbQmgrRemoveStream(U16 fwmark)
+
+{}
+#endif // AVB_FEATURE_FQTSS
+
+#endif // AVB_QMGR_H
diff --git a/lib/avtp_pipeline/rawsock/CMakeLists.txt b/lib/avtp_pipeline/rawsock/CMakeLists.txt
new file mode 100644
index 00000000..39c5c63c
--- /dev/null
+++ b/lib/avtp_pipeline/rawsock/CMakeLists.txt
@@ -0,0 +1,4 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/rawsock/rawsock_impl.c
+ PARENT_SCOPE
+)
diff --git a/lib/avtp_pipeline/rawsock/openavb_rawsock.h b/lib/avtp_pipeline/rawsock/openavb_rawsock.h
new file mode 100644
index 00000000..04671450
--- /dev/null
+++ b/lib/avtp_pipeline/rawsock/openavb_rawsock.h
@@ -0,0 +1,164 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : API for raw socket library.
+ */
+
+#ifndef RAWSOCK_H
+#define RAWSOCK_H 1
+
+#include "openavb_types.h"
+#include "openavb_osal.h"
+
+// Structure to hold information about a network interface
+typedef struct {
+ char name[IFNAMSIZ];
+ struct ether_addr mac;
+ int index;
+ int mtu;
+} if_info_t;
+
+// Get information about an interface
+// ifname - interface name
+// info - structure to be filled with info about iface
+bool openavbCheckInterface(const char *ifname, if_info_t *info);
+
+// Structure to hold fields from Ethernet header
+// Used to set information to be added to TX frames,
+// or to return info parsed from RX frames.
+typedef struct {
+ U8 *shost; // Source MAC address
+ U8 *dhost; // Destination MAC address
+ U16 ethertype; // Ethernet type (protocol)
+ bool vlan; // Include VLAN header?
+ U8 vlan_pcp; // VLAN Priority Code Point
+ U16 vlan_vid; // VLAN ID
+} hdr_info_t;
+
+
+// Open a raw socket, and setup circular buffer for sending or receiving frames.
+//
+// Returns rawsock handle which must be passed back to other rawsock library functions.
+//
+void *openavbRawsockOpen(const char *ifname, // network interface name to bind to
+ bool rx_mode, // TX mode flag
+ bool tx_mode, // RX mode flag
+ U16 ethertype, // Ethernet type (protocol)
+ U32 frame_size, // maximum size of frame to send/receive
+ U32 num_frames); // number of frames in the circular buffer
+
+// Set signal on RX mode
+void openavbSetRxSignalMode(void *rawsock, bool rxSignalMode);
+
+// Close the raw socket and release associated resources.
+void openavbRawsockClose(void *rawsock);
+
+// Get the socket used for this rawsock.
+// Client can use that socket for poll/select calls.
+int openavbRawsockGetSocket(void *rawsock);
+
+// Get the Ethernet address of the interface.
+// pBuf should point to "char buf[ETH_ALEN]"
+bool openavbRawsockGetAddr(void *rawsock, U8 addr[ETH_ALEN]);
+
+// Flags that can be passed to GetRxFrame instead of actual timeout values.
+#define OPENAVB_RAWSOCK_NONBLOCK (0)
+#define OPENAVB_RAWSOCK_BLOCK (-1)
+
+// RX FUNCTIONS
+//
+// Get a received frame.
+// Returns pointer to received frame, or NULL
+U8 *openavbRawsockGetRxFrame(void *rawsock, // rawsock handle
+ U32 usecTimeout, // timeout (microseconds)
+ // or use OPENAVB_RAWSOCK_BLOCK/NONBLOCK
+ U32 *offset, // offset of frame in the frame buffer
+ U32 *len); // returns length of received frame
+
+// Parse the frame header. Returns length of header, or -1 for failure
+int openavbRawsockRxParseHdr(void* rawsock, U8 *pBuffer, hdr_info_t *pInfo);
+
+// Release the received frame for re-use.
+bool openavbRawsockRelRxFrame(void *rawsock, U8 *pFrame);
+
+// Add (or drop) membership in link-layer multicast group
+bool openavbRawsockRxMulticast(void *rawsock, bool add_membership, const U8 buf[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 openavbRawsockRxAVTPSubtype(void *rawsock, U8 subtype);
+
+// TX FUNCTIONS
+//
+// Setup the header that we'll use on TX Ethernet frames.
+// Called once during intialization.
+bool openavbRawsockTxSetHdr(void *rawsock, hdr_info_t *pInfo);
+
+// Copy the pre-set Ethernet header into the frame
+bool openavbRawsockTxFillHdr(void *rawsock,
+ U8 *pBuffer,
+ U32 *hdrlen);
+
+// Set the SO_MARK option on the socket
+// (used to identify packets for FQTSS in kernel)
+bool openavbRawsockTxSetMark(void *rawsock, int prio);
+
+// Get a buffer to hold a frame for transmission.
+// Returns pointer to frame (or NULL).
+U8 *openavbRawsockGetTxFrame(void *rawsock, // rawsock handle
+ bool blocking, // TRUE blocks until frame buffer is available.
+ U32 *size); // size of the frame buffer
+
+// Release Tx buffer without sending it
+bool openavbRawsockRelTxFrame(void *rawsock, U8 *pBuffer);
+
+// Submit a frame and mark it "ready to send"
+bool openavbRawsockTxFrameReady(void *rawsock, // rawsock handle
+ U8 *pFrame, // pointer to frame buffer
+ U32 len); // length of frame to send
+
+// Send all packets that are marked "ready to send".
+// Returns count of bytes in sent frames - or < 0 for error.
+int openavbRawsockSend(void *rawsock);
+
+// Check Tx buffer level in sockets
+int openavbRawsockTxBufLevel(void *rawsock);
+
+// Check Rx buffer level in sockets
+int openavbRawsockRxBufLevel(void *rawsock);
+
+// returns number of TX out of buffer events noticed during streaming
+unsigned long openavbRawsockGetTXOutOfBuffers(void *pvRawsock);
+
+// returns number of TX out of buffer events noticed from the last reporting period
+unsigned long openavbRawsockGetTXOutOfBuffersCyclic(void *pvRawsock);
+
+#endif // RAWSOCK_H
diff --git a/lib/avtp_pipeline/rawsock/rawsock_impl.c b/lib/avtp_pipeline/rawsock/rawsock_impl.c
new file mode 100644
index 00000000..a8259ea7
--- /dev/null
+++ b/lib/avtp_pipeline/rawsock/rawsock_impl.c
@@ -0,0 +1,374 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 "rawsock_impl.h"
+#include "openavb_trace.h"
+
+#define AVB_LOG_COMPONENT "Raw Socket"
+#include "openavb_log.h"
+
+// Pre-set the ethernet header information that will be used on TX frames
+bool baseRawsockTxSetHdr(void *pvRawsock, hdr_info_t *pHdr)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Setting TX header; invalid argument");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ // source address
+ if (pHdr->shost) {
+ memcpy(&(rawsock->ethHdr.notag.shost), pHdr->shost, ETH_ALEN);
+ }
+ // destination address
+ if (pHdr->dhost) {
+ memcpy(&(rawsock->ethHdr.notag.dhost), pHdr->dhost, ETH_ALEN);
+ }
+
+ // VLAN tag?
+ if (!pHdr->vlan) {
+ // No, set ethertype in normal location
+ rawsock->ethHdr.notag.ethertype = htons(rawsock->ethertype);
+ // and set ethernet header length
+ rawsock->ethHdrLen = sizeof(eth_hdr_t);
+ }
+ else {
+ // Add VLAN tag
+ AVB_LOGF_DEBUG("VLAN=%d pcp=%d vid=%d", pHdr->vlan_vid, pHdr->vlan_pcp, pHdr->vlan_vid);
+
+ // Build bitfield with vlan_pcp and vlan_vid.
+ // I think CFI bit is alway 0
+ u_int16_t bits = 0;
+ bits |= (pHdr->vlan_pcp << 13) & 0xE000;
+ bits |= pHdr->vlan_vid & 0x0FFF;
+
+ // Create VLAN tag
+ rawsock->ethHdr.tagged.vlan.tpip = htons(ETHERTYPE_VLAN);
+ rawsock->ethHdr.tagged.vlan.bits = htons(bits);
+ rawsock->ethHdr.tagged.ethertype = htons(rawsock->ethertype);
+ // and set ethernet header length
+ rawsock->ethHdrLen = sizeof(eth_vlan_hdr_t);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return TRUE;
+}
+
+// Copy the pre-set header to the outgoing frame
+bool baseRawsockTxFillHdr(void *pvRawsock, U8 *pBuffer, unsigned int *hdrlen)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (!rawsock) {
+ AVB_LOG_ERROR("Filling TX header; invalid argument");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ // Copy the default Ethernet header into the buffer
+ if (hdrlen)
+ *hdrlen = rawsock->ethHdrLen;
+ memcpy((char*)pBuffer, &(rawsock->ethHdr), rawsock->ethHdrLen);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return TRUE;
+}
+
+// Get the ethernet address of the interface
+bool baseRawsockGetAddr(void *pvRawsock, U8 addr[ETH_ALEN])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (!rawsock) {
+ AVB_LOG_ERROR("Getting address; invalid arguments");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return FALSE;
+ }
+
+ memcpy(addr, &rawsock->ifInfo.mac.ether_addr_octet, ETH_ALEN);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void openavbSetRxSignalMode(void *pvRawsock, bool rxSignalMode)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.setRxSignalMode)
+ rawsock->cb.setRxSignalMode(pvRawsock, rxSignalMode);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+}
+
+void openavbRawsockClose(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.close)
+ rawsock->cb.close(pvRawsock);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+}
+
+U8 *openavbRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ U8 *ret = NULL;
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.getTxFrame)
+ ret = rawsock->cb.getTxFrame(pvRawsock, blocking, len);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return ret;
+}
+
+bool openavbRawsockTxSetMark(void *pvRawsock, int mark)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ bool ret = false;
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.txSetMark)
+ ret = rawsock->cb.txSetMark(pvRawsock, mark);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return ret;
+}
+
+bool openavbRawsockTxSetHdr(void *pvRawsock, hdr_info_t *pHdr)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ bool ret = false;
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.txSetHdr)
+ ret = rawsock->cb.txSetHdr(pvRawsock, pHdr);
+ else
+ ret = baseRawsockTxSetHdr(pvRawsock, pHdr);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return ret;
+}
+
+bool openavbRawsockTxFillHdr(void *pvRawsock, U8 *pBuffer, unsigned int *hdrlen)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ bool ret = false;
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.txFillHdr)
+ ret = rawsock->cb.txFillHdr(pvRawsock, pBuffer, hdrlen);
+ else
+ ret = baseRawsockTxFillHdr(pvRawsock, pBuffer, hdrlen);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return ret;
+}
+
+bool openavbRawsockRelTxFrame(void *pvRawsock, U8 *pBuffer)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ bool ret = false;
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.relTxFrame)
+ ret = rawsock->cb.relTxFrame(pvRawsock, pBuffer);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return ret;
+}
+
+bool openavbRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ bool ret = false;
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.txFrameReady)
+ ret = rawsock->cb.txFrameReady(pvRawsock, pBuffer, len);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return ret;
+}
+
+int openavbRawsockSend(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ int ret = -1;
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.send)
+ ret = rawsock->cb.send(pvRawsock);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return ret;
+}
+
+int openavbRawsockTxBufLevel(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ int ret = -1;
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.txBufLevel)
+ ret = rawsock->cb.txBufLevel(pvRawsock);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return ret;
+}
+
+int openavbRawsockRxBufLevel(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ int ret = -1;
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.rxBufLevel)
+ ret = rawsock->cb.rxBufLevel(pvRawsock);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return ret;
+}
+
+U8 *openavbRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ U8 *ret = NULL;
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.getRxFrame)
+ ret = rawsock->cb.getRxFrame(pvRawsock, timeout, offset, len);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return ret;
+}
+
+// Parse the ethernet frame header. Returns length of header, or -1 for failure
+int openavbRawsockRxParseHdr(void *pvRawsock, U8 *pBuffer, hdr_info_t *pInfo)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ int ret = -1;
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.rxParseHdr)
+ ret = rawsock->cb.rxParseHdr(pvRawsock, pBuffer, pInfo);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return ret;
+}
+
+// Release a RX frame held by the client
+bool openavbRawsockRelRxFrame(void *pvRawsock, U8 *pBuffer)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ bool ret = false;
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.relRxFrame)
+ ret = rawsock->cb.relRxFrame(pvRawsock, pBuffer);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return ret;
+}
+
+bool openavbRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[ETH_ALEN])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ bool ret = false;
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.rxMulticast)
+ ret = rawsock->cb.rxMulticast(pvRawsock, add_membership, addr);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return ret;
+}
+
+int openavbRawsockGetSocket(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ int ret = -1;
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.getSocket)
+ ret = rawsock->cb.getSocket(pvRawsock);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return ret;
+}
+
+bool openavbRawsockGetAddr(void *pvRawsock, U8 addr[ETH_ALEN])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ bool ret = false;
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.getAddr)
+ ret = rawsock->cb.getAddr(pvRawsock, addr);
+ else
+ ret = baseRawsockGetAddr(pvRawsock, addr);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return ret;
+}
+
+unsigned long openavbRawsockGetTXOutOfBuffers(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ unsigned long ret = 0;
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.getTXOutOfBuffers)
+ ret = rawsock->cb.getTXOutOfBuffers(pvRawsock);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return ret;
+}
+
+unsigned long openavbRawsockGetTXOutOfBuffersCyclic(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ unsigned long ret = 0;
+
+ base_rawsock_t *rawsock = (base_rawsock_t*)pvRawsock;
+ if (VALID_RAWSOCK(rawsock) && rawsock->cb.getTXOutOfBuffersCyclic)
+ ret = rawsock->cb.getTXOutOfBuffersCyclic(pvRawsock);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return ret;
+}
diff --git a/lib/avtp_pipeline/rawsock/rawsock_impl.h b/lib/avtp_pipeline/rawsock/rawsock_impl.h
new file mode 100644
index 00000000..3f207884
--- /dev/null
+++ b/lib/avtp_pipeline/rawsock/rawsock_impl.h
@@ -0,0 +1,122 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 RAWSOCK_IMPL_H
+#define RAWSOCK_IMPL_H
+
+#include "openavb_rawsock.h"
+
+// CORE TODO: This needs to be centralized; we have multiple defines for 0x8100 and some others like ETHERTYPE_AVTP
+#define ETHERTYPE_8021Q 0x8100
+
+// Ethernet header
+typedef struct {
+ U8 dhost[ETH_ALEN];
+ U8 shost[ETH_ALEN];
+ u_int16_t ethertype;
+} __attribute__ ((__packed__)) eth_hdr_t;
+
+// VLAN tag
+typedef struct {
+ u_int16_t tpip;
+ u_int16_t bits;
+} __attribute__ ((__packed__)) vlan_tag_t;
+
+// Ethernet header w/VLAN tag
+typedef struct {
+ U8 dhost[ETH_ALEN];
+ U8 shost[ETH_ALEN];
+ vlan_tag_t vlan;
+ u_int16_t ethertype;
+} __attribute__ ((__packed__)) eth_vlan_hdr_t;
+
+typedef struct {
+ void (*setRxSignalMode)(void* rawsock, bool rxSignalMode);
+ void (*close)(void* rawsock);
+ int (*getSocket)(void* rawsock);
+ bool (*getAddr)(void* rawsock, U8 addr[ETH_ALEN]);
+ U8* (*getRxFrame)(void* rawsock, U32 usecTimeout, U32* offset, U32* len);
+ int (*rxParseHdr)(void* rawsock, U8* pBuffer, hdr_info_t* pInfo);
+ bool (*relRxFrame)(void* rawsock, U8* pFrame);
+ bool (*rxMulticast)(void* rawsock, bool add_membership, const U8 buf[ETH_ALEN]);
+ bool (*rxAVTPSubtype)(void* rawsock, U8 subtype);
+ bool (*txSetHdr)(void* rawsock, hdr_info_t* pInfo);
+ bool (*txFillHdr)(void* rawsock, U8* pBuffer, U32* hdrlen);
+ bool (*txSetMark)(void* rawsock, int prio);
+ U8* (*getTxFrame)(void* rawsock, bool blocking, U32* size);
+ bool (*relTxFrame)(void* rawsock, U8* pBuffer);
+ bool (*txFrameReady)(void* rawsock, U8* pFrame, U32 len);
+ int (*send)(void* rawsock);
+ int (*txBufLevel)(void* rawsock);
+ int (*rxBufLevel)(void* rawsock);
+ unsigned long (*getTXOutOfBuffers)(void* pvRawsock);
+ unsigned long (*getTXOutOfBuffersCyclic)(void* pvRawsock);
+} rawsock_cb_t;
+
+// State information for raw socket
+//
+typedef struct base_rawsock {
+ // implementation callbacks
+ rawsock_cb_t cb;
+
+ // interface info
+ if_info_t ifInfo;
+
+ // saved Ethernet header for TX frames
+ union {
+ eth_hdr_t notag;
+ eth_vlan_hdr_t tagged;
+ } ethHdr;
+ unsigned ethHdrLen;
+
+ // Ethertype for TX/RX frames
+ unsigned ethertype;
+
+ // size of ethernet frame
+ int frameSize;
+
+ // TX usage of the socket
+ bool txMode;
+
+ // RX usage of the socket
+ bool rxMode;
+
+} base_rawsock_t;
+
+// Argument validation
+#define VALID_RAWSOCK(s) ((s) != NULL)
+#define VALID_TX_RAWSOCK(s) (VALID_RAWSOCK(s) && ((base_rawsock_t*)s)->txMode)
+#define VALID_RX_RAWSOCK(s) (VALID_RAWSOCK(s) && ((base_rawsock_t*)s)->rxMode)
+
+bool baseRawsockTxSetHdr(void *pvRawsock, hdr_info_t *pHdr);
+bool baseRawsockTxFillHdr(void *pvRawsock, U8 *pBuffer, unsigned int *hdrlen);
+bool baseRawsockGetAddr(void *pvRawsock, U8 addr[ETH_ALEN]);
+
+#endif // RAWSOCK_IMPL_H
diff --git a/lib/avtp_pipeline/sdk/CMakeLists.txt b/lib/avtp_pipeline/sdk/CMakeLists.txt
new file mode 100644
index 00000000..128b37c0
--- /dev/null
+++ b/lib/avtp_pipeline/sdk/CMakeLists.txt
@@ -0,0 +1,70 @@
+# Rules to build the SDK
+
+############
+# Install rules for the AVTP Interface Module SDK
+# Header files
+install ( FILES ../include/openavb_pub.h DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR} )
+install ( FILES ../include/openavb_types_pub.h DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR} )
+install ( FILES ../include/openavb_intf_pub.h DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR} )
+install ( FILES ../include/openavb_log_pub.h DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR} )
+install ( FILES ../include/openavb_trace_pub.h DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR} )
+install ( FILES ../include/openavb_platform_pub.h DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR} )
+install ( FILES ../mcr/openavb_mcr_hal_pub.h DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR} )
+install ( FILES ../mediaq/openavb_mediaq_pub.h DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR} )
+install ( FILES ../avtp/openavb_avtp_time_pub.h DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR} )
+install ( FILES ../map_mjpeg/openavb_map_mjpeg_pub.h DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR} )
+install ( FILES ../map_mpeg2ts/openavb_map_mpeg2ts_pub.h DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR} )
+install ( FILES ../map_null/openavb_map_null_pub.h DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR} )
+install ( FILES ../map_pipe/openavb_map_pipe_pub.h DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR} )
+install ( FILES ../intf_ctrl/openavb_intf_ctrl_pub.h DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR} )
+install ( FILES ../platform/${OPENAVB_OSAL}/openavb_osal_pub.h DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR} )
+install ( FILES ../platform/${OPENAVB_OSAL}/openavb_time_osal_pub.h DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR} )
+
+# Sample source files
+install ( FILES ../intf_echo/openavb_intf_echo.c DESTINATION ${SDK_INSTALL_SDK_INTF_MOD_DIR} )
+
+############
+# Install rules for the AVTP Mapping Module SDK
+# Header files
+install ( FILES ../include/openavb_pub.h DESTINATION ${SDK_INSTALL_SDK_MAP_MOD_DIR} )
+install ( FILES ../include/openavb_types_pub.h DESTINATION ${SDK_INSTALL_SDK_MAP_MOD_DIR} )
+install ( FILES ../include/openavb_map_pub.h DESTINATION ${SDK_INSTALL_SDK_MAP_MOD_DIR} )
+install ( FILES ../include/openavb_log_pub.h DESTINATION ${SDK_INSTALL_SDK_MAP_MOD_DIR} )
+install ( FILES ../include/openavb_trace_pub.h DESTINATION ${SDK_INSTALL_SDK_MAP_MOD_DIR} )
+install ( FILES ../mcr/openavb_mcr_hal_pub.h DESTINATION ${SDK_INSTALL_SDK_MAP_MOD_DIR} )
+install ( FILES ../mediaq/openavb_mediaq_pub.h DESTINATION ${SDK_INSTALL_SDK_MAP_MOD_DIR} )
+install ( FILES ../avtp/openavb_avtp_time_pub.h DESTINATION ${SDK_INSTALL_SDK_MAP_MOD_DIR} )
+install ( FILES ../map_mjpeg/openavb_map_mjpeg_pub.h DESTINATION ${SDK_INSTALL_SDK_MAP_MOD_DIR} )
+install ( FILES ../map_mpeg2ts/openavb_map_mpeg2ts_pub.h DESTINATION ${SDK_INSTALL_SDK_MAP_MOD_DIR} )
+install ( FILES ../map_null/openavb_map_null_pub.h DESTINATION ${SDK_INSTALL_SDK_MAP_MOD_DIR} )
+install ( FILES ../map_pipe/openavb_map_pipe_pub.h DESTINATION ${SDK_INSTALL_SDK_MAP_MOD_DIR} )
+
+# Sample source files
+install ( FILES ../map_null/openavb_map_null.c DESTINATION ${SDK_INSTALL_SDK_MAP_MOD_DIR} )
+
+
+############
+# Install rules for the EAVB SDK
+# Header files
+install ( FILES ../include/openavb_pub.h DESTINATION ${SDK_INSTALL_SDK_EAVB_DIR} )
+install ( FILES ../include/openavb_types_pub.h DESTINATION ${SDK_INSTALL_SDK_EAVB_DIR} )
+install ( FILES ../include/openavb_log_pub.h DESTINATION ${SDK_INSTALL_SDK_EAVB_DIR} )
+install ( FILES ../include/openavb_trace_pub.h DESTINATION ${SDK_INSTALL_SDK_EAVB_DIR} )
+install ( FILES ../tl/openavb_tl_pub.h DESTINATION ${SDK_INSTALL_SDK_EAVB_DIR} )
+install ( FILES ../mediaq/openavb_mediaq_pub.h DESTINATION ${SDK_INSTALL_SDK_EAVB_DIR} )
+install ( FILES ../platform/${OPENAVB_OSAL}/openavb_osal_pub.h DESTINATION ${SDK_INSTALL_SDK_EAVB_DIR} )
+install ( FILES ../platform/${OPENAVB_OSAL}/openavb_time_osal_pub.h DESTINATION ${SDK_INSTALL_SDK_EAVB_DIR} )
+install ( FILES ../include/openavb_platform_pub.h DESTINATION ${SDK_INSTALL_SDK_EAVB_DIR} )
+install ( FILES ../tl/openavb_tl_pub.h DESTINATION ${SDK_INSTALL_SDK_EAVB_DIR} )
+install ( FILES ../include/openavb_map_pub.h DESTINATION ${SDK_INSTALL_SDK_EAVB_DIR} )
+install ( FILES ../avtp/openavb_avtp_time_pub.h DESTINATION ${SDK_INSTALL_SDK_EAVB_DIR} )
+install ( FILES ../include/openavb_intf_pub.h DESTINATION ${SDK_INSTALL_SDK_EAVB_DIR} )
+
+# CORE_TODO: The avb host example could be moved to the OSAL.
+# Sample source files
+install ( FILES ../platform/Linux/avb_host/openavb_host.c DESTINATION ${SDK_INSTALL_SDK_EAVB_DIR} )
+
+# Add platform specific headers
+if ( EXISTS ${AVB_OSAL_DIR}/sdk/CMakeLists.txt )
+ add_subdirectory( ${AVB_OSAL_DIR}/sdk ${CMAKE_BINARY_DIR}/${OPENAVB_OSAL}/sdk )
+endif()
diff --git a/lib/avtp_pipeline/srp/openavb_srp.h b/lib/avtp_pipeline/srp/openavb_srp.h
new file mode 100755
index 00000000..e5d1471f
--- /dev/null
+++ b/lib/avtp_pipeline/srp/openavb_srp.h
@@ -0,0 +1,320 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 :
+*
+* Implementation of IEEE 802.1Q
+* Multiple Stream Reservation Protocol
+* (limited intial implementation for end stations)
+*
+* This file declares the "Private" portion - see also openavb_srp_api.h
+*/
+
+#ifndef OPENAVB_SRP_H
+#define OPENAVB_SRP_H
+
+#include "openavb_srp_api.h"
+//#include "openavb_srp_osal.h"
+#include "openavb_poll_osal.h"
+
+enum {
+ SRP_POLL_RAW_SOCK_FD = 0,
+ SRP_POLL_FD_COUNT // Must be the last entry.
+};
+
+// TBD - How often to [re]send (tx of the Applicant State Machine) - should be configurable
+#define OPENAVB_SRP_TX_PERIOD_SEC 10
+
+#define openavbSrp_PROTO_VERSION 0x00 // IEEE 802.1Q-2011 Section 35.2.2.3
+#define openavbSrp_ETHERTYPE 0x22EA // there should be a more general define for this someplace with other ether types
+
+// SR Class Id values are fixed. Priority (PCP) and VLAN Id values
+// have defaults specified, but should be configurable - TBD
+// Tables referenced here are per IEEE 802.1Q-2011
+// SR Class - SR Class Id - SR Class Priority - SR Class VID
+// - Table 35-7 Table 6-6 Table 9-2
+// A 6 3 2
+// B 5 2 2
+
+// SR Class IDs are defined here - used only in SRP messages
+#define SR_CLASS_A_ID 6
+#define SR_CLASS_B_ID 5
+
+// SR Class default Priority (PCP) values per IEEE 802.1Q-2011 Table 6-6
+#define SR_CLASS_A_DEFAULT_PRIORITY 3
+#define SR_CLASS_B_DEFAULT_PRIORITY 2
+// SR Class default VLAN Id values per IEEE 802.1Q-2011 Table 9-2
+#define SR_CLASS_A_DEFAULT_VID 2
+#define SR_CLASS_B_DEFAULT_VID 2
+
+// SR Class default delta bandwidth values per IEEE 802.1Q-2011 Section 34.3.1
+#define SR_CLASS_A_DEFAULT_DELTA_BW 75
+#define SR_CLASS_B_DEFAULT_DELTA_BW 0
+
+// SR Class Measurement Intervals / Frames Per Second
+// - see IEEE 802.1Q-2011 Sections 34.6.1 and 35.2.2.8.4 and Table 35-5
+// Class Class Measurement Interval Frames per Second
+// A 125 uSec 1 / .000125 = 8000
+// B 250 uSec 1 / .000250 = 4000
+#define SR_CLASS_A_FPS 8000
+#define SR_CLASS_B_FPS 4000
+
+
+// Ethernet Frame DA for openavbSrp packets is the
+// “Individual LAN Scope group address, Nearest Bridge group address” (per IEEE 802.1Q)
+static const U8 openavbSrpDA[ETH_MAC_ADDR_LEN] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x0E };
+
+enum openavbSrpAttributeLength { // IEEE 802.1Q-2011 Table 35-2
+ openavbSrp_AtLen_Lsnr = 0x08,
+ openavbSrp_AtLen_TlkrAdv = 0x19, // (= 25)
+ openavbSrp_AtLen_TlkrFld = 0x22, // (= 34)
+ openavbSrp_AtLen_Domain = 0x04
+};
+
+// openavbSrp Attribute Event (aka "ThreePacked Events") - IEEE 802.1Q-2011 Section 35.2.2.7.1
+typedef enum openavbSrpAtEvt {
+ openavbSrp_AtEvt_New = 0x00,
+ openavbSrp_AtEvt_JoinIn = 0x01,
+ openavbSrp_AtEvt_In = 0x02,
+ openavbSrp_AtEvt_JoinMt = 0x03,
+ openavbSrp_AtEvt_Mt = 0x04,
+ openavbSrp_AtEvt_Leave = 0x05,
+ openavbSrp_AtEvt_None
+} openavbSrpAtEvt_t;
+
+typedef struct openavbSrpSockInfo {
+ void* rawTxSock;
+ void* rawRxSock;
+ int RxSock;
+} openavbSrpSockInfo_t;
+
+typedef struct avtpCallbacks {
+ strmAttachCb_t attachCb;
+ strmRegCb_t registerCb;
+} avtpCallbacks_t;
+
+typedef struct SrClassParameters {
+ U8 priority;
+ U16 vid;
+ U32 operIdleSlope; // currently reserved bandwidth - bits per second
+ U32 deltaBandwidth; // %
+ // TBD - deltaBandwidth is supposed to be scaled by 1,000,000
+ // (100,000,000 == 100%), but it is NOT in this current implementation
+ U32 inverseIntervalSec; // 1/classMeasurementInterval (in seconds)
+} SrClassParameters_t;
+
+// Applicant State - IEEE 802.1Q Table 10-3
+// State here are simplified becasue:
+// - we are suppporting 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
+ openavbSrp_ApSt_AN = 0x01, // [at least] one new sent - one more pending
+ openavbSrp_ApSt_AA = 0x02, // [at least] one join sent - one more pending
+ openavbSrp_ApSt_QA = 0x03, // at least two new or join sent - none pending
+ openavbSrp_ApSt_LA = 0x04, // one leave sent - one more pending
+ openavbSrp_ApSt_VN = 0x05, // first new pending
+} openavbSrpAppState_t;
+
+// Registrar State - IEEE 802.1Q Table 10-4
+typedef enum openavbSrpRegState {
+ openavbSrp_RgSt_MT = 0x00, // Empty - note that we initialize to 0
+ openavbSrp_RgSt_LV = 0x01, // Leave
+ openavbSrp_RgSt_IN = 0x02, // In
+} openavbSrpRegState_t;
+
+
+// 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.
+// 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
+// because they are not thread-safe; the overall lists are mutex protected.
+//
+// On talker:
+// a list entry will exist only if the talker has a stream to declare
+// (or is in the process of withdrawing)
+// - declType is what this talker has most recently declared;
+// - declSubType is not used;
+// - regType / regSubType indicate what the talker has most recently received from
+// the listener(s), if anything;
+// - 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;
+// - kbpsReserved is the bandwidth currently reserved for the stream.
+//
+// On Listener:
+// a list entry will exist if the listener has either expressed interest in
+// receiving the stream (or is in the process of withdrawing interest) or has
+// received a talker declaration for the stream, or both.
+// - declType is what this listener has most recently declared (via
+// openavbSrpAttachStream()), if anything;
+// - declSubType is the listener declaration subtype, if any;
+// - regType indicates what talker declaration the listener has most recently
+// 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;
+// - SRClassIdx is derived from priority received in talker declaration packet;
+// - DA, tSpec, latency, and, if applicable, failInfo are
+// as received in talker declaration packet
+// - rank and kbpsReserved are not applicable on the listener;
+//
+typedef struct openavbSrpStrm {
+ struct openavbSrpStrm* prev;
+ struct openavbSrpStrm* next;
+ AVBStreamID_t strmId;
+ void* avtpHandle;
+ SRClassIdx_t SRClassIdx;
+ openavbSrpAttribType_t declType; // attribute type this station is declaring for this stream, if any;
+ // (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;
+ // not used on listener; valid only if regType == openavbSrp_AtTyp_Listener.
+ U8 DA[ETH_MAC_ADDR_LEN];
+ AVBTSpec_t tSpec;
+ U32 kbpsReserved;
+ bool rank;
+ U32 latency;
+ openavbSrpFailInfo_t failInfo;
+ openavbSrpAppState_t appState; // current applicant state of the stream on this station
+ openavbSrpRegState_t regState;
+} openavbSrpStrmElem_t;
+
+
+// SRP internal routines
+int openavbSrpGetIndexFromId (U8 SRClassId);
+void openavbSrpRemoveStrm (openavbSrpStrmElem_t** lstHead, openavbSrpStrmElem_t* pStream);
+openavbSrpStrmElem_t* openavbSrpFindOrCreateStrm (openavbSrpStrmElem_t** lstHead, AVBStreamID_t* streamId,
+ bool allowCreate, bool* created);
+void openavbSrpLogBw (void);
+void openavbSrpLogAllStreams (void);
+void openavbSrpRegState (openavbSrpAttribType_t atrbType);
+void openavbSrpCheckAsCapable (void);
+void openavbSrpCheckTalkerFailed(void);
+void openavbSrpResend (bool tx, openavbSrpAttribType_t atrbType);
+void* openavbSrpTxThread (void* notUsed);
+void* openavbSrpRcvThread (void* notUsed);
+openavbRC openavbSrpCheckStartLsnr (openavbSrpStrmElem_t* stream);
+openavbRC openavbSrpDomainSend (void);
+openavbRC openavbSrpSend (openavbSrpStrmElem_t* pStream, openavbSrpAtEvt_t atrbEvent);
+void openavbSrpReceive (U8* msrpdu, unsigned int pduLen);
+void openavbSrpCalcKbps (int SRClassIndex, AVBTSpec_t* tSpec, U32* kbps);
+openavbRC openavbSrpCheckAvlBw (int SRClassIndex, U32 kbps);
+openavbRC openavbSrpReserve (openavbSrpStrmElem_t* pStream);
+void openavbSrpRelease (openavbSrpStrmElem_t* pStream);
+
+openavbRC openavbSrpOpenPtpSharedMemory (void);
+void openavbSrpReleasePtpSharedMemory(void);
+bool openavbSrpAsCapable (void);
+
+int openavbSrpInitializePfd (OPENAVB_POLLFD_TYPE *pfd);
+
+// First Value content and size depend on the Declaration Type (openavbSrpAttribType_t)
+// see IEEE 802.1Q-2011 Section 35.2.2.8.1
+// (left column indicates byte index to start of parameter)
+// FirstValue ::=
+// 0 StreamID: 8 bytes
+// 0 [Src] MAC: 6 bytes (ETH_MAC_ADDR_LEN)
+// 6 UniqueID: 2 bytes, U16
+// end of the Listener attribute
+// 8 DataFrameParameters: 8 bytes
+// 8 DA: 6 bytes (ETH_MAC_ADDR_LEN)
+// 14 VID: 2 bytes
+// 16 TSpec: 4 bytes
+// 16 MaxFrameSize: 2 bytes, U16
+// 18 MaxIntervalFrames: 2 bytes, U16
+// 20 PriorityAndRank: 1 byte
+// 20 Priority: 3 bits
+// 20 Rank: 1 bit
+// 20 Reserved: 4 bits
+// 21 AccumulatedLatency: 4 bytes, U32
+// end of the Talker Advertise attribute
+// 25 FailureInformation: 9 bytes
+// 25 BridgeID: 8 bytes
+// 33 FailureCode: 1 byte
+// end of the Talker Failed attribute
+
+
+/* description of the limited MSRPDU being supported here
+ * (currently, only one declaration per packet is supported)
+ * openavbSrpDU ::= ProtocolVersion, Message
+ * ProtocolVersion BYTE ::= 0x00
+ * Message ::= AttributeType, AttributeLength [, AttributeListLength], AttributeList
+ * AttributeType BYTE ::= Talker Advertise | Talker Failed | Listener
+ * Talker Advertise::= 0x01
+ * Talker Failed::= 0x02
+ * Listener::= 0x03
+ * AttributeLength BYTE ::= 0x19 | 0x34 | 0x08
+ * AttributeListLength SHORT ::= AttributeLength + 3 | 4 (4 only if AttributeType = Listener)
+ * AttributeList ::= VectorAttribute {, VectorAttribute}, EndMark
+ * VectorAttribute ::= VectorHeader, FirstValue, Vector
+ * VectorHeader SHORT ::= 0x0001
+ * FirstValue ::=
+ * StreamID: 8 bytes
+ * [Src] MAC: 6 bytes
+ * UniqueID: 2 bytes, U16
+ * end of the Listener attribute
+ * DataFrameParameters: 8 bytes
+ * DA: 6 bytes
+ * VID: 2 bytes
+ * TSpec: 4 bytes
+ * MaxFrameSize: 2 bytes, U16
+ * MaxIntervalFrames: 2 bytes, U16
+ * PriorityAndRank: 1 byte
+ * Priority: 3 bits
+ * Rank: 1 bit
+ * Reserved: 4 bits
+ * AccumulatedLatency: 4 bytes, U32
+ * end of the Talker Advertise attribute
+ * FailureInformation: 9 bytes
+ * BridgeID: 8 bytes
+ * FailureCode: 1 byte
+ * end of the Talker Failed attribute
+ * Vector ::= ThreePackedEvent, [FourPackedEvent]
+ * ThreePackedEvents BYTE ::= New |Lv
+ * New ::= 0
+ * Lv ::= 5
+ * FourPackedEvents BYTE ::= Asking Failed | Ready | Ready Failed
+ * (FourPackedEvents is included only if AttributeType = Listener)
+ * Asking Failed ::= 1
+ * Ready ::= 2
+ * Ready Failed ::= 3
+ */
+
+#endif // OPENAVB_SRP_H
+
diff --git a/lib/avtp_pipeline/srp/openavb_srp_api.h b/lib/avtp_pipeline/srp/openavb_srp_api.h
new file mode 100755
index 00000000..4c13b637
--- /dev/null
+++ b/lib/avtp_pipeline/srp/openavb_srp_api.h
@@ -0,0 +1,179 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 :
+*
+* Implementation of IEEE 802.1Q
+* Multiple Stream Reservation Protocol
+* (limited intial implementation for end stations)
+*
+* This file declares the "Public" API.
+*
+* THIS IMPLEMENTATION ASSUMES THAT THERE WILL BE NO MORE THAN ONE
+* LISTENER THREAD FOR THE SAME STREAM ON A SINGLE END STATION.
+* (More than one talker for the same stream makes no sense at all.)
+*/
+
+#ifndef OPENAVB_SRP_API_H
+#define OPENAVB_SRP_API_H
+
+#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.
+// (we are probably toast if queue manager fails when removing a stream)
+
+// TBD - This implementation handles bandwidth in kilobits per second
+// the specs want bits per second (kbps will waste some bandwidth)
+
+// MSRP Declaration Type - IEEE 802.1Q-2011 Table 35-1
+typedef enum openavbSrpAttribType {
+ openavbSrp_AtTyp_None = 0x00, // not per spec - SRP internal use only
+ openavbSrp_AtTyp_TalkerAdvertise = 0x01,
+ openavbSrp_AtTyp_TalkerFailed = 0x02,
+ openavbSrp_AtTyp_Listener = 0x03,
+ openavbSrp_AtTyp_Domain = 0x04,
+} openavbSrpAttribType_t;
+
+// MSRP Listener Declaration Subtype (aka "FourPacked Event") - IEEE 802.1Q-2011 Table 35-3
+typedef enum openavbSrpLsnrDeclSubtype{
+ openavbSrp_LDSt_None = 0x00, // not per spec - SRP internal use (same as ignore is OK)
+ openavbSrp_LDSt_Ignore = 0x00,
+ openavbSrp_LDSt_Asking_Failed = 0x01,
+ openavbSrp_LDSt_Ready = 0x02,
+ openavbSrp_LDSt_Ready_Failed = 0x03,
+ openavbSrp_LDSt_Stream_Info = 0xFE, // NOT per IEEE spec - for use to inform talker when MAAP allocated.
+ openavbSrp_LDSt_Interest = 0xFF, // NOT per IEEE spec - for srpAttachStream() only
+} openavbSrpLsnrDeclSubtype_t;
+
+// Stream Reservation Failure Codes - IEEE 802.1Q-2011 Table 35-6
+enum openavbSrpFailureCode {
+ openavbSrp_FC_NoFail = 0, // 0: No failure,
+ // 1: Insufficient bandwidth,
+ // 2: Insufficient Bridge resources,
+ 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,
+ // 7: Reported latency has changed,
+ openavbSrp_FC_NotCapable = 8, // Egress port is not AVBCapable,
+ // 9: Use a different destination_address,
+ // 10: Out of MSRP resources,
+ // 11: Out of MMRP resources,
+ // 12: Cannot store destination_address,
+ // 13: Requested priority is not an SR Class priority,
+ // 14: MaxFrameSize is too large for media,
+ // 15: maxFanInPorts limit has been reached,
+ // 16: Changes in FirstValue for a registered StreamID,
+ // 17: VLAN is blocked on this egress port (Registration Forbidden),
+ // 18: VLAN tagging is disabled on this egress port (untagged set),
+ // 19: SR class priority mismatch.
+};
+
+typedef struct openavbSrpFailInfo{ // IEEE 802.1Q-2011 Section 35.2.2.8.7
+ U8 BridgeID[8];
+ U8 FailureCode; // openavbSrpFailureCode
+} openavbSrpFailInfo_t;
+
+
+// AVTP provided callbacks passed into openavbSrpInitialize:
+//
+// Callback for SRP to notify AVTP Talker that a Listener Declaration has been
+// registered (or de-registered)
+// - avtpHandle is provided to SRP by AVTP via openavbSrpRegisterStream()
+// and is passed back to AVTP in this call;
+// - [listener declaration] subtype is from the listener declaration.
+typedef openavbRC (*strmAttachCb_t) (void* avtpHandle,
+ openavbSrpLsnrDeclSubtype_t subtype);
+// Callback for SRP to notify AVTP Listener that a Talker Declaration has been
+// registered (or de-registered)
+// - avtpHandle is provided to SRP by AVTP via openavbSrpAttachStream()
+// and is passed back to AVTP in this call;
+// - declType, DA, tSpec and latency are from the Talker Declaration;
+// - SRClassId is derived from the priority attribute of the Talker
+// Declaration;
+// - pFailInfo is valid for only if declType is openavbSrp_AtTyp_TalkerFailed.
+typedef openavbRC (*strmRegCb_t) (void* avtpHandle,
+ openavbSrpAttribType_t declType,
+ U8 DA[],
+ AVBTSpec_t* tSpec,
+ SRClassIdx_t SRClassIdx,
+ U32 latency,
+ openavbSrpFailInfo_t* pFailInfo);
+
+// SRP API
+
+// Called by AVTP on talker or listener end station to start SRP.
+// TxRateKbps is the maximum rate which the interface indicated by ifname
+// can transmit, in kilobits per second. Set bypassAsCapableCheck true
+// to ignore the IEEE802.1ba section 6.4 requirement the SRP create
+// streams only on [IEEE802.1AS / gPTP] asCapable links.
+openavbRC openavbSrpInitialize (strmAttachCb_t attachCb, strmRegCb_t registerCb,
+ char* ifname, U32 TxRateKbps, bool bypassAsCapableCheck);
+
+// Called by AVTP on talker or listener end station to stop SRP
+void openavbSrpShutdown (void);
+
+// Called by AVTP on talker end station to advertise the indicated stream with
+// the supplied attributes. avtpHandle should be provided; it is not used by
+// SRP but is returned to AVTP as a parameter in calls to avtpStrmCb.attachCb()
+// and avtpStrmCb.detachCb().
+openavbRC openavbSrpRegisterStream (void* avtpHandle,
+ AVBStreamID_t* streamId,
+ U8 DA[],
+ AVBTSpec_t* tSpec,
+ SRClassIdx_t SRClassIdx,
+ bool Rank,
+ U32 Latency);
+
+// Called by AVTP on talker end station to withdraw the indicated stream
+openavbRC openavbSrpDeregisterStream (AVBStreamID_t* streamId);
+
+// Called by AVTP on listener to either express interest in the indicated stream
+// or to send a listener declaration back to the indicated stream's talker.
+// subType must be openavbSrp_LDSt_Interest, openavbSrp_LDSt_Ready, or openavbSrp_LDSt_Asking_Failed.
+// If subType == openavbSrp_LDSt_Interest, avtpHandle should be provided; it is not used
+// by SRP but is returned to AVTP as a parameter in calls to avtpStrmCb.registerCb()
+// and avtpStrmCb.deregisterCb().
+openavbRC openavbSrpAttachStream (void* avtpHandle,
+ AVBStreamID_t* streamId,
+ openavbSrpLsnrDeclSubtype_t type);
+
+// Called by AVTP on listener to withdraw both interest in,
+// and, if any, listener declaration for, the indicated stream.
+openavbRC openavbSrpDetachStream (AVBStreamID_t* streamId);
+
+// Get the Priority Code Point (PCP), VLAN Id and 1/classMeasurementInterval
+// (in seconds) for the indicated SR Class
+openavbRC openavbSrpGetClassParams (SRClassIdx_t SRClassIdx, U8* priority, U16* vid, U32* inverseIntervalSec);
+
+#endif // OPENAVB_SRP_API_H
+
diff --git a/lib/avtp_pipeline/tl/CMakeLists.txt b/lib/avtp_pipeline/tl/CMakeLists.txt
new file mode 100644
index 00000000..7c8a19d7
--- /dev/null
+++ b/lib/avtp_pipeline/tl/CMakeLists.txt
@@ -0,0 +1,29 @@
+SET (SRC_FILES_TL
+ ${AVB_SRC_DIR}/tl/openavb_tl.c
+ ${AVB_OSAL_DIR}/tl/openavb_tl_osal.c
+ ${AVB_SRC_DIR}/tl/openavb_listener.c
+ ${AVB_SRC_DIR}/tl/openavb_talker.c
+ )
+
+if(AVB_FEATURE_ENDPOINT)
+ #Additional Files for Endpoint
+ MESSAGE ("-- TL with Endpoint")
+ SET (SRC_FILES_TL_EXTRA
+ ${AVB_SRC_DIR}/endpoint/openavb_endpoint_client.c
+ ${AVB_SRC_DIR}/tl/openavb_tl_endpoint.c
+ ${AVB_SRC_DIR}/tl/openavb_talker_endpoint.c
+ ${AVB_SRC_DIR}/tl/openavb_listener_endpoint.c
+ )
+else()
+ #Additional Files for No Endpoint
+ MESSAGE ("-- TL without Endpoint")
+ SET (SRC_FILES_TL_EXTRA
+ ${AVB_SRC_DIR}/tl/openavb_tl_no_endpoint.c
+ ${AVB_SRC_DIR}/tl/openavb_talker_no_endpoint.c
+ ${AVB_SRC_DIR}/tl/openavb_listener_no_endpoint.c
+ )
+endif()
+
+SET ( SRC_FILES ${SRC_FILES} ${SRC_FILES_TL} ${SRC_FILES_TL_EXTRA} PARENT_SCOPE)
+
+
diff --git a/lib/avtp_pipeline/tl/NOTES.TXT b/lib/avtp_pipeline/tl/NOTES.TXT
new file mode 100644
index 00000000..b9400cad
--- /dev/null
+++ b/lib/avtp_pipeline/tl/NOTES.TXT
@@ -0,0 +1,28 @@
+The TL (talker/listener) modules manages the talker and listener functionality
+and the stream associated with them.
+
+The functionality is exposed via a public API as declared in openavb_tl_pub.h.
+These details of this API are described in the EAVB SDK Developer Guide.
+
+The general flow is as follows. The hosting application dynamically links in the
+TL functional. These TL API are implemented in openavb_tl.c. openavbTLInitialize() is
+called first to initialize the TL lists. openavbTLOpen() is called after that with
+the ini file name. There will be one call to openavbTLOpen for each talker or listener.
+openavbTLRun() is used to start the stream for the talker or listener. openavbTLClose()
+will stop the stream for the talker or listener. Finally the openavbTLShutdown() is
+used to cleanup the TL functionality.
+
+There are two hosting applications included with our AVB stack primarily as
+samples. These are openavb_tl_host and openavb_tl_harness. It is expected that most
+solutions will replace these with a customer specific application.
+
+At a lower level most things happen as a result of the stTLOpen() call. A thread
+is created for each talker and listener. So this means every stream has it's own
+thread. The main thread entry point is openavbTLThreadFn(). From there the detailed
+talker or listener functionality is called with openavbTLRunTalker() or
+openavbTLRunListener() respectively. It is in these talker and listener run functions
+the talker registers to the endpoint and the listener attaches to the endpoint.
+The endpoint will call back into the talker and listener with details of streams
+coming and going so that the talker and listener can determine when to send or not
+send and when to listen or not listen.
+
diff --git a/lib/avtp_pipeline/tl/openavb_listener.c b/lib/avtp_pipeline/tl/openavb_listener.c
new file mode 100644
index 00000000..506d327c
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_listener.c
@@ -0,0 +1,424 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Listener implementation
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "openavb_platform.h"
+#include "openavb_trace.h"
+#include "openavb_tl.h"
+#include "openavb_avtp.h"
+#include "openavb_listener.h"
+
+// DEBUG Uncomment to turn on logging for just this module.
+//#define AVB_LOG_ON 1
+
+#define AVB_LOG_COMPONENT "Listener"
+#include "openavb_log.h"
+
+#include "openavb_debug.h"
+
+bool listenerStartStream(tl_state_t *pTLState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid TLState");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ assert(!pTLState->bStreaming);
+
+ openavb_tl_cfg_t *pCfg = &pTLState->cfg;
+ listener_data_t *pListenerData = pTLState->pPvtListenerData;
+
+ openavbRC rc = openavbAvtpRxInit(pTLState->pMediaQ,
+ &pCfg->map_cb,
+ &pCfg->intf_cb,
+ pListenerData->ifname,
+ &pListenerData->streamID,
+ pListenerData->destAddr,
+ pCfg->raw_rx_buffers,
+ pCfg->rx_signal_mode,
+ &pListenerData->avtpHandle);
+ if (IS_OPENAVB_FAILURE(rc)) {
+ AVB_LOG_ERROR("Failed to create AVTP stream");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ // Setup timers
+ U64 nowNS;
+ CLOCK_GETTIME64(OPENAVB_TIMER_CLOCK, &nowNS);
+ pListenerData->nextReportNS = nowNS + (pCfg->report_seconds * NANOSECONDS_PER_SECOND);
+ pListenerData->nextSecondNS = nowNS + NANOSECONDS_PER_SECOND;
+
+ // Clear counters
+ pListenerData->nReportCalls = 0;
+ pListenerData->nReportFrames = 0;
+
+ // Clear stats
+ openavbListenerClearStats(pTLState);
+
+ // we're good to go!
+ pTLState->bStreaming = TRUE;
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TRUE;
+}
+
+void listenerStopStream(tl_state_t *pTLState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid TLState");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ listener_data_t *pListenerData = pTLState->pPvtListenerData;
+ if (!pListenerData) {
+ AVB_LOG_ERROR("Invalid listener data");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ openavbListenerAddStat(pTLState, TL_STAT_RX_CALLS, pListenerData->nReportCalls);
+ openavbListenerAddStat(pTLState, TL_STAT_RX_FRAMES, pListenerData->nReportFrames);
+ 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=%lld, frames=%lld, lost=%lld, bytes=%lld",
+ STREAMID_ARGS(&pListenerData->streamID),
+ openavbListenerGetStat(pTLState, TL_STAT_RX_CALLS),
+ openavbListenerGetStat(pTLState, TL_STAT_RX_FRAMES),
+ openavbListenerGetStat(pTLState, TL_STAT_RX_LOST),
+ openavbListenerGetStat(pTLState, TL_STAT_RX_BYTES));
+
+ if (pTLState->bStreaming) {
+ openavbAvtpShutdown(pListenerData->avtpHandle);
+ pTLState->bStreaming = FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+static inline bool listenerDoStream(tl_state_t *pTLState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid TLState");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ openavb_tl_cfg_t *pCfg = &pTLState->cfg;
+ listener_data_t *pListenerData = pTLState->pPvtListenerData;
+ bool bRet = FALSE;
+
+ if (pTLState->bStreaming) {
+ U64 nowNS;
+
+ pListenerData->nReportCalls++;
+
+ // Try to receive a frame
+ if (IS_OPENAVB_SUCCESS(openavbAvtpRx(pListenerData->avtpHandle))) {
+ pListenerData->nReportFrames++;
+ }
+
+ CLOCK_GETTIME64(OPENAVB_TIMER_CLOCK, &nowNS);
+
+ 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);
+
+ 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);
+ }
+ }
+
+ if (nowNS > pListenerData->nextSecondNS) {
+ pListenerData->nextSecondNS += NANOSECONDS_PER_SECOND;
+ bRet = TRUE;
+ }
+ }
+ else {
+ SLEEP(1);
+ bRet = TRUE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return bRet;
+}
+
+// Called from openavbTLThreadFn() which is started from openavbTLRun()
+void openavbTLRunListener(tl_state_t *pTLState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid TLState");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ openavb_tl_cfg_t *pCfg = &pTLState->cfg;
+
+ pTLState->pPvtListenerData = calloc(1, sizeof(listener_data_t));
+ if (!pTLState->pPvtListenerData) {
+ AVB_LOG_WARNING("Failed to allocate listener data.");
+ return;
+ }
+
+ AVBStreamID_t streamID;
+ memcpy(streamID.addr, pCfg->stream_addr.mac, ETH_ALEN);
+ streamID.uniqueID = pCfg->stream_uid;
+
+ AVB_LOGF_INFO("Attach "STREAMID_FORMAT, STREAMID_ARGS(&streamID));
+
+ // Create Stats Mutex
+ {
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "TLStatsMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(pTLState->statsMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'TLStatsMutex' mutex");
+ }
+
+ // 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
+ while (pTLState->bRunning && pTLState->bConnected) {
+
+ // Listen for an RX frame (or just sleep if not streaming)
+ bServiceIPC = listenerDoStream(pTLState);
+
+ if (bServiceIPC) {
+ // Look for messages from endpoint. Don't block (timeout=0)
+ if (!openavbEptClntService(pTLState->endpointHandle, 0)) {
+ AVB_LOGF_WARNING("Lost connection to endpoint "STREAMID_FORMAT, STREAMID_ARGS(&streamID));
+ pTLState->bConnected = FALSE;
+ pTLState->endpointHandle = 0;
+ }
+ }
+ }
+
+ // Stop streaming
+ listenerStopStream(pTLState);
+
+ {
+ MUTEX_CREATE_ERR();
+ MUTEX_DESTROY(pTLState->statsMutex); // Destroy Stats Mutex
+ MUTEX_LOG_ERR("Error destroying mutex");
+ }
+
+ // withdraw our listener attach
+ if (pTLState->bConnected)
+ openavbEptClntStopStream(pTLState->endpointHandle, &streamID);
+ }
+ else {
+ AVB_LOGF_WARNING("Failed to connect to endpoint "STREAMID_FORMAT, STREAMID_ARGS(&streamID));
+ }
+
+ if (pTLState->pPvtListenerData) {
+ free(pTLState->pPvtListenerData);
+ pTLState->pPvtListenerData = NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+void openavbTLPauseListener(tl_state_t *pTLState, bool bPause)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid TLState");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ listener_data_t *pListenerData = pTLState->pPvtListenerData;
+ if (!pListenerData) {
+ AVB_LOG_ERROR("Invalid private listener data");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ openavbAvtpPause(pListenerData->avtpHandle, bPause);
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+void openavbListenerClearStats(tl_state_t *pTLState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid TLState");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ listener_data_t *pListenerData = pTLState->pPvtListenerData;
+ if (!pListenerData) {
+ AVB_LOG_ERROR("Invalid private listener data");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ LOCK_STATS();
+ memset(&pListenerData->stats, 0, sizeof(pListenerData->stats));
+ UNLOCK_STATS();
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+void openavbListenerAddStat(tl_state_t *pTLState, tl_stat_t stat, U64 val)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid TLState");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ listener_data_t *pListenerData = pTLState->pPvtListenerData;
+ if (!pListenerData) {
+ AVB_LOG_ERROR("Invalid private listener data");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ LOCK_STATS();
+ switch (stat) {
+ case TL_STAT_TX_CALLS:
+ case TL_STAT_TX_FRAMES:
+ case TL_STAT_TX_LATE:
+ case TL_STAT_TX_BYTES:
+ break;
+ case TL_STAT_RX_CALLS:
+ pListenerData->stats.totalCalls += val;
+ break;
+ case TL_STAT_RX_FRAMES:
+ pListenerData->stats.totalFrames += val;
+ break;
+ case TL_STAT_RX_LOST:
+ pListenerData->stats.totalLost += val;
+ break;
+ case TL_STAT_RX_BYTES:
+ pListenerData->stats.totalBytes += val;
+ break;
+ }
+ UNLOCK_STATS();
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+U64 openavbListenerGetStat(tl_state_t *pTLState, tl_stat_t stat)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+ U64 val = 0;
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid TLState");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return 0;
+ }
+
+ listener_data_t *pListenerData = pTLState->pPvtListenerData;
+ if (!pListenerData) {
+ AVB_LOG_ERROR("Invalid private listener data");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return 0;
+ }
+
+ LOCK_STATS();
+ switch (stat) {
+ case TL_STAT_TX_CALLS:
+ case TL_STAT_TX_FRAMES:
+ case TL_STAT_TX_LATE:
+ case TL_STAT_TX_BYTES:
+ break;
+ case TL_STAT_RX_CALLS:
+ val = pListenerData->stats.totalCalls;
+ break;
+ case TL_STAT_RX_FRAMES:
+ val = pListenerData->stats.totalFrames;
+ break;
+ case TL_STAT_RX_LOST:
+ val = pListenerData->stats.totalLost;
+ break;
+ case TL_STAT_RX_BYTES:
+ val = pListenerData->stats.totalBytes;
+ break;
+ }
+ UNLOCK_STATS();
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return val;
+}
+
+
diff --git a/lib/avtp_pipeline/tl/openavb_listener.h b/lib/avtp_pipeline/tl/openavb_listener.h
new file mode 100644
index 00000000..f802d8cb
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_listener.h
@@ -0,0 +1,73 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Listener
+*/
+
+#ifndef OPENAVB_TL_LISTENER_H
+#define OPENAVB_TL_LISTENER_H 1
+
+#include "openavb_tl.h"
+
+typedef struct {
+ U64 totalCalls;
+ U64 totalFrames;
+ U64 totalLost;
+ U64 totalBytes;
+} listener_stats_t;
+
+typedef struct {
+ // Data from callback
+ char ifname[IFNAMSIZ];
+ AVBStreamID_t streamID;
+ U8 destAddr[ETH_ALEN];
+ AVBTSpec_t tSpec;
+ long nFramesRx;
+
+ // State info for streaming
+ void *avtpHandle;
+ unsigned long nReportFrames;
+ unsigned long nReportCalls;
+ U64 nextReportNS;
+ U64 nextSecondNS;
+ listener_stats_t stats;
+} listener_data_t;
+
+void openavbTLRunListener(tl_state_t *pTLState);
+void openavbTLPauseListener(tl_state_t *pTLState, bool bPause);
+void openavbListenerClearStats(tl_state_t *pTLState);
+void openavbListenerAddStat(tl_state_t *pTLState, tl_stat_t stat, U64 val);
+U64 openavbListenerGetStat(tl_state_t *pTLState, tl_stat_t stat);
+bool openavbTLRunListenerInit(int h, AVBStreamID_t *streamID);
+bool listenerStartStream(tl_state_t *pTLState);
+void listenerStopStream(tl_state_t *pTLState);
+
+#endif // OPENAVB_TL_LISTENER_H
diff --git a/lib/avtp_pipeline/tl/openavb_listener_endpoint.c b/lib/avtp_pipeline/tl/openavb_listener_endpoint.c
new file mode 100644
index 00000000..b1d4446e
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_listener_endpoint.c
@@ -0,0 +1,139 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Listener implementation
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "openavb_platform.h"
+#include "openavb_trace.h"
+#include "openavb_tl.h"
+#include "openavb_endpoint.h"
+#include "openavb_avtp.h"
+#include "openavb_listener.h"
+
+// DEBUG Uncomment to turn on logging for just this module.
+//#define AVB_LOG_ON 1
+
+#define AVB_LOG_COMPONENT "Listener"
+#include "openavb_log.h"
+
+/* Listener callback comes from endpoint, to indicate when talkers
+ * come and go. We may need to start or stop the listener thread.
+ */
+void openavbEptClntNotifyLstnrOfSrpCb(int endpointHandle,
+ AVBStreamID_t *streamID,
+ char *ifname,
+ U8 destAddr[],
+ openavbSrpAttribType_t tlkrDecl,
+ AVBTSpec_t *tSpec,
+ U8 srClassID,
+ U32 latency,
+ openavbSrpFailInfo_t *failInfo)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ static const U8 emptyMAC[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+ tl_state_t *pTLState = TLHandleListGet(endpointHandle);
+ openavb_tl_cfg_t *pCfg = &pTLState->cfg;
+ listener_data_t *pListenerData = pTLState->pPvtListenerData;
+
+ if (!pTLState) {
+ AVB_LOG_WARNING("Unable to get listener from endpoint handle.");
+ return;
+ }
+
+ AVB_LOGF_DEBUG("%s streaming=%d, tlkrDecl=%d", __FUNCTION__, pTLState->bStreaming, tlkrDecl);
+
+ if (!pTLState->bStreaming
+ && tlkrDecl == openavbSrp_AtTyp_TalkerAdvertise) {
+ // if(x_cfg.noSrp) this is sort of a recursive call into openavbEptClntAttachStream()
+ // but we are OK due to the intervening IPC.
+ bool rc = openavbEptClntAttachStream(pTLState->endpointHandle, streamID, openavbSrp_LDSt_Ready);
+ if (rc) {
+ // Save data provided by endpoint/SRP
+ strncpy(pListenerData->ifname, ifname, IFNAMSIZ);
+ memcpy(&pListenerData->streamID, streamID, sizeof(AVBStreamID_t));
+ if (memcmp(destAddr, emptyMAC, ETH_ALEN) != 0) {
+ memcpy(&pListenerData->destAddr, destAddr, ETH_ALEN);
+ memcpy(&pListenerData->tSpec, tSpec, sizeof(AVBTSpec_t));
+ }
+ else {
+ // manual stream configuration required to be obtained from config file;
+ // see comments at call to strmRegCb() in openavbEptClntAttachStream() in openavb_endpoint.c
+ AVB_LOG_INFO("Endpoint Configuration requires manual stream configuration on listener");
+ if ((!pCfg->dest_addr.mac) || memcmp(&(pCfg->dest_addr.mac->ether_addr_octet[0]), &(emptyMAC[0]), ETH_ALEN) == 0) {
+ AVB_LOG_ERROR(" Configuration Error - dest_addr required in listener config file");
+ }
+ 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]);
+ }
+ 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");
+ }
+ else {
+ pListenerData->tSpec.maxIntervalFrames = pCfg->max_interval_frames;
+ pListenerData->tSpec.maxFrameSize = pCfg->max_frame_size;
+ AVB_LOGF_INFO(" Listener configured max_interval_frames = %u, max_frame_size = %u",
+ pListenerData->tSpec.maxIntervalFrames, pListenerData->tSpec.maxFrameSize);
+ }
+ }
+
+ // We should start streaming
+ AVB_LOGF_INFO("Starting stream: "STREAMID_FORMAT, STREAMID_ARGS(streamID));
+ listenerStartStream(pTLState);
+ }
+ else {
+ AVB_LOG_DEBUG("Failed to attach listener stream");
+ }
+ }
+ else if (pTLState->bStreaming
+ && tlkrDecl != openavbSrp_AtTyp_TalkerAdvertise) {
+ AVB_LOGF_INFO("Stopping stream: "STREAMID_FORMAT, STREAMID_ARGS(streamID));
+ listenerStopStream(pTLState);
+
+ // We're still interested in the stream
+ openavbEptClntAttachStream(pTLState->endpointHandle, streamID, openavbSrp_LDSt_Interest);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+bool openavbTLRunListenerInit(int h, AVBStreamID_t *streamID)
+{
+ return(openavbEptClntAttachStream(h, streamID, openavbSrp_LDSt_Interest));
+}
diff --git a/lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c b/lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c
new file mode 100644
index 00000000..877d1c18
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c
@@ -0,0 +1,80 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Listener implementation
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "openavb_platform.h"
+#include "openavb_tl.h"
+#include "openavb_avtp.h"
+#include "openavb_listener.h"
+#include "openavb_endpoint.h"
+
+#define AVB_LOG_COMPONENT "Listener"
+#include "openavb_log.h"
+#include "openavb_trace.h"
+
+bool openavbTLRunListenerInit(int hnd, AVBStreamID_t *streamID)
+{
+ tl_state_t *pTLState = TLHandleListGet(hnd);
+ openavb_tl_cfg_t *pCfg = &pTLState->cfg;
+ listener_data_t *pListenerData = pTLState->pPvtListenerData;
+
+ strncpy(pListenerData->ifname, pCfg->ifname, IFNAMSIZ);
+ 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);
+ pListenerData->tSpec.maxIntervalFrames = pCfg->max_interval_frames;
+ pListenerData->tSpec.maxFrameSize = pCfg->max_frame_size;
+
+ 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;
+}
+
+
+void openavbEptClntNotifyLstnrOfSrpCb(int endpointHandle,
+ AVBStreamID_t *streamID,
+ char *ifname,
+ U8 destAddr[],
+ openavbSrpAttribType_t tlkrDecl,
+ AVBTSpec_t *tSpec,
+ U8 srClassID,
+ U32 latency,
+ openavbSrpFailInfo_t *failInfo)
+{
+}
+
diff --git a/lib/avtp_pipeline/tl/openavb_talker.c b/lib/avtp_pipeline/tl/openavb_talker.c
new file mode 100644
index 00000000..73d6a406
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_talker.c
@@ -0,0 +1,495 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Talker implementation
+*/
+
+#include <stdlib.h>
+#include "openavb_platform.h"
+#include "openavb_trace.h"
+#include "openavb_tl.h"
+#include "openavb_avtp.h"
+#include "openavb_talker.h"
+// #include "openavb_time.h"
+
+// DEBUG Uncomment to turn on logging for just this module.
+//#define AVB_LOG_ON 1
+
+#define AVB_LOG_COMPONENT "Talker"
+#include "openavb_log.h"
+
+#include "openavb_debug.h"
+
+
+
+bool talkerStartStream(tl_state_t *pTLState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid TLState");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ openavb_tl_cfg_t *pCfg = &pTLState->cfg;
+ talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
+
+ assert(!pTLState->bStreaming);
+
+ pTalkerData->wakeFrames = pCfg->max_interval_frames * pCfg->batch_factor;
+
+ // Set a max_transmit_deficit_usec default
+ if (pCfg->max_transmit_deficit_usec == 0)
+ pCfg->max_transmit_deficit_usec = 50000;
+
+ openavbRC rc = openavbAvtpTxInit(pTLState->pMediaQ,
+ &pCfg->map_cb,
+ &pCfg->intf_cb,
+ pTalkerData->ifname,
+ &pTalkerData->streamID,
+ pTalkerData->destAddr,
+ pCfg->max_transit_usec,
+ pTalkerData->fwmark,
+ pTalkerData->vlanID,
+ pTalkerData->vlanPCP,
+ pTalkerData->wakeFrames * pCfg->raw_tx_buffers,
+ &pTalkerData->avtpHandle);
+ if (IS_OPENAVB_FAILURE(rc)) {
+ AVB_LOG_ERROR("Failed to create AVTP stream");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ avtp_stream_t *pStream = (avtp_stream_t *)(pTalkerData->avtpHandle);
+
+ if (!pStream->pMapCB->map_transmit_interval_cb(pTLState->pMediaQ)) {
+ pTalkerData->wakeRate = pTalkerData->classRate / pCfg->batch_factor;
+ }
+ else {
+ // Override the class observation interval with the one provided by the mapping module.
+ pTalkerData->wakeRate = pStream->pMapCB->map_transmit_interval_cb(pTLState->pMediaQ) / pCfg->batch_factor;
+ }
+ pTalkerData->sleepUsec = MICROSECONDS_PER_SECOND / pTalkerData->wakeRate;
+ pTalkerData->intervalNS = NANOSECONDS_PER_SECOND / pTalkerData->wakeRate;
+
+ U32 SRKbps = ((unsigned long)pTalkerData->classRate * (unsigned long)pCfg->max_interval_frames * (unsigned long)pStream->frameLen * 8L) / 1000;
+ U32 DataKbps = ((unsigned long)pTalkerData->wakeRate * (unsigned long)pCfg->max_interval_frames * (unsigned long)pStream->frameLen * 8L) / 1000;
+
+ AVB_LOGF_INFO(STREAMID_FORMAT", sr-rate=%lu, data-rate=%lu, frames=%u, size=%u, batch=%u, sleep=%" PRId64 ", sr-Kbps=%d, data-Kbps=%d",
+ STREAMID_ARGS(&pTalkerData->streamID), (unsigned long)(pTalkerData->classRate), (unsigned long)(pTalkerData->wakeRate),
+ pTalkerData->tSpec.maxIntervalFrames, pTalkerData->tSpec.maxFrameSize,
+ pCfg->batch_factor, pTalkerData->intervalNS / 1000, SRKbps, DataKbps);
+
+
+ // number of intervals per report
+ pTalkerData->wakesPerReport = pCfg->report_seconds * NANOSECONDS_PER_SECOND / pTalkerData->intervalNS;
+ // counts of intervals and frames between reports
+ pTalkerData->cntFrames = 0;
+ pTalkerData->cntWakes = 0;
+
+ // setup the initial times
+ U64 nowNS;
+ CLOCK_GETTIME64(OPENAVB_TIMER_CLOCK, &nowNS);
+
+ // Align clock : allows for some performance gain
+ nowNS = ((nowNS + (pTalkerData->intervalNS)) / pTalkerData->intervalNS) * pTalkerData->intervalNS;
+
+ pTalkerData->nextReportNS = nowNS + (pCfg->report_seconds * NANOSECONDS_PER_SECOND);
+ pTalkerData->nextSecondNS = nowNS + NANOSECONDS_PER_SECOND;
+ pTalkerData->nextCycleNS = nowNS + pTalkerData->intervalNS;
+
+ // Clear stats
+ openavbTalkerClearStats(pTLState);
+
+ // we're good to go!
+ pTLState->bStreaming = TRUE;
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TRUE;
+}
+
+void talkerStopStream(tl_state_t *pTLState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid TLState");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
+ if (!pTalkerData) {
+ AVB_LOG_ERROR("Invalid listener data");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ void *rawsock = NULL;
+ if (pTalkerData->avtpHandle) {
+ rawsock = ((avtp_stream_t*)pTalkerData->avtpHandle)->rawsock;
+ }
+
+ 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_BYTES, openavbAvtpBytes(pTalkerData->avtpHandle));
+
+ AVB_LOGF_INFO("TX "STREAMID_FORMAT", Totals: calls=%lld, frames=%lld, late=%lld, bytes=%lld, TXOutOfBuffs=%ld",
+ STREAMID_ARGS(&pTalkerData->streamID),
+ openavbTalkerGetStat(pTLState, TL_STAT_TX_CALLS),
+ openavbTalkerGetStat(pTLState, TL_STAT_TX_FRAMES),
+ openavbTalkerGetStat(pTLState, TL_STAT_TX_LATE),
+ openavbTalkerGetStat(pTLState, TL_STAT_TX_BYTES),
+ openavbRawsockGetTXOutOfBuffers(rawsock)
+ );
+
+ if (pTLState->bStreaming) {
+ openavbAvtpShutdown(pTalkerData->avtpHandle);
+ pTLState->bStreaming = FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+static inline bool talkerDoStream(tl_state_t *pTLState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid TLState");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ openavb_tl_cfg_t *pCfg = &pTLState->cfg;
+ talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
+ bool bRet = FALSE;
+
+ if (pTLState->bStreaming) {
+ U64 nowNS;
+
+ if (!pCfg->tx_blocking_in_intf) {
+
+ // sleep until the next interval
+ SLEEP_UNTIL_NSEC(pTalkerData->nextCycleNS);
+
+ //AVB_DBG_INTERVAL(8000, TRUE);
+
+ // send the frames for this interval
+ int i;
+ for (i = pTalkerData->wakeFrames; i > 0; i--) {
+ if (IS_OPENAVB_SUCCESS(openavbAvtpTx(pTalkerData->avtpHandle, i == 1, pCfg->tx_blocking_in_intf)))
+ pTalkerData->cntFrames++;
+ else break;
+ }
+ }
+ else {
+ // Interface module block option
+ if (IS_OPENAVB_SUCCESS(openavbAvtpTx(pTalkerData->avtpHandle, TRUE, pCfg->tx_blocking_in_intf)))
+ pTalkerData->cntFrames++;
+ }
+
+ if (pTalkerData->cntWakes++ % pTalkerData->wakeRate == 0) {
+ // time to service the endpoint IPC
+ bRet = TRUE;
+ }
+
+ CLOCK_GETTIME64(OPENAVB_TIMER_CLOCK, &nowNS);
+
+ if (pCfg->report_seconds > 0) {
+ if (nowNS > pTalkerData->nextReportNS) {
+
+ 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);
+ }
+ }
+
+ if (nowNS > pTalkerData->nextSecondNS) {
+ pTalkerData->nextSecondNS += NANOSECONDS_PER_SECOND;
+ bRet = TRUE;
+ }
+
+ if (!pCfg->tx_blocking_in_intf) {
+ pTalkerData->nextCycleNS += pTalkerData->intervalNS;
+
+ if ((pTalkerData->nextCycleNS + (pCfg->max_transmit_deficit_usec * 1000)) < nowNS) {
+ // Hit max deficit time. Something must be wrong. Reset the cycle timer.
+ // Align clock : allows for some performance gain
+ nowNS = ((nowNS + (pTalkerData->intervalNS)) / pTalkerData->intervalNS) * pTalkerData->intervalNS;
+ pTalkerData->nextCycleNS = nowNS + pTalkerData->intervalNS;
+ }
+ }
+ }
+ else {
+ SLEEP(1);
+ // time to service the endpoint IPC
+ bRet = TRUE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return bRet;
+}
+
+
+// Called from openavbTLThreadFn() which is started from openavbTLRun()
+void openavbTLRunTalker(tl_state_t *pTLState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid TLState");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ pTLState->pPvtTalkerData = calloc(1, sizeof(talker_data_t));
+ if (!pTLState->pPvtTalkerData) {
+ AVB_LOG_WARNING("Failed to allocate talker data.");
+ return;
+ }
+
+ // Create Stats Mutex
+ {
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "TLStatsMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(pTLState->statsMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'TLStatsMutex' mutex");
+ }
+
+ /* If using endpoint register talker,
+ else register with tpsec */
+ pTLState->bConnected = openavbTLRunTalkerInit(pTLState);
+
+ if (pTLState->bConnected) {
+ bool bServiceIPC;
+
+ // Do until we are stopped or loose connection to endpoint
+ while (pTLState->bRunning && pTLState->bConnected) {
+
+ // Talk (or just sleep if not streaming.)
+ bServiceIPC = talkerDoStream(pTLState);
+
+ // TalkerDoStream() returns TRUE once per second,
+ // so that we can service our IPC at that low rate.
+ if (bServiceIPC) {
+ // Look for messages from endpoint. Don't block (timeout=0)
+ if (!openavbEptClntService(pTLState->endpointHandle, 0)) {
+ AVB_LOGF_WARNING("Lost connection to endpoint, will retry "STREAMID_FORMAT, STREAMID_ARGS(&(((talker_data_t *)pTLState->pPvtTalkerData)->streamID)));
+ pTLState->bConnected = FALSE;
+ pTLState->endpointHandle = 0;
+ }
+ }
+ }
+
+ // Stop streaming
+ talkerStopStream(pTLState);
+
+ {
+ MUTEX_CREATE_ERR();
+ MUTEX_DESTROY(pTLState->statsMutex); // Destroy Stats Mutex
+ MUTEX_LOG_ERR("Error destroying mutex");
+ }
+
+ // withdraw our talker registration
+ if (pTLState->bConnected)
+ openavbEptClntStopStream(pTLState->endpointHandle, &(((talker_data_t *)pTLState->pPvtTalkerData)->streamID));
+
+ openavbTLRunTalkerFinish(pTLState);
+ }
+ else {
+ AVB_LOGF_WARNING("Failed to connect to endpoint"STREAMID_FORMAT, STREAMID_ARGS(&(((talker_data_t *)pTLState->pPvtTalkerData)->streamID)));
+ }
+
+ if (pTLState->pPvtTalkerData) {
+ free(pTLState->pPvtTalkerData);
+ pTLState->pPvtTalkerData = NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+void openavbTLPauseTalker(tl_state_t *pTLState, bool bPause)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid TLState");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
+ if (!pTalkerData) {
+ AVB_LOG_ERROR("Invalid private talker data");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ openavbAvtpPause(pTalkerData->avtpHandle, bPause);
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+void openavbTalkerClearStats(tl_state_t *pTLState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid TLState");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
+ if (!pTalkerData) {
+ AVB_LOG_ERROR("Invalid private talker data");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ LOCK_STATS();
+ memset(&pTalkerData->stats, 0, sizeof(pTalkerData->stats));
+ UNLOCK_STATS();
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+void openavbTalkerAddStat(tl_state_t *pTLState, tl_stat_t stat, U64 val)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid TLState");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
+ if (!pTalkerData) {
+ AVB_LOG_ERROR("Invalid private talker data");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ LOCK_STATS();
+ switch (stat) {
+ case TL_STAT_TX_CALLS:
+ pTalkerData->stats.totalCalls += val;
+ break;
+ case TL_STAT_TX_FRAMES:
+ pTalkerData->stats.totalFrames += val;
+ break;
+ case TL_STAT_TX_LATE:
+ pTalkerData->stats.totalLate += val;
+ break;
+ case TL_STAT_TX_BYTES:
+ pTalkerData->stats.totalBytes += val;
+ break;
+ case TL_STAT_RX_CALLS:
+ case TL_STAT_RX_FRAMES:
+ case TL_STAT_RX_LOST:
+ case TL_STAT_RX_BYTES:
+ break;
+ }
+ UNLOCK_STATS();
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+U64 openavbTalkerGetStat(tl_state_t *pTLState, tl_stat_t stat)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+ U64 val = 0;
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid TLState");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return 0;
+ }
+
+ talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
+ if (!pTalkerData) {
+ AVB_LOG_ERROR("Invalid private talker data");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return 0;
+ }
+
+ LOCK_STATS();
+ switch (stat) {
+ case TL_STAT_TX_CALLS:
+ val = pTalkerData->stats.totalCalls;
+ break;
+ case TL_STAT_TX_FRAMES:
+ val = pTalkerData->stats.totalFrames;
+ break;
+ case TL_STAT_TX_LATE:
+ val = pTalkerData->stats.totalLate;
+ break;
+ case TL_STAT_TX_BYTES:
+ val = pTalkerData->stats.totalBytes;
+ break;
+ case TL_STAT_RX_CALLS:
+ case TL_STAT_RX_FRAMES:
+ case TL_STAT_RX_LOST:
+ case TL_STAT_RX_BYTES:
+ break;
+ }
+ UNLOCK_STATS();
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return val;
+}
+
diff --git a/lib/avtp_pipeline/tl/openavb_talker.h b/lib/avtp_pipeline/tl/openavb_talker.h
new file mode 100644
index 00000000..b180d12a
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_talker.h
@@ -0,0 +1,77 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Talker Listener process lifecycle interface
+*/
+
+#ifndef OPENAVB_TL_TALKER_H
+#define OPENAVB_TL_TALKER_H 1
+
+#include "openavb_tl.h"
+
+typedef struct {
+ // Data from callback
+ char ifname[IFNAMSIZ];
+ AVBStreamID_t streamID;
+ U8 destAddr[ETH_ALEN];
+ AVBTSpec_t tSpec;
+ U32 classRate;
+ U32 fwmark;
+ U16 vlanID;
+ U8 vlanPCP;
+
+ // State info for streaming
+ void *avtpHandle;
+ unsigned long sleepUsec;
+ unsigned long wakeRate;
+ unsigned long wakeFrames;
+ unsigned long wakesPerReport;
+ unsigned long cntWakes;
+ unsigned long cntFrames;
+ U64 nextCycleNS;
+ U64 intervalNS;
+ U64 nextReportNS;
+ U64 nextSecondNS;
+ talker_stats_t stats;
+} talker_data_t;
+
+
+void openavbTLRunTalker(tl_state_t *pTLState);
+void openavbTLPauseTalker(tl_state_t *pTLState, bool bPause);
+void openavbTalkerClearStats(tl_state_t *pTLState);
+void openavbTalkerAddStat(tl_state_t *pTLState, tl_stat_t stat, U64 val);
+U64 openavbTalkerGetStat(tl_state_t *pTLState, tl_stat_t stat);
+bool talkerStartStream(tl_state_t *pTLState);
+void talkerStopStream(tl_state_t *pTLState);
+bool openavbTLRunTalkerInit(tl_state_t *pTLState);
+void openavbTLRunTalkerFinish(tl_state_t *pTLState);
+
+#endif // OPENAVB_TL_TALKER_H
diff --git a/lib/avtp_pipeline/tl/openavb_talker_endpoint.c b/lib/avtp_pipeline/tl/openavb_talker_endpoint.c
new file mode 100644
index 00000000..27511f96
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_talker_endpoint.c
@@ -0,0 +1,163 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Talker implementation for use with endpoint
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "openavb_platform.h"
+#include "openavb_trace.h"
+#include "openavb_tl.h"
+#include "openavb_endpoint.h"
+#include "openavb_avtp.h"
+#include "openavb_talker.h"
+#include "openavb_time.h"
+
+// DEBUG Uncomment to turn on logging for just this module.
+//#define AVB_LOG_ON 1
+
+#define AVB_LOG_COMPONENT "Talker"
+#include "openavb_log.h"
+
+/* Talker callback comes from endpoint, to indicate when listeners
+ * come and go. We may need to start or stop the talker thread.
+ */
+void openavbEptClntNotifyTlkrOfSrpCb(int endpointHandle,
+ AVBStreamID_t *streamID,
+ char *ifname,
+ U8 destAddr[],
+ openavbSrpLsnrDeclSubtype_t lsnrDecl,
+ U32 classRate,
+ U16 vlanID,
+ U8 priority,
+ U16 fwmark)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = TLHandleListGet(endpointHandle);
+ talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
+
+ if (!pTLState) {
+ AVB_LOG_WARNING("Unable to get talker from endpoint handle.");
+ return;
+ }
+
+ AVB_LOGF_DEBUG("%s streaming=%d, lsnrDecl=%d", __FUNCTION__, pTLState->bStreaming, lsnrDecl);
+
+ 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);
+ memcpy(&pTalkerData->streamID, streamID, sizeof(AVBStreamID_t));
+ memcpy(&pTalkerData->destAddr, destAddr, ETH_ALEN);
+ pTalkerData->classRate = classRate;
+ pTalkerData->vlanID = vlanID;
+ pTalkerData->vlanPCP = priority;
+ pTalkerData->fwmark = fwmark;
+
+ // We should start streaming
+ AVB_LOGF_INFO("Starting stream: "STREAMID_FORMAT, STREAMID_ARGS(streamID));
+ talkerStartStream(pTLState);
+ }
+ 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);
+ memcpy(&pTalkerData->streamID, streamID, sizeof(AVBStreamID_t));
+ memcpy(&pTalkerData->destAddr, destAddr, ETH_ALEN);
+ pTalkerData->classRate = classRate;
+ pTalkerData->vlanID = vlanID;
+ pTalkerData->vlanPCP = priority;
+ pTalkerData->fwmark = fwmark;
+ }
+ }
+ else {
+ if (lsnrDecl != openavbSrp_LDSt_Ready
+ && lsnrDecl != openavbSrp_LDSt_Ready_Failed) {
+ // Nobody is listening any more
+ AVB_LOGF_INFO("Stopping stream: "STREAMID_FORMAT, STREAMID_ARGS(streamID));
+ talkerStopStream(pTLState);
+ }
+ }
+
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+bool openavbTLRunTalkerInit(tl_state_t *pTLState)
+{
+ openavb_tl_cfg_t *pCfg = &pTLState->cfg;
+ talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
+
+ AVBStreamID_t streamID;
+ memset(&streamID, 0, sizeof(AVBStreamID_t));
+ if (pCfg->stream_addr.mac)
+ memcpy(streamID.addr, pCfg->stream_addr.mac, ETH_ALEN);
+ streamID.uniqueID = pCfg->stream_uid;
+
+ unsigned int maxBitrate = 0;
+ if (pCfg->intf_cb.intf_get_src_bitrate_cb != NULL) {
+ maxBitrate = pCfg->intf_cb.intf_get_src_bitrate_cb(pTLState->pMediaQ);
+ }
+ if (maxBitrate > 0) {
+ if (pCfg->map_cb.map_set_src_bitrate_cb != NULL) {
+ pCfg->map_cb.map_set_src_bitrate_cb(pTLState->pMediaQ, maxBitrate);
+ }
+
+ if (pCfg->map_cb.map_get_max_interval_frames_cb != NULL) {
+ 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;
+
+ // The TSpec frame size is the L2 payload - i.e. no Ethernet headers, VLAN, FCS, etc...
+ pTalkerData->tSpec.maxFrameSize = pCfg->map_cb.map_max_data_size_cb(pTLState->pMediaQ);
+
+ AVB_LOGF_INFO("Register "STREAMID_FORMAT": class: %c frame size: %d frame interval: %d", STREAMID_ARGS(&streamID), AVB_CLASS_LABEL(pCfg->sr_class), pTalkerData->tSpec.maxFrameSize, pTalkerData->tSpec.maxIntervalFrames);
+
+ // Tell endpoint to register our stream.
+ // SRP will send out talker declarations on the LAN.
+ // If there are listeners, we'll get callback (above.)
+ return (openavbEptClntRegisterStream(pTLState->endpointHandle,
+ &streamID,
+ pCfg->dest_addr.mac->ether_addr_octet,
+ &pTalkerData->tSpec,
+ pCfg->sr_class,
+ pCfg->sr_rank,
+ pCfg->internal_latency));
+}
+
+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
new file mode 100644
index 00000000..5d1aec64
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_talker_no_endpoint.c
@@ -0,0 +1,149 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Talker implementation for use without endpoint
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "openavb_tl.h"
+#include "openavb_avtp.h"
+#include "openavb_talker.h"
+#include "openavb_qmgr.h"
+#include "openavb_endpoint.h"
+
+#define AVB_LOG_COMPONENT "Talker"
+#include "openavb_log.h"
+#include "openavb_trace.h"
+
+// SR Class default Priority (PCP) values per IEEE 802.1Q-2011 Table 6-6
+#define SR_CLASS_A_DEFAULT_PRIORITY 3
+#define SR_CLASS_B_DEFAULT_PRIORITY 2
+
+// SR Class default VLAN Id values per IEEE 802.1Q-2011 Table 9-2
+#define SR_CLASS_A_DEFAULT_VID 2
+#define SR_CLASS_B_DEFAULT_VID 2
+
+// Returns TRUE, to say we're connected and registers tspec with FQTSS tspec should be initialized
+bool openavbTLRunTalkerInit(tl_state_t *pTLState)
+{
+ openavb_tl_cfg_t *pCfg = &pTLState->cfg;
+ talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
+ //avtp_stream_t *pStream = (avtp_stream_t *)(pTalkerData->avtpHandle);
+
+ strncpy(pTalkerData->ifname, pCfg->ifname, IFNAMSIZ);
+
+ // 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;
+ if (pCfg->sr_class == SR_CLASS_A) {
+ pTalkerData->classRate = 8000;
+ pTalkerData->vlanID = SR_CLASS_A_DEFAULT_VID;
+ pTalkerData->vlanPCP = SR_CLASS_A_DEFAULT_PRIORITY;
+ }
+ else if (pCfg->sr_class == SR_CLASS_B) {
+ pTalkerData->classRate = 4000;
+ pTalkerData->vlanID = SR_CLASS_B_DEFAULT_VID;
+ pTalkerData->vlanPCP = SR_CLASS_B_DEFAULT_PRIORITY;
+ }
+ memcpy(&pTalkerData->destAddr, &pCfg->dest_addr.mac->ether_addr_octet, ETH_ALEN);
+
+ unsigned int maxBitrate = 0;
+ if (pCfg->intf_cb.intf_get_src_bitrate_cb != NULL) {
+ maxBitrate = pCfg->intf_cb.intf_get_src_bitrate_cb(pTLState->pMediaQ);
+ }
+ if (maxBitrate > 0) {
+ if (pCfg->map_cb.map_set_src_bitrate_cb != NULL) {
+ pCfg->map_cb.map_set_src_bitrate_cb(pTLState->pMediaQ, maxBitrate);
+ }
+
+ if (pCfg->map_cb.map_get_max_interval_frames_cb != NULL) {
+ 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;
+ }
+ else {
+ // Override the class observation interval with the one provided by the mapping module.
+ pTalkerData->wakeRate = pCfg->map_cb.map_transmit_interval_cb(pTLState->pMediaQ) / pCfg->batch_factor;
+ }
+
+ if_info_t ifinfo;
+ openavbCheckInterface(pTalkerData->ifname, &ifinfo);
+
+ pTalkerData->fwmark = openavbQmgrAddStream((SRClassIdx_t)pCfg->sr_class,
+ pTalkerData->wakeRate,
+ pTalkerData->tSpec.maxIntervalFrames,
+ pTalkerData->tSpec.maxFrameSize);
+
+ 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);
+
+ return TRUE;
+}
+
+void openavbTLRunTalkerFinish(tl_state_t *pTLState)
+{
+ talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
+ openavbQmgrRemoveStream(pTalkerData->fwmark);
+}
+
+void openavbEptClntNotifyTlkrOfSrpCb(
+int endpointHandle,
+AVBStreamID_t *streamID,
+char *ifname,
+U8 destAddr[],
+openavbSrpLsnrDeclSubtype_t lsnrDecl,
+U32 classRate,
+U16 vlanID,
+U8 priority,
+U16 fwmark)
+{
+}
+
diff --git a/lib/avtp_pipeline/tl/openavb_tl.c b/lib/avtp_pipeline/tl/openavb_tl.c
new file mode 100755
index 00000000..f22191a9
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_tl.c
@@ -0,0 +1,733 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Common implementation for the talker and listener
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "openavb_tl.h"
+#include "openavb_trace.h"
+#include "openavb_mediaq.h"
+#include "openavb_talker.h"
+#include "openavb_listener.h"
+// #include "openavb_avtp.h"
+#include "openavb_platform.h"
+
+#define AVB_LOG_COMPONENT "Talker / Listener"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+U32 gMaxTL;
+tl_handle_t *gTLHandleList;
+
+// We are accessed from multiple threads, so need a mutex
+MUTEX_HANDLE(gTLStateMutex);
+
+#define MATCH(A, B)(strcasecmp((A), (B)) == 0)
+//#define MATCH_LEFT(A, B, C)(strncasecmp((A), (B), (C)) == 0)
+#define MATCH_LEFT(A, B, C) (memcmp((A), (B), (C)) == 0)
+
+THREAD_TYPE(listenerThread);
+THREAD_TYPE(talkerThread);
+
+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 timespec_add_usec(struct timespec *t, unsigned long us)
+{
+ t->tv_nsec += us * NANOSECONDS_PER_USEC;
+ t->tv_sec += t->tv_nsec / NANOSECONDS_PER_SECOND;
+ t->tv_nsec = t->tv_nsec % NANOSECONDS_PER_SECOND;
+}
+
+void timespec_sub_usec(struct timespec *t, unsigned long us)
+{
+ t->tv_nsec -= us * NANOSECONDS_PER_USEC;
+ t->tv_sec += t->tv_nsec / NANOSECONDS_PER_SECOND;
+ t->tv_nsec = t->tv_nsec % NANOSECONDS_PER_SECOND;
+ if (t->tv_nsec < 0) {
+ t->tv_sec--;
+ t->tv_nsec = NANOSECONDS_PER_SECOND + t->tv_nsec;
+ }
+}
+
+unsigned long timespec_usec_diff(struct timespec *t1, struct timespec *t2)
+{
+ return (t1->tv_sec - t2->tv_sec) * MICROSECONDS_PER_SECOND
+ + (t1->tv_nsec - t2->tv_nsec) / NANOSECONDS_PER_USEC;
+}
+
+int timespec_cmp(struct timespec *a, struct timespec *b)
+{
+ if (a->tv_sec > b->tv_sec)
+ return 1;
+ else if (a->tv_sec < b->tv_sec)
+ return -1;
+ else {
+ if (a->tv_nsec > b->tv_nsec)
+ return 1;
+ else if (a->tv_nsec < b->tv_nsec)
+ return -1;
+ }
+ return 0;
+}
+
+static bool TLHandleListAdd(tl_handle_t handle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!handle || !gTLHandleList) {
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ TL_LOCK();
+ int i1;
+ for (i1 = 0; i1 < gMaxTL; i1++) {
+ if (!gTLHandleList[i1]) {
+ gTLHandleList[i1] = handle;
+ TL_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TRUE;
+ }
+ }
+ TL_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+}
+
+bool TLHandleListRemove(tl_handle_t handle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!handle || !gTLHandleList) {
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ TL_LOCK();
+ int i1;
+ for (i1 = 0; i1 < gMaxTL; i1++) {
+ if (gTLHandleList[i1] == handle) {
+ gTLHandleList[i1] = NULL;
+ TL_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TRUE;
+ }
+ }
+ TL_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+}
+
+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'.");
+ // 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'.");
+ // 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'.");
+ 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'.");
+ // 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'.");
+ validCfg = FALSE;
+ }
+ if (!pCfg->intf_cb.intf_end_cb) {
+ AVB_LOG_WARNING("INI file doesn't specify inferface 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'.");
+ // 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'.");
+ // validCfg = FALSE;
+ }
+
+ return validCfg;
+}
+
+static bool checkMapCallbacks(openavb_tl_cfg_t *pCfg)
+{
+ bool validCfg = TRUE;
+
+ if (!pCfg->map_cb.map_cfg_cb) {
+ AVB_LOG_WARNING("INI doesn't specify mapping callback for '_cfg'.");
+ // validCfg = FALSE;
+ }
+ if (!pCfg->map_cb.map_subtype_cb) {
+ AVB_LOG_WARNING("INI doesn't specify mapping callback for '_subtype'.");
+ // validCfg = FALSE;
+ }
+ if (!pCfg->map_cb.map_avtp_version_cb) {
+ AVB_LOG_WARNING("INI doesn't specify mapping callback for '_avtp_version'.");
+ // validCfg = FALSE;
+ }
+ if ((pCfg->role == AVB_ROLE_TALKER) && !pCfg->map_cb.map_tx_init_cb) {
+ AVB_LOG_WARNING("INI doesn't specify mapping callback for '_tx_init'.");
+ // validCfg = FALSE;
+ }
+ if ((pCfg->role == AVB_ROLE_TALKER) && !pCfg->map_cb.map_tx_cb) {
+ AVB_LOG_ERROR("INI doesn't specify mapping callback for '_tx'.");
+ validCfg = FALSE;
+ }
+ if ((pCfg->role == AVB_ROLE_LISTENER) && !pCfg->map_cb.map_rx_init_cb) {
+ AVB_LOG_WARNING("INI doesn't specify mapping callback for '_rx_init'.");
+ // validCfg = FALSE;
+ }
+ if ((pCfg->role == AVB_ROLE_LISTENER) && !pCfg->map_cb.map_rx_cb) {
+ AVB_LOG_ERROR("INI doesn't specify mapping callback for '_rx'.");
+ validCfg = FALSE;
+ }
+ if (!pCfg->map_cb.map_end_cb) {
+ AVB_LOG_WARNING("INI doesn't specify mapping callback for '_end'.");
+ // validCfg = FALSE;
+ }
+ if (!pCfg->map_cb.map_gen_init_cb) {
+ AVB_LOG_WARNING("INI doesn't specify mapping callback for '_gen_init'.");
+ // validCfg = FALSE;
+ }
+ if (!pCfg->map_cb.map_gen_end_cb) {
+ 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;
+}
+
+void openavbTLUnconfigure(tl_state_t *pTLState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ // CORE_TODO: Disable this functionality until updated to properly handle distinction between values point to static const char
+ // and dynamically allocated strings.
+#if 0
+ openavb_tl_cfg_t *pCfg = &pTLState->cfg;
+
+ int i1;
+ for (i1 = 0; i1 < pCfg->nLibCfgItems; i1++) {
+ if (pCfg->libCfgNames[i1])
+ free(pCfg->libCfgNames[i1]);
+ if (pNVCfg->libCfgValues[i1])
+ free(pNVCfg->libCfgValues[i1]);
+ pCfg->libCfgNames[i1] = pNVCfg->libCfgValues[i1] = NULL;
+ }
+ pCfg->nLibCfgItems = 0;
+#endif
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+
+/* Public APIs
+ */
+// General initizlization of the talker and listener library. Must be called prior to using any other TL APIs.
+EXTERN_DLL_EXPORT bool openavbTLInitialize(U32 maxTL)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+ LOG_EAVB_CORE_VERSION();
+
+ // CORE_TODO : This can be used to AVB stack init functionality once such a thing exists in the reference implementation
+ AVB_TIME_INIT();
+
+ gMaxTL = maxTL;
+
+ {
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "gTLStateMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(gTLStateMutex, mta);
+ MUTEX_LOG_ERR("Error creating mutex");
+ }
+
+ gTLHandleList = calloc(1, sizeof(tl_handle_t) * gMaxTL);
+ if (gTLHandleList) {
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TRUE;
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+}
+
+// General cleanup of the talker and listener library. Should be called after all Talker and Listeners are closed.
+EXTERN_DLL_EXPORT bool openavbTLCleanup()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+ if (gTLHandleList) {
+ free(gTLHandleList);
+ gTLHandleList = NULL;
+ }
+ else {
+ return FALSE;
+ }
+
+ {
+ MUTEX_CREATE_ERR();
+ MUTEX_DESTROY(gTLStateMutex);
+ MUTEX_LOG_ERR("Error destroying mutex");
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TRUE;
+}
+
+EXTERN_DLL_EXPORT bool openavbGetVersion(U8 *major, U8 *minor, U8 *revision)
+{
+ if (!major || !minor || !revision) {
+ return FALSE;
+ }
+
+ *major = AVB_CORE_VER_MAJOR;
+ *minor = AVB_CORE_VER_MINOR;
+ *revision = AVB_CORE_VER_REVISION;
+ return TRUE;
+}
+
+EXTERN_DLL_EXPORT tl_handle_t openavbTLOpen(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = calloc(1, sizeof(tl_state_t));
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Unable to allocate talker listener state data.");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return NULL;
+ }
+
+ if (!TLHandleListAdd(pTLState)) {
+ AVB_LOG_ERROR("To many talker listeners open.");
+ free(pTLState);
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return NULL;
+ }
+
+ return pTLState;
+}
+
+EXTERN_DLL_EXPORT void openavbTLInitCfg(openavb_tl_cfg_t *pCfg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ memset(pCfg, 0, sizeof(openavb_tl_cfg_t));
+
+ // Set default values.
+ pCfg->role = AVB_ROLE_UNDEFINED;
+ //pCfg->map_cb;
+ //pCfg->intf_cb;
+ //pCfg->dest_addr;
+ //pCfg->stream_addr;
+ pCfg->stream_uid = -1;
+ 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->pMapInitFn = NULL;
+ pCfg->pIntfInitFn = NULL;
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+EXTERN_DLL_EXPORT bool openavbTLConfigure(tl_handle_t handle, openavb_tl_cfg_t *pCfgIn, openavb_tl_cfg_name_value_t *pNVCfg)
+{
+ 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 FALSE;
+ }
+
+ // Create the mediaQ
+ pTLState->pMediaQ = openavbMediaQCreate();
+ if (!pTLState->pMediaQ) {
+ AVB_LOG_ERROR("Unable to create media queue");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ // CORE_TODO: It's not safe to simply copy the openavb_tl_cfg_t since there are embedded pointers in the cfg_mac_t member.
+ // Those pointers need to be updated after a copy. Longer term the cfg_mac_t should be changed to not contain the mac
+ // member to remedy this issue and avoid further bugs.
+ memcpy(&pTLState->cfg, pCfgIn, sizeof(openavb_tl_cfg_t));
+ pTLState->cfg.dest_addr.mac = &pTLState->cfg.dest_addr.buffer;
+ pTLState->cfg.stream_addr.mac = &pTLState->cfg.stream_addr.buffer;
+
+ openavb_tl_cfg_t *pCfg = &pTLState->cfg;
+
+ if (!((pCfg->role == AVB_ROLE_TALKER) || (pCfg->role == AVB_ROLE_LISTENER))) {
+ AVB_LOG_ERROR("Talker - Listener Config Error: invalid role");
+ return FALSE;
+ }
+
+ if ((pCfg->role == AVB_ROLE_TALKER) && (pCfg->max_interval_frames == 0)) {
+ AVB_LOG_ERROR("Talker - Listener Config Error: talker role requires 'max_interval_frames'");
+ return FALSE;
+ }
+
+ openavbMediaQSetMaxStaleTail(pTLState->pMediaQ, pCfg->max_stale);
+
+ if (!openavbTLOpenLinkLibsOsal(pTLState)) {
+ AVB_LOG_ERROR("Failed to open mapping / interface library");
+ return FALSE;
+ }
+
+ if (pCfg->pMapInitFn && pCfg->pMapInitFn(pTLState->pMediaQ, &pCfg->map_cb, pCfg->max_transit_usec)) {
+ checkMapCallbacks(&pTLState->cfg);
+ }
+ else {
+ AVB_LOG_ERROR("Mapping initialize function error.");
+ return FALSE;
+ }
+
+ if (pCfg->pIntfInitFn && pCfg->pIntfInitFn(pTLState->pMediaQ, &pCfg->intf_cb)) {
+ checkIntfCallbacks(&pTLState->cfg);
+ }
+ else {
+ AVB_LOG_ERROR("Interface initialize function error.");
+ return FALSE;
+ }
+
+ // Submit configuration values to mapping and interface modules
+ int i;
+ for (i = 0; i < pNVCfg->nLibCfgItems; i++) {
+ if (MATCH_LEFT(pNVCfg->libCfgNames[i], "intf_nv_", 8)) {
+ if (pCfg->intf_cb.intf_cfg_cb) {
+ pCfg->intf_cb.intf_cfg_cb(pTLState->pMediaQ, pNVCfg->libCfgNames[i], pNVCfg->libCfgValues[i]);
+ }
+ else {
+ AVB_LOGF_ERROR("No interface module cfg function; ignoring %s", pNVCfg->libCfgNames[i]);
+ }
+ }
+ else if (MATCH_LEFT(pNVCfg->libCfgNames[i], "map_nv_", 7)) {
+ if (pCfg->map_cb.map_cfg_cb) {
+ pCfg->map_cb.map_cfg_cb(pTLState->pMediaQ, pNVCfg->libCfgNames[i], pNVCfg->libCfgValues[i]);
+ }
+ else {
+ AVB_LOGF_ERROR("No mapping module cfg function; ignoring %s", pNVCfg->libCfgNames[i]);
+ }
+ }
+ else {
+ assert(0);
+ }
+ } // for loop ends
+
+ pTLState->cfg.map_cb.map_gen_init_cb(pTLState->pMediaQ);
+ pTLState->cfg.intf_cb.intf_gen_init_cb(pTLState->pMediaQ);
+
+ return TRUE;
+}
+
+EXTERN_DLL_EXPORT bool openavbTLRun(tl_handle_t handle)
+{
+ bool retVal = FALSE;
+
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = (tl_state_t *)handle;
+
+ do {
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid handle.");
+ break;
+ }
+
+ pTLState->bRunning = TRUE;
+ if (pTLState->cfg.role == AVB_ROLE_TALKER) {
+ THREAD_CREATE_TALKER();
+ }
+ else if (pTLState->cfg.role == AVB_ROLE_LISTENER) {
+ THREAD_CREATE_LISTENER();
+ }
+
+ retVal = TRUE;
+
+ } while (0);
+
+
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return retVal;
+}
+
+extern DLL_EXPORT bool openavbTLStop(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 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.
+ //pTLState->bStreaming = FALSE;
+ pTLState->bRunning = FALSE;
+
+ THREAD_JOIN(pTLState->TLThread, NULL);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TRUE;
+}
+
+EXTERN_DLL_EXPORT bool openavbTLClose(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 FALSE;
+ }
+
+ if (pTLState->bRunning == TRUE) {
+ // In case openavbTLStop wasn't called stop is now.
+ openavbTLStop(handle);
+ }
+
+ pTLState->cfg.intf_cb.intf_gen_end_cb(pTLState->pMediaQ);
+ pTLState->cfg.map_cb.map_gen_end_cb(pTLState->pMediaQ);
+
+ TLHandleListRemove(handle);
+
+ openavbTLUnconfigure(pTLState);
+ openavbTLCloseLinkLibsOsal(pTLState);
+
+ if (pTLState->pMediaQ) {
+ openavbMediaQDelete(pTLState->pMediaQ);
+ pTLState->pMediaQ = NULL;
+ }
+
+ // Free TLState
+ free(pTLState);
+ pTLState = NULL;
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TRUE;
+}
+
+EXTERN_DLL_EXPORT void* openavbTLGetIntfHostCBList(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 FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return pTLState->cfg.intf_cb.intf_host_cb_list;
+}
+
+EXTERN_DLL_EXPORT void* openavbTLGetIntfHandle(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 FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return pTLState->pMediaQ;
+}
+
+EXTERN_DLL_EXPORT bool openavbTLIsRunning(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 FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return pTLState->bRunning;
+}
+
+EXTERN_DLL_EXPORT bool openavbTLIsConnected(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 FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return pTLState->bConnected;
+}
+
+EXTERN_DLL_EXPORT bool openavbTLIsStreaming(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 FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return pTLState->bStreaming;
+}
+
+EXTERN_DLL_EXPORT avb_role_t openavbTLGetRole(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 AVB_ROLE_UNDEFINED;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return pTLState->cfg.role;
+}
+
+
+EXTERN_DLL_EXPORT U64 openavbTLStat(tl_handle_t handle, tl_stat_t stat)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+ U64 val = 0;
+
+ tl_state_t *pTLState = (tl_state_t *)handle;
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid handle");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return 0;
+ }
+
+ if (pTLState->cfg.role == AVB_ROLE_TALKER) {
+ val = openavbTalkerGetStat(pTLState, stat);
+ }
+ else if (pTLState->cfg.role == AVB_ROLE_LISTENER) {
+ val = openavbListenerGetStat(pTLState, stat);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return val;
+}
+
+EXTERN_DLL_EXPORT void openavbTLPauseStream(tl_handle_t handle, bool bPause)
+{
+ 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;
+ }
+
+ if (pTLState->cfg.role == AVB_ROLE_TALKER) {
+ openavbTLPauseTalker(pTLState, bPause);
+ }
+ else if (pTLState->cfg.role == AVB_ROLE_LISTENER) {
+ openavbTLPauseListener(pTLState, bPause);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+
+
diff --git a/lib/avtp_pipeline/tl/openavb_tl.h b/lib/avtp_pipeline/tl/openavb_tl.h
new file mode 100755
index 00000000..82f38417
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_tl.h
@@ -0,0 +1,164 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Talker Listener header
+*/
+
+#ifndef OPENAVB_TL_H
+#define OPENAVB_TL_H 1
+
+#include "openavb_types.h"
+#include "openavb_osal.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_tl_pub.h"
+
+typedef enum OPENAVB_TL_AVB_VER_STATE
+{
+ OPENAVB_TL_AVB_VER_UNKNOWN = 0,
+ OPENAVB_TL_AVB_VER_INVALID,
+ OPENAVB_TL_AVB_VER_VALID,
+} openavbTLAVBVerState_t;
+
+typedef struct {
+ U64 totalCalls;
+ U64 totalFrames;
+ U64 totalLate;
+ U64 totalBytes;
+} talker_stats_t;
+
+THREAD_TYPE(TLThread);
+
+typedef struct {
+ // Running flag. (assumed atomic)
+ bool bRunning;
+
+ // Connected to endpoint flag. (assumed atomic)
+ bool bConnected;
+
+ // Streaming data flag. (assumed atomic)
+ bool bStreaming;
+
+ // The status of the version check to make sure endpoint and TL are running the same version.
+ openavbTLAVBVerState_t AVBVerState;
+
+ // Configuration settings. (Values are set once from a single thread no lock needed).
+ openavb_tl_cfg_t cfg;
+
+ // Handle to the endpoint. (Set once from a single thread no lock needed.)
+ int endpointHandle;
+
+ // Media queue struct.
+ media_q_t *pMediaQ;
+
+ // Private talker data.
+ void *pPvtTalkerData;
+
+ // Private listener data.
+ void *pPvtListenerData;
+
+ // Thread for talker or listener
+ THREAD_DEFINITON(TLThread);
+
+ // Per stream Stats Mutex
+ MUTEX_HANDLE(statsMutex);
+
+ LINK_LIB(mapLib);
+
+ LINK_LIB(intfLib);
+} tl_state_t;
+
+// Clock that we use for all timers in TL
+//#define TIMER_CLOCK CLOCK_MONOTONIC
+
+////////////////
+// TL state mutex
+////////////////
+extern MUTEX_HANDLE(gTLStateMutex);
+#define TL_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(gTLStateMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define TL_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(gTLStateMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+////////////////
+// TL stats mutex
+////////////////
+#define LOCK_STATS() { MUTEX_CREATE_ERR(); MUTEX_LOCK(pTLState->statsMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define UNLOCK_STATS() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(pTLState->statsMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+////////////////
+// timespec support functions
+////////////////
+void timespec_add_usec(struct timespec *t, unsigned long us);
+void timespec_sub_usec(struct timespec *t, unsigned long us);
+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.
+////////////////
+// Get a tl_handle_t from the TLHandleList given an endpointHandle.
+extern U32 gMaxTL;
+extern tl_handle_t *gTLHandleList;
+tl_handle_t TLHandleListGet(int endpointHandle);
+
+bool TLHandleListRemove(tl_handle_t handle);
+void openavbTLUnconfigure(tl_state_t *pTLState);
+
+// Remove a tl_handle_t from the TL handle list.
+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);
+bool openavbTLOpenLinkLibsOsal(tl_state_t *pTLState);
+bool openavbTLCloseLinkLibsOsal(tl_state_t *pTLState);
+
+/* These were in openavb_endpoint.h, but was moved here
+ * for implementations that do not have endpoint */
+bool openavbEptClntService(int h, int timeout);
+bool openavbEptClntStopStream(int h, AVBStreamID_t *streamID);
+
+#endif // OPENAVB_TL_H
diff --git a/lib/avtp_pipeline/tl/openavb_tl_endpoint.c b/lib/avtp_pipeline/tl/openavb_tl_endpoint.c
new file mode 100644
index 00000000..d6a4ad13
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_tl_endpoint.c
@@ -0,0 +1,278 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Common implementation for the talker and listener
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "openavb_tl.h"
+#include "openavb_trace.h"
+#include "openavb_mediaq.h"
+#include "openavb_talker.h"
+#include "openavb_listener.h"
+#include "openavb_endpoint.h"
+#include "openavb_avtp.h"
+#include "openavb_platform.h"
+#include "openavb_endpoint_osal.h"
+
+#define AVB_LOG_COMPONENT "Talker / Listener"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+void openavbEptClntCheckVerMatchesSrvr(int endpointHandle, U32 AVBVersion)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = TLHandleListGet(endpointHandle);
+
+ if (AVBVersion == AVB_CORE_VER_FULL) {
+ pTLState->AVBVerState = OPENAVB_TL_AVB_VER_VALID;
+ }
+ else {
+ pTLState->AVBVerState = OPENAVB_TL_AVB_VER_INVALID;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+/* Talker Listener thread function that talks primarily with the endpoint
+ */
+void* openavbTLThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = (tl_state_t *)pv;
+
+ while (pTLState->bRunning) {
+ AVB_TRACE_LINE(AVB_TRACE_TL_DETAIL);
+
+ int endpointHandle = openavbEptClntOpenSrvrConnection(pTLState);
+
+ if (endpointHandle == AVB_ENDPOINT_HANDLE_INVALID) {
+ // error connecting to endpoint, already logged
+ }
+ else {
+ pTLState->endpointHandle = endpointHandle;
+
+ // Validate the AVB version for TL and Endpoint are the same before continuing
+ pTLState->AVBVerState = OPENAVB_TL_AVB_VER_UNKNOWN;
+ pTLState->bConnected = openavbEptClntRequestVersionFromServer(pTLState->endpointHandle);
+ while (pTLState->bRunning && pTLState->bConnected && pTLState->AVBVerState == OPENAVB_TL_AVB_VER_UNKNOWN) {
+ // Check for endpoint version message. Timeout in 50 msec.
+ if (!openavbEptClntService(pTLState->endpointHandle, 50)) {
+ AVB_LOG_WARNING("Lost connection to endpoint, will retry");
+ pTLState->bConnected = FALSE;
+ pTLState->endpointHandle = 0;
+ }
+ }
+ if (pTLState->AVBVerState == OPENAVB_TL_AVB_VER_INVALID) {
+ AVB_LOG_ERROR("AVB core version is different than Endpoint AVB core version. Streams will not be started. Will reconnect to the endpoint and check again.");
+ }
+
+ if (pTLState->bConnected && pTLState->AVBVerState == OPENAVB_TL_AVB_VER_VALID) {
+ if (pTLState->cfg.role == AVB_ROLE_TALKER) {
+ openavbTLRunTalker(pTLState);
+ }
+ else {
+ openavbTLRunListener(pTLState);
+ }
+ }
+
+ // Close the endpoint connection. unless connection already gone in which case the socket could already be reused.
+ if (pTLState->bConnected) {
+ openavbEptClntCloseSrvrConnection(endpointHandle);
+ pTLState->bConnected = FALSE;
+ pTLState->endpointHandle = 0;
+ }
+ }
+
+ if (pTLState->bRunning) {
+ SLEEP(1);
+ }
+ }
+
+ THREAD_JOINABLE(pTLState->TLThread);
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return NULL;
+}
+
+// This is currently only for used for Endpoint
+tl_handle_t TLHandleListGet(int endpointHandle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!endpointHandle || !gTLHandleList) {
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return NULL;
+ }
+
+ TL_LOCK();
+ int i1;
+ for (i1 = 0; i1 < gMaxTL; i1++) {
+ if (gTLHandleList[i1]) {
+ tl_state_t *pTLState = (tl_state_t *)gTLHandleList[i1];
+ if (pTLState->endpointHandle == endpointHandle) {
+ TL_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return pTLState;
+ }
+ }
+ }
+ TL_UNLOCK();
+ 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
new file mode 100644
index 00000000..85173d2c
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_tl_no_endpoint.c
@@ -0,0 +1,134 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Common implementation for the talker and listener
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "openavb_tl.h"
+#include "openavb_trace.h"
+//#include "openavb_mediaq.h"
+#include "openavb_talker.h"
+#include "openavb_listener.h"
+#include "openavb_avtp.h"
+#include "openavb_endpoint.h"
+
+#include "openavb_platform.h"
+
+#define AVB_LOG_COMPONENT "Talker / Listener"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+void openavbEptClntCheckVerMatchesSrvr(int endpointHandle, U32 AVBVersion)
+{
+}
+
+
+// Talker Listener thread function
+void* openavbTLThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = (tl_state_t *)pv;
+
+ openavbTLThreadFnOsal(pTLState);
+
+ TL_LOCK();
+ // Assign a unique endpoint handle
+ static int gEndpointHandle = 1;
+ pTLState->endpointHandle = gEndpointHandle++;
+ TL_UNLOCK();
+
+ while (pTLState->bRunning) {
+ AVB_TRACE_LINE(AVB_TRACE_TL_DETAIL);
+
+ if (pTLState->cfg.role == AVB_ROLE_TALKER) {
+ openavbTLRunTalker(pTLState);
+ }
+ else {
+ openavbTLRunListener(pTLState);
+ }
+
+ // Close the endpoint connection. unless connection already gone in which case the socket could already be reused.
+ if (pTLState->bConnected) {
+ pTLState->bConnected = FALSE;
+ pTLState->endpointHandle = 0;
+ }
+
+ if (pTLState->bRunning) {
+ SLEEP(1);
+ }
+ }
+
+ THREAD_JOINABLE(pTLState->TLThread);
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return NULL;
+}
+
+tl_handle_t TLHandleListGet(int endpointHandle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!endpointHandle || !gTLHandleList) {
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return NULL;
+ }
+
+ TL_LOCK();
+ int i1;
+ for (i1 = 0; i1 < gMaxTL; i1++) {
+ if (gTLHandleList[i1]) {
+ tl_state_t *pTLState = (tl_state_t *)gTLHandleList[i1];
+ if (pTLState->endpointHandle == endpointHandle) {
+ TL_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return pTLState;
+ }
+ }
+ }
+ TL_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return NULL;
+}
+
+bool openavbEptClntStopStream(int h, AVBStreamID_t *streamID)
+{
+ return TRUE;
+}
+
+bool openavbEptClntService(int h, int timeout)
+{
+ return TRUE;
+}
+
diff --git a/lib/avtp_pipeline/tl/openavb_tl_pub.h b/lib/avtp_pipeline/tl/openavb_tl_pub.h
new file mode 100755
index 00000000..58b59dfd
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_tl_pub.h
@@ -0,0 +1,342 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Talker Listener Public Interface
+*/
+
+#ifndef OPENAVB_TL_PUB_H
+#define OPENAVB_TL_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_map_pub.h"
+#include "openavb_intf_pub.h"
+#include "openavb_avtp_time_pub.h"
+
+/** \file
+ * Talker Listener Public Interface.
+ */
+
+/// Handle to a single talker or listener.
+typedef void *tl_handle_t;
+
+/// Types of statistics gathered
+typedef enum {
+ /// Number of TX calls
+ TL_STAT_TX_CALLS,
+ /// Number of TX frames
+ TL_STAT_TX_FRAMES,
+ /// NUmber of late TX frames
+ TL_STAT_TX_LATE,
+ /// Number of bytes send
+ TL_STAT_TX_BYTES,
+ /// Number of RX calls
+ TL_STAT_RX_CALLS,
+ /// Number of RX frames
+ TL_STAT_RX_FRAMES,
+ /// Number of RX frames lost
+ TL_STAT_RX_LOST,
+ /// Number of bytes received
+ TL_STAT_RX_BYTES,
+} tl_stat_t;
+
+/// Maximum number of configuration parameters inside INI file a host can have
+#define MAX_LIB_CFG_ITEMS 64
+
+
+/// Maximum size of interface name
+#define IFNAMSIZE 16
+
+/// Structure containing configuration of the host
+typedef struct {
+ /// Role of the host
+ avb_role_t role;
+ /// Structure with callbacks to mapping
+ openavb_map_cb_t map_cb;
+ /// Structure with callbacks to inteface
+ 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;
+ /// 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 operatea ::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;
+ /// Network interface name. Not used on all platforms.
+ char ifname[IFNAMSIZE];
+ /// When set incoming packets will trigger a signal to the stream task to wakeup.
+ bool rx_signal_mode;
+
+ /// Initialization function in mapper
+ openavb_map_initialize_fn_t pMapInitFn;
+ /// Initialization function in interface
+ openavb_intf_initialize_fn_t pIntfInitFn;
+} openavb_tl_cfg_t;
+
+/// Structure holding configuration of mapping and interface modules
+typedef struct openavb_tl_cfg_name_value_t {
+ /// Configuration parameters Names for interface and mapping modules
+ char *libCfgNames[MAX_LIB_CFG_ITEMS];
+ /// Configuration parameters Values for interface and mapping modules
+ char *libCfgValues[MAX_LIB_CFG_ITEMS];
+ /// Number of configuration parameters defined
+ U32 nLibCfgItems;
+} openavb_tl_cfg_name_value_t;
+
+
+/** Initialize the talker listener library.
+ *
+ * This function must be called first before any other in the openavb_tl API.
+ * Any AVTP wide initialization occurs at this point
+ *
+ * \param maxTL The maximum number of talkers and listeners that will be started
+ * \return TRUE on success or FALSE on failure
+ *
+ * \warning Must be called prior to using any other TL APIs
+ */
+bool openavbTLInitialize(U32 maxTL);
+
+/** Final cleanup of the talker listener library.
+ *
+ * This function must be called last after all talkers and listeners have been closed
+ *
+ * \return TRUE on success or FALSE on failure
+ *
+ * \warning Should be called after all Talker and Listeners are closed
+ */
+bool openavbTLCleanup(void);
+
+/** Get the version of the AVB stack.
+ *
+ * Fills the major, minor and revision parameters with the values version
+ * information of the AVB stack
+ *
+ * \param major The major part of the version number
+ * \param minor The minor part of the version number
+ * \param revision The revision part of the version number
+ * \return TRUE on success or FALSE on failure
+ */
+bool openavbGetVersion(U8 *major, U8 *minor, U8 *revision);
+
+/** Open a talker or listener.
+ *
+ * This will create a talker / listener
+ *
+ * \return handle of the talker/listener. NULL if the talker or listener could not be loaded
+ */
+tl_handle_t openavbTLOpen(void);
+
+/** Initialize the configuration to default values.
+ * Initializes configuration file to default values
+ *
+ * \param pCfg Pointer to configuration structure
+ */
+void openavbTLInitCfg(openavb_tl_cfg_t *pCfg);
+
+/** Configure the talker / listener.
+ *
+ * Configures talker/listener with configuration values from configuration
+ * 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
+ * structure
+ * \return TRUE on success or FALSE on failure
+ */
+bool openavbTLConfigure(tl_handle_t handle, openavb_tl_cfg_t *pCfg, openavb_tl_cfg_name_value_t *pNVCfg);
+
+/** Run the talker or listener.
+ *
+ * The talker or listener indicated by handle that was previously loaded with
+ * the openavbTLOpen() function will be run. The stream will be opened at this time.
+ * Two threads created, one for endpoint IPC and one for stream handling.
+ *
+ * \param handle The handle return from openavbTLOpen()
+ * \return TRUE on success or FALSE on failure
+ */
+bool openavbTLRun(tl_handle_t handle);
+
+/** Stop a single talker or listener.
+ *
+ * Stop a single talker or listener. At this point data will not be sent or recieved
+ *
+ * \param handle The handle return from openavbTLOpen()
+ * \return TRUE on success or FALSE on failure
+ */
+bool openavbTLStop(tl_handle_t handle);
+
+/** Pause or resume as stream.
+ *
+ * A paused stream will do everything except will toss both tx and rx packets
+ *
+ * \param handle The handle return from openavbTLOpen()
+ * \param bPause TRUE to pause, FALSE to resume
+ * \return TRUE on success or FALSE on failure
+ */
+void openavbTLPauseStream(tl_handle_t handle, bool bPause);
+
+/** Close the talker or listener.
+ *
+ * The talker or listener indicated by handle that was previously loaded with
+ * the openavbTLOpen() function will be closed. The stream will be shutdown at this
+ * time and the threads created for this talker or listener will be killed
+ *
+ * \param handle The handle return from openavbTLOpen()
+ * \return TRUE on success or FALSE on failure
+ */
+bool openavbTLClose(tl_handle_t handle);
+
+/** Get a pointer to a list of interfaces module callbacks.
+ *
+ * In cases where a host application needs to call directly into an interface
+ * module it is preferable to do so with the APIs supplied in this SDK. This
+ * will allow passing back into the interface module a handle to its data. This
+ * handle is the value returned from openavbTLGetIntfHandle()
+ *
+ * \param handle The handle return from openavbTLOpen()
+ * \return A void * is returned. This is a pointer that can be resolved when
+ * combined with a public API defined by the specific interface module
+ */
+void* openavbTLGetIntfHostCBList(tl_handle_t handle);
+
+/** Get a handle to the interface module data from this talker or listener.
+ *
+ * Returns a handle to the interface module data. This handle will be used in
+ * call backs into the interface module from the host application and allows the
+ * interface module to associate the call back with the correct talker /
+ * listener (stream)
+ *
+ * \param handle The handle return from openavbTLOpen() \return Handle as a void *
+ * to the interface module data. This returned value is only intended to be
+ * passed back to the interface module in call backs from the host application.
+ */
+void* openavbTLGetIntfHandle(tl_handle_t handle);
+
+/** Check if a talker or listener is running.
+ *
+ * Checks if the talker or listener indicated by handle is running. The running
+ * status will be true after calling openavbTLRun()
+ *
+ * \param handle The handle return from openavbTLOpen()
+ * \return TRUE if running FALSE if not running
+ */
+bool openavbTLIsRunning(tl_handle_t handle);
+
+/** Checks if a talker or listener is connected to the endpoint.
+ *
+ * Checks if the talker or listener indicated by handle is connected to the
+ * endpoint process
+ *
+ * \param handle The handle return from openavbTLOpen()
+ * \return TRUE if connected FALSE if not connected
+ */
+bool openavbTLIsConnected(tl_handle_t handle);
+
+/** Checks if a talker or listener has an open stream.
+ *
+ * Checks if the talker or listener indicated by handle has an open stream
+ *
+ * \param handle The handle return from openavbTLOpen()
+ * \return TRUE if streaming FALSE if not streaming
+ */
+bool openavbTLIsStreaming(tl_handle_t handle);
+
+/** Return the role of the current stream handle.
+ *
+ * Returns if the current open stream is a talker or listener
+ *
+ * \param handle The handle return from openavbTLOpen()
+ * \return The current role
+ */
+avb_role_t openavbTLGetRole(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
+ *
+ * \param handle The handle return from openavbTLOpen()
+ * \param stat Which stat to retrieve
+ * \return the requested counter
+ */
+U64 openavbTLStat(tl_handle_t handle, tl_stat_t stat);
+
+/** 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
+ * structure
+ * \return TRUE on success or FALSE on failure
+ *
+ * \warning Not available on all platforms
+ */
+bool openavbTLReadIniFileOsal(tl_handle_t TLhandle, const char *fileName, openavb_tl_cfg_t *pCfg, openavb_tl_cfg_name_value_t *pNVCfg);
+
+
+/** \example openavb_host.c
+ * Talker / Listener example host application.
+ */
+#endif // OPENAVB_TL_PUB_H
diff --git a/lib/avtp_pipeline/util/CMakeLists.txt b/lib/avtp_pipeline/util/CMakeLists.txt
new file mode 100644
index 00000000..3e87f341
--- /dev/null
+++ b/lib/avtp_pipeline/util/CMakeLists.txt
@@ -0,0 +1,14 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/util/openavb_result_codes.c
+ ${AVB_SRC_DIR}/util/openavb_list.c
+ ${AVB_SRC_DIR}/util/openavb_array.c
+ ${AVB_SRC_DIR}/util/openavb_debug.c
+ ${AVB_SRC_DIR}/util/openavb_plugin.c
+ ${AVB_SRC_DIR}/util/openavb_log.c
+ ${AVB_SRC_DIR}/util/openavb_queue.c
+ ${AVB_SRC_DIR}/util/openavb_time.c
+ ${AVB_SRC_DIR}/util/openavb_timestamp.c
+ ${AVB_SRC_DIR}/util/openavb_printbuf.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/util/openavb_array.c b/lib/avtp_pipeline/util/openavb_array.c
new file mode 100644
index 00000000..ffebeba8
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_array.c
@@ -0,0 +1,443 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Implementation for a basic dynamic array abstraction.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "openavb_debug.h"
+#include "openavb_array.h"
+
+OPENAVB_CODE_MODULE_PRI
+
+struct openavb_array_elem {
+ void *data;
+ bool managed;
+ S32 idx;
+};
+
+struct openavb_array {
+ U32 elemSize;
+ S32 size;
+ S32 count;
+ S32 iterIdx;
+ openavb_array_elem_t elemArray;
+};
+
+openavb_array_t openavbArrayNewArray(U32 size)
+{
+ openavb_array_t retArray = calloc(1, sizeof(struct openavb_array));
+ if (retArray) {
+ retArray->elemSize = size;
+ retArray->size = 0;
+ retArray->count = 0;
+ retArray->iterIdx = 0;
+ }
+
+ return retArray;
+}
+
+bool openavbArraySetInitSize(openavb_array_t array, U32 size)
+{
+ if (array) {
+ if (!array->size) {
+ array->elemArray = calloc(size, sizeof(struct openavb_array_elem));
+ if (array->elemArray) {
+ array->size = size;
+
+ // Initialize each elem
+ S32 i1;
+ for (i1 = 0; i1 < array->size; i1++) {
+ array->elemArray[i1].data = NULL;
+ array->elemArray[i1].managed = FALSE;
+ array->elemArray[i1].idx = i1;
+ }
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+void openavbArrayDeleteArray(openavb_array_t array)
+{
+ if (array && array->elemArray) {
+ openavb_array_elem_t elem;
+ elem = openavbArrayIterFirst(array);
+ while (elem) {
+ openavbArrayDelete(array, elem);
+ elem = openavbArrayIterNext(array);
+ }
+ free(array->elemArray);
+ array->elemArray = NULL;
+ free(array);
+ }
+}
+
+openavb_array_elem_t openavbArrayAdd(openavb_array_t array, void *data)
+{
+ openavb_array_elem_t retElem = NULL;
+
+ if (array && data) {
+ if (array->elemArray && (array->count < array->size)) {
+ // Find the empty slot
+ S32 i1;
+ for (i1 = 0; i1 < array->size; i1++) {
+ if (!array->elemArray[i1].data) {
+ retElem = &array->elemArray[i1];
+ break;
+ }
+ }
+ }
+ else {
+ // Need to make room for new element
+ openavb_array_elem_t newElemArray = realloc(array->elemArray, (array->size + 1) * sizeof(struct openavb_array_elem));
+ if (newElemArray) {
+ array->elemArray = newElemArray;
+ retElem = &array->elemArray[array->size];
+ retElem->data = NULL;
+ retElem->managed = FALSE;
+ retElem->idx = array->size;
+ array->size++;
+ }
+ }
+
+ if (retElem) {
+ retElem->data = data;
+ array->count++;
+ }
+ }
+
+ return retElem;
+}
+
+openavb_array_elem_t openavbArrayNew(openavb_array_t array)
+{
+ openavb_array_elem_t retElem = NULL;
+
+ if (array) {
+ void *data = calloc(1, array->elemSize);
+ if (data) {
+ retElem = openavbArrayAdd(array, data);
+ if (retElem) {
+ retElem->managed = TRUE;
+ } else {
+ free(data);
+ }
+ }
+ }
+
+ return retElem;
+}
+
+bool openavbArrayMultiNew(openavb_array_t array, S32 count)
+{
+ int i1;
+ for (i1 = 0; i1 < count; i1++) {
+ if (!openavbArrayNew(array))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void openavbArrayDelete(openavb_array_t array, openavb_array_elem_t elem)
+{
+ if (array && elem) {
+ if (elem->managed) {
+ free(elem->data);
+ }
+ elem->data = NULL;
+ array->count--;
+ }
+}
+
+openavb_array_elem_t openavbArrayIdx(openavb_array_t array, S32 idx)
+{
+ openavb_array_elem_t retElem = NULL;
+
+ if (array && array->elemArray && idx >= 0 && idx < array->size) {
+ if (array->elemArray[idx].data) {
+ retElem = &array->elemArray[idx];
+ }
+ }
+ return retElem;
+}
+
+openavb_array_elem_t openavbArrayIterFirst(openavb_array_t array)
+{
+ openavb_array_elem_t retElem = NULL;
+
+ if (array && array->elemArray) {
+ S32 i1;
+ for (i1 = 0; i1 < array->size; i1++) {
+ if (array->elemArray[i1].data) {
+ retElem = &array->elemArray[i1];
+ array->iterIdx = i1;
+ break;
+ }
+ }
+ }
+ return retElem;
+}
+
+openavb_array_elem_t openavbArrayIterLast(openavb_array_t array)
+{
+ openavb_array_elem_t retElem = NULL;
+
+ if (array && array->elemArray) {
+ S32 i1;
+ for (i1 = array->size - 1; i1 >= 0; i1--) {
+ if (array->elemArray[i1].data) {
+ retElem = &array->elemArray[i1];
+ array->iterIdx = i1;
+ break;
+ }
+ }
+ }
+ return retElem;
+}
+
+openavb_array_elem_t openavbArrayIterNext(openavb_array_t array)
+{
+ openavb_array_elem_t retElem = NULL;
+
+ if (array && array->elemArray) {
+ S32 i1;
+ for (i1 = array->iterIdx + 1; i1 < array->size; i1++) {
+ if (array->elemArray[i1].data) {
+ retElem = &array->elemArray[i1];
+ array->iterIdx = i1;
+ break;
+ }
+ }
+ }
+ return retElem;
+}
+
+openavb_array_elem_t openavbArrayIterPrev(openavb_array_t array)
+{
+ openavb_array_elem_t retElem = NULL;
+
+ if (array && array->elemArray) {
+ S32 i1;
+ for (i1 = array->iterIdx - 1; i1 >= 0; i1--) {
+ if (array->elemArray[i1].data) {
+ retElem = &array->elemArray[i1];
+ array->iterIdx = i1;
+ break;
+ }
+ }
+ }
+ return retElem;
+}
+
+openavb_array_elem_t openavbArrayIterFirstAlt(openavb_array_t array, U32 *iter)
+{
+ openavb_array_elem_t retElem = NULL;
+
+ if (array && array->elemArray) {
+ S32 i1;
+ for (i1 = 0; i1 < array->size; i1++) {
+ if (array->elemArray[i1].data) {
+ retElem = &array->elemArray[i1];
+ *iter = i1;
+ break;
+ }
+ }
+ }
+ return retElem;
+}
+
+openavb_array_elem_t openavbArrayIterLastAlt(openavb_array_t array, U32 *iter)
+{
+ openavb_array_elem_t retElem = NULL;
+
+ if (array && array->elemArray) {
+ S32 i1;
+ for (i1 = array->size - 1; i1 >= 0; i1--) {
+ if (array->elemArray[i1].data) {
+ retElem = &array->elemArray[i1];
+ *iter = i1;
+ break;
+ }
+ }
+ }
+ return retElem;
+}
+
+openavb_array_elem_t openavbArrayIterNextAlt(openavb_array_t array, U32 *iter)
+{
+ openavb_array_elem_t retElem = NULL;
+
+ if (array && array->elemArray) {
+ S32 i1;
+ for (i1 = *iter + 1; i1 < array->size; i1++) {
+ if (array->elemArray[i1].data) {
+ retElem = &array->elemArray[i1];
+ *iter = i1;
+ break;
+ }
+ }
+ }
+ return retElem;
+}
+
+openavb_array_elem_t openavbArrayIterPrevAlt(openavb_array_t array, U32 *iter)
+{
+ openavb_array_elem_t retElem = NULL;
+
+ if (array && array->elemArray) {
+ S32 i1;
+ for (i1 = *iter - 1; i1 >= 0; i1--) {
+ if (array->elemArray[i1].data) {
+ retElem = &array->elemArray[i1];
+ *iter = i1;
+ break;
+ }
+ }
+ }
+ return retElem;
+}
+
+void *openavbArrayData(openavb_array_elem_t elem)
+{
+ if (elem) {
+ return elem->data;
+ }
+ return NULL;
+}
+
+void *openavbArrayDataIdx(openavb_array_t array, S32 idx)
+{
+ if (array) {
+ openavb_array_elem_t elem = openavbArrayIdx(array, idx);
+
+ if (elem) {
+ return elem->data;
+ }
+ }
+ return NULL;
+}
+
+void *openavbArrayDataNew(openavb_array_t array)
+{
+ if (array) {
+ openavb_array_elem_t elem = openavbArrayNew(array);
+
+ if (elem) {
+ return elem->data;
+ }
+ }
+ return NULL;
+}
+
+S32 openavbArrayFindData(openavb_array_t array, void *data)
+{
+ S32 retIdx = -1;
+ if (array && data) {
+ S32 i1;
+ for (i1 = 0; i1 < array->size; i1++) {
+ if (array->elemArray[i1].data == data) {
+ retIdx = i1;
+ break;
+ }
+ }
+ }
+ return retIdx;
+}
+
+
+S32 openavbArraySize(openavb_array_t array)
+{
+ if (array) {
+ return array->size;
+ }
+ return 0;
+}
+
+S32 openavbArrayCount(openavb_array_t array)
+{
+ if (array) {
+ return array->count;
+ }
+ return 0;
+}
+
+S32 openavbArrayGetIdx(openavb_array_elem_t elem)
+{
+ if (elem) {
+ return elem->idx;
+ }
+ return -1;
+}
+
+bool openavbArrayIsManaged(openavb_array_elem_t elem)
+{
+ if (elem) {
+ if (elem->managed) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void openavbArrayDump(openavb_array_t array)
+{
+ printf("TEST DUMP: Array contents\n");
+ if (array) {
+ printf("array: %p\n", array);
+ printf("elemSize: %u\n", (unsigned int)(array->elemSize));
+ printf("size: %d\n", (int)(array->size));
+ printf("count: %d\n", (int)(array->count));
+ printf("iterIdx: %d\n", (int)(array->iterIdx));
+ printf("elemArray %p\n", array->elemArray);
+
+ if (array->elemArray) {
+ S32 i1;
+ for (i1 = 0; i1 < array->size; i1++) {
+ printf("elemArray[%02d] %p\n", (int)i1, &array->elemArray[i1]);
+ printf("elemArray[%02d].data %p\n", (int)i1, array->elemArray[i1].data);
+ printf("elemArray[%02d].managed %d\n", (int)i1, array->elemArray[i1].managed);
+ printf("elemArray[%02d].idx %d\n", (int)i1, (int)(array->elemArray[i1].idx));
+ openavbDebugDumpBuf(array->elemArray[i1].data, array->elemSize);
+ }
+ }
+
+ return;
+ }
+ printf("Invalid array pointer\n");
+}
+
+
diff --git a/lib/avtp_pipeline/util/openavb_array.h b/lib/avtp_pipeline/util/openavb_array.h
new file mode 100644
index 00000000..ba55a5b8
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_array.h
@@ -0,0 +1,122 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Interface for a basic dynamic array abstraction.
+*
+* - Array dynamically grows as needed.
+* - Elements can be removed. This leaves an empty slot.
+* - Elements can not be moved once placed in the array.
+*/
+
+#ifndef OPENAVB_ARRAY_H
+#define OPENAVB_ARRAY_H 1
+
+#include "openavb_types.h"
+
+typedef struct openavb_array_elem * openavb_array_elem_t;
+typedef struct openavb_array * openavb_array_t;
+
+// Create an array. Returns NULL on failure.
+openavb_array_t openavbArrayNewArray(U32 elemSize);
+
+// Sets the initial number of array slots. Can only be used before adding elements to the array.
+bool openavbArraySetInitSize(openavb_array_t array, U32 size);
+
+// Delete an array.
+void openavbArrayDeleteArray(openavb_array_t array);
+
+// Add a data element to the array. Returns NULL on failure.
+openavb_array_elem_t openavbArrayAdd(openavb_array_t array, void *data);
+
+// Allocate and manage data element and add to the array. Returns NULL on failure.
+openavb_array_elem_t openavbArrayNew(openavb_array_t array);
+
+// Allocate and manage multiple data element and add to the array. Returns FALSE on failure.
+bool openavbArrayMultiNew(openavb_array_t array, S32 count);
+
+// Remove (delete) element. Will result in an empty slot.
+void openavbArrayDelete(openavb_array_t array, openavb_array_elem_t elem);
+
+// Gets the element at index. Returns FALSE on error.
+openavb_array_elem_t openavbArrayIdx(openavb_array_t array, S32 idx);
+
+// Gets the first element. Returns FALSE on error or empty array.
+openavb_array_elem_t openavbArrayIterFirst(openavb_array_t array);
+
+// Gets the last element. Returns FALSE on error or empty array.
+openavb_array_elem_t openavbArrayIterLast(openavb_array_t array);
+
+// Gets the next element. Returns FALSE on error or last element.
+openavb_array_elem_t openavbArrayIterNext(openavb_array_t array);
+
+// Gets the previous element. Returns FALSE on error or first element.
+openavb_array_elem_t openavbArrayIterPrev(openavb_array_t array);
+
+// Gets the first element. Returns FALSE on error or empty array. Alternate version with iter passed in for possible multi-threaded use.
+openavb_array_elem_t openavbArrayIterFirstAlt(openavb_array_t array, U32 *iter);
+
+// Gets the last element. Returns FALSE on error or empty array. Alternate version with iter passed in for possible multi-threaded use.
+openavb_array_elem_t openavbArrayIterLastAlt(openavb_array_t array, U32 *iter);
+
+// Gets the next element. Returns FALSE on error or last element. Alternate version with iter passed in for possible multi-threaded use.
+openavb_array_elem_t openavbArrayIterNextAlt(openavb_array_t array, U32 *iter);
+
+// Gets the previous element. Returns FALSE on error or first element. Alternate version with iter passed in for possible multi-threaded use.
+openavb_array_elem_t openavbArrayIterPrevAlt(openavb_array_t array, U32 *iter);
+
+// Get data of the element. Returns NULL on failure.
+void *openavbArrayData(openavb_array_elem_t elem);
+
+// Get data of the element at the Idx. Returns NULL on failure.
+void *openavbArrayDataIdx(openavb_array_t array, S32 idx);
+
+// Get data of a new element. Returns NULL on failure.
+void *openavbArrayDataNew(openavb_array_t array);
+
+// Find the index of the element data. Returns -1 if not found.
+S32 openavbArrayFindData(openavb_array_t array, void *data);
+
+// Get the size of the array. Allocated element slots
+S32 openavbArraySize(openavb_array_t array);
+
+// Get the count of the array. Valid elements in the array.
+S32 openavbArrayCount(openavb_array_t array);
+
+// Returns the index of the array element. -1 on error.
+S32 openavbArrayGetIdx(openavb_array_elem_t elem);
+
+// Returns TRUE is node data element memory is being managed by the list.
+bool openavbArrayIsManaged(openavb_array_elem_t elem);
+
+// Dump array details to console
+void openavbArrayDump(openavb_array_t array);
+
+#endif // OPENAVB_ARRAY_H
diff --git a/lib/avtp_pipeline/util/openavb_debug.c b/lib/avtp_pipeline/util/openavb_debug.c
new file mode 100644
index 00000000..42ebb977
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_debug.c
@@ -0,0 +1,90 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Implementation of debugging aid functions.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_debug.h"
+
+#define AVB_LOG_COMPONENT "Debug"
+#include "openavb_log_pub.h"
+
+void openavbDebugDumpBuf(U8 *pBuf, U32 len)
+{
+ printf("Dump buffer %p: ", pBuf);
+ if (pBuf) {
+ U32 i1;
+ for (i1 = 0; i1 < len; i1++) {
+ printf("%02X ", *pBuf);
+ pBuf++;
+ }
+ }
+ printf("\n");
+}
+
+void openavbDebugInterval(U32 interval, bool log, U32 *maxInterval, U32 *minInterval, U32 *cntInterval, U32 *accInterval, U64 *prevNS)
+{
+ U32 deltaUS;
+ U64 nowNS;
+
+ if (*prevNS > 0) {
+ CLOCK_GETTIME64(OPENAVB_CLOCK_MONOTONIC, &nowNS);
+ deltaUS = (nowNS - *prevNS) / 1000;
+ (*cntInterval)++;
+ if (deltaUS > *maxInterval)
+ *maxInterval = deltaUS;
+ if (deltaUS < *minInterval)
+ *minInterval = deltaUS;
+ *accInterval += deltaUS;
+
+ if (*cntInterval % interval == 0) {
+ if (log) {
+ AVB_LOGF_INFO("Gap(us):%u Gap Min(us):%u Gap Max(us):%u Gap Avg(us):%u",
+ (unsigned int)deltaUS,
+ (unsigned int)*minInterval,
+ (unsigned int)*maxInterval,
+ (unsigned int)(*accInterval / *cntInterval));
+ }
+ *cntInterval = 0;
+ *maxInterval = 0;
+ *minInterval = (U32)-1;
+ *accInterval = 0;
+ }
+ }
+
+ CLOCK_GETTIME64(OPENAVB_CLOCK_MONOTONIC, prevNS);
+}
diff --git a/lib/avtp_pipeline/util/openavb_debug.h b/lib/avtp_pipeline/util/openavb_debug.h
new file mode 100644
index 00000000..b3c7b439
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_debug.h
@@ -0,0 +1,57 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Implementation of debugging aid functions.
+*/
+
+#ifndef OPENAVB_DEBUG_H
+#define OPENAVB_DEBUG_H 1
+
+#include "openavb_types.h"
+
+#define DBG_VARx(x, y) x ## y
+#define DBG_VAR(x, y) DBG_VARx(x, y)
+
+// Dump the buffer to the console
+void openavbDebugDumpBuf(U8 *pBuf, U32 len);
+
+// Interval Testing
+#define AVB_DBG_INTERVAL(interval, log) \
+ static U32 DBG_VAR(maxInterval,__LINE__) = 0; \
+ static U32 DBG_VAR(minInterval,__LINE__) = (U32)-1; \
+ static U32 DBG_VAR(cntInterval,__LINE__) = 0; \
+ static U32 DBG_VAR(accInterval,__LINE__) = 0; \
+ static U64 DBG_VAR(prevNS,__LINE__) = 0; \
+ openavbDebugInterval(interval, log, &DBG_VAR(maxInterval,__LINE__), &DBG_VAR(minInterval,__LINE__), &DBG_VAR(cntInterval,__LINE__), &DBG_VAR(accInterval,__LINE__), &DBG_VAR(prevNS,__LINE__))
+void openavbDebugInterval(U32 interval, bool log, U32 *maxInterval, U32 *minInterval, U32 *cntInterval, U32 *accInterval, U64 *prevNS);
+
+
+#endif // OPENAVB_DEBUG_H
diff --git a/lib/avtp_pipeline/util/openavb_list.c b/lib/avtp_pipeline/util/openavb_list.c
new file mode 100644
index 00000000..9f36d819
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_list.c
@@ -0,0 +1,290 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Implementation for a basic doubly link list abstraction
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "openavb_debug.h"
+#include "openavb_list.h"
+
+OPENAVB_CODE_MODULE_PRI
+
+struct openavb_list_node {
+ void *data;
+ bool managed;
+ openavb_list_node_t prev;
+ openavb_list_node_t next;
+};
+
+struct openavb_list {
+ openavb_list_node_t head;
+ openavb_list_node_t tail;
+ openavb_list_node_t iter;
+};
+
+openavb_list_t openavbListNewList()
+{
+ return calloc(1, sizeof(struct openavb_list));
+}
+
+void openavbListDeleteList(openavb_list_t list)
+{
+ if (list) {
+ openavb_list_node_t node;
+ while ((node = openavbListFirst(list))) {
+ openavbListDelete(list, node);
+ }
+ free(list);
+ }
+}
+
+openavb_list_node_t openavbListAdd(openavb_list_t list, void *data)
+{
+ openavb_list_node_t retNode = NULL;
+ if (list) {
+ retNode = calloc(1, sizeof(struct openavb_list_node));
+ if (retNode) {
+ retNode->data = data;
+ retNode->prev = NULL;
+ if (!list->head) {
+ list->head = retNode;
+ list->tail = retNode;
+ }
+ else {
+ retNode->prev = list->tail;
+ list->tail->next = retNode;
+ list->tail = retNode;
+ }
+ }
+ }
+ return retNode;
+}
+
+openavb_list_node_t openavbListNew(openavb_list_t list, U32 size)
+{
+ openavb_list_node_t retNode = NULL;
+ if (list && size) {
+ void *data = calloc(1, size);
+ if (data) {
+ retNode = openavbListAdd(list, data);
+ if (retNode) {
+ retNode->managed = TRUE;
+ } else {
+ free(data);
+ }
+ }
+ }
+
+ return retNode;
+}
+
+openavb_list_node_t openavbListDelete(openavb_list_t list, openavb_list_node_t node)
+{
+ openavb_list_node_t retNode = NULL;
+ if (list && node) {
+ // Update head and tail if needed
+ if (node == list->head) {
+ list->head = node->next;
+ }
+ if (node == list->tail) {
+ list->tail = node->prev;
+ }
+
+ // Unchain ourselves
+ if (node->prev) {
+ node->prev->next = node->next;
+ }
+ if (node->next) {
+ node->next->prev = node->prev;
+ retNode = node->next;
+ }
+
+ // Free managed memory
+ if (node->managed && node->data) {
+ free(node->data);
+ node->data = NULL;
+ }
+ free(node);
+ }
+ return retNode;
+}
+
+openavb_list_node_t openavbListNext(openavb_list_t list, openavb_list_node_t node)
+{
+ openavb_list_node_t retNode = NULL;
+ if (list && node) {
+ retNode = node->next;
+ }
+ return retNode;
+}
+
+openavb_list_node_t openavbListPrev(openavb_list_t list, openavb_list_node_t node)
+{
+ openavb_list_node_t retNode = NULL;
+ if (list && node) {
+ retNode = node->prev;
+ }
+ return retNode;
+}
+
+openavb_list_node_t openavbListFirst(openavb_list_t list)
+{
+ openavb_list_node_t retNode = NULL;
+ if (list) {
+ return list->head;
+ }
+ return retNode;
+}
+
+openavb_list_node_t openavbListLast(openavb_list_t list)
+{
+ openavb_list_node_t retNode = NULL;
+ if (list) {
+ return list->tail;
+ }
+ return retNode;
+}
+
+openavb_list_node_t openavbListIterFirst(openavb_list_t list)
+{
+ openavb_list_node_t retNode = NULL;
+ if (list) {
+ list->iter = list->head;
+ retNode = list->iter;
+ }
+ return retNode;
+}
+
+
+openavb_list_node_t openavbListIterLast(openavb_list_t list)
+{
+ openavb_list_node_t retNode = NULL;
+ if (list) {
+ list->iter = list->tail;
+ retNode = list->iter;
+ }
+ return retNode;
+}
+
+openavb_list_node_t openavbListIterNext(openavb_list_t list)
+{
+ openavb_list_node_t retNode = NULL;
+ if (list && list->iter) {
+ list->iter = list->iter->next;
+ retNode = list->iter;
+ }
+ return retNode;
+}
+
+
+openavb_list_node_t openavbListIterPrev(openavb_list_t list)
+{
+ openavb_list_node_t retNode = NULL;
+ if (list && list->iter) {
+ list->iter = list->iter->prev;
+ retNode = list->iter;
+ }
+ return retNode;
+}
+
+void *openavbListData(openavb_list_node_t node)
+{
+ if (node) {
+ return node->data;
+ }
+ return NULL;
+}
+
+bool openavbListIsFirst(openavb_list_t list, openavb_list_node_t node)
+{
+ if (list && node) {
+ if (list->head == node) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+bool openavbListIsLast(openavb_list_t list, openavb_list_node_t node)
+{
+ if (list && node) {
+ if (list->tail == node) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+bool openavbListIsManaged(openavb_list_node_t node)
+{
+ if (node) {
+ if (node->managed) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void openavbListDump(openavb_list_t list, U32 dataSize)
+{
+ U32 count = 0;
+
+ printf("TEST DUMP: List contents\n");
+ if (list) {
+
+ printf("listHead %p\n", list->head);
+ printf("listTail %p\n", list->tail);
+ printf("listIter %p\n", list->iter);
+
+ openavb_list_node_t node = openavbListFirst(list);
+ while (node) {
+ count++;
+ printf("listNode Count %i\n", (int)count);
+ printf("listNodeData %p\n", node->data);
+ printf("listNodeManaged %i\n", node->managed);
+ printf("listNodePrev %p\n", node->prev);
+ printf("listNodeNext %p\n", node->next);
+ openavbDebugDumpBuf(node->data, dataSize);
+ node = openavbListNext(list, node);
+ }
+
+ return;
+ }
+ printf("Invalid list pointer\n");
+}
+
+
+
+
diff --git a/lib/avtp_pipeline/util/openavb_list.h b/lib/avtp_pipeline/util/openavb_list.h
new file mode 100644
index 00000000..0d974abb
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_list.h
@@ -0,0 +1,99 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Interface for a basic doubly link list abstraction
+* - Nodes can be added to the end of the list.
+* - Nodes can be removed at any location in the list.
+*/
+
+#ifndef OPENAVB_LIST_H
+#define OPENAVB_LIST_H 1
+
+#include "openavb_types.h"
+
+typedef struct openavb_list_node * openavb_list_node_t;
+typedef struct openavb_list * openavb_list_t;
+
+// Create a link list. Returns NULL on failure
+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.
+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.
+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.
+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.
+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.
+openavb_list_node_t openavbListFirst(openavb_list_t list);
+
+// Gets the lastt (tail) node. Returns FALSE 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.
+openavb_list_node_t openavbListIterFirst(openavb_list_t list);
+
+// Gets the last node and preps for iteration. Returns FALSE 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.
+openavb_list_node_t openavbListIterNext(openavb_list_t list);
+
+// Gets the prev node in the iteration. Returns FALSE on error or beginning of list.
+openavb_list_node_t openavbListIterPrev(openavb_list_t list);
+
+// Get data element. Returns NULL on failure.
+void *openavbListData(openavb_list_node_t node);
+
+// Returns TRUE is node is the head.
+bool openavbListIsFirst(openavb_list_t list, openavb_list_node_t node);
+
+// Returns TRUE is node is the tail.
+bool openavbListIsLast(openavb_list_t list, openavb_list_node_t node);
+
+// Returns TRUE is node data element memory is being managed by the list.
+bool openavbListIsManaged(openavb_list_node_t node);
+
+// Dump the contents of the list to the console. Debugging purposes only.
+void openavbListDump(openavb_list_t list, U32 dataSize);
+
+#endif // OPENAVB_LIST_H
diff --git a/lib/avtp_pipeline/util/openavb_log.c b/lib/avtp_pipeline/util/openavb_log.c
new file mode 100644
index 00000000..a0c937c4
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_log.c
@@ -0,0 +1,394 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_types_pub.h"
+#include "openavb_platform_pub.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include "openavb_queue.h"
+#include "openavb_tcal_pub.h"
+
+#include "openavb_log.h"
+
+typedef struct {
+ U8 msg[LOG_QUEUE_MSG_SIZE];
+ bool bRT; // TRUE = Details are in RT queue
+} log_queue_item_t;
+
+typedef struct {
+ char *pFormat;
+ log_rt_datatype_t dataType;
+ union {
+ struct timespec nowTS;
+ U16 unsignedShortVar;
+ S16 signedShortVar;
+ U32 unsignedLongVar;
+ S32 signedLongVar;
+ U64 unsignedLongLongVar;
+ S64 signedLongLongVar;
+ float floatVar;
+ } data;
+ bool bEnd;
+} log_rt_queue_item_t;
+
+static openavb_queue_t logQueue;
+static openavb_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 bool loggingThreadRunning = false;
+extern void *loggingThreadFn(void *pv);
+THREAD_TYPE(loggingThread);
+THREAD_DEFINITON(loggingThread);
+
+static MUTEX_HANDLE_ALT(gLogMutex);
+#define LOG_LOCK() MUTEX_LOCK_ALT(gLogMutex)
+#define LOG_UNLOCK() MUTEX_UNLOCK_ALT(gLogMutex)
+
+void avbLogRTRender(log_queue_item_t *pLogItem)
+{
+ if (logRTQueue) {
+ pLogItem->msg[0] = 0x00;
+ bool bMore = TRUE;
+ while (bMore) {
+ openavb_queue_elem_t elem = openavbQueueTailLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)openavbQueueData(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 (OPENAVB_TCAL_LOG_EXTRA_NEWLINE)
+ strcat((char *)pLogItem->msg, "\n");
+ bMore = FALSE;
+ }
+ openavbQueueTailPull(logRTQueue);
+ }
+
+ }
+ }
+}
+
+extern U32 DLL_EXPORT avbLogGetMsg(U8 *pBuf, U32 bufSize)
+{
+ U32 dataLen = 0;
+ if (logQueue) {
+ 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);
+
+ dataLen = strlen((const char *)pLogItem->msg);
+ if (dataLen <= bufSize)
+ memcpy(pBuf, (U8 *)pLogItem->msg, dataLen);
+ else
+ memcpy(pBuf, (U8 *)pLogItem->msg, bufSize);
+ openavbQueueTailPull(logQueue);
+ return dataLen;
+ }
+ }
+ return dataLen;
+}
+
+void *loggingThreadFn(void *pv)
+{
+ while (loggingThreadRunning) {
+ SLEEP_MSEC(LOG_QUEUE_SLEEP_MSEC);
+
+ bool more = TRUE;
+
+ 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);
+ openavbQueueTailPull(logQueue);
+ more = TRUE;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+extern void DLL_EXPORT avbLogInit(void)
+{
+ MUTEX_CREATE_ALT(gLogMutex);
+
+ logQueue = openavbQueueNewQueue(sizeof(log_queue_item_t), LOG_QUEUE_MSG_CNT);
+ if (!logQueue) {
+ printf("Failed to initialize logging facility\n");
+ }
+
+ logRTQueue = openavbQueueNewQueue(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 (OPENAVB_LOG_FROM_THREAD) {
+ bool errResult;
+ loggingThreadRunning = true;
+ THREAD_CREATE(loggingThread, loggingThread, NULL, loggingThreadFn, NULL);
+ THREAD_CHECK_ERROR(loggingThread, "Thread / task creation failed", errResult);
+ if (errResult); // Already reported
+ }
+}
+
+extern void DLL_EXPORT avbLogExit()
+{
+ if (OPENAVB_LOG_FROM_THREAD) {
+ loggingThreadRunning = false;
+ THREAD_JOIN(loggingThread, NULL);
+ }
+}
+
+extern void DLL_EXPORT avbLogFn(
+ int level,
+ const char *tag,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line,
+ const char *fmt,
+ ...)
+{
+ if (level <= AVB_LOG_LEVEL) {
+ va_list args;
+ va_start(args, fmt);
+
+ LOG_LOCK();
+
+ vsprintf(msg, fmt, args);
+
+ if (OPENAVB_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 (OPENAVB_LOG_PROC_INFO) {
+ sprintf(proc_msg, " P:%5.5d", GET_PID());
+ }
+ if (OPENAVB_LOG_THREAD_INFO) {
+ sprintf(thread_msg, " 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);
+ }
+ 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);
+ }
+
+ // 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);
+ 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);
+
+ if (!OPENAVB_LOG_FROM_THREAD && !OPENAVB_LOG_PULL_MODE) {
+ fputs(full_msg, AVB_LOG_OUTPUT_FD);
+ }
+ else {
+ if (logQueue) {
+ openavb_queue_elem_t elem = openavbQueueHeadLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)openavbQueueData(elem);
+ pLogItem->bRT = FALSE;
+ strncpy((char *)pLogItem->msg, full_msg, LOG_QUEUE_MSG_LEN);
+ openavbQueueHeadPush(logQueue);
+ }
+ }
+ }
+
+ va_end(args);
+
+ LOG_UNLOCK();
+ }
+}
+
+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();
+
+ 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 = 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 (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_UNLOCK();
+ }
+ }
+ }
+}
+
diff --git a/lib/avtp_pipeline/util/openavb_plugin.c b/lib/avtp_pipeline/util/openavb_plugin.c
new file mode 100644
index 00000000..1400cad4
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_plugin.c
@@ -0,0 +1,75 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_array.h"
+#include "openavb_plugin.h"
+
+#define AVB_LOG_COMPONENT "Plugin"
+#include "openavb_log_pub.h"
+
+openavb_array_t staticMapModeleArray;
+openavb_array_t staticIntfModeleArray;
+
+bool registerStaticMapModule(openavb_map_initialize_fn_t fn)
+{
+ if (!staticMapModeleArray) {
+ staticMapModeleArray = openavbArrayNewArray(sizeof(openavb_map_initialize_fn_t));
+ if (!staticMapModeleArray)
+ return FALSE;
+ if (!openavbArraySetInitSize(staticMapModeleArray, 8))
+ return FALSE;
+ }
+
+ openavbArrayAdd(staticMapModeleArray, fn);
+ return TRUE;
+}
+
+bool registerStaticIntfModule(openavb_intf_initialize_fn_t fn)
+{
+ if (!staticIntfModeleArray) {
+ staticIntfModeleArray = openavbArrayNewArray(sizeof(openavb_intf_initialize_fn_t));
+ if (!staticIntfModeleArray)
+ return FALSE;
+ if (!openavbArraySetInitSize(staticIntfModeleArray, 8))
+ return FALSE;
+ }
+
+ openavbArrayAdd(staticIntfModeleArray, fn);
+ return TRUE;
+}
+
+
+
diff --git a/lib/avtp_pipeline/util/openavb_plugin.h b/lib/avtp_pipeline/util/openavb_plugin.h
new file mode 100644
index 00000000..9b0b2d59
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_plugin.h
@@ -0,0 +1,47 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_PLUGIN_H
+#define OPENAVB_PLUGIN_H 1
+
+#include "openavb_platform.h"
+#include "openavb_types.h"
+#include "openavb_intf_pub.h"
+#include "openavb_map_pub.h"
+
+// This module exist solely to allow for interface and mapping module (plugins) to be statically linked.
+// There isn't good cross-platform linker support to force non-referenced functions from being removed
+// from a final image. Therefore these functions exist to ensure the initizlation function for
+// interface and mapping modules can have a reference as far as the linker is concerned.
+
+bool registerStaticMapModule(openavb_map_initialize_fn_t fn);
+bool registerStaticIntfModule(openavb_intf_initialize_fn_t fn);
+
+#endif // OPENAVB_PLUGIN_H
diff --git a/lib/avtp_pipeline/util/openavb_printbuf.c b/lib/avtp_pipeline/util/openavb_printbuf.c
new file mode 100644
index 00000000..ba435b6c
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_printbuf.c
@@ -0,0 +1,112 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Implementation of buffered printf for debugging purposes.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_printbuf.h"
+
+#define OPENAVB_PRINTBUF_MAX_MSG_SIZE 1024
+
+struct openavb_printbuf {
+ U32 size;
+ U32 idx;
+ U32 outputInterval;
+ U32 cnt;
+ U8 *buffer;
+};
+
+openavb_printbuf_t openavbPrintbufNew(U32 size, U32 outputInterval)
+{
+ openavb_printbuf_t printbuf = calloc(1, sizeof(struct openavb_printbuf));
+ if (printbuf) {
+ printbuf->buffer = calloc(1, size + 1); // Leave 1 for the string terminater
+ if (printbuf->buffer) {
+ printbuf->size = size;
+ printbuf->outputInterval = outputInterval;
+ }
+ }
+ return printbuf;
+}
+
+void openavbPrintbufDelete(openavb_printbuf_t printbuf)
+{
+ if (printbuf) {
+ if (printbuf->buffer) {
+ free(printbuf->buffer);
+ printbuf->buffer = NULL;
+ }
+ free(printbuf);
+ }
+}
+
+void openavbPrintbufOutput(openavb_printbuf_t printbuf)
+{
+ if (printbuf && printbuf->buffer) {
+ printf("%s", printbuf->buffer);
+ printbuf->idx = 0;
+ printbuf->cnt = 0;
+ }
+}
+
+void openavbPrintbufPrintf(openavb_printbuf_t printbuf, const char *fmt, ...)
+{
+ if (printbuf) {
+ va_list args;
+ va_start(args, fmt);
+
+ char msg[OPENAVB_PRINTBUF_MAX_MSG_SIZE];
+ U32 len = vsprintf(msg, fmt, args);
+
+ if (printbuf->idx + len > printbuf->size) {
+ openavbPrintbufOutput(printbuf);
+ }
+
+ memcpy(printbuf->buffer + printbuf->idx, msg, len);
+ printbuf->cnt++;
+ printbuf->idx += len;
+
+ if (printbuf->cnt >= printbuf->outputInterval) {
+ openavbPrintbufOutput(printbuf);
+ }
+
+ va_end(args);
+ }
+}
+
+
diff --git a/lib/avtp_pipeline/util/openavb_printbuf.h b/lib/avtp_pipeline/util/openavb_printbuf.h
new file mode 100644
index 00000000..a3732a75
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_printbuf.h
@@ -0,0 +1,54 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Implementation of buffered printf for debugging purposes.
+*/
+
+#ifndef AVB_PRINTBUF_H
+#define AVB_PRINTBUF_H 1
+
+#include "openavb_types.h"
+
+typedef struct openavb_printbuf * openavb_printbuf_t;
+
+// Create a new printbuf
+openavb_printbuf_t openavbPrintbufNew(U32 size, U32 outputInterval);
+
+// Delete a printbuf
+void openavbPrintbufDelete(openavb_printbuf_t printbuf);
+
+// Output the buffer to stdio
+void openavbPrintbufOutput(openavb_printbuf_t printbuf);
+
+// Format and add a message to the buffer
+void openavbPrintbufPrintf(openavb_printbuf_t printbuf, const char *fmt, ...);
+
+#endif // AVB_PRINTBUF_H
diff --git a/lib/avtp_pipeline/util/openavb_queue.c b/lib/avtp_pipeline/util/openavb_queue.c
new file mode 100644
index 00000000..4dbbf366
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_queue.c
@@ -0,0 +1,196 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "openavb_debug.h"
+#include "openavb_queue.h"
+
+OPENAVB_CODE_MODULE_PRI
+
+struct openavb_queue_elem {
+ bool setFlg;
+ void *data;
+};
+
+struct openavb_queue {
+ // Size of each element
+ U32 elemSize;
+
+ // Number of queue element slots
+ U32 queueSize;
+
+ // Next element to be filled
+ int head;
+
+ // Next element to be pulled
+ int tail;
+
+ openavb_queue_elem_t elemArray;
+};
+
+openavb_queue_t openavbQueueNewQueue(U32 elemSize, U32 queueSize)
+{
+ if (elemSize < 1 || queueSize < 1)
+ return NULL;
+
+ openavb_queue_t retQueue = calloc(1, sizeof(struct openavb_queue));
+ if (retQueue) {
+ retQueue->elemArray = calloc(queueSize, sizeof(struct openavb_queue_elem));
+ if (retQueue->elemArray) {
+ U32 i1;
+ for (i1 = 0; i1 < queueSize; i1++) {
+ retQueue->elemArray[i1].data = calloc(1, elemSize);
+ if (!retQueue->elemArray[i1].data) {
+ openavbQueueDeleteQueue(retQueue);
+ return NULL;
+ }
+ }
+ }
+ else {
+ openavbQueueDeleteQueue(retQueue);
+ return NULL;
+ }
+
+ retQueue->elemSize = elemSize;
+ retQueue->queueSize = queueSize;
+ retQueue->head = 0;
+ retQueue->tail = 0;
+ }
+
+ return retQueue;
+}
+
+void openavbQueueDeleteQueue(openavb_queue_t queue)
+{
+ if (queue) {
+ U32 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);
+ }
+}
+
+U32 openavbQueueGetQueueSize(openavb_queue_t queue)
+{
+ if (queue) {
+ return queue->queueSize;
+ }
+ return 0;
+}
+
+U32 openavbQueueGetElemCount(openavb_queue_t queue)
+{
+ U32 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;
+}
+
+U32 openavbQueueGetElemSize(openavb_queue_t queue)
+{
+ if (queue) {
+ return queue->elemSize;
+ }
+ return 0;
+}
+
+void *openavbQueueData(openavb_queue_elem_t elem)
+{
+ if (elem) {
+ return elem->data;
+ }
+ return NULL;
+}
+
+openavb_queue_elem_t openavbQueueHeadLock(openavb_queue_t queue)
+{
+ if (queue) {
+ if (!queue->elemArray[queue->head].setFlg) {
+ return &queue->elemArray[queue->head];
+ }
+ }
+ return NULL;
+}
+
+void openavbQueueHeadUnlock(openavb_queue_t queue)
+{
+}
+
+void openavbQueueHeadPush(openavb_queue_t queue)
+{
+ if (queue) {
+ queue->elemArray[queue->head++].setFlg = TRUE;
+ if (queue->head >= queue->queueSize) {
+ queue->head = 0;
+ }
+ }
+}
+
+openavb_queue_elem_t openavbQueueTailLock(openavb_queue_t queue)
+{
+ if (queue) {
+ if (queue->elemArray[queue->tail].setFlg) {
+ return &queue->elemArray[queue->tail];
+ }
+ }
+ return NULL;
+}
+
+void openavbQueueTailUnlock(openavb_queue_t queue)
+{
+}
+
+void openavbQueueTailPull(openavb_queue_t queue)
+{
+ if (queue) {
+ queue->elemArray[queue->tail++].setFlg = FALSE;
+ if (queue->tail >= queue->queueSize) {
+ queue->tail = 0;
+ }
+ }
+}
diff --git a/lib/avtp_pipeline/util/openavb_queue.h b/lib/avtp_pipeline/util/openavb_queue.h
new file mode 100644
index 00000000..69e22011
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_queue.h
@@ -0,0 +1,85 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : 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 OPENAVB_QUEUE_H
+#define OPENAVB_QUEUE_H 1
+
+#include "openavb_types.h"
+
+typedef struct openavb_queue_elem * openavb_queue_elem_t;
+typedef struct openavb_queue * openavb_queue_t;
+
+// Create an queue. Returns NULL on failure.
+openavb_queue_t openavbQueueNewQueue(U32 elemSize, U32 queueSize);
+
+// Delete an array.
+void openavbQueueDeleteQueue(openavb_queue_t queue);
+
+// Get number of queue slots
+U32 openavbQueueGetQueueSize(openavb_queue_t queue);
+
+// Get number of element
+U32 openavbQueueGetElemCount(openavb_queue_t queue);
+
+// Get element size
+U32 openavbQueueGetElemSize(openavb_queue_t queue);
+
+// Get data of the element. Returns NULL on failure.
+void *openavbQueueData(openavb_queue_elem_t elem);
+
+// Lock the head element.
+openavb_queue_elem_t openavbQueueHeadLock(openavb_queue_t queue);
+
+// Unlock the head element.
+void openavbQueueHeadUnlock(openavb_queue_t queue);
+
+// Push the head element making it available for tail access.
+void openavbQueueHeadPush(openavb_queue_t queue);
+
+// Lock the tail element.
+openavb_queue_elem_t openavbQueueTailLock(openavb_queue_t queue);
+
+// Unlock the tail element.
+void openavbQueueTailUnlock(openavb_queue_t queue);
+
+// Pull (remove) the tail element
+void openavbQueueTailPull(openavb_queue_t queue);
+
+#endif // OPENAVB_QUEUE_H
diff --git a/lib/avtp_pipeline/util/openavb_result_codes.c b/lib/avtp_pipeline/util/openavb_result_codes.c
new file mode 100755
index 00000000..61dd12b1
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_result_codes.c
@@ -0,0 +1,174 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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_types.h"
+#include "openavb_result_codes.h"
+
+openavbRC openavbUtilRCRecord(openavbRC rc)
+{
+ return rc;
+}
+
+char *openavbUtilRCResultToString(openavbRC rc)
+{
+ if (IS_OPENAVB_SUCCESS(rc)) return "Success";
+ else return "Failure";
+}
+
+char *openavbUtilRCModuleToString(openavbRC rc)
+{
+ switch (rc & OPENAVB_RC_MODULE_MASK) {
+ case OPENAVB_MODULE_GLOBAL: return "AVB";
+ case OPENAVB_MODULE_GPTP: return "gPTP";
+ case OPENAVB_MODULE_SRP: return "SRP";
+ case OPENAVB_MODULE_AVTP: return "AVTP";
+ case OPENAVB_MODULE_AVTP_TIME: return "AVTP TIME";
+ case OPENAVB_MODULE_AVDECC: return "AVDECC";
+ default: return "Unknown";
+ }
+}
+
+char *openavbUtilRCCodeToString(openavbRC rc)
+{
+ // General result codes
+ switch (rc & OPENAVB_RC_CODE_MASK) {
+ case OPENAVB_RC_GENERIC: return "";
+ case OPENAVB_RC_RAWSOCK_OPEN: return "Failed to open rawsock";
+ case OPENAVB_RC_OUT_OF_MEMORY: return "Out of memory";
+ case OPENAVB_RC_INVALID_ARGUMENT: return "Invalid function argument";
+ case OPENAVB_RC_FAILED_TO_OPEN: return "Failed to open";
+ // No Default
+ }
+
+ // gPTP Result Codes
+ if ((rc & OPENAVB_RC_MODULE_MASK) == OPENAVB_MODULE_GPTP) {
+ switch (rc & OPENAVB_RC_CODE_MASK) {
+ case OPENAVBPTP_RC_GENERIC: return "";
+ case OPENAVBPTP_RC_SHARED_MEMORY_OPEN: return "Failed to open shared memory file";
+ case OPENAVBPTP_RC_SHARED_MEMORY_TRANC: return "Failed to truncate shared memory file";
+ case OPENAVBPTP_RC_SHARED_MEMORY_MMAP: return "Failed to memory map shared memory file";
+ case OPENAVBPTP_RC_SHARED_MEMORY_ENTRY: return "Failed to locate matching shared memory item";
+ case OPENAVBPTP_RC_SHARED_MEMORY_UPDATE: return "Failed to update shared memory item";
+ case OPENAVBPTP_RC_PTP_DEV_OPEN: return "Failed to open ptp device";
+ case OPENAVBPTP_RC_PTP_DEV_CLOCKID: return "Failed to obtain ptp device clock ID";
+ case OPENAVBPTP_RC_SOCK_OPEN: return "Failed to open socket";
+ case OPENAVBPTP_RC_SOCK_NET_INTERFACE: return "Unable to obtain network interface";
+ case OPENAVBPTP_RC_SOCK_DEVICE_INDEX: return "Unable to obtain socket device index";
+ case OPENAVBPTP_RC_SOCK_REUSE: return "Unable to reuse socket";
+ case OPENAVBPTP_RC_SOCK_BIND: return "Unable to bind socket";
+ case OPENAVBPTP_RC_SOCK_TIMESTAMP: return "Hardware timestamping not supported";
+ case OPENAVBPTP_RC_SOCK_LINK_DOWN: return "Socket network link not active";
+ case OPENAVBPTP_RC_TIMER_CREATE: return "Failed to create timer(s)";
+ case OPENAVBPTP_RC_SIGNAL_HANDLER: return "Failed to create signal handler";
+ case OPENAVBPTP_RC_CONFIG_FILE_OPEN: return "Failed to open configuration file";
+ case OPENAVBPTP_RC_CONFIG_FILE_READ: return "Failed to read configuration file";
+ case OPENAVBPTP_RC_CONFIG_FILE_DATA: return "Invalid data encountered in configuration file";
+ case OPENAVBPTP_RC_CONFIG_FILE_WRITE: return "Failed to write configuration file";
+ case OPENAVBPTP_RC_NEW_CONFIG_FILE_WRITE: return "SUCCESSFULLY wrote recreated configuration file";
+ case OPENAVBPTP_RC_CLOCK_GET_TIME: return "Failed to obtain time";
+ case OPENAVBPTP_RC_SEND_FAIL: return "Failed to send packet";
+ case OPENAVBPTP_RC_SEND_SHORT: return "Failed to send complete packet";
+ case OPENAVBPTP_RC_SOCK_ADD_MULTI: return "Failed to set multicast address";
+ // No Default
+ }
+ }
+
+
+ // SRP Result Codes
+ if ((rc & OPENAVB_RC_MODULE_MASK) == OPENAVB_MODULE_SRP) {
+ switch (rc & OPENAVB_RC_CODE_MASK) {
+ case OPENAVBSRP_RC_GENERIC: return "";
+ case OPENAVBSRP_RC_ALREADY_INIT: return "Already initialized";
+ case OPENAVBSRP_RC_SOCK_OPEN: return "Failed to open socket";
+ case OPENAVBSRP_RC_THREAD_CREATE: return "Failed to create thread";
+ case OPENAVBSRP_RC_BAD_CLASS: return "Attempt to register / access stream with a bad class index";
+ case OPENAVBSRP_RC_REG_NULL_HDL: return "Attempt to register a stream with a null handle";
+ case OPENAVBSRP_RC_REREG: return "Attempt to [re]register an exisiting stream Id";
+ case OPENAVBSRP_RC_NO_MEMORY: return "Out of memory";
+ case OPENAVBSRP_RC_NO_BANDWIDTH: return "Insufficient bandwidth";
+ case OPENAVBSRP_RC_SEND: return "Failed to send packet";
+ case OPENAVBSRP_RC_DEREG_NO_XST: return "Attempt to deregister a non-existent stream";
+ case OPENAVBSRP_RC_DETACH_NO_XST: return "Attempt to detach from non-existent stream";
+ case OPENAVBSRP_RC_INVALID_SUBTYPE: return "Invalid listener declaration subtype";
+ case OPENAVBSRP_RC_FRAME_BUFFER: return "Failed to get a transmit frame buffer";
+ case OPENAVBSRP_RC_SHARED_MEM_MMAP: return "Failed to mmap openavb_gPTP shared memory";
+ case OPENAVBSRP_RC_SHARED_MEM_OPEN: return "Failed to open openavb_gPTP shared memory";
+ case OPENAVBSRP_RC_BAD_VERSION: return "AVB core stack version mismatch endpoint / srp vs gptp";
+ // No Default
+ }
+ }
+
+ // AVTP Result Codes
+ if ((rc & OPENAVB_RC_MODULE_MASK) == OPENAVB_MODULE_AVTP) {
+ switch (rc & OPENAVB_RC_CODE_MASK) {
+ case OPENAVBAVTP_RC_GENERIC: return "";
+ case OPENAVBAVTP_RC_TX_PACKET_NOT_READY: return "Transmit packet not ready";
+ case OPENAVBAVTP_RC_MAPPING_CB_NOT_SET: return "Mapping callback structure not set";
+ case OPENAVBAVTP_RC_INTERFACE_CB_NOT_SET: return "Interface callback structure not set";
+ case OPENAVBAVTP_RC_NO_FRAMES_PROCESSED: return "No frames processed";
+ case OPENAVBAVTP_RC_INVALID_AVTP_VERSION: return "Invalid AVTP version configured";
+ case OPENAVBAVTP_RC_IGNORING_STREAMID: return "Ignoring unexpected streamID";
+ case OPENAVBAVTP_RC_IGNORING_CONTROL_PACKET: return "Ignoring unexpected AVTP control packet";
+ case OPENAVBAVTP_RC_PARSING_FRAME_HEADER: return "Parsing frame header";
+ // No Default
+ }
+ }
+
+ // AVTP Time Result Codes
+ if ((rc & OPENAVB_RC_MODULE_MASK) == OPENAVB_MODULE_AVTP_TIME) {
+ switch (rc & OPENAVB_RC_CODE_MASK) {
+ case OPENAVBAVTPTIME_RC_GENERIC: return "";
+ case OPENAVBAVTPTIME_RC_PTP_TIME_DESCRIPTOR: return "PTP file descriptor not available";
+ case OPENAVBAVTPTIME_RC_OPEN_SRC_PTP_NOT_AVAIL: return "Open source PTP configured but not available in this build";
+ case OPENAVBAVTPTIME_RC_GET_TIME_ERROR: return "PTP get time error";
+ case OPENAVBAVTPTIME_RC_OPENAVB_PTP_NOT_AVAIL: return "OPENAVB PTP configured but not available in this build";
+ case OPENAVBAVTPTIME_RC_INVALID_PTP_TIME: return "Invalid avtp_time_t";
+ // No Default
+ }
+ }
+
+ // AVDECC Result Codes
+ if ((rc & OPENAVB_RC_MODULE_MASK) == OPENAVB_MODULE_AVDECC) {
+ switch (rc & OPENAVB_RC_CODE_MASK) {
+ case OPENAVBAVDECC_RC_GENERIC: return "";
+ case OPENAVBAVDECC_RC_BUFFER_TOO_SMALL: return "Buffer size is too small";
+ case OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING: return "The Entity Model has not been created";
+ 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";
+ // No Default
+
+ }
+ }
+
+ return "";
+}
+
+
diff --git a/lib/avtp_pipeline/util/openavb_result_codes.h b/lib/avtp_pipeline/util/openavb_result_codes.h
new file mode 100644
index 00000000..082828da
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_result_codes.h
@@ -0,0 +1,209 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Common types and defines for result codes
+*/
+
+#ifndef AVB_RESULT_CODES_H
+#define AVB_RESULT_CODES_H 1
+
+// Result Code (success or error code)
+// First (left) byte:
+// bits 0 thru 6 reserved;
+// bit 7 (rightmost) - 0 indicates success, 1 indicates failure.
+// Second Byte:
+// indicates specific software module - see enum openavbModules below
+// Third & Forth (right) Bytes;
+// defined independently by each module to indicate specific failure (or success)
+typedef U32 openavbRC;
+
+// Example usage:
+// openavbRC foo()
+// {
+// .
+// .
+// return AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVB_RC_OUT_OF_MEMORY)
+// }
+//
+// openavbRC result;
+// result = foo();
+// if (IS_OPENAVB_SUCCESS(result)) {
+// ...
+// }
+
+#define OPENAVB_RC_MODULE_MASK 0x00FF0000
+#define OPENAVB_RC_CODE_MASK 0x0000FFFF
+
+#define OPENAVB_SUCCESS 0x00000000
+#define OPENAVB_FAILURE 0x01000000
+
+// 2nd byte only
+enum openavbModules {
+ OPENAVB_MODULE_GLOBAL = 0x00010000,
+ OPENAVB_MODULE_GPTP = 0x00020000,
+ OPENAVB_MODULE_SRP = 0x00030000,
+ OPENAVB_MODULE_AVTP = 0x00040000,
+ OPENAVB_MODULE_AVTP_TIME = 0x00050000,
+ OPENAVB_MODULE_AVDECC = 0x00060000,
+};
+
+// When adding result codes be sure to update the openavbUtilRCCodeToString() function in openavb_result_codes.c
+
+enum openavbCommonResultCodes {
+ OPENAVB_RC_GENERIC = 0x1000,
+ OPENAVB_RC_RAWSOCK_OPEN = 0x1001, // Failed to open rawsock
+ OPENAVB_RC_OUT_OF_MEMORY = 0x1002, // Out of memory
+ OPENAVB_RC_INVALID_ARGUMENT = 0x1003, // Invalid function argument
+ OPENAVB_RC_FAILED_TO_OPEN = 0x1004, // Failed to open
+};
+
+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
+ OPENAVBPTP_RC_SHARED_MEMORY_MMAP = 0x0003, // Failed to memory map shared memory file
+ OPENAVBPTP_RC_SHARED_MEMORY_ENTRY = 0x0004, // Failed to locate matching shared memory item
+ OPENAVBPTP_RC_SHARED_MEMORY_UPDATE = 0x0005, // Failed to update shared memory item
+ OPENAVBPTP_RC_PTP_DEV_OPEN = 0x0006, // Failed to open ptp device
+ OPENAVBPTP_RC_PTP_DEV_CLOCKID = 0x0007, // Failed to obtain ptp device clock ID
+ OPENAVBPTP_RC_SOCK_OPEN = 0x0008, // Failed to open socket
+ OPENAVBPTP_RC_SOCK_NET_INTERFACE = 0x0009, // Unable to obtain network interface
+ OPENAVBPTP_RC_SOCK_DEVICE_INDEX = 0x0010, // Unable to obtain socket device index //
+ OPENAVBPTP_RC_SOCK_REUSE = 0x0011, // unable to reuse socket
+ OPENAVBPTP_RC_SOCK_BIND = 0x0012, // Unable to bind socket
+ OPENAVBPTP_RC_SOCK_TIMESTAMP = 0x0013, // Hardware timestamping not supported
+ OPENAVBPTP_RC_SOCK_LINK_DOWN = 0x0014, // Socket network link not active
+ OPENAVBPTP_RC_TIMER_CREATE = 0x0015, // Failed to create timer(s)
+ OPENAVBPTP_RC_SIGNAL_HANDLER = 0x0016, // Failed to create signal handler
+ OPENAVBPTP_RC_CONFIG_FILE_OPEN = 0x0017, // Failed to open configuration file
+ OPENAVBPTP_RC_CONFIG_FILE_READ = 0x0018, // Failed to read configuration file
+ OPENAVBPTP_RC_CONFIG_FILE_DATA = 0x0019, // Invalid data encountered in configuration file
+ OPENAVBPTP_RC_CONFIG_FILE_WRITE = 0x0020, // Failed to write configuration file
+ OPENAVBPTP_RC_NEW_CONFIG_FILE_WRITE = 0x0021, // SUCCESSFULLY wrote recreated configuration file
+ OPENAVBPTP_RC_CLOCK_GET_TIME = 0x0022, // Failed to obtain time
+ OPENAVBPTP_RC_SEND_FAIL = 0x0023, // Failed to send packet
+ OPENAVBPTP_RC_SEND_SHORT = 0x0024, // Failed to send complete packet
+ OPENAVBPTP_RC_SOCK_ADD_MULTI = 0x0025, // Failed to set multicast address
+ OPENAVBPTP_RC_TX_TIMESTAMP_FAIL = 0x0026, // Failed to get egress timestamp
+};
+
+enum openavbSrpResultCodes {
+ OPENAVBSRP_RC_GENERIC = 0x0000,
+ OPENAVBSRP_RC_ALREADY_INIT = 0x0001, // Already initialized
+ OPENAVBSRP_RC_SOCK_OPEN = 0x0002, // Failed to open socket
+ OPENAVBSRP_RC_THREAD_CREATE = 0x0003, // Failed to create thread
+ OPENAVBSRP_RC_BAD_CLASS = 0x0004, // Attempt to register / access stream with a bad class index
+ OPENAVBSRP_RC_REG_NULL_HDL = 0x0005, // Attempt to register a stream with a null handle
+ OPENAVBSRP_RC_REREG = 0x0006, // Attempt to [re]register an exisiting stream Id
+ OPENAVBSRP_RC_NO_MEMORY = 0x0007, // Out of memory
+ OPENAVBSRP_RC_NO_BANDWIDTH = 0x0008, // Insufficient bandwidth
+ OPENAVBSRP_RC_SEND = 0x0009, // Failed to send packet
+ OPENAVBSRP_RC_DEREG_NO_XST = 0x0010, // Attempt to deregister a non-existent stream
+ OPENAVBSRP_RC_DETACH_NO_XST = 0x0011, // Attempt to detach from non-existent stream
+ OPENAVBSRP_RC_INVALID_SUBTYPE = 0x0012, // Invalid listener declaration subtype
+ OPENAVBSRP_RC_FRAME_BUFFER = 0x0013, // Failed to get a transmit frame buffer
+ OPENAVBSRP_RC_SHARED_MEM_MMAP = 0x0014, // Failed to mmap openavb_gPTP shared memory
+ OPENAVBSRP_RC_SHARED_MEM_OPEN = 0x0015, // Failed to open openavb_gPTP shared memory
+ OPENAVBSRP_RC_BAD_VERSION = 0x0016, // AVB core stack version mismatch endpoint / srp vs gptp
+ OPENAVBSRP_RC_SOCK_JN_MULTI = 0x0017, // Failed to join multicast group for the Nearest Bridge group address
+ OPENAVBSRP_RC_SOCK_ADDR = 0x0018, // Failed to get our own mac address
+ OPENAVBSRP_RC_MUTEX_INIT = 0x0019, // Failed to create / initialize mutex
+ OPENAVBSRP_RC_SOCK_TX_HDR = 0x0020, // Failed to set Ethernet frame transmit header
+// limited to two bytes; max 0xffff
+};
+
+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
+ OPENAVBAVTP_RC_INTERFACE_CB_NOT_SET = 0x0003, // Interface callback structure not set
+ OPENAVBAVTP_RC_NO_FRAMES_PROCESSED = 0x0004, // No frames processed
+ OPENAVBAVTP_RC_INVALID_AVTP_VERSION = 0x0005, // Invalid AVTP version configured
+ OPENAVBAVTP_RC_IGNORING_STREAMID = 0x0006, // Ignoring unexpected streamID
+ OPENAVBAVTP_RC_IGNORING_CONTROL_PACKET = 0x0007, // Ignoring unexpected AVTP control packet
+ OPENAVBAVTP_RC_PARSING_FRAME_HEADER = 0x0008, // Parsing frame header
+};
+
+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
+ OPENAVBAVTPTIME_RC_GET_TIME_ERROR = 0x0003, // PTP get time error
+ OPENAVBAVTPTIME_RC_OPENAVB_PTP_NOT_AVAIL = 0x0004, // OPENAVB PTP configured but not available in this build
+ OPENAVBAVTPTIME_RC_INVALID_PTP_TIME = 0x0005, // Invalid avtp_time_t
+};
+
+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
+};
+
+
+#define OPENAVB_PTP_SUCCESS (OPENAVB_SUCCESS | OPENAVB_MODULE_GPTP)
+#define OPENAVB_PTP_FAILURE (OPENAVB_FAILURE | OPENAVB_MODULE_GPTP)
+
+#define OPENAVB_SRP_SUCCESS (OPENAVB_SUCCESS | OPENAVB_MODULE_SRP)
+#define OPENAVB_SRP_FAILURE (OPENAVB_FAILURE | OPENAVB_MODULE_SRP)
+
+#define OPENAVB_AVTP_SUCCESS (OPENAVB_SUCCESS | OPENAVB_MODULE_AVTP)
+#define OPENAVB_AVTP_FAILURE (OPENAVB_FAILURE | OPENAVB_MODULE_AVTP)
+
+#define OPENAVB_AVTP_TIME_SUCCESS (OPENAVB_SUCCESS | OPENAVB_MODULE_AVTP_TIME)
+#define OPENAVB_AVTP_TIME_FAILURE (OPENAVB_FAILURE | OPENAVB_MODULE_AVTP_TIME)
+
+#define OPENAVB_AVDECC_SUCCESS (OPENAVB_SUCCESS | OPENAVB_MODULE_AVDECC)
+#define OPENAVB_AVDECC_FAILURE (OPENAVB_FAILURE | OPENAVB_MODULE_AVDECC)
+
+
+// Helper functions
+openavbRC openavbUtilRCRecord(openavbRC rc);
+char* openavbUtilRCResultToString(openavbRC rc);
+char* openavbUtilRCModuleToString(openavbRC rc);
+char* openavbUtilRCCodeToString(openavbRC rc);
+
+// Helper macros
+#define IS_OPENAVB_SUCCESS(_rc_) (!((_rc_) & 0x01000000))
+#define IS_OPENAVB_FAILURE(_rc_) ((_rc_) & 0x01000000)
+#define AVB_RC(_rc_) (openavbUtilRCRecord(_rc_))
+#define AVB_RC_RET(_rc_) return (_rc_)
+#define AVB_RC_MSG(_rc_) openavbUtilRCCodeToString(_rc_)
+#define AVB_RC_LOG(_rc_) AVB_LOGF_ERROR("%s", openavbUtilRCCodeToString(_rc_))
+#define AVB_RC_LOG_RET(_rc_) AVB_LOGF_ERROR("%s", openavbUtilRCCodeToString(_rc_)); return (_rc_)
+#define AVB_RC_LOG_TRACE_RET(_rc_, _trace_) AVB_LOGF_ERROR("%s", openavbUtilRCCodeToString(_rc_)); AVB_TRACE_EXIT(_trace_); return (_rc_)
+#define AVB_RC_TRACE_RET(_rc_, _trace_) AVB_TRACE_EXIT(_trace_); return (_rc_)
+#define AVB_RC_FAIL_RET(_rc_) if (IS_OPENAVB_FAILURE(_rc_)) return (_rc_)
+#define AVB_RC_FAIL_TRACE_RET(_rc_, _trace_) if (IS_OPENAVB_FAILURE(_rc_)) {AVB_TRACE_EXIT(_trace_); return (_rc_);}
+
+#endif // AVB_RESULT_CODES_H
diff --git a/lib/avtp_pipeline/util/openavb_time.c b/lib/avtp_pipeline/util/openavb_time.c
new file mode 100644
index 00000000..7b624806
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_time.c
@@ -0,0 +1,134 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Implementation of time support functions.
+*/
+
+#include "openavb_time.h"
+
+OPENAVB_CODE_MODULE_PRI
+
+U64 openavbTimeTimespecToNSec(struct timespec *pTime)
+{
+ if (!pTime) {
+ return 0; // Error case
+ }
+
+ return ((U64)pTime->tv_sec * (U64)NANOSECONDS_PER_SECOND) + (U64)pTime->tv_nsec;
+}
+
+void openavbTimeTimespecFromNSec(struct timespec *pTime, U64 nSec)
+{
+ if (!pTime) {
+ return; // Error case
+ }
+
+ pTime->tv_sec = nSec / NANOSECONDS_PER_SECOND;
+ pTime->tv_nsec = nSec % NANOSECONDS_PER_SECOND;
+}
+
+void openavbTimeTimespecAddUsec(struct timespec *pTime, U32 us)
+{
+ if (!pTime) {
+ 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;
+}
+
+void openavbTimeTimespecSubUsec(struct timespec *pTime, U32 us)
+{
+ if (!pTime) {
+ 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;
+}
+
+S64 openavbTimeTimespecUsecDiff(struct timespec *pTime1, struct timespec *pTime2)
+{
+ if (!pTime1 || !pTime2) {
+ return 0; // Error case - undefined behavior
+ }
+
+ U64 timeUSec1 = (pTime1->tv_sec * MICROSECONDS_PER_SECOND) + (pTime1->tv_nsec / NANOSECONDS_PER_USEC);
+ U64 timeUSec2 = (pTime2->tv_sec * MICROSECONDS_PER_SECOND) + (pTime2->tv_nsec / NANOSECONDS_PER_USEC);
+ return timeUSec2 - timeUSec1;
+}
+
+S32 openavbTimeTimespecCmp(struct timespec *pTime1, struct timespec *pTime2)
+{
+ if (!pTime1 || !pTime2) {
+ return -1; // Error case - undefined behavior
+ }
+
+ if (pTime1->tv_sec < pTime2->tv_sec) {
+ return -1;
+ }
+ if (pTime1->tv_sec > pTime2->tv_sec) {
+ return 1;
+ }
+ if (pTime1->tv_sec == pTime2->tv_sec) {
+ if (pTime1->tv_nsec < pTime2->tv_nsec) {
+ return -1;
+ }
+ if (pTime1->tv_nsec > pTime2->tv_nsec) {
+ return 1;
+ }
+ }
+ return 0; // Equal
+}
+
+U64 openavbTimeUntilUSec(struct timespec *pTime1, struct timespec *pTime2)
+{
+ if (!pTime1 || !pTime2) {
+ return 0; // Error case - undefined behavior
+ }
+
+ U64 timeUSec1 = (pTime1->tv_sec * MICROSECONDS_PER_SECOND) + (pTime1->tv_nsec / NANOSECONDS_PER_USEC);
+ U64 timeUSec2 = (pTime2->tv_sec * MICROSECONDS_PER_SECOND) + (pTime2->tv_nsec / NANOSECONDS_PER_USEC);
+
+ if (timeUSec2 > timeUSec1) {
+ return timeUSec2 - timeUSec1;
+ }
+ return 0;
+}
+
+U32 openavbTimeUntilMSec(struct timespec *pTime1, struct timespec *pTime2)
+{
+ return openavbTimeUntilUSec(pTime1, pTime2) / 1000;
+}
+
diff --git a/lib/avtp_pipeline/util/openavb_time.h b/lib/avtp_pipeline/util/openavb_time.h
new file mode 100644
index 00000000..1a3e7d72
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_time.h
@@ -0,0 +1,65 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Implementation of Time support functions.
+*/
+
+#ifndef OPENAVB_TIME_H
+#define OPENAVB_TIME_H 1
+
+#include <stdlib.h>
+#include "openavb_types.h"
+
+// Returns a time in nanoseconds
+U64 openavbTimeTimespecToNSec(struct timespec *pTime);
+
+// Sets a timespec from nanoseconds
+void openavbTimeTimespecFromNSec(struct timespec *pTime, U64 nSec);
+
+// Add micro seconds to a timespec
+void openavbTimeTimespecAddUsec(struct timespec *pTime, U32 us);
+
+// Subtract micro seconds from a timespec
+void openavbTimeTimespecSubUsec(struct timespec *pTime, U32 us);
+
+// Find the difference in micro seconds between 2 timespecs
+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
+U64 openavbTimeUntilUSec(struct timespec *pTime1, struct timespec *pTime2);
+
+// Milliseconds until Time2 reaches Time1. Returns 0 if Time2 is already past Time1
+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
new file mode 100644
index 00000000..442fa82c
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_timestamp.c
@@ -0,0 +1,171 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Implementation of Timestamp evaluation useful for reporting and smoothing jitter.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "openavb_printbuf.h"
+#include "openavb_timestamp.h"
+
+OPENAVB_CODE_MODULE_PRI
+
+#define OPENAVB_TIMESTAMP_PRINT_BUFFER_SIZE 2048
+#define OPENAVB_TIMESTAMP_DUMP_PRINTBUF_INTERVAL 30
+
+// CORE_TODO: This should be enhanced to account for dropped packet detection and perhaps PTP time adjusts
+
+struct openavb_timestamp_eval {
+ // Flags
+ bool started;
+
+ // Settings
+ U32 tsRateInterval;
+ bool smoothing;
+ U32 tsSmoothingMaxJitter;
+ U32 tsSmoothingMaxDrift;
+ U32 reportInterval;
+
+ // Data
+ U32 tsCnt;
+ U32 tsPrev;
+ U32 tsInterval;
+ U32 tsJitter;
+ U64 tsAccumJitter;
+ U32 tsDrift;
+ U64 tsTtlReal;
+ U64 tsTtlCalc;
+ U32 tsMaxJitter;
+ U32 tsMaxDrift;
+ openavb_printbuf_t printbuf;
+};
+
+
+openavb_timestamp_eval_t openavbTimestampEvalNew(void)
+{
+ return calloc(1, sizeof(struct openavb_timestamp_eval));
+}
+
+void openavbTimestampEvalDelete(openavb_timestamp_eval_t tsEval)
+{
+ if (tsEval) {
+ free(tsEval);
+ tsEval = NULL;
+ }
+}
+
+void openavbTimestampEvalInitialize(openavb_timestamp_eval_t tsEval, U32 tsRateInterval)
+{
+ if (tsEval) {
+ tsEval->started = FALSE;
+ tsEval->tsRateInterval = tsRateInterval;
+ tsEval->printbuf = openavbPrintbufNew(OPENAVB_TIMESTAMP_PRINT_BUFFER_SIZE, OPENAVB_TIMESTAMP_DUMP_PRINTBUF_INTERVAL);
+ }
+}
+
+void openavbTimestampEvalSetReport(openavb_timestamp_eval_t tsEval, U32 reportInterval)
+{
+ if (tsEval) {
+ tsEval->reportInterval = reportInterval;
+ }
+}
+
+void openavbTimestampEvalSetSmoothing(openavb_timestamp_eval_t tsEval, U32 tsMaxJitter, U32 tsMaxDrift)
+{
+ if (tsEval) {
+ tsEval->smoothing = TRUE;
+ tsEval->tsSmoothingMaxJitter = tsMaxJitter;
+ tsEval->tsSmoothingMaxDrift = tsMaxDrift;
+ }
+}
+
+U32 openavbTimestampEvalTimestamp(openavb_timestamp_eval_t tsEval, U32 ts)
+{
+ U32 tsRet = ts;
+
+ if (tsEval) {
+ // Determine the Jitter
+ if (tsEval->tsPrev > ts) {
+ tsEval->tsInterval = (((U32)-1) - tsEval->tsPrev) + ts;
+ }
+ else {
+ tsEval->tsInterval = ts - tsEval->tsPrev;
+ }
+
+ // Save real ts for not interval
+ tsEval->tsPrev = ts;
+
+ // Increment the main timestamp counter
+ tsEval->tsCnt++;
+
+ // Accumulate totals
+ if (!tsEval->started) {
+ // First timestamp interval
+ tsEval->tsTtlCalc = 0;
+ tsEval->tsTtlReal = 0;
+ tsEval->started = TRUE;
+ }
+ else {
+ // All but first timestamp
+ tsEval->tsTtlCalc += tsEval->tsRateInterval;
+ tsEval->tsTtlReal += tsEval->tsInterval;
+
+ tsEval->tsJitter = abs(tsEval->tsRateInterval - tsEval->tsInterval);
+ if (tsEval->tsJitter > tsEval->tsMaxJitter) {
+ tsEval->tsMaxJitter = tsEval->tsJitter;
+ }
+ tsEval->tsAccumJitter += tsEval->tsJitter;
+
+ tsEval->tsDrift = abs(tsEval->tsTtlCalc - tsEval->tsTtlReal);
+
+ // Reporting
+ if (tsEval->reportInterval) {
+ if ((tsEval->tsCnt % tsEval->reportInterval) == 0) {
+ //printf("Jitter:%9u AvgJitter:%9u MaxJitter:%9u Drift:%9u\n", tsEval->tsJitter, (U32)(tsEval->tsAccumJitter / tsEval->tsCnt), tsEval->tsMaxJitter, tsEval->tsDrift);
+ openavbPrintbufPrintf(tsEval->printbuf, "Jitter:%9u AvgJitter:%9u MaxJitter:%9u Drift:%9u\n", tsEval->tsJitter, (U32)(tsEval->tsAccumJitter / tsEval->tsCnt), tsEval->tsMaxJitter, tsEval->tsDrift);
+ }
+ }
+ }
+ }
+
+ return tsRet;
+}
+
+
+void openavbTimestampEvalTimestampSkip(openavb_timestamp_eval_t tsEval, U32 cnt)
+{
+ if (tsEval) {
+ }
+}
+
diff --git a/lib/avtp_pipeline/util/openavb_timestamp.h b/lib/avtp_pipeline/util/openavb_timestamp.h
new file mode 100644
index 00000000..0b4d77b8
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_timestamp.h
@@ -0,0 +1,78 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+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 : Header for Timestamp evaluation useful for reporting and smoothing jitter.
+*/
+
+#ifndef OPENAVB_TIMESTAMP_H
+#define OPENAVB_TIMESTAMP_H 1
+
+#include <stdlib.h>
+#include "openavb_types.h"
+
+typedef struct openavb_timestamp_eval * openavb_timestamp_eval_t;
+
+// Create and initialize the timestamp evaluator.
+// tsInterval is the expected timestamp interval in nanoseconds.
+openavb_timestamp_eval_t openavbTimestampEvalNew(void);
+
+// Delete a timestamp evaluator.
+void openavbTimestampEvalDelete(openavb_timestamp_eval_t tsEval);
+
+// Set timestamp interval.
+void openavbTimestampEvalInitialize(openavb_timestamp_eval_t tsEval, U32 tsRateInterval);
+
+// Set the report interval. If not set there will be no reporting.
+void openavbTimestampEvalSetReport(openavb_timestamp_eval_t tsEval, U32 reportInterval);
+
+// Set the timestamp smoothing parameters.
+void openavbTimestampEvalSetSmoothing(openavb_timestamp_eval_t tsEval, U32 tsMaxJitter, U32 tsMaxDrift);
+
+// Record timestamp and optionally smooth it.
+U32 openavbTimestampEvalTimestamp(openavb_timestamp_eval_t tsEval, U32 ts);
+
+// Skip cnt number of timestamp intervals
+void openavbTimestampEvalTimestampSkip(openavb_timestamp_eval_t tsEval, U32 cnt);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#endif // OPENAVB_TIMESTAMP_H
diff --git a/run_echo_listener.sh b/run_echo_listener.sh
new file mode 100755
index 00000000..61ab3b90
--- /dev/null
+++ b/run_echo_listener.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+# Simple script to run echo_listener
+
+if [ "$#" -eq "0" ]; then
+ echo "please enter network interface name as parameter. For example:"
+ echo "sudo ./run_echo_talker eth1"
+ exit -1
+fi
+
+cd lib/avtp_pipeline/build/bin
+exec ./openavb_host -I $1 echo_listener.ini,stream_addr=ba:bc:1a:ba:bc:1a
diff --git a/run_echo_talker.sh b/run_echo_talker.sh
new file mode 100755
index 00000000..a4a11594
--- /dev/null
+++ b/run_echo_talker.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+# Simple script to run echo_talker
+
+if [ "$#" -eq "0" ]; then
+ echo "please enter network interface name as parameter. For example:"
+ echo "sudo ./run_echo_talker eth1"
+ exit -1
+fi
+
+cd lib/avtp_pipeline/build/bin
+exec ./openavb_host -I $1 echo_talker.ini,stream_addr=ba:bc:1a:ba:bc:1a
diff --git a/run_gptp.sh b/run_gptp.sh
new file mode 100755
index 00000000..35fd4e38
--- /dev/null
+++ b/run_gptp.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+# Simple script to run gptp
+
+if [ "$#" -eq "0" ]; then
+ echo "please enter network interface name as parameter. For example:"
+ echo "sudo ./run_gptp.sh eth1"
+ exit -1
+fi
+
+groupadd ptp
+daemons/gptp/linux/build/obj/daemon_cl $1
diff --git a/run_igb.sh b/run_igb.sh
new file mode 100755
index 00000000..cb2bdc76
--- /dev/null
+++ b/run_igb.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+# Simple script to run igb_avb
+
+if [ "$#" -eq "0" ]; then
+ echo "please enter network interface name as parameter. For example:"
+ echo "sudo ./run_igb.sh eth1"
+ exit -1
+fi
+
+rmmod igb
+modprobe i2c_algo_bit
+modprobe dca
+modprobe ptp
+insmod kmod/igb/igb_avb.ko
+
+ethtool -i $1
diff --git a/run_simple_talker.sh b/run_simple_talker.sh
new file mode 100755
index 00000000..1421c817
--- /dev/null
+++ b/run_simple_talker.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+# Simple script to the simple_talker
+
+if [ "$#" -eq "0" ]; then
+ echo "please enter network interface name as parameter. For example:"
+ echo "sudo ./run_simple_talker.sh eth1"
+ exit -1
+fi
+
+examples/simple_talker/simple_talker -i $1 -t 2
diff --git a/run_srp.sh b/run_srp.sh
new file mode 100755
index 00000000..f75c9c12
--- /dev/null
+++ b/run_srp.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+# Simple script to run srp
+
+if [ "$#" -eq "0" ]; then
+ echo "please enter network interface name as parameter. For example:"
+ echo "sudo ./run_srp.sh eth1"
+ exit -1
+fi
+
+daemons/mrpd/mrpd -s -i $1
diff --git a/travis.sh b/travis.sh
index 5afad5e7..54a2b78a 100755
--- a/travis.sh
+++ b/travis.sh
@@ -4,6 +4,7 @@ make igb
make lib
make daemons_all
make examples_all
+make avtp_pipeline
mkdir build
cd build
cmake .. -G "Unix Makefiles"