summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen Carlino <Kenneth.Carlino@Symphonyteleca.com>2015-07-17 12:56:00 -0500
committerKen Carlino <Kenneth.Carlino@Symphonyteleca.com>2015-07-17 12:56:00 -0500
commitb8512cf1d4a2675cd941fd2ed723cc25afba0de7 (patch)
treebcfaecf5b7488897275857a35dd9e84fd1b0c4c1
parent365cf04f73715780e123312ddadd83d202aa1bdd (diff)
downloadOpen-AVB-b8512cf1d4a2675cd941fd2ed723cc25afba0de7.tar.gz
STC AVTP Pipeline : Work in progress 1
-rw-r--r--lib/avtp_pipeline/CMakeLists.txt40
-rw-r--r--lib/avtp_pipeline/LICENSE30
-rw-r--r--lib/avtp_pipeline/README.md72
-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/cmake/FindALSA.cmake36
-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.in355
-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/stc_logo_small.pngbin0 -> 9614 bytes
-rw-r--r--lib/avtp_pipeline/documents/index.md52
-rw-r--r--lib/avtp_pipeline/documents/sdk_avtp_interface_module_dev.md165
-rw-r--r--lib/avtp_pipeline/documents/sdk_avtp_stream_cfg.md344
-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.txt39
-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.h238
-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_talker.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/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.c791
-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.c447
-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.h364
-rw-r--r--lib/avtp_pipeline/openavb_common/README.TXT9
-rw-r--r--lib/avtp_pipeline/openavb_common/avb.c552
-rw-r--r--lib/avtp_pipeline/openavb_common/avb.h206
-rw-r--r--lib/avtp_pipeline/openavb_common/listener_mrp_client.c239
-rw-r--r--lib/avtp_pipeline/openavb_common/listener_mrp_client.h58
-rw-r--r--lib/avtp_pipeline/openavb_common/talker_mrp_client.c597
-rw-r--r--lib/avtp_pipeline/openavb_common/talker_mrp_client.h82
-rw-r--r--lib/avtp_pipeline/platform/Linux/CMakeLists.txt301
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_host/CMakeLists.txt84
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c512
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c232
-rw-r--r--lib/avtp_pipeline/platform/Linux/avtp/openavb_avtp_time_osal.c34
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/CMakeLists.txt38
-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.c173
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.h58
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_server_osal.c254
-rw-r--r--lib/avtp_pipeline/platform/Linux/generic.cmake15
-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_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.c1040
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/CMakeLists.txt10
-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.ini105
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_talker.ini131
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/openavb_intf_mjpeg_gst.c532
-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.txt9
-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.ini114
-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.c552
-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.c57
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal.h41
-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.c206
-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/openavb_rawsock.c1172
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock_igb.c654
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/openavb_sockets.c625
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/openavb_sockets.h173
-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/tl/openavb_tl_osal.c443
-rw-r--r--lib/avtp_pipeline/platform/Linux/x86_i210_linux.cmake30
-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.c206
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/openavb_ether_hal.h75
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/openavb_hal.h38
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/openavb_time_hal.c61
-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.c87
-rw-r--r--lib/avtp_pipeline/qmgr/openavb_qmgr.h104
-rw-r--r--lib/avtp_pipeline/rawsock/CMakeLists.txt1
-rw-r--r--lib/avtp_pipeline/rawsock/openavb_rawsock.h164
-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.c187
-rw-r--r--lib/avtp_pipeline/tl/openavb_talker_no_endpoint.c156
-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.c277
-rw-r--r--lib/avtp_pipeline/tl/openavb_tl_no_endpoint.c134
-rwxr-xr-xlib/avtp_pipeline/tl/openavb_tl_pub.h339
-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.c386
-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_talker.sh12
-rwxr-xr-xrun_gptp.sh11
-rwxr-xr-xrun_igb.sh16
-rwxr-xr-xrun_simple_talker.sh10
-rwxr-xr-xrun_srp.sh10
267 files changed, 40758 insertions, 0 deletions
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..7f46621a
--- /dev/null
+++ b/lib/avtp_pipeline/LICENSE
@@ -0,0 +1,30 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..5eab7b04
--- /dev/null
+++ b/lib/avtp_pipeline/README.md
@@ -0,0 +1,72 @@
+# STC AVTP Pipeline Contribution Notes
+
+## General Status
+- Consider the AVTP Pipeline a work in progress.
+- Integrated with OpenAVB:
+ - gPTP
+- Not yet integreated with OpenAVB:
+ - MSRP
+ - igb direct for packet TX. Current linux raw sockets are used for both TX and RX.
+ - igb credit based shaper
+ - Build system
+- Very limited tested as been down. Primarily just the Echo talker which is a simple test stream.
+- Documentation and doc generation has not been fully updated.
+
+## Building Current OpenAVB
+### Tool chain and libraries
+- Ubuntu 14.04
+- Build OpenAVB Next branch (OpenAVB Master doesn't igb doesn't build properly)
+- Install ($ 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)
+
+### Building
+- Building from the repo root
+- $ make igb
+- $ make lib
+- $ ARCH=I210 make gptp
+- $ make mrpd
+- $ make maap
+- $ make examples_all
+
+## Building STC AVTP Pipeline
+### Get packages
+- $ 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
+
+### Setup AVTP Pipeline build directory
+- Building from the repo root
+- $ cd ..
+- $ mkdir build
+- $ cd build
+- `$ cmake -DCMAKE_TOOLCHAIN_FILE=repo/lib/avtp_pipeline/platform/Linux/x86_i210_linux.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ../repo/lib/avtp_pipeline`
+
+### Build AVTP Pipeline
+- $ make all install
+
+## Running OpenAVB
+- 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.
+- `$ sudo ./run_simple_talker.sh eth1`
+ - Run the current OpenAVB simple talker example. Supply the interface name (ethx) as parameter.
+
+## Running OpenAVB with STC Echo Talker (without SRP currently)
+- `$ 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_echo_talker.sh eth1`
+ - Run the AVTP Echo talker test stream. Supply the interface name (ethx) as parameter.
+
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..6b646d08
--- /dev/null
+++ b/lib/avtp_pipeline/avtp/openavb_avtp.c
@@ -0,0 +1,701 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..aa506ff7
--- /dev/null
+++ b/lib/avtp_pipeline/avtp/openavb_avtp.h
@@ -0,0 +1,192 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..39140c87
--- /dev/null
+++ b/lib/avtp_pipeline/avtp/openavb_avtp_time.c
@@ -0,0 +1,438 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..c91ee104
--- /dev/null
+++ b/lib/avtp_pipeline/avtp/openavb_avtp_time_pub.h
@@ -0,0 +1,275 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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/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/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..77df2da4
--- /dev/null
+++ b/lib/avtp_pipeline/documents/Doxyfile.in
@@ -0,0 +1,355 @@
+# Doxyfile 1.8.6
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+DOXYFILE_ENCODING = UTF-8
+PROJECT_NAME = "OPENAVB EAVB SDK"
+PROJECT_NUMBER = 1.4
+PROJECT_BRIEF =
+PROJECT_LOGO = @CMAKE_CURRENT_SOURCE_DIR@/images/openavb_logo_small.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@/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_camera \
+ @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_pipe_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 \
+# @CMAKE_CURRENT_SOURCE_DIR@/../adp \
+# @CMAKE_CURRENT_SOURCE_DIR@/../aecp \
+# @CMAKE_CURRENT_SOURCE_DIR@/../aem \
+# @CMAKE_CURRENT_SOURCE_DIR@/../avdecc \
+# @CMAKE_CURRENT_SOURCE_DIR@/../intf_ctrl \
+# @CMAKE_CURRENT_SOURCE_DIR@/../map_ctrl \
+# @CMAKE_CURRENT_SOURCE_DIR@/../map_h264 \
+# @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_saf_audio \
+# @CMAKE_CURRENT_SOURCE_DIR@/../map_uncmp_audio \
+
+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/stc_logo_small.png b/lib/avtp_pipeline/documents/images/stc_logo_small.png
new file mode 100644
index 00000000..7a316664
--- /dev/null
+++ b/lib/avtp_pipeline/documents/images/stc_logo_small.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..edf2d08e
--- /dev/null
+++ b/lib/avtp_pipeline/documents/index.md
@@ -0,0 +1,52 @@
+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 Camera (mjpeg_camera)](@ref mjpeg_camera_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..10dc4d07
--- /dev/null
+++ b/lib/avtp_pipeline/documents/sdk_avtp_stream_cfg.md
@@ -0,0 +1,344 @@
+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 Camera (mjpeg_camera)](@ref mjpeg_camera_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..24b6d058
--- /dev/null
+++ b/lib/avtp_pipeline/endpoint/CMakeLists.txt
@@ -0,0 +1,39 @@
+include_directories(
+ ${AVB_OSAL_DIR}/endpoint
+ ${AVB_OSAL_DIR}/maap
+ ${AVB_OSAL_DIR}/tl
+ ${AVB_SRC_DIR}/maap
+ ${AVB_SRC_DIR}/endpoint
+ ${AVB_SRC_DIR}/srp
+ ${AVB_SRC_DIR}/tl
+ ${AVB_OSAL_DIR}/fqtss/qmgr
+ ${AVB_OSAL_DIR}/srp
+ )
+
+# File sets are curreintly the same for AVB_FEATURE_ENDPOINT or not. Needs code changes to properly allow linux to run with and without SRP/MAPP
+if (AVB_FEATURE_ENDPOINT)
+ 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
+ )
+else(AVB_FEATURE_ENDPOINT)
+ 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
+ )
+endif (AVB_FEATURE_ENDPOINT)
+
+# If FQTSS is enabled...
+if ( AVB_FEATURE_FQTSS )
+ # set define for ifdefs
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAVB_FEATURE_FQTSS=1" )
+ # and add library to link list
+ set ( AVB_ENDPOINT_LIBRARIES "${AVB_ENDPOINT_LIBRARIES}" qmgr )
+endif ( AVB_FEATURE_FQTSS )
+
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..f4059c92
--- /dev/null
+++ b/lib/avtp_pipeline/endpoint/openavb_endpoint.c
@@ -0,0 +1,528 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..782e660a
--- /dev/null
+++ b/lib/avtp_pipeline/endpoint/openavb_endpoint.h
@@ -0,0 +1,279 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..da10d734
--- /dev/null
+++ b/lib/avtp_pipeline/endpoint/openavb_endpoint_client.c
@@ -0,0 +1,199 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..a609d2ed
--- /dev/null
+++ b/lib/avtp_pipeline/endpoint/openavb_endpoint_server.c
@@ -0,0 +1,394 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..5e5c3775
--- /dev/null
+++ b/lib/avtp_pipeline/include/avb_sched.h
@@ -0,0 +1,126 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..2bb8a00f
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_audio_pub.h
@@ -0,0 +1,157 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..5594e7fd
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_intf_pub.h
@@ -0,0 +1,230 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..9acb2fab
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_log.h
@@ -0,0 +1,43 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..4b7f01e0
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_log_pub.h
@@ -0,0 +1,246 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..3eb1afc0
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_map_pub.h
@@ -0,0 +1,238 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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 (OPENAVB) Specific formats used AVTP headers.
+#define MAP_NULL_OPENAVB_FORMAT 0x00
+#define MAP_PIPE_OPENAVB_FORMAT 0x01
+
+// Vendor (OPENAVB) Specific CTRL formats used AVTP .
+#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..6aa44de8
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_platform.h
@@ -0,0 +1,47 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..a8d1b02a
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_platform_pub.h
@@ -0,0 +1,42 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..d3b72c99
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_pub.h
@@ -0,0 +1,87 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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 "OpenAVB 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..140c2d0e
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_trace.h
@@ -0,0 +1,78 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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 1
+#define AVB_TRACE_ADP 1
+#define AVB_TRACE_AECP 1
+#define AVB_TRACE_AEM 1
+#define AVB_TRACE_AVDECC 1
+#define AVB_TRACE_AVTP 1
+#define AVB_TRACE_AVTP_DETAIL 1
+#define AVB_TRACE_AVTP_TIME 1
+#define AVB_TRACE_AVTP_TIME_DETAIL 1
+#define AVB_TRACE_ENDPOINT 1
+#define AVB_TRACE_MEDIAQ 1
+#define AVB_TRACE_MEDIAQ_DETAIL 1
+#define AVB_TRACE_QUEUE_MANAGER 1
+#define AVB_TRACE_MAAP 1
+#define AVB_TRACE_RAWSOCK 1
+#define AVB_TRACE_RAWSOCK_DETAIL 1
+#define AVB_TRACE_SRP_PUBLIC 1
+#define AVB_TRACE_SRP_PRIVATE 1
+#define AVB_TRACE_TL 1
+#define AVB_TRACE_TL_DETAIL 1
+#define AVB_TRACE_PTP 1
+#define AVB_TRACE_FQTSS 1
+#define AVB_TRACE_FQTSS_DETAIL 1
+#define AVB_TRACE_HR_TMR 1
+#define AVB_TRACE_NANOSLEEP 1
+#define AVB_TRACE_TIME 1
+#define AVB_TRACE_HAL_ETHER 1
+#define AVB_TRACE_HAL_ETHER_DETAIL 1
+#define AVB_TRACE_HAL_TASK_TIMER 1
+#define AVB_TRACE_DEBUG 1
+#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..71e4a275
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_trace_pub.h
@@ -0,0 +1,247 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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 1
+#define AVB_TRACE_MAP_DETAIL 1
+#define AVB_TRACE_MAP_LINE 1
+#define AVB_TRACE_INTF 1
+#define AVB_TRACE_INTF_DETAIL 1
+#define AVB_TRACE_INTF_LINE 1
+#define AVB_TRACE_HOST 1
+
+#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..cf24142b
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_types.h
@@ -0,0 +1,45 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..dab5e35f
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_types_base.h
@@ -0,0 +1,79 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..a78ef307
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_types_base_pub.h
@@ -0,0 +1,120 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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 <stdint.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..45016c68
--- /dev/null
+++ b/lib/avtp_pipeline/include/openavb_types_pub.h
@@ -0,0 +1,48 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..c999b20d
--- /dev/null
+++ b/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl.c
@@ -0,0 +1,385 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..372ef978
--- /dev/null
+++ b/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl_pub.h
@@ -0,0 +1,66 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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_talker.ini b/lib/avtp_pipeline/intf_echo/echo_talker.ini
new file mode 100644
index 00000000..f083033d
--- /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 = 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_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..9173644d
--- /dev/null
+++ b/lib/avtp_pipeline/intf_echo/openavb_intf_echo.c
@@ -0,0 +1,349 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..48517ad5
--- /dev/null
+++ b/lib/avtp_pipeline/intf_logger/openavb_intf_logger.c
@@ -0,0 +1,201 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..47c1b395
--- /dev/null
+++ b/lib/avtp_pipeline/intf_null/openavb_intf_null.c
@@ -0,0 +1,208 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..dc7babce
--- /dev/null
+++ b/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.c
@@ -0,0 +1,524 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..65143e1a
--- /dev/null
+++ b/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.md
@@ -0,0 +1,30 @@
+Tone Generator Interface {#tongen_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..7f83632c
--- /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..2f7139c9
--- /dev/null
+++ b/lib/avtp_pipeline/intf_viewer/openavb_intf_viewer.c
@@ -0,0 +1,520 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..734823dc
--- /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/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..2cd4a82c
--- /dev/null
+++ b/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c
@@ -0,0 +1,791 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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");
+ 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_INFO("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..b0db72cf
--- /dev/null
+++ b/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio_pub.h
@@ -0,0 +1,52 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..a4047290
--- /dev/null
+++ b/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl.c
@@ -0,0 +1,484 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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 {
+ 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..ff2b9a6f
--- /dev/null
+++ b/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl_pub.h
@@ -0,0 +1,44 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..32dbfe27
--- /dev/null
+++ b/lib/avtp_pipeline/map_h264/openavb_map_h264.c
@@ -0,0 +1,447 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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)
+
+//////
+// 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) {
+ pPvtData->maxPayloadSize = strtol(value, &pEnd, 10);
+ pPvtData->maxDataSize = (pPvtData->maxPayloadSize + TOTAL_HEADER_SIZE);
+ pPvtData->itemSize = pPvtData->maxDataSize;
+ }
+ }
+
+ 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]
+
+ // 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 >= 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 {
+ 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 = 1412;
+ 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_h264/openavb_map_h264_pub.h b/lib/avtp_pipeline/map_h264/openavb_map_h264_pub.h
new file mode 100755
index 00000000..e70111ab
--- /dev/null
+++ b/lib/avtp_pipeline/map_h264/openavb_map_h264_pub.h
@@ -0,0 +1,58 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..782a6d04
--- /dev/null
+++ b/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg.c
@@ -0,0 +1,427 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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 {
+ 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..9af7180a
--- /dev/null
+++ b/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg_pub.h
@@ -0,0 +1,77 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..1f37d535
--- /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..409a6090
--- /dev/null
+++ b/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts.c
@@ -0,0 +1,734 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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 5
+
+// 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
+ 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..3d876708
--- /dev/null
+++ b/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts_pub.h
@@ -0,0 +1,62 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..4a2e9984
--- /dev/null
+++ b/lib/avtp_pipeline/map_mpeg2ts/ts_packet_size.c
@@ -0,0 +1,117 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..f79b0424
--- /dev/null
+++ b/lib/avtp_pipeline/map_null/openavb_map_null.c
@@ -0,0 +1,386 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..3252b9e7
--- /dev/null
+++ b/lib/avtp_pipeline/map_null/openavb_map_null_pub.h
@@ -0,0 +1,44 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..61fa7653
--- /dev/null
+++ b/lib/avtp_pipeline/map_pipe/openavb_map_pipe.c
@@ -0,0 +1,488 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..badb8c0b
--- /dev/null
+++ b/lib/avtp_pipeline/map_pipe/openavb_map_pipe_pub.h
@@ -0,0 +1,44 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..20ce0c88
--- /dev/null
+++ b/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio.c
@@ -0,0 +1,759 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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 = 4;
+ }
+ 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->packetAudioDataSizeBytes, 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 += 4;
+ }
+ }
+ 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 += 4;
+ itemSizeWritten += 4;
+ }
+ }
+ }
+
+ 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..56bc1dd2
--- /dev/null
+++ b/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio_pub.h
@@ -0,0 +1,132 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..e163a308
--- /dev/null
+++ b/lib/avtp_pipeline/mcr/openavb_mcr_hal_pub.h
@@ -0,0 +1,65 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..2dc419e8
--- /dev/null
+++ b/lib/avtp_pipeline/mediaq/openavb_mediaq.c
@@ -0,0 +1,1073 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..b620a610
--- /dev/null
+++ b/lib/avtp_pipeline/mediaq/openavb_mediaq.h
@@ -0,0 +1,60 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..405575ce
--- /dev/null
+++ b/lib/avtp_pipeline/mediaq/openavb_mediaq_pub.h
@@ -0,0 +1,364 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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 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 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.
+ * \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..200489b6
--- /dev/null
+++ b/lib/avtp_pipeline/openavb_common/avb.c
@@ -0,0 +1,552 @@
+ /*
+ * 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(errno));
+ continue;
+ }
+
+ err = igb_attach_tx(igb_dev);
+ if (err) {
+ printf("attach_tx failed! (%s)\n", strerror(errno));
+ 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;
+}
+
+/* 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..019c9d65
--- /dev/null
+++ b/lib/avtp_pipeline/openavb_common/avb.h
@@ -0,0 +1,206 @@
+ /*
+ * 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 struct {
+ int64_t ml_phoffset;
+ int64_t ls_phoffset;
+ long double ml_freqoffset;
+ long double 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);
+
+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/listener_mrp_client.c b/lib/avtp_pipeline/openavb_common/listener_mrp_client.c
new file mode 100644
index 00000000..1e5652c1
--- /dev/null
+++ b/lib/avtp_pipeline/openavb_common/listener_mrp_client.c
@@ -0,0 +1,239 @@
+/*
+ Copyright (c) 2013 Katja Rohloff <Katja.Rohloff@uni-jena.de>
+ Copyright (c) 2014, Parrot SA
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "listener_mrp_client.h"
+
+/* global variables */
+
+int control_socket;
+volatile int talker = 0;
+unsigned char stream_id[8];
+
+/*
+ * private
+ */
+
+int send_msg(char *data, int data_len)
+{
+ struct sockaddr_in addr;
+
+ if (control_socket == -1)
+ return -1;
+ if (data == NULL)
+ return -1;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ 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,
+ (struct sockaddr*)&addr, (socklen_t)sizeof(addr));
+}
+
+int msg_process(char *buf, int buflen)
+{
+ uint32_t id;
+ int j, l;
+
+ fprintf(stderr, "Msg: %s\n", buf);
+ if (strncmp(buf, "SNE T:", 6) == 0 || strncmp(buf, "SJO T:", 6) == 0)
+ {
+ l = 6; /* skip "Sxx T:" */
+ while ((l < buflen) && ('S' != buf[l++]));
+ if (l == buflen)
+ return -1;
+ l++;
+ for(j = 0; j < 8 ; l+=2, j++)
+ {
+ sscanf(&buf[l],"%02x",&id);
+ stream_id[j] = (unsigned char)id;
+ }
+ 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)
+ {
+ free(databuf);
+ return -1;
+ }
+ ret = msg_process(databuf, bytes);
+ free(databuf);
+
+ return ret;
+}
+
+/*
+ * public
+ */
+
+int create_socket() // TODO FIX! =:-|
+{
+ struct sockaddr_in addr;
+ control_socket = socket(AF_INET, SOCK_DGRAM, 0);
+
+ /** in POSIX fd 0,1,2 are reserved */
+ if (2 > control_socket)
+ {
+ if (-1 > control_socket)
+ close(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))))
+ {
+ fprintf(stderr, "Could not bind socket.\n");
+ close(control_socket);
+ return -1;
+ }
+ return 0;
+}
+
+int report_domain_status()
+{
+ char* msgbuf;
+ int rc;
+
+ msgbuf = malloc(1500);
+ if (NULL == msgbuf)
+ return -1;
+ memset(msgbuf, 0, 1500);
+ sprintf(msgbuf, "S+D:C=6,P=3,V=0002");
+ rc = send_msg(msgbuf, 1500);
+ free(msgbuf);
+
+ if (rc != 1500)
+ return -1;
+ else
+ return 0;
+}
+
+int 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_msg(msgbuf, 1500);
+ free(msgbuf);
+
+ if (rc != 1500)
+ return -1;
+ else
+ return 0;
+}
+
+int await_talker()
+{
+ while (0 == talker)
+ recv_msg();
+ return 0;
+}
+
+int send_ready()
+{
+ 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_msg(databuf, 1500);
+ free(databuf);
+
+ if (rc != 1500)
+ return -1;
+ else
+ return 0;
+}
+
+int send_leave()
+{
+ 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_msg(databuf, 1500);
+ free(databuf);
+
+ if (rc != 1500)
+ return -1;
+ else
+ return 0;
+}
+
+int mrp_disconnect()
+{
+ int rc;
+ char *msgbuf = malloc(1500);
+
+ if (NULL == msgbuf)
+ return -1;
+ memset(msgbuf, 0, 1500);
+
+ sprintf(msgbuf, "BYE");
+ rc = send_msg(msgbuf, 1500);
+ free(msgbuf);
+
+ if (rc != 1500)
+ return -1;
+ else
+ return 0;
+}
diff --git a/lib/avtp_pipeline/openavb_common/listener_mrp_client.h b/lib/avtp_pipeline/openavb_common/listener_mrp_client.h
new file mode 100644
index 00000000..142d8f39
--- /dev/null
+++ b/lib/avtp_pipeline/openavb_common/listener_mrp_client.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (c) 2013 Katja Rohloff <Katja.Rohloff@uni-jena.de>
+ Copyright (c) 2014, Parrot SA
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef _LISTENER_MRP_CLIENT_H_
+#define _LISTENER_MRP_CLIENT_H_
+
+/*
+ * simple_listener MRP client part
+ */
+
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <stdio.h> // TODO fprintf, to be removed
+#include <unistd.h>
+
+#include "mrpd.h"
+
+/* global variables */
+
+// TODO move these in a talker_context struct + init func
+
+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();
+
+#endif /* _LISTENER_MRP_CLIENT_H_ */
diff --git a/lib/avtp_pipeline/openavb_common/talker_mrp_client.c b/lib/avtp_pipeline/openavb_common/talker_mrp_client.c
new file mode 100644
index 00000000..1b42fabb
--- /dev/null
+++ b/lib/avtp_pipeline/openavb_common/talker_mrp_client.c
@@ -0,0 +1,597 @@
+/******************************************************************************
+
+ 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 "talker_mrp_client.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;
+ int i, j, k;
+ unsigned int substate;
+ unsigned char recovered_streamid[8];
+ k = 0;
+ next_line:if (k >= buflen)
+ return 0;
+ switch (buf[k]) {
+ case 'E':
+ printf("%s from mrpd\n", buf);
+ fflush(stdout);
+ mrp_error = 1;
+ break;
+ case 'O':
+ mrp_okay = 1;
+ break;
+ case 'M':
+ case 'V':
+ printf("%s unhandled from mrpd\n", buf);
+ fflush(stdout);
+
+ /* 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;
+ } printf
+ ("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:
+ printf("with state ignore\n");
+ break;
+ case 1:
+ printf("with state askfailed\n");
+ break;
+ case 2:
+ printf("with state ready\n");
+ break;
+ case 3:
+ printf("with state readyfail\n");
+ break;
+ default:
+ printf("with state UNKNOWN (%d)\n", substate);
+ break;
+ }
+ if (substate > MSRP_LISTENER_ASKFAILED) {
+ if (memcmp
+ (recovered_streamid, monitor_stream_id,
+ sizeof(recovered_streamid)) == 0) {
+ listeners = 1;
+ printf("added listener\n");
+ }
+ }
+ fflush(stdout);
+
+ /* 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':
+
+ /* as simple_talker we don't care about other talkers */
+ i = k;
+ 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;
+ } printf
+ ("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:
+ printf("with state ignore\n");
+ break;
+ case 1:
+ printf("with state askfailed\n");
+ break;
+ case 2:
+ printf("with state ready\n");
+ break;
+ case 3:
+ printf("with state readyfail\n");
+ break;
+ default:
+ printf("with state UNKNOWN (%d)\n", substate);
+ break;
+ }
+ switch (buf[k + 1]) {
+ case 'L':
+ printf("got a leave indication\n");
+ if (memcmp
+ (recovered_streamid, monitor_stream_id,
+ sizeof(recovered_streamid)) == 0) {
+ listeners = 0;
+ printf("listener left\n");
+ }
+ break;
+ case 'J':
+ case 'N':
+ printf("got a new/join indication\n");
+ if (substate > MSRP_LISTENER_ASKFAILED) {
+ if (memcmp
+ (recovered_streamid,
+ monitor_stream_id,
+ sizeof(recovered_streamid)) == 0)
+ listeners = 1;
+ }
+ break;
+ }
+
+ /* only care about listeners ... */
+ 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;
+ 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;
+
+ /* 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))
+ 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 0;
+}
+
+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;
+}
+
diff --git a/lib/avtp_pipeline/openavb_common/talker_mrp_client.h b/lib/avtp_pipeline/openavb_common/talker_mrp_client.h
new file mode 100644
index 00000000..60ced4cd
--- /dev/null
+++ b/lib/avtp_pipeline/openavb_common/talker_mrp_client.h
@@ -0,0 +1,82 @@
+/******************************************************************************
+
+ 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;
+
+/* 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);
+
+#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..7f04b1d0
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/CMakeLists.txt
@@ -0,0 +1,301 @@
+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" )
+
+# 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)
+ pkg_check_modules(GST_PKG gstreamer-app-0.10)
+ 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} )
+
+# 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}/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 )
+SET ( SRC_FILES ${SRC_FILES} ${AVB_OSAL_DIR}/openavb_osal.c )
+SET ( SRC_FILES ${SRC_FILES} ${AVB_OSAL_DIR}/rawsock/openavb_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/listener_mrp_client.c )
+SET ( SRC_FILES ${SRC_FILES} ${AVB_SRC_DIR}/openavb_common/talker_mrp_client.c )
+
+add_library ( avbTl ${SRC_FILES} )
+target_link_libraries ( avbTl dl )
+
+install ( TARGETS avbTl ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
+
+# avb_host (openavb_host and openavb_harness)
+add_subdirectory ( ${AVB_OSAL_DIR}/avb_host )
+
+# mapping modules
+macro (add_map_mod MAP_NAME)
+ SET ( SRC_FILES "" )
+ add_subdirectory ( ${MAP_NAME} )
+ add_library ( ${MAP_NAME} ${SRC_FILES} )
+ install ( TARGETS ${MAP_NAME} ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
+endmacro()
+add_map_mod ( "map_ctrl" )
+add_map_mod ( "map_mjpeg" )
+add_map_mod ( "map_mpeg2ts" )
+add_map_mod ( "map_null" )
+add_map_mod ( "map_pipe" )
+add_map_mod ( "map_aaf_audio" )
+add_map_mod ( "map_uncmp_audio" )
+add_map_mod ( "map_h264" )
+
+# Interface modules (common)
+macro (add_intf_mod INTF_NAME)
+ SET ( SRC_FILES "" )
+ add_subdirectory ( ${INTF_NAME} )
+ add_library ( ${INTF_NAME} ${SRC_FILES} )
+ install ( TARGETS ${INTF_NAME} ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
+ install ( DIRECTORY "${AVB_SRC_DIR}/${INTF_NAME}/" DESTINATION ${AVB_INSTALL_BIN_DIR} FILES_MATCHING PATTERN "*.ini" )
+endmacro()
+add_intf_mod ( "intf_ctrl" )
+add_intf_mod ( "intf_echo" )
+add_intf_mod ( "intf_logger" )
+add_intf_mod ( "intf_null" )
+add_intf_mod ( "intf_tonegen" )
+add_intf_mod ( "intf_viewer" )
+
+# Interface modules (platform)
+macro (add_intf_mod_platform INTF_NAME)
+ SET ( SRC_FILES "" )
+ SET ( INTF_INCLUDE_DIR "")
+ SET ( INTF_LIBRARY_DIR "")
+ SET ( INTF_LIBRARY "")
+ add_subdirectory ( ${AVB_OSAL_DIR}/${INTF_NAME} )
+ include_directories ( ${INTF_INCLUDE_DIR} )
+ add_library ( ${INTF_NAME} ${SRC_FILES} )
+ install ( TARGETS ${INTF_NAME} ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
+ install ( DIRECTORY "${AVB_OSAL_DIR}/${INTF_NAME}/" DESTINATION ${AVB_INSTALL_BIN_DIR} FILES_MATCHING PATTERN "*.ini" )
+endmacro()
+
+add_intf_mod_platform ( "intf_alsa" )
+if (AVB_FEATURE_GSTREAMER)
+ add_intf_mod_platform ( "intf_mpeg2ts_gst" )
+ add_intf_mod_platform ( "intf_mjpeg_gst" )
+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..2d28ff93
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avb_host/CMakeLists.txt
@@ -0,0 +1,84 @@
+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
+ 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
+ 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..bb2e4353
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c
@@ -0,0 +1,512 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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);
+
+
+/***********************************************
+ * 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"
+ "\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 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);
+}
+
+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;
+
+ // 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); // TODO_OPENAVB : Not sure why MJPEG is having an issue linking GST RTP
+ registerStaticIntfModule(openavbIntfMpeg2tsFileInitialize);
+ registerStaticIntfModule(openavbIntfMpeg2tsGstInitialize);
+ registerStaticIntfModule(openavbIntfWavFileInitialize);
+
+ osalAVBInitialize();
+
+ // Process command line
+ programName = strrchr(argv[0], '/');
+ programName = programName ? programName + 1 : argv[0];
+
+ if (argc < 2) {
+ osalAVBFinalize();
+ openavbTlHarnessUsage(programName);
+ exit(-1);
+ }
+
+ bool optDone = FALSE;
+ while (!optDone) {
+ int opt = getopt(argc, argv, "a:his:");
+ 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 '?':
+ default:
+ openavbTlHarnessUsage(programName);
+ osalAVBFinalize();
+ exit(-1);
+ }
+ }
+ else {
+ optDone = TRUE;
+ }
+ }
+
+ // 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 iniFile1[1024];
+ char iniFile2[1024];
+ if (optStreamAddr) {
+ sprintf(iniFile1, "%s,stream_addr=%s", argv[i1 + iniIdx], optStreamAddr);
+ }
+ else {
+ sprintf(iniFile1, "%s", argv[i1 + iniIdx]);
+ }
+
+ if (!optStreamCountSet) {
+ tlIniList[tlIndex++] = strdup(iniFile1);
+ }
+ else {
+ for (i2 = 0; i2 < optStreamCount; i2++) {
+ sprintf(iniFile2, "%s,stream_uid=%d", iniFile1, tlIndex);
+ tlIniList[tlIndex++] = strdup(iniFile2);
+ }
+ }
+ }
+
+#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..2a3f5cd4
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c
@@ -0,0 +1,232 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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);
+
+/***********************************************
+ * 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);
+}
+
+
+/**********************************************
+ * main
+ */
+int main(int argc, char *argv[])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HOST);
+
+ if (argc < 2) {fprintf(stderr, "error: usage is:\n\t%s inifile1 [infile2...]\n", argv[0]);
+ exit(-1);
+ }
+
+ U32 tlCount = argc - 1;
+ tl_handle_t *tlHandleList = NULL;
+ int i1;
+
+ osalAVBInitialize();
+
+ 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); // TODO_OPENAVB : Not sure why MJPEG is having an issue linking GST RTP
+ registerStaticIntfModule(openavbIntfMpeg2tsFileInitialize);
+ registerStaticIntfModule(openavbIntfMpeg2tsGstInitialize);
+ registerStaticIntfModule(openavbIntfWavFileInitialize);
+
+ 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;
+
+ openavbTLInitCfg(&cfg);
+ memset(&NVCfg, 0, sizeof(NVCfg));
+
+ if (!openavbTLReadIniFileOsal(tlHandleList[i1], argv[i1 + 1], &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..d923a1e8
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avtp/openavb_avtp_time_osal.c
@@ -0,0 +1,34 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..c993ded2
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/CMakeLists.txt
@@ -0,0 +1,38 @@
+# CORE_TODO: This build logic may have been better in the primary Linux CMakeList.txt however some dependany issue occurs when doing so
+# related copying the kernel files for FQTSS. Basically the FQTSS custom commands for copy files was not engaged.
+
+# Places to get include files
+include_directories(
+ ${AVB_OSAL_DIR}/endpoint
+ ${AVB_OSAL_DIR}/maap
+ ${AVB_OSAL_DIR}/tl
+ ${AVB_SRC_DIR}/maap
+ ${AVB_SRC_DIR}/endpoint
+ ${AVB_SRC_DIR}/srp
+ ${AVB_SRC_DIR}/tl
+ ${AVB_OSAL_DIR}/fqtss/qmgr
+ ${AVB_OSAL_DIR}/srp
+ )
+
+SET ( SRC_FILES "" )
+add_library (rawsock ${AVB_OSAL_DIR}/rawsock/openavb_rawsock.c)
+add_subdirectory ( ${AVB_SRC_DIR}/maap ${CMAKE_BINARY_DIR}/maap )
+add_subdirectory ( ${AVB_SRC_DIR}/srp ${CMAKE_BINARY_DIR}/srp )
+add_subdirectory ( ${AVB_SRC_DIR}/endpoint ${CMAKE_BINARY_DIR}/endpoint )
+add_library ( endpoint ${SRC_FILES} )
+set ( AVB_ENDPOINT_LIBRARIES avbTl pthread rt m )
+if ( AVB_FEATURE_FQTSS )
+ # set define for ifdefs
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAVB_FEATURE_FQTSS=1" )
+ # and add library to link list
+ set ( AVB_ENDPOINT_LIBRARIES "${AVB_ENDPOINT_LIBRARIES}" qmgr )
+endif ( AVB_FEATURE_FQTSS )
+target_link_libraries (endpoint ${AVB_ENDPOINT_LIBRARIES} )
+add_executable (
+ openavb_endpoint
+ ${AVB_OSAL_DIR}/endpoint/openavb_endpoint_osal.c
+ )
+target_link_libraries (openavb_endpoint endpoint )
+install ( TARGETS openavb_endpoint RUNTIME DESTINATION ${AVB_INSTALL_BIN_DIR} )
+
+
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..d9bb80a7
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c
@@ -0,0 +1,224 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..6dcbc8cd
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.h
@@ -0,0 +1,63 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..71878f56
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_client_osal.c
@@ -0,0 +1,179 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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_ERROR("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_ERROR("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..f10b5aad
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.c
@@ -0,0 +1,173 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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"
+
+#define AVB_LOG_COMPONENT "Endpoint"
+#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 void sigHandler(int signal)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ AVB_LOGF_DEBUG("Received signal: %d", signal);
+ // SIGINT means we should shut ourselves down
+ if (signal == SIGINT)
+ endpointRunning = FALSE;
+ else if (signal == SIGUSR2)
+ openavbSrpLogAllStreams();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+}
+
+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;
+}
+
+/*************************************************************
+ *
+ * main() - sets up signal handlers, and reads configuration file
+ *
+ */
+int main(int argc, char* argv[])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+ LOG_EAVB_CORE_VERSION();
+
+ char *inifile = NULL;
+ int exitVal = -1;
+
+ avbLogInit();
+
+ do {
+
+ switch (argc) {
+ case 1:
+ inifile = DEFAULT_INI_FILE;
+ break;
+ case 2:
+ inifile = argv[1];
+ break;
+ default:
+ fprintf(stderr, "Error: usage is:\n\t%s [endpoint.ini]\n\n", argv[0]);
+ break;;
+ }
+
+ // 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: %s needs to run as root\n\n", argv[0]);
+ break;
+ }
+
+ // Setup signal handlers
+ //
+ // We catch SIGINT and shutdown cleanly
+ endpointRunning = TRUE;
+
+ struct sigaction sa;
+ sa.sa_handler = sigHandler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0; // not SA_RESTART
+
+ if(sigaction(SIGUSR2, &sa, NULL) == -1)
+ {
+ AVB_LOG_ERROR("Failed to setup USR2 signal handler");
+ }
+
+ if (sigaction(SIGINT, &sa, NULL) == -1)
+ {
+ AVB_LOG_ERROR("Failed to setup signal handler");
+ break;
+ }
+
+ // Parse our INI file
+ memset(&x_cfg, 0, sizeof(openavb_endpoint_cfg_t));
+ AVB_LOGF_INFO("Reading configuration: %s", inifile);
+
+ if (openavbReadConfig(inifile, &x_cfg) == 0) {
+ if(avbEndpointLoop() < 0)
+ break;
+ }else {
+ AVB_LOG_ERROR("Failed to read configuration");
+ }
+
+ AVB_LOG_INFO("Shutting down");
+
+ openavbUnconfigure(&x_cfg);
+
+ exitVal = 0;
+ } while (0);
+
+ avbLogExit();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ exit(exitVal);
+}
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..8ab9f545
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.h
@@ -0,0 +1,58 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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;
+
+#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..829f7872
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_server_osal.c
@@ -0,0 +1,254 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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, -1);
+
+ 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..588b68d0
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/generic.cmake
@@ -0,0 +1,15 @@
+# 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" )
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..4c4fd179
--- /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_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..2b9eb256
--- /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 = 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_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..9c8a3b82
--- /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..36bdf6de
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/openavb_intf_alsa.c
@@ -0,0 +1,1040 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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) {
+ 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_mjpeg_gst/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/CMakeLists.txt
new file mode 100644
index 00000000..4176d2a3
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/CMakeLists.txt
@@ -0,0 +1,10 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_OSAL_DIR}/intf_mjpeg_gst/openavb_intf_mjpeg_gst.c
+ PARENT_SCOPE
+)
+
+# Need include and link directories for GST
+SET (INTF_INCLUDE_DIR ${INTF_INCLUDE_DIR} ${GLIB_PKG_INCLUDE_DIRS} ${GST_PKG_INCLUDE_DIRS} 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..02a8cf99
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_listener.ini
@@ -0,0 +1,105 @@
+#####################################################################
+# 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
+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 ! omx_scaler ! video/x-raw-yuv,width=1920,height=800 ! omx_ctrl display-mode=OMX_DC_MODE_1080P_60 ! omx_videosink sync=false
+
+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..fba0fece
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_talker.ini
@@ -0,0 +1,131 @@
+#####################################################################
+# 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_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
+
+#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
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..12478176
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/openavb_intf_mjpeg_gst.c
@@ -0,0 +1,532 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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"
+
+#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 {
+ char *pPipelineStr;
+
+ bool ignoreTimestamp;
+
+ GstElement *pipe;
+ GstElement *appsink;
+ GstElement *appsrc;
+
+ U32 bufwr;
+ U32 bufrd;
+ U32 seq;
+ GstBuffer *rxBufs[NBUFS];
+ bool asyncRx;
+ bool blockingRx;
+
+} 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");
+ }
+ GstCaps *sinkCaps = gst_caps_from_string("application/x-rtp");
+ //No limits for internal sink buffers. This may cause large memory consumption.
+ g_object_set(pPvtData->appsink, "max-buffers", 0, "drop", 0, "caps", sinkCaps, NULL);
+ gst_caps_unref(sinkCaps);
+ //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;
+ GstBuffer *txBuf = gst_app_sink_pull_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_rtp_buffer_get_payload_len(txBuf);
+
+ //Transmit data --BEGIN--
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ pMediaQItem->dataLen = paySize;
+ memcpy(pMediaQItem->pPubData, gst_rtp_buffer_get_payload(txBuf), paySize);
+ if (gst_rtp_buffer_get_marker(txBuf))
+ {
+ ((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;
+ }
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ openavbMediaQHeadPush(pMediaQ);
+ gst_buffer_unref(txBuf);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ AVB_LOG_INFO("GStreamer returned NULL buffer, pipeline stopped");
+ return FALSE; // Media queue full
+ }
+ // never here....
+ gst_buffer_unref(txBuf);
+ 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)
+ {
+ LOCK();
+ if (pPvtData->bufwr <= pPvtData->bufrd)
+ {
+ UNLOCK();
+ pthread_mutex_lock(&asyncReadMutex);
+ pthread_cond_wait(&asyncReadCond, &asyncReadMutex);
+ pthread_mutex_unlock(&asyncReadMutex);
+ }
+ else
+ {
+ UNLOCK();
+ }
+ LOCK();
+ GstBuffer *rxBuf = pPvtData->rxBufs[pPvtData->bufrd%NBUFS];
+ pPvtData->bufrd++;
+ UNLOCK();
+ if (rxBuf && (pPvtData->bufwr - pPvtData->bufrd) < NBUFS)
+ {
+ GstFlowReturn ret = gst_app_src_push_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("Th Buf %x %d skipped, OO!!", rxBuf, pPvtData->bufrd);
+// gst_buffer_unref(rxBuf);
+ }
+ }
+ 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);
+// pPvtData->pipe = gst_parse_launch("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 ! omx_scaler ! omx_ctrl display-mode=OMX_DC_MODE_1080P_60 ! omx_videosink sync=false", &error);
+// pPvtData->pipe = gst_parse_launch("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", &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");
+ }
+ GstCaps *srcCaps = gst_caps_from_string("application/x-rtp");
+ if (!srcCaps)
+ {
+ AVB_LOGF_DEBUG("Caps=%x",srcCaps);
+ }
+ gst_app_src_set_caps ((GstAppSrc *)pPvtData->appsrc, srcCaps);
+ gst_caps_unref(srcCaps);
+ gst_app_src_set_max_bytes((GstAppSrc *)pPvtData->appsrc, 3000);
+
+ 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);
+ if (!pMediaQItem)
+ {
+ moreSourcePackets = FALSE;
+ openavbMediaQTailPull(pMediaQ);
+ continue;
+ }
+ if (!pMediaQItem->dataLen)
+ {
+ AVB_LOG_DEBUG("No dataLen");
+ openavbMediaQTailPull(pMediaQ);
+ continue;
+ }
+ if (pPvtData->asyncRx)
+ {
+ LOCK();
+ unsigned long mdif = pPvtData->bufwr - pPvtData->bufrd;
+ if (pPvtData->bufwr > pPvtData->bufrd && mdif >= NBUFS)
+ {
+ openavbMediaQTailPull(pMediaQ);
+ AVB_LOGF_INFO("Rx async queue full, dropping (%lu - %lu = %lu)",pPvtData->bufwr,pPvtData->bufrd,mdif);
+ UNLOCK();
+ continue;
+ }
+ UNLOCK();
+ }
+ GstBuffer *rxBuf = gst_rtp_buffer_new_allocate (pMediaQItem->dataLen, 0,0);
+ if (!rxBuf)
+ {
+ AVB_LOG_ERROR("gst_rtp_buffer_allocate failed!");
+ openavbMediaQTailUnlock(pMediaQ);
+ return FALSE;
+ }
+ memcpy(gst_rtp_buffer_get_payload(rxBuf), pMediaQItem->pPubData, pMediaQItem->dataLen);
+
+ GST_BUFFER_TIMESTAMP(rxBuf) = GST_CLOCK_TIME_NONE;
+ GST_BUFFER_DURATION(rxBuf) = -1;
+
+ if ( ((media_q_item_map_mjpeg_pub_data_t *)pMediaQItem->pPubMapData)->lastFragment )
+ {
+ gst_rtp_buffer_set_marker(rxBuf,TRUE);
+ }
+
+ gst_rtp_buffer_set_ssrc(rxBuf,5);
+ gst_rtp_buffer_set_payload_type(rxBuf,96);
+ gst_rtp_buffer_set_version(rxBuf,2);
+ gst_rtp_buffer_set_seq(rxBuf,pPvtData->seq++);
+
+ if (pPvtData->asyncRx)
+ {
+ LOCK();
+ pPvtData->rxBufs[pPvtData->bufwr%NBUFS] = rxBuf;
+ pPvtData->bufwr++;
+ UNLOCK();
+ if (pPvtData->bufwr > pPvtData->bufrd)
+ {
+ pthread_mutex_lock(&asyncReadMutex);
+ pthread_cond_signal(&asyncReadCond);
+ pthread_mutex_unlock(&asyncReadMutex);
+ }
+ }
+ else
+ {
+ GstFlowReturn ret = gst_app_src_push_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;
+
+ 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..01f448a4
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/openavb_intf_mpeg2ts_file.c
@@ -0,0 +1,706 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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) {
+ //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..cd37f416
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/CMakeLists.txt
@@ -0,0 +1,9 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_OSAL_DIR}/intf_mpeg2ts_gst/openavb_intf_mpeg2ts_gst.c
+ PARENT_SCOPE
+)
+
+# Need include and link directories for gstreamer
+SET (INTF_INCLUDE_DIR ${INTF_INCLUDE_DIR} ${GLIB_PKG_INCLUDE_DIRS} ${GST_PKG_INCLUDE_DIRS} 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..68ae616a
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_listener.ini
@@ -0,0 +1,114 @@
+#####################################################################
+# 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
+intf_nv_gst_pipeline = appsrc name=avbsrc ! queue ! mpegtsdemux ! h264parse ! omx_h264dec ! omx_scaler ! omx_ctrl display-mode=OMX_DC_MODE_1080P_60 ! gstperf ! omx_videosink sync=false
+
+# 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..59656771
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/openavb_intf_mpeg2ts_gst.c
@@ -0,0 +1,552 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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"
+
+#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 sinkNewBuffer(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));
+ cbfns.new_buffer = sinkNewBuffer;
+ 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;
+ GstBuffer *txBuf;
+
+ while (g_atomic_int_get(&pPvtData->nWaiting) > 0) {
+
+ // Get a mediaQItem to hold the buffered data
+ pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (!pMediaQItem) {
+ //AVB_LOG_ERROR("Media queue full");
+ break;
+ }
+
+ /* Retrieve the buffer
+ */
+ txBuf = gst_app_sink_pull_buffer(pPvtData->appsink);
+ if (txBuf) {
+ g_atomic_int_add(&pPvtData->nWaiting, -1);
+
+ if ( GST_BUFFER_SIZE(txBuf) > pMediaQItem->itemSize ) {
+ AVB_LOGF_ERROR("GStreamer buffer too large (size=%d) for mediaQ item (dataLen=%d)",
+ GST_BUFFER_SIZE(txBuf), pMediaQItem->itemSize);
+ pMediaQItem->dataLen = 0;
+ openavbMediaQHeadUnlock(pMediaQ);
+ }
+ else {
+ memcpy(pMediaQItem->pPubData, GST_BUFFER_DATA(txBuf), GST_BUFFER_SIZE(txBuf));
+ pMediaQItem->dataLen = GST_BUFFER_SIZE(txBuf);
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ openavbMediaQHeadPush(pMediaQ);
+ }
+
+ gst_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) {
+ GstBuffer *rxBuf = gst_buffer_new_and_alloc(len);
+ if (rxBuf) {
+ GST_BUFFER_TIMESTAMP(rxBuf) = GST_CLOCK_TIME_NONE;
+ GST_BUFFER_DURATION(rxBuf) = GST_CLOCK_TIME_NONE;
+ memcpy(GST_BUFFER_DATA(rxBuf), pMediaQItem->pPubData, GST_BUFFER_SIZE(rxBuf));
+ GstFlowReturn gstret = gst_app_src_push_buffer(GST_APP_SRC(pPvtData->appsrc), rxBuf);
+ if (gstret != GST_FLOW_OK) {
+ AVB_LOGF_ERROR("Pushing buffer to gstreamer failed: %d", gstret);
+ gst_buffer_unref(rxBuf);
+ 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..be8474fb
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_wav_file/openavb_intf_wav_file.c
@@ -0,0 +1,698 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..565ce467
--- /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..81792e8c
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_ether_osal.c
@@ -0,0 +1,39 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..33965963
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_ether_osal.h
@@ -0,0 +1,40 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..e119c84d
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal.h
@@ -0,0 +1,169 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..19d47b36
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal_pub.h
@@ -0,0 +1,109 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..4ebfe1ba
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal.c
@@ -0,0 +1,57 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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(void)
+{
+ avbLogInit();
+ halEthernetInitialize(NULL, TRUE);
+ osalAVBTimeInit();
+ openavbQmgrInitialize(FQTSS_MODE_HW_CLASS, 0, NULL, 0, 0, 0);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool osalAVBFinalize(void)
+{
+ openavbQmgrFinalize();
+ osalAVBTimeClose();
+ halEthernetFinalize();
+ 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..79dc8c1a
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal.h
@@ -0,0 +1,41 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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_pub.h b/lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h
new file mode 100644
index 00000000..4ce91c81
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h
@@ -0,0 +1,44 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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(void);
+
+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..4b78730e
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_poll_osal.h
@@ -0,0 +1,77 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..1e222ed9
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_tasks.h
@@ -0,0 +1,106 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..0e99778f
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_time_osal.c
@@ -0,0 +1,206 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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;
+static 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);
+
+ // TODO_OPENAVB : There may be a reasonable way to avoid calling this each time. Really only need to update it after gPTP SYNC.
+ 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;
+ unsigned delta_8021as;
+ unsigned delta_local;
+
+ if (halTimeGetLocaltime(&now_local)) {
+ update_8021as = gPtpTD.local_time - gPtpTD.ml_phoffset;
+ delta_local = (unsigned)(now_local - gPtpTD.local_time);
+ delta_8021as = (unsigned)(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);
+
+ 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..9db4cb6b
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_time_osal.h
@@ -0,0 +1,36 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..a1029a76
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_time_osal_pub.h
@@ -0,0 +1,69 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..27bdb437
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/avtp_rx.c
@@ -0,0 +1,227 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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/openavb_rawsock.c b/lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock.c
new file mode 100644
index 00000000..080509da
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock.c
@@ -0,0 +1,1172 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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 raw socket library.
+ *
+ * The raw socket library allows its user to send manually-created
+ * Etherent frames, and to receive full frames directly off the network
+ * interface.
+ *
+ * AVB needs to do this because Linux doesn't have an in-kernel
+ * implementation of the SRP or AVTP protocols. We handle those
+ * protocols in our userspace processes.
+ *
+ * We use Linux's MMAP method of sending/receiving raw socket frames
+ * because it's more efficient than the normal socket read/write method.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <poll.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <linux/if_packet.h>
+#include <assert.h>
+#include "openavb_rawsock.h"
+#include "openavb_trace.h"
+#include <linux/filter.h>
+
+#define AVB_LOG_COMPONENT "Raw Socket"
+#include "openavb_log.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;
+
+// State information for raw socket
+//
+typedef struct {
+
+ // 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;
+
+ // the underlying socket
+ int sock;
+
+ // number and size of the frames that the ring can hold
+ int frameCount;
+ int frameSize;
+
+ // 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;
+
+
+ // TX usage of the socket
+ bool txMode;
+
+ // RX usage of the socket
+ bool rxMode;
+
+ // 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;
+} raw_sock_t;
+
+// Kernel block size
+#define BLOCK_SIZE 4096
+
+// Argument validation
+#define VALID_RAWSOCK(s) ((s) != NULL && (s)->pMem != (void*)(-1) && (s)->sock != -1)
+#define VALID_TX_RAWSOCK(s) (VALID_RAWSOCK(s) && (s)->txMode)
+#define VALID_RX_RAWSOCK(s) (VALID_RAWSOCK(s) && (s)->rxMode)
+
+// Get information about an interface
+bool openavbCheckInterface(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 *openavbRawsockOpen(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);
+
+ /* Allocate struct to hold info about the raw socket
+ * that we're going to create.
+ */
+ raw_sock_t *rawsock = malloc(sizeof(raw_sock_t));
+ if (!rawsock) {
+ AVB_LOG_ERROR("Creating rawsock; malloc failed");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+ memset(rawsock, 0, sizeof(raw_sock_t));
+ rawsock->sock = -1;
+ rawsock->pMem = (void*)(-1);
+ rawsock->rxMode = rx_mode;
+ rawsock->txMode = tx_mode;
+ rawsock->frameSize = frame_size;
+ rawsock->ethertype = ethertype;
+
+ // Get info about the network device
+ if (!openavbCheckInterface(ifname, &(rawsock->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->frameSize == 0) {
+ // use interface MTU as max frames size, if none specified
+ rawsock->frameSize = rawsock->ifInfo.mtu;
+ }
+ else if (rawsock->frameSize > rawsock->ifInfo.mtu) {
+ AVB_LOG_ERROR("Creating raswsock; requested frame size exceeds MTU");
+ free(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+ rawsock->frameSize = TPACKET_ALIGN(rawsock->frameSize);
+
+ // Prepare default Ethernet header.
+ rawsock->ethHdrLen = sizeof(eth_hdr_t);
+ memset(&(rawsock->ethHdr.notag.dhost), 0xFF, ETH_ALEN);
+ memcpy(&(rawsock->ethHdr.notag.shost), &(rawsock->ifInfo.mac), ETH_ALEN);
+ rawsock->ethHdr.notag.ethertype = htons(rawsock->ethertype);
+
+ // Create socket
+ rawsock->sock = socket(PF_PACKET, SOCK_RAW, htons(rawsock->ethertype));
+ if (rawsock->sock == -1) {
+ AVB_LOGF_ERROR("Creating rawsock; opening socket: %s", strerror(errno));
+ openavbRawsockClose(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");
+ openavbRawsockClose(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->ethertype);
+ my_addr.sll_ifindex = rawsock->ifInfo.index;
+
+ if (bind(rawsock->sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == -1) {
+ AVB_LOGF_ERROR("Creating rawsock; bind socket: %s", strerror(errno));
+ openavbRawsockClose(rawsock);
+ 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));
+ openavbRawsockClose(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));
+ openavbRawsockClose(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+ rawsock->bufHdrSize = TPACKET_ALIGN(val);
+
+ if (rawsock->rxMode) {
+ rawsock->bufHdrSize = rawsock->bufHdrSize + TPACKET_ALIGN(sizeof(struct sockaddr_ll));
+ }
+ rawsock->bufferSize = rawsock->frameSize + rawsock->bufHdrSize;
+ rawsock->frameCount = num_frames;
+ AVB_LOGF_DEBUG("frameSize=%d, bufHdrSize=%d(%d+%d) bufferSize=%d, frameCount=%d",
+ rawsock->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->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));
+ openavbRawsockClose(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));
+ openavbRawsockClose(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));
+ openavbRawsockClose(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;
+}
+
+// Set signal on RX mode
+void openavbSetRxSignalMode(void *pvRawsock, bool rxSignalMode)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+
+ // CORE_TODO : Nothing to do on Linux
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+}
+
+// Close the rawsock
+void openavbRawsockClose(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+
+ if (rawsock) {
+ // free ring memory
+ if (rawsock->pMem != (void*)(-1)) {
+ munmap(rawsock->pMem, rawsock->memSize);
+ rawsock->pMem = (void*)(-1);
+ }
+ // 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 *openavbRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_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->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;
+}
+
+// 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 openavbRawsockTxSetMark(void *pvRawsock, int mark)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_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 openavbRawsockTxSetHdr(void *pvRawsock, hdr_info_t *pHdr)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_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
+inline bool openavbRawsockTxFillHdr(void *pvRawsock, U8 *pBuffer, unsigned int *hdrlen)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+ if (!VALID_TX_RAWSOCK(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;
+}
+
+// Release a TX frame, without marking it as ready to send
+bool openavbRawsockRelTxFrame(void *pvRawsock, U8 *pBuffer)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_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 openavbRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_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->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");
+ openavbRawsockSend(pvRawsock);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return TRUE;
+}
+
+// Send all packets that are ready (i.e. tell kernel to send them)
+int openavbRawsockSend(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_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 openavbRawsockTxBufLevel(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_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->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 openavbRawsockRxBufLevel(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_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->txMode) {
+ if (pHdr->tp_status & TP_STATUS_USER)
+ nInUse++;
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return nInUse;
+}
+
+
+// Get a RX frame
+U8 *openavbRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_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;
+ }
+
+ // Return pointer to the buffer and length
+ *offset = pHdr->tp_mac - rawsock->bufHdrSize;
+ *len = pHdr->tp_len;
+
+ // 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;
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return (U8*)pBuffer;
+}
+
+// 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);
+ raw_sock_t *rawsock = (raw_sock_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 openavbRawsockRelRxFrame(void *pvRawsock, U8 *pBuffer)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_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;
+}
+
+// Setup the rawsock to receive multicast packets
+bool openavbRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[ETH_ALEN])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+
+ raw_sock_t *rawsock = (raw_sock_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->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 openavbRawsockGetSocket(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ raw_sock_t *rawsock = (raw_sock_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;
+}
+
+// Get the ethernet address of the interface
+bool openavbRawsockGetAddr(void *pvRawsock, U8 addr[ETH_ALEN])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ raw_sock_t *rawsock = (raw_sock_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;
+}
+
+unsigned long openavbRawsockGetTXOutOfBuffers(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ unsigned long counter = 0;
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+
+ if(VALID_TX_RAWSOCK(rawsock)) {
+ counter = rawsock->txOutOfBuffer;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return counter;
+}
+
+unsigned long openavbRawsockGetTXOutOfBuffersCyclic(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ unsigned long counter = 0;
+ raw_sock_t *rawsock = (raw_sock_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/openavb_rawsock_igb.c b/lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock_igb.c
new file mode 100644
index 00000000..0c4d852f
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock_igb.c
@@ -0,0 +1,654 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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 "stc_avb_platform.h"
+#include "stc_sockets.h"
+#include <stdlib.h>
+#include <string.h>
+#include "stc_rawsock.h"
+#include "stc_avb_trace.h"
+
+#define AVB_LOG_COMPONENT "Raw Socket"
+#include "stc_avb_log.h"
+#include "stc_rawsock_tcal.h"
+
+// State information for raw socket
+//
+typedef struct {
+
+ // 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;
+
+ // the underlying socket
+ int sock;
+
+ // number and size of the frames requested
+ int frameSize;
+
+ eth_frame_t *pTxFrame;
+ eth_frame_t *pRxFrame;
+
+ // Task
+ thread_type *pTask; // Used by Task Manager suspend/resume
+
+ // TX usage of the socket
+ bool txMode;
+
+ // RX usage of the socket
+ bool rxMode;
+} raw_sock_t;
+
+// Kernel block size
+#define BLOCK_SIZE 4096
+
+// Argument validation
+#define VALID_RAWSOCK(s) ((s) != NULL && (s)->sock != -1)
+#define VALID_TX_RAWSOCK(s) (VALID_RAWSOCK(s) && (s)->txMode)
+#define VALID_RX_RAWSOCK(s) (VALID_RAWSOCK(s) && (s)->rxMode)
+
+// Get information about an interface
+bool stcAvbCheckInterface(const char *ifname, if_info_t *info){
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ bool retVal = FALSE;
+
+ if (!ifname || !info) {
+ AVB_LOG_ERROR("Checking interface; invalid arguments");
+ }
+ else {
+ // zap the result struct
+ memset(info, 0, sizeof(if_info_t));
+
+ AVB_LOGF_DEBUG("ifname=%s", ifname);
+ strncpy(info->name, ifname, IFNAMSIZ - 1);
+
+ // TODO_OPENAVB: Link is checked at Ethernet init time.
+ // is interface up?
+ //if(!halIsLinkUp()) {
+ // AVB_LOGF_ERROR("Checking interface; interface is not up: %s", ifname);
+ //}
+ //else {
+ info->index = 0; // index not used
+
+ osalGetMacAddr(info->mac.ether_addr_octet);
+ info->mtu = halGetMTU();
+
+ retVal = TRUE;
+ //}
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return retVal;
+}
+
+
+// Open a rawsock for TX or RX
+void *stcRawsockOpen(const char *ifname, bool rx_mode, bool tx_mode, U16 ethertype, U32 frame_size, U32 num_frames) {
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ raw_sock_t *rawsock = NULL;
+
+ AVB_LOGF_DEBUG("Open, rx=%d, tx=%d, ethertype=%x size=%d, num=%d", rx_mode, tx_mode, ethertype, frame_size, num_frames);
+
+ do {
+ /* Allocate struct to hold info about the raw socket
+ * that we're going to create.
+ */
+ rawsock = calloc(1, sizeof(raw_sock_t));
+ if (!rawsock) {
+ AVB_LOG_ERROR("Creating rawsock; malloc failed");
+ break;
+ }
+
+ rawsock->sock = -1;
+ rawsock->rxMode = rx_mode;
+ rawsock->txMode = tx_mode;
+ rawsock->frameSize = frame_size;
+ rawsock->ethertype = ethertype;
+
+ // Get info about the network device
+ if (!stcAvbCheckInterface(ifname, &(rawsock->ifInfo))) {
+ AVB_LOGF_ERROR("Creating rawsock; bad interface name: %s", ifname);
+ free(rawsock);
+ rawsock = NULL;
+ break;
+ }
+
+ // Deal with frame size.
+ if (rawsock->frameSize == 0) {
+ // use interface MTU as max frames size, if none specified
+ rawsock->frameSize = rawsock->ifInfo.mtu;
+ }
+ else if (rawsock->frameSize > rawsock->ifInfo.mtu) {
+ AVB_LOG_ERROR("Creating raswsock; requested frame size exceeds MTU");
+ free(rawsock);
+ rawsock = NULL;
+ break;
+ }
+ else {
+ rawsock->frameSize = TPACKET_ALIGN(rawsock->frameSize);
+ }
+
+ // Prepare default Ethernet header.
+ rawsock->ethHdrLen = sizeof(eth_hdr_t);
+ memset(&(rawsock->ethHdr.notag.dhost), 0xFF, ETH_ALEN);
+ stc_safe_memcpy(&(rawsock->ethHdr.notag.shost), &(rawsock->ifInfo.mac), ETH_ALEN);
+ rawsock->ethHdr.notag.ethertype = htons(rawsock->ethertype);
+
+ // Create socket
+ rawsock->sock = osalSocket(PF_PACKET, SOCK_RAW, htons(rawsock->ethertype));
+ if (rawsock->sock == -1) {
+ AVB_LOG_ERROR("Creating rawsock; opening socket:");
+ free(rawsock);
+ rawsock = NULL;
+ break;
+ }
+
+ // request Tx frames
+ if (tx_mode) {
+ if (osalSetTxMode(rawsock->sock, num_frames, frame_size) == -1) {
+ AVB_LOG_ERROR("Creating rawsock: Allocating tx buffers");
+ stcRawsockClose(rawsock);
+ rawsock = NULL;
+ break;
+ }
+ }
+
+ // request Rx frames
+ if (rx_mode) {
+ if (osalSetRxMode(rawsock->sock, num_frames, frame_size) == -1) {
+ AVB_LOG_ERROR("Creating rawsock: Allocating rx buffers");
+ stcRawsockClose(rawsock);
+ rawsock = NULL;
+ break;
+ }
+ }
+
+ rawsock->pTask = stcTaskMgrGetCurrentTask();
+
+ if (osalBind(rawsock->sock) == -1) {
+ AVB_LOG_ERROR("Creating rawsock; bind socket");
+ stcRawsockClose(rawsock);
+ rawsock = NULL;
+ break;
+ }
+
+ } while (0);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return rawsock;
+}
+
+// Set signal on RX mode
+void stcSetRxSignalMode(void *pvRawsock, bool rxSignalMode)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+
+ if (rawsock) {
+ if (rawsock->sock != -1) {
+ osalSetRxSignalMode(rawsock->sock, rxSignalMode);
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+}
+
+
+// Close the rawsock
+void stcRawsockClose(void *pvRawsock){
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+
+ if (rawsock) {
+ // close the socket
+ if (rawsock->sock != -1) {
+ osalCloseSocket(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 *stcRawsockGetTxFrame(void *pvRawsock, bool blocking, U32 *len){
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+ U8 *pBuffer = NULL;
+
+ if (!VALID_TX_RAWSOCK(rawsock) || len == NULL) {
+ AVB_LOG_ERROR("Getting TX frame; bad arguments");
+ }
+ else {
+ do {
+ rawsock->pTxFrame = osalSocketGetTxBuf(rawsock->sock);
+ if (rawsock->pTxFrame) {
+ pBuffer = rawsock->pTxFrame->data;
+ break;
+ }
+ else {
+ IF_LOG_INTERVAL(1000) {
+ AVB_LOG_ERROR("Getting TX frame: too many TX buffers in use");
+ }
+ break;
+ }
+ //if (blocking) {
+ // SLEEP_MSEC(1);
+ //}
+ } while (1);
+
+ if (pBuffer) {
+ // Remind client how big the frame buffer is
+ if (len) {
+ *len = rawsock->pTxFrame->length;
+ }
+ }
+ }
+
+ 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.
+// FQTSS creates a mark that includes the AVB class and streamBytesPerSec
+bool stcRawsockTxSetMark(void *pvRawsock, int mark){
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+ bool retval = FALSE;
+
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Setting TX mark; invalid argument passed");
+ }
+ else if (osalSetsockopt(rawsock->sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) {
+ AVB_LOG_ERROR("Setting TX mark; osalSetsockopt failed");
+ }
+ 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 stcRawsockTxSetHdr(void *pvRawsock, hdr_info_t *pHdr){
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+ bool retVal = FALSE;
+
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Setting TX header; invalid argument");
+ }
+ else {
+ // source address
+ if (pHdr->shost) {
+ stc_safe_memcpy(&(rawsock->ethHdr.notag.shost), pHdr->shost, ETH_ALEN);
+ }
+ // destination address
+ if (pHdr->dhost) {
+ stc_safe_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
+ uint16_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);
+ }
+ retVal = TRUE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return retVal;
+}
+
+// Copy the pre-set header to the outgoing frame
+bool stcRawsockTxFillHdr(void *pvRawsock, U8 *pBuffer, U32 *hdrlen) {
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+ bool retVal = FALSE;
+
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Filling TX header; invalid argument");
+ }
+ else {
+ // Copy the default Ethernet header into the buffer
+ if (hdrlen)
+ *hdrlen = rawsock->ethHdrLen;
+ stc_safe_memcpy((char*)pBuffer, &(rawsock->ethHdr), rawsock->ethHdrLen);
+
+ retVal = TRUE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return retVal;
+}
+
+// Release a TX frame, without marking it as ready to send
+bool stcRawsockRelTxFrame(void *pvRawsock, U8 *pBuffer){
+ bool retVal = TRUE;
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+
+ if (!VALID_TX_RAWSOCK(rawsock) || pBuffer == NULL) {
+ AVB_LOG_ERROR("Releasing TX frame; invalid argument");
+ retVal = FALSE;
+ }
+ else if (osalSocketRelTxBuf(rawsock->sock)) {
+ AVB_LOG_ERROR("Releasing TX frame");
+ retVal = FALSE;
+ }
+
+ rawsock->pTxFrame = NULL;
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return retVal;
+}
+
+// Ready Tx frame. pBuffer parameter not used in this implementation.
+bool stcRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, U32 len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+ bool retVal = FALSE;
+
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Marking TX frame ready; invalid argument");
+ }
+ else {
+ rawsock->pTxFrame->length = len;
+
+ retVal = TRUE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return retVal;
+}
+
+// Send all packets that are ready (i.e. tell kernel to send them)
+int stcRawsockSend(void *pvRawsock) {
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+ int sent = -1;
+
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Send; invalid argument");
+ }
+ else {
+ osalSocketPushTxBuf(rawsock->sock);
+ rawsock->pTxFrame = NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return sent;
+}
+
+int stcRawsockTxBufLevel(void *pvRawsock){
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+ int retVal = 0;
+
+ if (!VALID_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("getting buffer level; invalid arguments");
+ }
+ else {
+ retVal = osalGetTxSockLevel(rawsock->sock);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return retVal;
+}
+
+int stcRawsockRxBufLevel(void *pvRawsock){
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+ int retVal = 0;
+
+ if (!VALID_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("getting buffer level; invalid arguments");
+ }
+ else {
+ retVal = osalGetRxSockLevel(rawsock->sock);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return retVal;
+}
+
+// Get a RX frame
+U8 *stcRawsockGetRxFrame(void *pvRawsock, U32 timeoutUSec, U32 *offset, U32 *len) {
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+ U8 *pBuffer = NULL;
+
+ if (!VALID_RX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Getting RX frame; invalid arguments");
+ }
+ else {
+ while (!rawsock->pRxFrame) {
+ rawsock->pRxFrame = osalSocketGetRxBuf(rawsock->sock);
+ if (!rawsock->pRxFrame) {
+ if (timeoutUSec == STC_RAWSOCK_NONBLOCK) {
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+ if (timeoutUSec == (U32)STC_RAWSOCK_BLOCK) {
+ TASK_MGR_SUSPEND(rawsock->pTask);
+ rawsock->pRxFrame = osalSocketGetRxBuf(rawsock->sock);
+ }
+ else {
+ TASK_MGR_NANOSLEEP(rawsock->pTask, timeoutUSec * 1000);
+ rawsock->pRxFrame = osalSocketGetRxBuf(rawsock->sock);
+ break; // Assumed timed out or packet ready. Caller will sort it out.
+ }
+ }
+ }
+
+ if (rawsock->pRxFrame) {
+ *offset = 0;
+ *len = rawsock->pRxFrame->length;
+ pBuffer = rawsock->pRxFrame->data;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return pBuffer;
+}
+
+// Parse the Ethernet frame header. Returns length of header, or -1 for failure
+int stcRawsockRxParseHdr(void *pvRawsock, U8 *pBuffer, hdr_info_t *pInfo){
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+
+ // Current usage of this function of only to determine the header length.
+ // and the only usage of this port is always has a VLAN tag therefore
+ // the implementation is hidden
+ // ATNEL_TODO PERF this block isn't really needed consider using the simple case.
+#if 0
+ int pduOffset = -1;
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+ if (!VALID_RX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Parsing Ethernet headers; invalid arguments");
+ }
+ else {
+
+ memset(pInfo, 0, sizeof(hdr_info_t));
+
+ pduOffset = sizeof(eth_hdr_t);
+
+ eth_hdr_t *pNoTag = (eth_hdr_t*)pBuffer;
+ pInfo->shost = pNoTag->shost;
+ pInfo->dhost = pNoTag->dhost;
+ pInfo->ethertype = ntohs(pNoTag->ethertype);
+
+ if (pInfo->ethertype == ETHERTYPE_VLAN) {
+ uint16_t tp_vlan_tci = ntohs(*(uint16_t *)(pBuffer + pduOffset));
+ pInfo->vlan = TRUE;
+ pInfo->vlan_vid = tp_vlan_tci & 0x0FFF;
+ pInfo->vlan_pcp = (tp_vlan_tci >> 13) & 0x0007;
+ pInfo->ethertype = ntohs(*(uint16_t *)(pBuffer + pduOffset + 2));
+ pduOffset += 4; // sizeof 802.1Q header
+ }
+ }
+#else
+ int pduOffset = sizeof(eth_hdr_t) + 4;
+#endif
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return pduOffset;
+}
+
+// Release a RX frame held by the client
+bool stcRawsockRelRxFrame(void *pvRawsock, U8 *pBuffer){
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+ bool retVal = FALSE;
+
+ if (!VALID_RX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Releasing RX frame; invalid arguments");
+ }
+ else {
+ retVal = osalSocketPullRxBuf(rawsock->sock);
+ rawsock->pRxFrame = NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return retVal;
+}
+
+// Setup the rawsock to receive multicast packets
+bool stcRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[ETH_ALEN]){
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+
+ bool retVal = FALSE;
+
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+ if (!VALID_RX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Setting multicast; invalid arguments");
+ }
+ else {
+ if (osalSetsockopt(rawsock->sock, SOL_SOCKET, (add_membership ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP), addr, ETH_ALEN) < 0) {
+ AVB_LOG_ERROR("Setting multicast at HAL");
+ }
+ else {
+ retVal = TRUE;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return retVal;
+}
+
+bool stcRawsockRxAVTPSubtype(void *pvRawsock, U8 subtype){
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+
+ bool retVal = FALSE;
+
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+ if (!VALID_RX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Setting AVTP subtype: invalid arguments");
+ }
+ else {
+ if (osalSetAvtpSubtype(rawsock->sock, subtype) < 0) {
+ AVB_LOG_ERROR("Setting AVTP subtype filter");
+ }
+ else {
+ retVal = TRUE;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return retVal;
+}
+
+// Get the socket used for this rawsock; can be used for poll/select
+int stcRawsockGetSocket(void *pvRawsock){
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+ int retVal = -1;
+
+ if (!rawsock) {
+ AVB_LOG_ERROR("Getting socket; invalid arguments");
+ }
+ else {
+ retVal = rawsock->sock;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return retVal;
+}
+
+// Get the Ethernet address of the interface
+bool stcRawsockGetAddr(void *pvRawsock, U8 addr[ETH_ALEN]){
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ bool retVal = FALSE;
+ raw_sock_t *rawsock = (raw_sock_t*)pvRawsock;
+ if (!rawsock) {
+ AVB_LOG_ERROR("Getting address; invalid arguments");
+ }
+ else {
+ stc_safe_memcpy(addr, &rawsock->ifInfo.mac.ether_addr_octet, ETH_ALEN);
+ retVal = TRUE;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return retVal;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/openavb_sockets.c b/lib/avtp_pipeline/platform/Linux/rawsock/openavb_sockets.c
new file mode 100644
index 00000000..e88d8665
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/openavb_sockets.c
@@ -0,0 +1,625 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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 <string.h>
+#include <stdint.h>
+#include <stdio.h>
+#include "stc_avb_platform.h"
+
+#include "stc_avb_ether_hal.h"
+#include "stc_qmgr.h"
+#include "stc_sockets.h"
+#include "stc_avb_tasks.h"
+#include "stc_avb_types.h"
+#include "stc_array.h"
+#include "stc_queue.h"
+#include "stc_debug.h"
+
+#define AVB_LOG_COMPONENT "OSAL Socket Layer"
+#include "stc_avb_pub.h"
+#include "stc_avb_log.h"
+
+#define SOCK_VALID (1<<0)
+#define SOCK_BIND (1<<1)
+#define SOCK_MULTICAST (1<<2)
+
+#define VLAN_TYPE_NS 0x0081
+
+STC_CODE_MODULE_PRI
+
+THREAD_TYPE(socketRXThread);
+THREAD_DEFINITON(socketRXThread);
+
+THREAD_TYPE(socketTXThread);
+THREAD_DEFINITON(socketTXThread);
+
+STC_DATA_PRI COMPILER_ALIGNED(8) static MUTEX_HANDLE_ALT(gSocketMutex);
+#define SOCKET_LOCK() MUTEX_LOCK_ALT(gSocketMutex)
+#define SOCKET_UNLOCK() MUTEX_UNLOCK_ALT(gSocketMutex)
+
+STC_DATA_PRI COMPILER_ALIGNED(8) static MUTEX_HANDLE_ALT(gSocketTxMutex);
+#define SOCKET_TX_LOCK() MUTEX_LOCK_ALT(gSocketTxMutex)
+#define SOCKET_TX_UNLOCK() MUTEX_UNLOCK_ALT(gSocketTxMutex)
+
+typedef struct {
+ int flags;
+ uint16_t protocol; // in network format
+ int mark;
+ uint8_t multicastAddr[6];
+ bool bAvtpSubtype; // Filter based on AvtpSubType
+ uint8_t avtpSubtype; // AVTP subtype to filter on Including the CD indicator
+ bool bPollMode; // TRUE is socket RX using Poll FD
+ bool bRxSignalMode; // TRUE to send signal on RX packet
+ bool bRx; // Socket used for RX (used for filtering rx packets)
+ bool bTx; // Socket used for TX (used for filtering tx packets)
+ STC_POLLFD_DEF pollFd;
+
+ thread_type *pTask; // Direct task resume via Task Manager
+ rxSockBufStruct *rxSockBuf;
+ stc_queue_t rxQueue;
+ stc_queue_t txQueue; // Currently not used
+ int sockId;
+} socket_t;
+
+// Array of sockets
+STC_DATA_PRI COMPILER_ALIGNED(8) stc_array_t socketArray;
+
+thread_type *pSocketRXTask = NULL;
+thread_type *pSocketTXTask = NULL;
+
+static inline socket_t *findSocket(int sk)
+{
+ return stcArrayDataIdx(socketArray, sk);
+}
+
+void socketRXDirectAVTP(void)
+{
+ U32 frameSize;
+ U8 *pRxBuf = halGetRxBufAVTP(&frameSize);
+ while (pRxBuf) {
+ // If AVB isn't running yet toss AVTP packets
+ if (bAVBRunning) {
+ ethFrameStruct *ethFrame;
+ ethFrame = (ethFrameStruct *)pRxBuf;
+
+ U32 iter;
+ stc_array_elem_t elem;
+ elem = stcArrayIterFirstAlt(socketArray, &iter);
+ while (elem) {
+ socket_t *sock = stcArrayData(elem);
+
+ if (sock &&
+ (sock->flags & SOCK_BIND) &&
+ (sock->bRx ) &&
+ ((memcmp((void *)sock->multicastAddr, ethFrame->destAddr, 6) == 0)))
+ {
+ stc_queue_elem_t elem = stcQueueHeadLock(sock->rxQueue);
+ if (elem) {
+ eth_frame_t *pFrame = stcQueueData(elem);
+ pFrame->length = frameSize;
+ stc_safe_memcpy(pFrame->data, pRxBuf, frameSize);
+ stcQueueHeadPush(sock->rxQueue);
+
+ if (sock->bRxSignalMode) {
+ TASK_MGR_SIGNAL(sock->pTask);
+ }
+ else {
+ if (stcQueueGetElemCount(sock->rxQueue) >= (stcQueueGetQueueSize(sock->rxQueue) >> 1)) {
+ // rx buffer 1/2 full start signalling anyway
+ TASK_MGR_SIGNAL(sock->pTask);
+ }
+ }
+ }
+ }
+
+ elem = stcArrayIterNextAlt(socketArray, &iter);
+ }
+ }
+ // Read next frame
+ pRxBuf = halGetRxBufAVTP(&frameSize);
+ }
+}
+
+// Socket RX Task
+static void socketRXThreadFn(void *p_arg)
+{
+ pSocketRXTask = TASK_MGR_TASKDATA(socketRXThread);
+ stcTaskMgrAdd(pSocketRXTask);
+
+ while (bAVBRunning) {
+ // The HAL Ethernet driver is the only way this task will wakeup.
+ // NOTE: Using a semaphore here is costly therefore task suspend is used in combination with TaskMgr.
+ TASK_MGR_SUSPEND(pSocketRXTask);
+
+ U32 frameSize;
+ bool bPtpCBUsed;
+ U8 *pRxBuf = halGetRxBufAVB(&frameSize, &bPtpCBUsed);
+ while (pRxBuf || bPtpCBUsed) {
+ if (pRxBuf) {
+ ethFrameStruct *ethFrame;
+ U16 ethernetType;
+ U16 typeVlan;
+
+ ethFrame = (ethFrameStruct *)pRxBuf;
+ typeVlan = ntohs(*(U16 *)(&ethFrame->payload + 2));
+ ethernetType = ntohs(ethFrame->type);
+
+ U32 iter;
+ stc_array_elem_t elem;
+ elem = stcArrayIterFirstAlt(socketArray, &iter);
+ while (elem) {
+ socket_t *sock = stcArrayData(elem);
+
+ if (sock &&
+ (sock->flags & SOCK_BIND) &&
+ (sock->bRx ) &&
+ (((ethernetType == VLAN_TYPE_NS) && (sock->protocol == typeVlan)) || (ethernetType == sock->protocol)) &&
+ (((sock->flags & SOCK_MULTICAST) == 0) || (memcmp((void *)sock->multicastAddr, ethFrame->destAddr, 6) == 0)) &&
+ ((sock->bAvtpSubtype == FALSE) || (pRxBuf[18] == sock->avtpSubtype)))
+ {
+ stc_queue_elem_t elem = stcQueueHeadLock(sock->rxQueue);
+ if (elem) {
+ eth_frame_t *pFrame = stcQueueData(elem);
+ pFrame->length = frameSize;
+ stc_safe_memcpy(pFrame->data, pRxBuf, frameSize);
+ stcQueueHeadPush(sock->rxQueue);
+
+ if (sock->bRxSignalMode) {
+ if (sock->bPollMode) {
+ STC_POLLFD_SIG(&sock->pollFd);
+ }
+ else {
+ TASK_MGR_SIGNAL(sock->pTask);
+ }
+ }
+ else {
+ if (stcQueueGetElemCount(sock->rxQueue) >= (stcQueueGetQueueSize(sock->rxQueue) >> 1)) {
+ // rx buffer 1/2 full start signalling anyway
+ if (sock->bPollMode) {
+ STC_POLLFD_SIG(&sock->pollFd);
+ }
+ else {
+ TASK_MGR_SIGNAL(sock->pTask);
+ }
+ }
+ }
+ }
+ else {
+ // TODO: This output causes lockup. Why?
+ // AVB_LOG_ERROR("out of socket RX Queue buffers");
+ }
+ }
+
+ elem = stcArrayIterNextAlt(socketArray, &iter);
+ }
+ }
+
+ // Read next frame
+ pRxBuf = halGetRxBufAVB(&frameSize, &bPtpCBUsed);
+ }
+ }
+}
+
+// Socket TX Task : Currently not used
+#if 0
+static void socketTXThreadFn(void *p_arg)
+{
+ pSocketTXTask = TASK_MGR_TASKDATA(socketTXThread);
+ stcTaskMgrAdd(pSocketTXTask);
+
+ while (bAVBRunning) {
+ TASK_MGR_SUSPEND(pSocketTXTask);
+
+ // TODO: This algorithm for sending is minimalistic and inefficient and will need to be revisited
+ // when more than 1 stream is supported.
+ // Send as many frames as the Hal Ether will take
+ U32 iter;
+ stc_array_elem_t sockElem;
+ sockElem = stcArrayIterFirstAlt(socketArray, &iter);
+ while (sockElem) {
+ socket_t *sock = stcArrayData(sockElem);
+
+ stc_queue_elem_t elem = stcQueueTailLock(sock->txQueue);
+ while (elem) {
+ eth_frame_t *pFrame = stcQueueData(elem);
+
+ if (!halSendTxBuffer(pFrame->data, pFrame->length, TC_AVB_MARK_CLASS(sock->mark))) {
+ // No buffers were available. Release the queue item and process next time.
+ stcQueueTailUnlock(sock->txQueue);
+ break;
+ }
+
+ stcQueueTailPull(sock->txQueue);
+ elem = stcQueueTailLock(sock->txQueue);
+ }
+
+ sockElem = stcArrayIterNextAlt(socketArray, &iter);
+ }
+ }
+}
+#endif
+
+bool osalInitSockets(U32 maxSockets)
+{
+ // Check parameter
+ if (!maxSockets)
+ return FALSE;
+
+ // Create array to hold sockets
+ socketArray = stcArrayNewArray(sizeof(socket_t));
+ if (!socketArray)
+ return FALSE;
+ if (!stcArraySetInitSize(socketArray, maxSockets))
+ return FALSE;
+
+ MUTEX_CREATE_ALT(gSocketMutex);
+ MUTEX_CREATE_ALT(gSocketTxMutex);
+
+ // Start the Rx Parser Task
+ {
+ bool errResult;
+ THREAD_CREATE(socketRXThread, socketRXThread, NULL, socketRXThreadFn, NULL);
+ THREAD_CHECK_ERROR(socketRXThread, "Task create failed", errResult);
+ if (errResult); // Already reported
+ }
+
+ // Start the Tx Parser Task : Currently not used
+#if 0
+ {
+ bool errResult;
+ THREAD_CREATE(socketTXThread, socketTXThread, NULL, socketTXThreadFn, NULL);
+ THREAD_CHECK_ERROR(socketTXThread, "Task create failed", errResult);
+ if (errResult); // Already reported
+ }
+#endif
+
+ return TRUE;
+}
+
+int osalSocket(int domain, int type, int protocol)
+{
+ int retSk = -1;
+
+ // only support PF_PACKET and SOCK_RAW
+ if ((domain == PF_PACKET) && (type == SOCK_RAW)) {
+ SOCKET_LOCK();
+
+ stc_array_elem_t elem = stcArrayNew(socketArray);
+ if (elem) {
+ socket_t *newSocket = stcArrayData(elem);
+ newSocket->sockId = stcArrayGetIdx(elem);
+ newSocket->flags = SOCK_VALID; // socket is valid
+ newSocket->protocol = ntohs((uint16_t)protocol); // store protocol in network format
+ newSocket->bRxSignalMode = TRUE;
+
+ newSocket->pTask = stcTaskMgrGetCurrentTask();
+
+ retSk = newSocket->sockId;
+ }
+ else {
+ AVB_LOG_ERROR("Too many sockets");
+ }
+ SOCKET_UNLOCK();
+ }
+
+ return retSk;
+}
+
+int osalSetsockopt(int sk, int level, int optname, const void *optval, socklen_t optlen)
+{
+ int retSk = -1;
+ socket_t *sock = findSocket(sk);
+
+ if (sock && (optval != NULL)) {
+ if ((level == SOL_SOCKET) && (optname == SO_MARK) && (optlen == sizeof(int))) {
+ sock->mark = *(int *)optval;
+ retSk = sk;
+ }
+ else if ((level == SOL_SOCKET) && (optname == PACKET_ADD_MEMBERSHIP) && (optlen == 6)) {
+ stc_safe_memcpy(sock->multicastAddr, optval, 6);
+ sock->flags |= SOCK_MULTICAST;
+ if (halEtherAddMulticast(sock->multicastAddr, TRUE))
+ retSk = sk;
+ }
+ else if ((level == SOL_SOCKET) && (optname == PACKET_DROP_MEMBERSHIP)) {
+ if (halEtherAddMulticast(sock->multicastAddr, FALSE))
+ retSk = sk;
+ memset(sock->multicastAddr, 0, 6);
+ sock->flags &= ~SOCK_MULTICAST;
+ }
+ }
+
+ return retSk;
+}
+
+int osalSetAvtpSubtype(int sk, uint8_t avtpSubtype)
+{
+ int retSk = -1;
+ socket_t *sock = findSocket(sk);
+
+ if (sock) {
+ sock->bAvtpSubtype = TRUE;
+ sock->avtpSubtype = avtpSubtype;
+ retSk = sk;
+ }
+
+ return retSk;
+}
+
+int osalEnablePoll(int sk)
+{
+ int retSk = -1;
+ socket_t *sock = findSocket(sk);
+
+ if (sock) {
+ sock->bPollMode = TRUE;
+ STC_POLLFD_INIT(&sock->pollFd);
+ retSk = sk;
+ }
+
+ return retSk;
+}
+
+
+int osalSetRxMode(int sk, int bufCount, int bufSize)
+{
+ int retSk = -1;
+ socket_t *sock = findSocket(sk);
+
+ if (sock) {
+ sock->bRx = TRUE;
+
+ sock->rxQueue = stcQueueNewQueue(sizeof(eth_frame_t) + bufSize, bufCount);
+ if (!sock->rxQueue) {
+ AVB_LOG_ERROR("Out of memory creating socket rxQueue");
+ }
+ else {
+ retSk = sk;
+ }
+ }
+
+ return retSk;
+}
+
+int osalSetRxSignalMode(int sk, bool rxSignalMode)
+{
+ int retSk = -1;
+ socket_t *sock = findSocket(sk);
+
+ if (sock) {
+ sock->bRxSignalMode = rxSignalMode;
+ }
+
+ return retSk;
+}
+
+
+int osalSetTxMode(int sk, int bufCount, int bufSize)
+{
+ int retSk = -1;
+ socket_t *sock = findSocket(sk);
+
+ if (sock) {
+ sock->bTx = TRUE;
+
+ sock->txQueue = stcQueueNewQueue(sizeof(eth_frame_t) + bufSize, bufCount);
+ if (!sock->txQueue) {
+ AVB_LOG_ERROR("Out of memory creating socket txQueue");
+ }
+ else {
+ retSk = sk;
+ }
+ }
+
+ return retSk;
+}
+
+int osalBind(int sk)
+{
+ int retSk = -1;
+ socket_t *sock = findSocket(sk);
+
+ if (sock) {
+ sock->flags |= SOCK_BIND;
+ retSk = sk;
+ }
+
+ return retSk;
+}
+
+int osalCloseSocket(int sk)
+{
+ int retSk = -1;
+ socket_t *sock = findSocket(sk);
+
+ if (sock) {
+ SOCKET_LOCK();
+
+ // check to see if there is a multicastAddr, if so do a halEtherAddMulticast(del)
+ if (sock->flags & SOCK_MULTICAST) {
+ // delete multicast addr
+ if (!halEtherAddMulticast(sock->multicastAddr, 0)) {
+ AVB_LOG_ERROR("Sock Close: HAL delete multicast");
+ }
+ }
+
+ STC_POLLFD_DESTROY(&sock->pollFd);
+
+ if (sock->bRx) {
+ stcQueueDeleteQueue(sock->rxQueue);
+ }
+ if (sock->bTx) {
+ stcQueueDeleteQueue(sock->txQueue);
+ }
+
+ stc_array_elem_t elem = stcArrayIdx(socketArray, sk);
+ if (elem) {
+ stcArrayDelete(socketArray, elem);
+ }
+
+ SOCKET_UNLOCK();
+
+ retSk = sk;
+ }
+
+ return retSk;
+}
+
+STC_POLLFD_PTR osalGetSocketPollFd(int sk)
+{
+ socket_t *sock = findSocket(sk);
+
+ if (sock) {
+ return &sock->pollFd;
+ }
+ return NULL;
+}
+
+
+int osalGetRxSockLevel(int sk)
+{
+ int retLevel = 0;
+ socket_t *sock = findSocket(sk);
+
+ if (sock) {
+ retLevel = stcQueueGetElemCount(sock->rxQueue);
+ }
+
+ return retLevel;
+}
+
+int osalGetTxSockLevel(int sk)
+{
+ int retLevel = 0;
+ socket_t *sock = findSocket(sk);
+
+ if (sock) {
+ retLevel = stcQueueGetElemCount(sock->txQueue);
+ }
+
+ return retLevel;
+}
+
+// Get the next Rx buffer locking it. Null if none available
+eth_frame_t *osalSocketGetRxBuf(int sk)
+{
+ socket_t *sock = findSocket(sk);
+
+ if (sock) {
+ stc_queue_elem_t elem = stcQueueTailLock(sock->rxQueue);
+ if (elem) {
+ return (eth_frame_t *)stcQueueData(elem);
+ }
+ }
+
+ return NULL;
+}
+
+// Release (unlock) the Rx buffer for a socket keeping it in the queue. Returns TRUE on success
+bool osalSocketRelRxBuf(int sk)
+{
+ socket_t *sock = findSocket(sk);
+
+ if (sock) {
+ stcQueueTailUnlock(sock->rxQueue);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// Pulls the Rx buffer off the queue. Returns TRUE on success.
+bool osalSocketPullRxBuf(int sk)
+{
+ socket_t *sock = findSocket(sk);
+
+ if (sock) {
+ stcQueueTailPull(sock->rxQueue);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// Get the next Tx buffer locking it. Null if none available
+eth_frame_t *osalSocketGetTxBuf(int sk)
+{
+ socket_t *sock = findSocket(sk);
+
+ if (sock) {
+ stc_queue_elem_t elem = stcQueueHeadLock(sock->txQueue);
+ if (elem) {
+ eth_frame_t *pEthFrame = stcQueueData(elem);
+ pEthFrame->length = stcQueueGetElemSize(sock->txQueue);
+ return pEthFrame;
+ }
+ }
+
+ return NULL;
+}
+
+// Release (unlock) the Tx buffer. Returns TRUE on success
+bool osalSocketRelTxBuf(int sk)
+{
+ socket_t *sock = findSocket(sk);
+
+ if (sock) {
+ stcQueueHeadUnlock(sock->txQueue);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// Pushes the Tx buffer onto the queue. Returns TRUE on success.
+bool osalSocketPushTxBuf(int sk)
+{
+ socket_t *sock = findSocket(sk);
+
+ if (sock) {
+ stcQueueHeadPush(sock->txQueue);
+
+ SOCKET_TX_LOCK();
+ stc_queue_elem_t elem = stcQueueTailLock(sock->txQueue);
+ while (elem) {
+ eth_frame_t *pFrame = stcQueueData(elem);
+
+ if (!halSendTxBuffer(pFrame->data, pFrame->length, TC_AVB_MARK_CLASS(sock->mark))) {
+ // No buffers were available. Release the queue item and process next time.
+ stcQueueTailUnlock(sock->txQueue);
+ break;
+ }
+
+ stcQueueTailPull(sock->txQueue);
+ elem = stcQueueTailLock(sock->txQueue);
+ }
+ SOCKET_TX_UNLOCK();
+
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/openavb_sockets.h b/lib/avtp_pipeline/platform/Linux/rawsock/openavb_sockets.h
new file mode 100644
index 00000000..ec9f6ba9
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/openavb_sockets.h
@@ -0,0 +1,173 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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 STC_SOCKETS_H
+#define STC_SOCKETS_H 1
+
+#include <stdint.h>
+#include <stddef.h>
+#include "stc_avb_platform.h"
+#include "stc_avb_time_osal.h"
+
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 1
+#endif
+
+typedef struct {
+ U16 length;
+ U8 data[]; // Empty array points to data. struct memory must be manually allocated.
+} eth_frame_t;
+
+typedef struct ethFrameStruct {
+ uint8_t destAddr[6];
+ uint8_t srcAddr[6];
+ uint16_t type;
+ uint8_t payload;
+} ethFrameStruct;
+
+typedef struct ethFrameVlanStruct {
+ uint8_t destAddr[6];
+ uint8_t srcAddr[6];
+ uint8_t tag[4];
+ uint16_t type;
+ uint8_t payload;
+}ethFrameVlanStruct;
+
+typedef struct rxSockBufStruct {
+ struct rxSockBufStruct *next;
+ uint8_t *packet; // pointer to start of packet (which starts with length)
+}rxSockBufStruct;
+
+#define AF_INET 2
+#define PF_PACKET 17 // Packet family.
+
+// Socket protocol types (TCP/UDP/RAW)
+#define SOCK_STREAM 1
+#define SOCK_DGRAM 2
+#define SOCK_RAW 3
+
+struct sockaddr {
+ uint8_t sa_len;
+ uint8_t sa_family;
+ char sa_data[14];
+};
+
+#define PACKET_MR_MULTICAST 0
+#define PACKET_MR_PROMISC 1
+#define PACKET_MR_ALLMULTI 2
+
+#define PACKET_ADD_MEMBERSHIP 1
+#define PACKET_DROP_MEMBERSHIP 2
+#define PACKET_RECV_OUTPUT 3
+#define PACKET_STATISTICS 6
+
+#define IFF_UP 0x1 // interface is up
+
+#define TPACKET_ALIGNMENT 16
+#define TPACKET_ALIGN(x) (((x)+TPACKET_ALIGNMENT-1)&~(TPACKET_ALIGNMENT-1))
+
+#ifndef socklen_t
+# define socklen_t int
+#endif
+
+#define SOL_SOCKET 1
+#define SOL_PACKET 263
+#define SO_MARK 36
+#define ETHERTYPE_VLAN 0x8100 // IEEE 802.1Q VLAN tagging
+#define MSG_DONTWAIT 0x08 // Nonblocking i/o for this operation only
+#define EINTR 4 // Interrupted system call
+
+// Supported error numbers
+#define ENOMEM 12 // Out of memory
+#define EINVAL 22 // Invalid argument
+
+// initialize sockets and the Rx buffer task
+bool osalInitSockets(U32 maxSockets);
+
+// Create a new socket of type TYPE in domain DOMAIN, using
+// protocol PROTOCOL. If PROTOCOL is zero, one is chosen automatically.
+// Returns a file descriptor for the new socket, or -1 for errors.
+int osalSocket(int domain, int type, int protocol);
+
+// Set socket options
+int osalSetsockopt(int sk, int level, int optname, const void *optval, socklen_t optlen);
+
+// Set the AVTP subtype for filtering
+int osalSetAvtpSubtype(int sk, uint8_t avtpSubtype);
+
+// Enable Poll Mode
+int osalEnablePoll(int sk);
+
+// Set socket as RX
+int osalSetRxMode(int sk, int bufCount, int bufSize);
+
+// Set socket signal on RX mode
+int osalSetRxSignalMode(int sk, bool rxSignalMode);
+
+// Set socket as TX
+int osalSetTxMode(int sk, int bufCount, int bufSize);
+
+// bind, allows transmission, and reception of socket data
+int osalBind(int sk);
+
+// close socket
+int osalCloseSocket(int sk);
+
+// Get the PollFd for the socket
+STC_POLLFD_PTR osalGetSocketPollFd(int sk);
+
+// get unprocessed Rx buffers
+int osalGetRxSockLevel(int sk);
+
+// get unprocessed Tx buffers
+int osalGetTxSockLevel(int sk);
+
+// Get the next Rx buffer locking it. Null if none available
+eth_frame_t *osalSocketGetRxBuf(int sk);
+
+// Release (unlock) the Rx buffer for a socket keeping it in the queue. Returns TRUE on success
+bool osalSocketRelRxBuf(int sk);
+
+// Pulls the Rx buffer off the queue. Returns TRUE on success.
+bool osalSocketPullRxBuf(int sk);
+
+// Get the next Tx buffer locking it. Null if none available
+eth_frame_t *osalSocketGetTxBuf(int sk);
+
+// Release (unlock) the Tx buffer. Returns TRUE on success
+bool osalSocketRelTxBuf(int sk);
+
+// Pushes the Tx buffer onto the queue. Returns TRUE on success.
+bool osalSocketPushTxBuf(int sk);
+
+// Direct call (not in task) to process a AVTP packet or packets
+void socketRXDirectAVTP(void);
+
+#endif // STC_SOCKETS_H
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..aed29f2d
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_rx.c
@@ -0,0 +1,194 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..1e683bab
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_tx.c
@@ -0,0 +1,219 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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/tl/openavb_tl_osal.c b/lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c
new file mode 100644
index 00000000..2911ce98
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c
@@ -0,0 +1,443 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..a8d891e1
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/x86_i210_linux.cmake
@@ -0,0 +1,30 @@
+# 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" )
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..56fdd691
--- /dev/null
+++ b/lib/avtp_pipeline/platform/generic/openavb_hal.h
@@ -0,0 +1,37 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..637c7fbe
--- /dev/null
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.c
@@ -0,0 +1,39 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..46de34ab
--- /dev/null
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.h
@@ -0,0 +1,37 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..d6428845
--- /dev/null
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal_pub.h
@@ -0,0 +1,38 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..dc107386
--- /dev/null
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_tcal_pub.h
@@ -0,0 +1,38 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..2ef4c096
--- /dev/null
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_time_tcal_pub.h
@@ -0,0 +1,49 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..8cd00ecb
--- /dev/null
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_types_base_tcal_pub.h
@@ -0,0 +1,40 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..058ae0e4
--- /dev/null
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_warnings_tcal.h
@@ -0,0 +1,37 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..9f1eebfe
--- /dev/null
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/rawsock/openavb_rawsock_tcal.h
@@ -0,0 +1,59 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..f0b84319
--- /dev/null
+++ b/lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.c
@@ -0,0 +1,62 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..8e377c0a
--- /dev/null
+++ b/lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.h
@@ -0,0 +1,37 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..6d531e60
--- /dev/null
+++ b/lib/avtp_pipeline/platform/x86_i210/openavb_ether_hal.c
@@ -0,0 +1,206 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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 <pci/pci.h>
+#include "igb.h"
+#include "avb.h"
+
+
+#include "openavb_ether_hal.h"
+#include "openavb_osal.h"
+
+#define AVB_LOG_COMPONENT "HAL Ethernet"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+#include "openavb_trace.h"
+
+#define MAX_MTU 1536
+
+static pthread_mutex_t gHALTimeInitMutex = PTHREAD_MUTEX_INITIALIZER;
+#define LOCK() pthread_mutex_lock(&gHALTimeInitMutex)
+#define UNLOCK() pthread_mutex_unlock(&gHALTimeInitMutex)
+
+static bool bInitialized = FALSE;
+static device_t gIgbDev;
+
+static bool x_HalEtherInit(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HAL_ETHER);
+ int rslt;
+
+ rslt = pci_connect(&gIgbDev);
+ if (rslt) {
+ AVB_LOGF_ERROR("connect failed (%s) - are you running as root?", strerror(errno));
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+ return FALSE;
+ }
+
+ rslt = igb_init(&gIgbDev);
+ if (rslt) {
+ AVB_LOGF_ERROR("init failed (%s) - is the driver really loaded?\n", strerror(errno));
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+ return TRUE;
+}
+
+
+// Initialize HAL layer Ethernet driver
+bool halEthernetInitialize(U8 *macAddr, bool gmacAutoNegotiate)
+{
+ LOCK();
+ if (!bInitialized) {
+ if (x_HalEtherInit())
+ bInitialized = TRUE;
+ }
+ UNLOCK();
+
+ return bInitialized;
+}
+
+bool halEthernetFinalize(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HAL_ETHER);
+
+ // TODO_OPENAVB : shutdown igb
+
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+ return TRUE;
+}
+
+bool halEtherAddMulticast(U8 *multicastAddr, bool add)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HAL_ETHER);
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+ return TRUE;
+}
+
+U8 *halGetRxBufAVTP(U32 *frameSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HAL_ETHER);
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+ return NULL;
+}
+
+// Get next Rx packet. NOTE: Expected to be called from a single task (socket task)
+U8 *halGetRxBufAVB(U32 *frameSize, bool *bPtpCBUsed)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HAL_ETHER);
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+ return NULL;
+}
+
+U8 *halGetRxBufGEN(U32 *frameSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HAL_ETHER);
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+ return NULL;
+}
+
+// Send Tx Packet to driver
+bool halSendTxBuffer(U8 *pDataBuf, U32 frameSize, int class)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HAL_ETHER);
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+ return FALSE;
+}
+
+// Is the link up. Returns TRUE if it is.
+bool halIsLinkUp(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HAL_ETHER);
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+ return FALSE;
+}
+
+// Returns the MTU
+U32 halGetMTU(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HAL_ETHER);
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+ return MAX_MTU;
+}
+
+U8 *halGetMacAddr(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HAL_ETHER);
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+ return NULL;
+}
+
+bool halGetLocaltime(U64 *localTime64)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HAL_ETHER);
+ if (igb_get_wallclock(&gIgbDev, localTime64, NULL ) > 0) {
+ AVB_LOG_ERROR("Failed to get wallclock time");
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+ return FALSE;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_HAL_ETHER);
+ return TRUE;
+}
+
+void halTrafficShaperAddStream(int class, uint32_t streamsBytesPerSec)
+{
+
+// TODO_OPENAVB : it appears the igb_set_class_bandwidth() helper function is designed about the concept of a single Class A and single Class B
+// stream. Perhaps it could be used in the short term, however, a final solution may be to talk to the igb driver directly supply the E1000 reg
+// values directly.
+//
+// igb_set_class_bandwidth(dev)
+
+// TODO_OPENAVB
+// if (class == AVB_CLASS_B) {
+// }
+// else if (class == AVB_CLASS_A) {
+// }
+}
+
+void halTrafficShaperRemoveStream(int class, uint32_t streamsBytesPerSec)
+{
+
+// TODO_OPENAVB : it appears the igb_set_class_bandwidth() helper function is designed about the concept of a single Class A and single Class B
+// stream. Perhaps it could be used in the short term, however, a final solution may be to talk to the igb driver directly supply the E1000 reg
+// values directly.
+//
+// igb_set_class_bandwidth(dev)
+
+// TODO_OPENAVB
+// if (class == AVB_CLASS_B) {
+// }
+// else if (class == AVB_CLASS_A) {
+// }
+}
+
+
+
+
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..99e562b3
--- /dev/null
+++ b/lib/avtp_pipeline/platform/x86_i210/openavb_ether_hal.h
@@ -0,0 +1,75 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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"
+
+// Initialize HAL layer Ethernet driver
+bool halEthernetInitialize(U8 *macAddr, bool gmacAutoNegotiate);
+
+// Finalize HAL layer Ethernet driver
+bool halEthernetFinalize(void);
+
+// Setup for multicast filtering
+bool halEtherAddMulticast(U8 *multicastAddr, bool add);
+
+// Get next AVTP Rx packet
+U8 *halGetRxBufAVTP(U32 *frameSize);
+
+// Get next AVB Rx packet. pPtpCBUsed will be set to true when rx data was send to the RX cb rather than returning the buffer.
+U8 *halGetRxBufAVB(U32 *frameSize, bool *bPtpCBUsed);
+
+// Get next GEN Rx packet
+U8 *halGetRxBufGEN(U32 *frameSize);
+
+// Send Tx Packet to driver
+bool halSendTxBuffer(U8 *pDataBuf, U32 frameSize, int class);
+
+// Is the link up. Returns TRUE if it is.
+bool halIsLinkUp(void);
+
+// Returns pointer to mac address
+U8 *halGetMacAddr(void);
+
+// Return the MTU
+U32 halGetMTU(void);
+
+bool halGetLocaltime(U64 *localTime64);
+
+// Add stream to the credit based shaper
+void halTrafficShaperAddStream(int class, uint32_t streamsBytesPerSec);
+
+// Remove stream from the credit based shaper
+void halTrafficShaperRemoveStream(int class, uint32_t streamsBytesPerSec);
+
+#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..4551d453
--- /dev/null
+++ b/lib/avtp_pipeline/platform/x86_i210/openavb_hal.h
@@ -0,0 +1,38 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..d0a44235
--- /dev/null
+++ b/lib/avtp_pipeline/platform/x86_i210/openavb_time_hal.c
@@ -0,0 +1,61 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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_time_hal.h"
+#include "openavb_trace.h"
+
+#define AVB_LOG_COMPONENT "halTime"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+bool halTimeInitialize(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TIME);
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return TRUE;
+}
+
+bool halTimeFinalize(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TIME);
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return TRUE;
+}
+
+bool halTimeGetLocaltime(U64 *localTime64)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TIME);
+ bool bRslt = halGetLocaltime(localTime64);
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return bRslt;
+}
+
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..172c192a
--- /dev/null
+++ b/lib/avtp_pipeline/platform/x86_i210/openavb_time_hal.h
@@ -0,0 +1,38 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..a9617712
--- /dev/null
+++ b/lib/avtp_pipeline/qmgr/openavb_qmgr.c
@@ -0,0 +1,87 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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"
+#include "openavb_log.h"
+#include "openavb_trace.h"
+
+#include "openavb_qmgr.h"
+#include "avb_sched.h"
+
+static int fqtss_mode;
+
+bool openavbQmgrInitialize(int mode, int ifindex, char* ifname, unsigned mtu, unsigned link_kbit, unsigned nsr_kbit)
+{
+ fqtss_mode = mode;
+ return TRUE;
+}
+
+void openavbQmgrFinalize(void)
+{
+}
+
+U16 openavbQmgrAddStream(SRClassIdx_t nClass, unsigned classRate, unsigned maxIntervalFrames, unsigned maxFrameSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_QUEUE_MANAGER);
+
+ unsigned long streamBytesPerSec = (maxFrameSize + OPENAVB_AVTP_ETHER_FRAME_OVERHEAD) * maxIntervalFrames * classRate;
+ int fwmarkClass = AVB_CLASS_NR;
+ if (nClass == SR_CLASS_A)
+ fwmarkClass = AVB_CLASS_A;
+ else
+ fwmarkClass = AVB_CLASS_B;
+ int fwmark = TC_AVB_MARK(streamBytesPerSec, fwmarkClass);
+
+ AVB_LOGF_DEBUG("Adding stream; class=%d, rate=%u frames=%u, size=%u, bytes/sec=%lu", nClass, classRate, maxIntervalFrames, maxFrameSize, streamBytesPerSec);
+
+ if (fqtss_mode == FQTSS_MODE_HW_CLASS) {
+ halTrafficShaperAddStream(TC_AVB_MARK_CLASS(fwmark), streamBytesPerSec);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_QUEUE_MANAGER);
+ return fwmark;
+}
+
+void openavbQmgrRemoveStream(U16 fwmark, unsigned classRate, unsigned maxIntervalFrames, unsigned maxFrameSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_QUEUE_MANAGER);
+
+ if (fqtss_mode == FQTSS_MODE_HW_CLASS) {
+ halTrafficShaperRemoveStream(TC_AVB_MARK_CLASS(fwmark), TC_AVB_MARK_STREAM(fwmark));
+ }
+
+ 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..700e6f14
--- /dev/null
+++ b/lib/avtp_pipeline/qmgr/openavb_qmgr.h
@@ -0,0 +1,104 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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,
+ 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,
+ 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,
+ 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,
+ unsigned classRate,
+ unsigned maxIntervalFrames,
+ unsigned maxFrameSize);
+
+{}
+#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..3e3b4110
--- /dev/null
+++ b/lib/avtp_pipeline/rawsock/CMakeLists.txt
@@ -0,0 +1 @@
+# No common code
diff --git a/lib/avtp_pipeline/rawsock/openavb_rawsock.h b/lib/avtp_pipeline/rawsock/openavb_rawsock.h
new file mode 100644
index 00000000..858aced0
--- /dev/null
+++ b/lib/avtp_pipeline/rawsock/openavb_rawsock.h
@@ -0,0 +1,164 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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/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..9489a2e5
--- /dev/null
+++ b/lib/avtp_pipeline/srp/openavb_srp.h
@@ -0,0 +1,320 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..9d99fafa
--- /dev/null
+++ b/lib/avtp_pipeline/srp/openavb_srp_api.h
@@ -0,0 +1,179 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..ef5817db
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_listener.c
@@ -0,0 +1,424 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..89d2f6fe
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_listener.h
@@ -0,0 +1,73 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..e1521e17
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_listener_endpoint.c
@@ -0,0 +1,139 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..90502d77
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c
@@ -0,0 +1,80 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..c142f559
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_talker.c
@@ -0,0 +1,495 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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=%lu, size=%lu, batch=%ld, sleep=%lldus, 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..253377ac
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_talker.h
@@ -0,0 +1,77 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..b9dd7d34
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_talker_endpoint.c
@@ -0,0 +1,187 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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);
+
+ {
+ // TODO_OPENAVB : Consider this a placeholder. But it maybe the correct thing to do.
+ 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("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)
+{
+ {
+ // TODO_OPENAVB : Consider this a placeholder. But it maybe the correct thing to do.
+ talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
+
+ openavbQmgrRemoveStream(pTalkerData->fwmark,
+ pTalkerData->wakeRate,
+ pTalkerData->tSpec.maxIntervalFrames,
+ pTalkerData->tSpec.maxFrameSize);
+ }
+}
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..a6ad68d7
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_talker_no_endpoint.c
@@ -0,0 +1,156 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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)
+{
+ {
+ // TODO_OPENAVB : Consider this a placeholder. But it maybe the correct thing to do.
+ talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
+
+ openavbQmgrRemoveStream(pTalkerData->fwmark,
+ pTalkerData->wakeRate,
+ pTalkerData->tSpec.maxIntervalFrames,
+ pTalkerData->tSpec.maxFrameSize);
+ }
+}
+
+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..68267785
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_tl.c
@@ -0,0 +1,733 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..8cbcdd5f
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_tl.h
@@ -0,0 +1,164 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..4c36db34
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_tl_endpoint.c
@@ -0,0 +1,277 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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_acmp.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;
+}
+
+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;
+}
+
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..1dce6284
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_tl_no_endpoint.c
@@ -0,0 +1,134 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..cde88223
--- /dev/null
+++ b/lib/avtp_pipeline/tl/openavb_tl_pub.h
@@ -0,0 +1,339 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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
+
+#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;
+
+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 handle 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..426212ec
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_array.c
@@ -0,0 +1,443 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..90fb3b7d
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_array.h
@@ -0,0 +1,122 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..c652d279
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_debug.c
@@ -0,0 +1,90 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..646183ab
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_debug.h
@@ -0,0 +1,57 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..82b8b3dd
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_list.c
@@ -0,0 +1,290 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..f184e631
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_list.h
@@ -0,0 +1,99 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..a5fe4381
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_log.c
@@ -0,0 +1,386 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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 = true;
+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:%10lu] ", 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);
+ }
+
+ }
+ }
+}
+
+
+U32 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;
+ 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()
+{
+ 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:%10lu ", 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;
+ openavbQueueHeadPush(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..404fa0f4
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_plugin.c
@@ -0,0 +1,75 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..ad8a3f66
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_plugin.h
@@ -0,0 +1,47 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..ebcc3726
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_printbuf.c
@@ -0,0 +1,112 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..57e6c015
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_printbuf.h
@@ -0,0 +1,54 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..65b479f4
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_queue.c
@@ -0,0 +1,196 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..6d1a8897
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_queue.h
@@ -0,0 +1,85 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..07b0f796
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_result_codes.c
@@ -0,0 +1,174 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..0aea33f1
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_result_codes.h
@@ -0,0 +1,209 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..73ef800e
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_time.c
@@ -0,0 +1,134 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..83d51033
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_time.h
@@ -0,0 +1,65 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..a5d7fd89
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_timestamp.c
@@ -0,0 +1,171 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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..36398f4b
--- /dev/null
+++ b/lib/avtp_pipeline/util/openavb_timestamp.h
@@ -0,0 +1,78 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2013, 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_talker.sh b/run_echo_talker.sh
new file mode 100755
index 00000000..33712285
--- /dev/null
+++ b/run_echo_talker.sh
@@ -0,0 +1,12 @@
+#!/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
+
+# TODO_OPENAVB : Currently assumes a bin directory.
+cd ../build/bin
+exec ./openavb_host echo_talker.ini,ifname=$1
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