pax_global_header00006660000000000000000000000064142010263070014505gustar00rootroot0000000000000052 comment=3599a5bf2d18fc3ae89b64f208d8380e6ee3a866 libavtp-0.2.0/000077500000000000000000000000001420102630700131455ustar00rootroot00000000000000libavtp-0.2.0/.clang-format000066400000000000000000000412301420102630700155200ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0 # # clang-format configuration file. Intended for clang-format >= 9. # # For more information, see: # # Documentation/process/clang-format.rst # https://clang.llvm.org/docs/ClangFormat.html # https://clang.llvm.org/docs/ClangFormatStyleOptions.html # --- AccessModifierOffset: -4 AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignConsecutiveMacros: true #AlignEscapedNewlines: Left # Unknown to clang-format-4.0 AlignOperands: true AlignTrailingComments: false AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: None AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: false BinPackArguments: true BinPackParameters: true BraceWrapping: AfterClass: false AfterControlStatement: false AfterEnum: false AfterFunction: true AfterNamespace: true AfterObjCDeclaration: false AfterStruct: false AfterUnion: false #AfterExternBlock: false # Unknown to clang-format-5.0 BeforeCatch: false BeforeElse: false IndentBraces: false #SplitEmptyFunction: true # Unknown to clang-format-4.0 #SplitEmptyRecord: true # Unknown to clang-format-4.0 #SplitEmptyNamespace: true # Unknown to clang-format-4.0 BreakBeforeBinaryOperators: None BreakBeforeBraces: Custom #BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0 BreakBeforeTernaryOperators: false BreakConstructorInitializersBeforeComma: false #BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0 BreakAfterJavaFieldAnnotations: false BreakStringLiterals: false ColumnLimit: 80 CommentPragmas: '^ IWYU pragma:' #CompactNamespaces: false # Unknown to clang-format-4.0 ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 8 ContinuationIndentWidth: 8 Cpp11BracedListStyle: false DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false #FixNamespaceComments: false # Unknown to clang-format-4.0 # Taken from: # git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \ # | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \ # | sort | uniq ForEachMacros: - 'apei_estatus_for_each_section' - 'ata_for_each_dev' - 'ata_for_each_link' - '__ata_qc_for_each' - 'ata_qc_for_each' - 'ata_qc_for_each_raw' - 'ata_qc_for_each_with_internal' - 'ax25_for_each' - 'ax25_uid_for_each' - '__bio_for_each_bvec' - 'bio_for_each_bvec' - 'bio_for_each_bvec_all' - 'bio_for_each_integrity_vec' - '__bio_for_each_segment' - 'bio_for_each_segment' - 'bio_for_each_segment_all' - 'bio_list_for_each' - 'bip_for_each_vec' - 'bitmap_for_each_clear_region' - 'bitmap_for_each_set_region' - 'blkg_for_each_descendant_post' - 'blkg_for_each_descendant_pre' - 'blk_queue_for_each_rl' - 'bond_for_each_slave' - 'bond_for_each_slave_rcu' - 'bpf_for_each_spilled_reg' - 'btree_for_each_safe128' - 'btree_for_each_safe32' - 'btree_for_each_safe64' - 'btree_for_each_safel' - 'card_for_each_dev' - 'cgroup_taskset_for_each' - 'cgroup_taskset_for_each_leader' - 'cpufreq_for_each_entry' - 'cpufreq_for_each_entry_idx' - 'cpufreq_for_each_valid_entry' - 'cpufreq_for_each_valid_entry_idx' - 'css_for_each_child' - 'css_for_each_descendant_post' - 'css_for_each_descendant_pre' - 'device_for_each_child_node' - 'displayid_iter_for_each' - 'dma_fence_chain_for_each' - 'do_for_each_ftrace_op' - 'drm_atomic_crtc_for_each_plane' - 'drm_atomic_crtc_state_for_each_plane' - 'drm_atomic_crtc_state_for_each_plane_state' - 'drm_atomic_for_each_plane_damage' - 'drm_client_for_each_connector_iter' - 'drm_client_for_each_modeset' - 'drm_connector_for_each_possible_encoder' - 'drm_for_each_bridge_in_chain' - 'drm_for_each_connector_iter' - 'drm_for_each_crtc' - 'drm_for_each_crtc_reverse' - 'drm_for_each_encoder' - 'drm_for_each_encoder_mask' - 'drm_for_each_fb' - 'drm_for_each_legacy_plane' - 'drm_for_each_plane' - 'drm_for_each_plane_mask' - 'drm_for_each_privobj' - 'drm_mm_for_each_hole' - 'drm_mm_for_each_node' - 'drm_mm_for_each_node_in_range' - 'drm_mm_for_each_node_safe' - 'flow_action_for_each' - 'for_each_acpi_dev_match' - 'for_each_active_dev_scope' - 'for_each_active_drhd_unit' - 'for_each_active_iommu' - 'for_each_aggr_pgid' - 'for_each_available_child_of_node' - 'for_each_bio' - 'for_each_board_func_rsrc' - 'for_each_bvec' - 'for_each_card_auxs' - 'for_each_card_auxs_safe' - 'for_each_card_components' - 'for_each_card_dapms' - 'for_each_card_pre_auxs' - 'for_each_card_prelinks' - 'for_each_card_rtds' - 'for_each_card_rtds_safe' - 'for_each_card_widgets' - 'for_each_card_widgets_safe' - 'for_each_cgroup_storage_type' - 'for_each_child_of_node' - 'for_each_clear_bit' - 'for_each_clear_bit_from' - 'for_each_cmsghdr' - 'for_each_compatible_node' - 'for_each_component_dais' - 'for_each_component_dais_safe' - 'for_each_comp_order' - 'for_each_console' - 'for_each_cpu' - 'for_each_cpu_and' - 'for_each_cpu_not' - 'for_each_cpu_wrap' - 'for_each_dapm_widgets' - 'for_each_dev_addr' - 'for_each_dev_scope' - 'for_each_dma_cap_mask' - 'for_each_dpcm_be' - 'for_each_dpcm_be_rollback' - 'for_each_dpcm_be_safe' - 'for_each_dpcm_fe' - 'for_each_drhd_unit' - 'for_each_dss_dev' - 'for_each_dtpm_table' - 'for_each_efi_memory_desc' - 'for_each_efi_memory_desc_in_map' - 'for_each_element' - 'for_each_element_extid' - 'for_each_element_id' - 'for_each_endpoint_of_node' - 'for_each_evictable_lru' - 'for_each_fib6_node_rt_rcu' - 'for_each_fib6_walker_rt' - 'for_each_free_mem_pfn_range_in_zone' - 'for_each_free_mem_pfn_range_in_zone_from' - 'for_each_free_mem_range' - 'for_each_free_mem_range_reverse' - 'for_each_func_rsrc' - 'for_each_hstate' - 'for_each_if' - 'for_each_iommu' - 'for_each_ip_tunnel_rcu' - 'for_each_irq_nr' - 'for_each_link_codecs' - 'for_each_link_cpus' - 'for_each_link_platforms' - 'for_each_lru' - 'for_each_matching_node' - 'for_each_matching_node_and_match' - 'for_each_member' - 'for_each_memcg_cache_index' - 'for_each_mem_pfn_range' - '__for_each_mem_range' - 'for_each_mem_range' - '__for_each_mem_range_rev' - 'for_each_mem_range_rev' - 'for_each_mem_region' - 'for_each_migratetype_order' - 'for_each_msi_entry' - 'for_each_msi_entry_safe' - 'for_each_msi_vector' - 'for_each_net' - 'for_each_net_continue_reverse' - 'for_each_netdev' - 'for_each_netdev_continue' - 'for_each_netdev_continue_rcu' - 'for_each_netdev_continue_reverse' - 'for_each_netdev_feature' - 'for_each_netdev_in_bond_rcu' - 'for_each_netdev_rcu' - 'for_each_netdev_reverse' - 'for_each_netdev_safe' - 'for_each_net_rcu' - 'for_each_new_connector_in_state' - 'for_each_new_crtc_in_state' - 'for_each_new_mst_mgr_in_state' - 'for_each_new_plane_in_state' - 'for_each_new_private_obj_in_state' - 'for_each_node' - 'for_each_node_by_name' - 'for_each_node_by_type' - 'for_each_node_mask' - 'for_each_node_state' - 'for_each_node_with_cpus' - 'for_each_node_with_property' - 'for_each_nonreserved_multicast_dest_pgid' - 'for_each_of_allnodes' - 'for_each_of_allnodes_from' - 'for_each_of_cpu_node' - 'for_each_of_pci_range' - 'for_each_old_connector_in_state' - 'for_each_old_crtc_in_state' - 'for_each_old_mst_mgr_in_state' - 'for_each_oldnew_connector_in_state' - 'for_each_oldnew_crtc_in_state' - 'for_each_oldnew_mst_mgr_in_state' - 'for_each_oldnew_plane_in_state' - 'for_each_oldnew_plane_in_state_reverse' - 'for_each_oldnew_private_obj_in_state' - 'for_each_old_plane_in_state' - 'for_each_old_private_obj_in_state' - 'for_each_online_cpu' - 'for_each_online_node' - 'for_each_online_pgdat' - 'for_each_pci_bridge' - 'for_each_pci_dev' - 'for_each_pci_msi_entry' - 'for_each_pcm_streams' - 'for_each_physmem_range' - 'for_each_populated_zone' - 'for_each_possible_cpu' - 'for_each_present_cpu' - 'for_each_prime_number' - 'for_each_prime_number_from' - 'for_each_process' - 'for_each_process_thread' - 'for_each_prop_codec_conf' - 'for_each_prop_dai_codec' - 'for_each_prop_dai_cpu' - 'for_each_prop_dlc_codecs' - 'for_each_prop_dlc_cpus' - 'for_each_prop_dlc_platforms' - 'for_each_property_of_node' - 'for_each_registered_fb' - 'for_each_requested_gpio' - 'for_each_requested_gpio_in_range' - 'for_each_reserved_mem_range' - 'for_each_reserved_mem_region' - 'for_each_rtd_codec_dais' - 'for_each_rtd_components' - 'for_each_rtd_cpu_dais' - 'for_each_rtd_dais' - 'for_each_set_bit' - 'for_each_set_bit_from' - 'for_each_set_clump8' - 'for_each_sg' - 'for_each_sg_dma_page' - 'for_each_sg_page' - 'for_each_sgtable_dma_page' - 'for_each_sgtable_dma_sg' - 'for_each_sgtable_page' - 'for_each_sgtable_sg' - 'for_each_sibling_event' - 'for_each_subelement' - 'for_each_subelement_extid' - 'for_each_subelement_id' - '__for_each_thread' - 'for_each_thread' - 'for_each_unicast_dest_pgid' - 'for_each_vsi' - 'for_each_wakeup_source' - 'for_each_zone' - 'for_each_zone_zonelist' - 'for_each_zone_zonelist_nodemask' - 'fwnode_for_each_available_child_node' - 'fwnode_for_each_child_node' - 'fwnode_graph_for_each_endpoint' - 'gadget_for_each_ep' - 'genradix_for_each' - 'genradix_for_each_from' - 'hash_for_each' - 'hash_for_each_possible' - 'hash_for_each_possible_rcu' - 'hash_for_each_possible_rcu_notrace' - 'hash_for_each_possible_safe' - 'hash_for_each_rcu' - 'hash_for_each_safe' - 'hctx_for_each_ctx' - 'hlist_bl_for_each_entry' - 'hlist_bl_for_each_entry_rcu' - 'hlist_bl_for_each_entry_safe' - 'hlist_for_each' - 'hlist_for_each_entry' - 'hlist_for_each_entry_continue' - 'hlist_for_each_entry_continue_rcu' - 'hlist_for_each_entry_continue_rcu_bh' - 'hlist_for_each_entry_from' - 'hlist_for_each_entry_from_rcu' - 'hlist_for_each_entry_rcu' - 'hlist_for_each_entry_rcu_bh' - 'hlist_for_each_entry_rcu_notrace' - 'hlist_for_each_entry_safe' - 'hlist_for_each_entry_srcu' - '__hlist_for_each_rcu' - 'hlist_for_each_safe' - 'hlist_nulls_for_each_entry' - 'hlist_nulls_for_each_entry_from' - 'hlist_nulls_for_each_entry_rcu' - 'hlist_nulls_for_each_entry_safe' - 'i3c_bus_for_each_i2cdev' - 'i3c_bus_for_each_i3cdev' - 'ide_host_for_each_port' - 'ide_port_for_each_dev' - 'ide_port_for_each_present_dev' - 'idr_for_each_entry' - 'idr_for_each_entry_continue' - 'idr_for_each_entry_continue_ul' - 'idr_for_each_entry_ul' - 'in_dev_for_each_ifa_rcu' - 'in_dev_for_each_ifa_rtnl' - 'inet_bind_bucket_for_each' - 'inet_lhash2_for_each_icsk_rcu' - 'key_for_each' - 'key_for_each_safe' - 'klp_for_each_func' - 'klp_for_each_func_safe' - 'klp_for_each_func_static' - 'klp_for_each_object' - 'klp_for_each_object_safe' - 'klp_for_each_object_static' - 'kunit_suite_for_each_test_case' - 'kvm_for_each_memslot' - 'kvm_for_each_vcpu' - 'list_for_each' - 'list_for_each_codec' - 'list_for_each_codec_safe' - 'list_for_each_continue' - 'list_for_each_entry' - 'list_for_each_entry_continue' - 'list_for_each_entry_continue_rcu' - 'list_for_each_entry_continue_reverse' - 'list_for_each_entry_from' - 'list_for_each_entry_from_rcu' - 'list_for_each_entry_from_reverse' - 'list_for_each_entry_lockless' - 'list_for_each_entry_rcu' - 'list_for_each_entry_reverse' - 'list_for_each_entry_safe' - 'list_for_each_entry_safe_continue' - 'list_for_each_entry_safe_from' - 'list_for_each_entry_safe_reverse' - 'list_for_each_entry_srcu' - 'list_for_each_prev' - 'list_for_each_prev_safe' - 'list_for_each_safe' - 'llist_for_each' - 'llist_for_each_entry' - 'llist_for_each_entry_safe' - 'llist_for_each_safe' - 'mci_for_each_dimm' - 'media_device_for_each_entity' - 'media_device_for_each_intf' - 'media_device_for_each_link' - 'media_device_for_each_pad' - 'nanddev_io_for_each_page' - 'netdev_for_each_lower_dev' - 'netdev_for_each_lower_private' - 'netdev_for_each_lower_private_rcu' - 'netdev_for_each_mc_addr' - 'netdev_for_each_uc_addr' - 'netdev_for_each_upper_dev_rcu' - 'netdev_hw_addr_list_for_each' - 'nft_rule_for_each_expr' - 'nla_for_each_attr' - 'nla_for_each_nested' - 'nlmsg_for_each_attr' - 'nlmsg_for_each_msg' - 'nr_neigh_for_each' - 'nr_neigh_for_each_safe' - 'nr_node_for_each' - 'nr_node_for_each_safe' - 'of_for_each_phandle' - 'of_property_for_each_string' - 'of_property_for_each_u32' - 'pci_bus_for_each_resource' - 'pcl_for_each_chunk' - 'pcl_for_each_segment' - 'pcm_for_each_format' - 'ping_portaddr_for_each_entry' - 'plist_for_each' - 'plist_for_each_continue' - 'plist_for_each_entry' - 'plist_for_each_entry_continue' - 'plist_for_each_entry_safe' - 'plist_for_each_safe' - 'pnp_for_each_card' - 'pnp_for_each_dev' - 'protocol_for_each_card' - 'protocol_for_each_dev' - 'queue_for_each_hw_ctx' - 'radix_tree_for_each_slot' - 'radix_tree_for_each_tagged' - 'rb_for_each' - 'rbtree_postorder_for_each_entry_safe' - 'rdma_for_each_block' - 'rdma_for_each_port' - 'rdma_umem_for_each_dma_block' - 'resource_list_for_each_entry' - 'resource_list_for_each_entry_safe' - 'rhl_for_each_entry_rcu' - 'rhl_for_each_rcu' - 'rht_for_each' - 'rht_for_each_entry' - 'rht_for_each_entry_from' - 'rht_for_each_entry_rcu' - 'rht_for_each_entry_rcu_from' - 'rht_for_each_entry_safe' - 'rht_for_each_from' - 'rht_for_each_rcu' - 'rht_for_each_rcu_from' - '__rq_for_each_bio' - 'rq_for_each_bvec' - 'rq_for_each_segment' - 'scsi_for_each_prot_sg' - 'scsi_for_each_sg' - 'sctp_for_each_hentry' - 'sctp_skb_for_each' - 'shdma_for_each_chan' - '__shost_for_each_device' - 'shost_for_each_device' - 'sk_for_each' - 'sk_for_each_bound' - 'sk_for_each_entry_offset_rcu' - 'sk_for_each_from' - 'sk_for_each_rcu' - 'sk_for_each_safe' - 'sk_nulls_for_each' - 'sk_nulls_for_each_from' - 'sk_nulls_for_each_rcu' - 'snd_array_for_each' - 'snd_pcm_group_for_each_entry' - 'snd_soc_dapm_widget_for_each_path' - 'snd_soc_dapm_widget_for_each_path_safe' - 'snd_soc_dapm_widget_for_each_sink_path' - 'snd_soc_dapm_widget_for_each_source_path' - 'tb_property_for_each' - 'tcf_exts_for_each_action' - 'udp_portaddr_for_each_entry' - 'udp_portaddr_for_each_entry_rcu' - 'usb_hub_for_each_child' - 'v4l2_device_for_each_subdev' - 'v4l2_m2m_for_each_dst_buf' - 'v4l2_m2m_for_each_dst_buf_safe' - 'v4l2_m2m_for_each_src_buf' - 'v4l2_m2m_for_each_src_buf_safe' - 'virtio_device_for_each_vq' - 'while_for_each_ftrace_op' - 'xa_for_each' - 'xa_for_each_marked' - 'xa_for_each_range' - 'xa_for_each_start' - 'xas_for_each' - 'xas_for_each_conflict' - 'xas_for_each_marked' - 'xbc_array_for_each_value' - 'xbc_for_each_key_value' - 'xbc_node_for_each_array_value' - 'xbc_node_for_each_child' - 'xbc_node_for_each_key_value' - 'zorro_for_each_dev' #IncludeBlocks: Preserve # Unknown to clang-format-5.0 IncludeCategories: - Regex: '.*' Priority: 1 IncludeIsMainRegex: '(Test)?$' IndentCaseLabels: false #IndentPPDirectives: None # Unknown to clang-format-5.0 IndentWidth: 8 IndentWrappedFunctionNames: false JavaScriptQuotes: Leave JavaScriptWrapImports: true KeepEmptyLinesAtTheStartOfBlocks: false MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: None #ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0 ObjCBlockIndentWidth: 8 ObjCSpaceAfterProperty: true ObjCSpaceBeforeProtocolList: true # Taken from git's rules #PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0 PenaltyBreakBeforeFirstCallParameter: 30 PenaltyBreakComment: 10 PenaltyBreakFirstLessLess: 0 PenaltyBreakString: 10 PenaltyExcessCharacter: 100 PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Right ReflowComments: false SortIncludes: false #SortUsingDeclarations: false # Unknown to clang-format-4.0 SpaceAfterCStyleCast: false SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true #SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0 #SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0 SpaceBeforeParens: ControlStatements #SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0 SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: false SpacesInContainerLiterals: false SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Cpp03 TabWidth: 8 UseTab: Always ... libavtp-0.2.0/.gitignore000066400000000000000000000000101420102630700151240ustar00rootroot00000000000000build *~libavtp-0.2.0/.travis.yml000066400000000000000000000020471420102630700152610ustar00rootroot00000000000000dist: trusty sudo: required language: c compiler: gcc before_install: - sudo apt-get update -qq - sudo apt-get install cmake curl unzip pkg-config gcc-4.8 - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 20 - sudo update-alternatives --install /usr/bin/cc cc /usr/bin/gcc 30 - sudo update-alternatives --set cc /usr/bin/gcc install: - sudo apt-get install -y python3-pip linux-headers-4.4.0-75-generic - curl -L "https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip" -o ninja-linux.zip - sudo unzip ninja-linux.zip -d /usr/local/bin - sudo chmod 755 /usr/local/bin/ninja - sudo pip3 install meson==0.44.0 - curl -L "https://cmocka.org/files/1.1/cmocka-1.1.1.tar.xz" -o cmocka-1.1.1.tar.xz - tar -xf cmocka-1.1.1.tar.xz - pushd cmocka-1.1.1 - mkdir build - cd build - cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug .. - make - sudo make install - popd - sudo cp /usr/src/linux-headers-4.4.0-75/include/uapi/linux/if_ether.h /usr/include/linux script: ./travis.sh libavtp-0.2.0/CONTRIBUTING.md000066400000000000000000000023711420102630700154010ustar00rootroot00000000000000Copyright (C) 2019 Intel Corporation. All rights reserved. All contributions to this project are contributed under the terms of the BSD-3-Clause licence. By making a contribution to this project, you certify that: (a) The contribution was created in whole or in part by you, and you have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of your knowledge, is covered under an appropriate open source license and you have the right under that license to submit that work with modifications, whether created in whole or in part by you, under the same open source license (unless you am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to you by some other person who certified (a), (b) or (c) and you have not modified it. (d) You understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information you submit with it, including your sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. libavtp-0.2.0/HACKING.md000066400000000000000000000043371420102630700145420ustar00rootroot00000000000000# Contributing If you have a bug fixed or added support for some AVTP feature, your patches are welcomed! In order to get your patches merged faster, please follow the guidelines: * Check if all patches are following the coding style from libavtp project. See section 'Coding Style' for more information. * Before submitting your patch to review, make sure it doesn't break any unit test. See section 'Running Unit Tests' for information about how to build and run unit tests. * Besides the bugfix/feature itself, also provide unit test covering the code you're contributing. See section 'Code Coverage' to check how you can easily generate coverage reports and see where you need to work on to get your code covered. * If your patch adds new public APIs to libavtp, please also provide patches adding example applications (or modify an existing one if it makes sense) which demonstrate how to use the new APIs. * Make sure the author's name and email are set properly. # Coding Style The coding style from libavtp is pretty much the same from Linux kernel described in https://www.kernel.org/doc/html/latest/process/coding-style.html. The style for line wrapping is to indent as far as possible to the right without hitting the 80 columns limit. Example: ``` /* Correct */ int avtp_aaf_pdu_set(struct avtp_stream_pdu *pdu, enum avtp_aaf_field field, uint64_t val) /* Wrong */ int avtp_aaf_pdu_set(struct avtp_stream_pdu *pdu, enum avtp_aaf_field field, uint64_t val) ``` # Running Unit Tests Unit tests required libcmocka so make sure you have cmocka packages installed in your system. Run the following command to build and run all unit tests. Make sure the build system files are generated already, see section 'Build' in the README.md file for more information. ``` $ ninja -C build test ``` # Code Coverage Meson build system provides some built-in code coverage support based on `lcov` so make sure you have this package installed on your system in order to generate coverage reports. To generate html reports run the following commands: ``` $ rm -rf build/ $ meson build -Db_coverage=true $ ninja -C build/ test $ ninja -C build/ coverage-html ``` The coverage report can be found in build/meson-logs/coveragereport/ directory. libavtp-0.2.0/LICENSE000066400000000000000000000027341420102630700141600ustar00rootroot00000000000000Copyright (c) 2017, Intel Corporation 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 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. libavtp-0.2.0/README.md000066400000000000000000000030101420102630700144160ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/AVnu/libavtp.svg?branch=master)](https://travis-ci.org/AVnu/libavtp) # About Open source implementation of Audio Video Transport Protocol (AVTP) specified in IEEE 1722-2016 spec. Libavtp is under BSD License. For more information see LICENSE file. # Build Before building libavtp make sure you have all the required software installed in your system. Below are the requirements and their tested versions: * Meson >= 0.43 * Ninja >= 1.8.2 The first step to build libavtp is to generate the build system files. ``` $ meson build ``` Then build libavtp by running the following command. The building artifacts will be created under the build/ in the top-level directory. ``` $ ninja -C build ``` To install libavtp on your system run: ``` $ sudo ninja -C build install ``` # AVTP Formats Support AVTP protocol defines several AVTPDU type formats (see Table 6 from IEEE 1722-2016 spec). Libavtp doesn't support all of them yet. The list of supported formarts is: * AAF (PCM encapsulation only) * CRF * CVF (H.264 only) * RVF # Examples The `examples/` directory in the top-level directory provides example applications which demonstrate the libavtp functionalities. To build an example application run `$ ninja -C build `. Information about what exactly each example application does and how it works is provided in the beginning of the .c file from each application. # Security issues Please report any security issues with this code to https://github.com/AVnu/libavtp/issues libavtp-0.2.0/examples/000077500000000000000000000000001420102630700147635ustar00rootroot00000000000000libavtp-0.2.0/examples/aaf-listener.c000066400000000000000000000255601420102630700175110ustar00rootroot00000000000000/* * Copyright (c) 2017, Intel Corporation * * 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 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. */ /* AAF Listener example. * * This example implements a very simple AAF listener application which * receives AFF packets from the network, retrieves the PCM samples, and * writes them to stdout once the presentation time is reached. * * For simplicity, the example accepts only AAF packets with the following * specification: * - Sample format: 16-bit little endian * - Sample rate: 48 kHz * - Number of channels: 2 (stereo) * * TSN stream parameters such as destination mac address are passed via * command-line arguments. Run 'aaf-listener --help' for more information. * * This example relies on the system clock to schedule PCM samples for * playback. So make sure the system clock is synchronized with the PTP * Hardware Clock (PHC) from your NIC and that the PHC is synchronized with * the PTP time from the network. For further information on how to synchronize * those clocks see ptp4l(8) and phc2sys(8) man pages. * * The easiest way to use this example is combining it with 'aplay' tool * provided by alsa-utils. 'aplay' reads a PCM stream from stdin and sends it * to a ALSA playback device (e.g. your speaker). So, to play Audio from a TSN * stream, you should do something like this: * * $ aaf-listener | aplay -f dat -t raw -D */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "avtp.h" #include "avtp_aaf.h" #include "examples/common.h" #define STREAM_ID 0xAABBCCDDEEFF0001 #define SAMPLE_SIZE 2 /* Sample size in bytes. */ #define NUM_CHANNELS 2 #define DATA_LEN (SAMPLE_SIZE * NUM_CHANNELS) #define PDU_SIZE (sizeof(struct avtp_stream_pdu) + DATA_LEN) #define NSEC_PER_SEC 1000000000ULL struct sample_entry { STAILQ_ENTRY(sample_entry) entries; struct timespec tspec; uint8_t pcm_sample[DATA_LEN]; }; static STAILQ_HEAD(sample_queue, sample_entry) samples; static char ifname[IFNAMSIZ]; static uint8_t macaddr[ETH_ALEN]; static uint8_t expected_seq; static struct argp_option options[] = { {"dst-addr", 'd', "MACADDR", 0, "Stream Destination MAC address" }, {"ifname", 'i', "IFNAME", 0, "Network Interface" }, { 0 } }; static error_t parser(int key, char *arg, struct argp_state *state) { int res; switch (key) { case 'd': res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], &macaddr[5]); if (res != 6) { fprintf(stderr, "Invalid address\n"); exit(EXIT_FAILURE); } break; case 'i': strncpy(ifname, arg, sizeof(ifname) - 1); break; } return 0; } static struct argp argp = { options, parser }; /* Schedule 'pcm_sample' to be presented at time specified by 'tspec'. */ static int schedule_sample(int fd, struct timespec *tspec, uint8_t *pcm_sample) { struct sample_entry *entry; entry = malloc(sizeof(*entry)); if (!entry) { fprintf(stderr, "Failed to allocate memory\n"); return -1; } entry->tspec.tv_sec = tspec->tv_sec; entry->tspec.tv_nsec = tspec->tv_nsec; memcpy(entry->pcm_sample, pcm_sample, DATA_LEN); STAILQ_INSERT_TAIL(&samples, entry, entries); /* If this was the first entry inserted onto the queue, we need to arm * the timer. */ if (STAILQ_FIRST(&samples) == entry) { int res; res = arm_timer(fd, tspec); if (res < 0) { STAILQ_REMOVE(&samples, entry, sample_entry, entries); free(entry); return -1; } } return 0; } static bool is_valid_packet(struct avtp_stream_pdu *pdu) { struct avtp_common_pdu *common = (struct avtp_common_pdu *) pdu; uint64_t val64; uint32_t val32; int res; res = avtp_pdu_get(common, AVTP_FIELD_SUBTYPE, &val32); if (res < 0) { fprintf(stderr, "Failed to get subtype field: %d\n", res); return false; } if (val32 != AVTP_SUBTYPE_AAF) { fprintf(stderr, "Subtype mismatch: expected %u, got %u\n", AVTP_SUBTYPE_AAF, val32); return false; } res = avtp_pdu_get(common, AVTP_FIELD_VERSION, &val32); if (res < 0) { fprintf(stderr, "Failed to get version field: %d\n", res); return false; } if (val32 != 0) { fprintf(stderr, "Version mismatch: expected %u, got %u\n", 0, val32); return false; } res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_TV, &val64); if (res < 0) { fprintf(stderr, "Failed to get tv field: %d\n", res); return false; } if (val64 != 1) { fprintf(stderr, "tv mismatch: expected %u, got %" PRIu64 "\n", 1, val64); return false; } res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_SP, &val64); if (res < 0) { fprintf(stderr, "Failed to get sp field: %d\n", res); return false; } if (val64 != AVTP_AAF_PCM_SP_NORMAL) { fprintf(stderr, "sp mismatch: expected %u, got %" PRIu64 "\n", AVTP_AAF_PCM_SP_NORMAL, val64); return false; } res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_STREAM_ID, &val64); if (res < 0) { fprintf(stderr, "Failed to get stream ID field: %d\n", res); return false; } if (val64 != STREAM_ID) { fprintf(stderr, "Stream ID mismatch: expected %" PRIu64 ", got %" PRIu64 "\n", STREAM_ID, val64); return false; } res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_SEQ_NUM, &val64); if (res < 0) { fprintf(stderr, "Failed to get sequence num field: %d\n", res); return false; } if (val64 != expected_seq) { /* If we have a sequence number mismatch, we simply log the * issue and continue to process the packet. We don't want to * invalidate it since it is a valid packet after all. */ fprintf(stderr, "Sequence number mismatch: expected %u, got %" PRIu64 "\n", expected_seq, val64); expected_seq = val64; } expected_seq++; res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_FORMAT, &val64); if (res < 0) { fprintf(stderr, "Failed to get format field: %d\n", res); return false; } if (val64 != AVTP_AAF_FORMAT_INT_16BIT) { fprintf(stderr, "Format mismatch: expected %u, got %" PRIu64 "\n", AVTP_AAF_FORMAT_INT_16BIT, val64); return false; } res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_NSR, &val64); if (res < 0) { fprintf(stderr, "Failed to get sample rate field: %d\n", res); return false; } if (val64 != AVTP_AAF_PCM_NSR_48KHZ) { fprintf(stderr, "Sample rate mismatch: expected %u, got %" PRIu64 "\n", AVTP_AAF_PCM_NSR_48KHZ, val64); return false; } res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_CHAN_PER_FRAME, &val64); if (res < 0) { fprintf(stderr, "Failed to get channels field: %d\n", res); return false; } if (val64 != NUM_CHANNELS) { fprintf(stderr, "Channels mismatch: expected %u, got %" PRIu64 "\n", NUM_CHANNELS, val64); return false; } res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_BIT_DEPTH, &val64); if (res < 0) { fprintf(stderr, "Failed to get depth field: %d\n", res); return false; } if (val64 != 16) { fprintf(stderr, "Depth mismatch: expected %u, got %" PRIu64 "\n", 16, val64); return false; } res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_STREAM_DATA_LEN, &val64); if (res < 0) { fprintf(stderr, "Failed to get data_len field: %d\n", res); return false; } if (val64 != DATA_LEN) { fprintf(stderr, "Data len mismatch: expected %u, got %" PRIu64 "\n", DATA_LEN, val64); return false; } return true; } static int new_packet(int sk_fd, int timer_fd) { int res; ssize_t n; uint64_t avtp_time; struct timespec tspec; struct avtp_stream_pdu *pdu = alloca(PDU_SIZE); memset(pdu, 0, PDU_SIZE); n = recv(sk_fd, pdu, PDU_SIZE, 0); if (n < 0 || n != PDU_SIZE) { perror("Failed to receive data"); return -1; } if (!is_valid_packet(pdu)) { fprintf(stderr, "Dropping packet\n"); return 0; } res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_TIMESTAMP, &avtp_time); if (res < 0) { fprintf(stderr, "Failed to get AVTP time from PDU\n"); return -1; } res = get_presentation_time(avtp_time, &tspec); if (res < 0) return -1; res = schedule_sample(timer_fd, &tspec, pdu->avtp_payload); if (res < 0) return -1; return 0; } static int timeout(int fd) { int res; ssize_t n; uint64_t expirations; struct sample_entry *entry; n = read(fd, &expirations, sizeof(uint64_t)); if (n < 0) { perror("Failed to read timerfd"); return -1; } assert(expirations == 1); entry = STAILQ_FIRST(&samples); assert(entry != NULL); res = present_data(entry->pcm_sample, DATA_LEN); if (res < 0) return -1; STAILQ_REMOVE_HEAD(&samples, entries); free(entry); if (!STAILQ_EMPTY(&samples)) { entry = STAILQ_FIRST(&samples); res = arm_timer(fd, &entry->tspec); if (res < 0) return -1; } return 0; } int main(int argc, char *argv[]) { int sk_fd, timer_fd, res; struct pollfd fds[2]; argp_parse(&argp, argc, argv, 0, NULL, NULL); STAILQ_INIT(&samples); sk_fd = create_listener_socket(ifname, macaddr, ETH_P_TSN); if (sk_fd < 0) return 1; timer_fd = timerfd_create(CLOCK_REALTIME, 0); if (timer_fd < 0) { close(sk_fd); return 1; } fds[0].fd = sk_fd; fds[0].events = POLLIN; fds[1].fd = timer_fd; fds[1].events = POLLIN; while (1) { res = poll(fds, 2, -1); if (res < 0) { perror("Failed to poll() fds"); goto err; } if (fds[0].revents & POLLIN) { res = new_packet(sk_fd, timer_fd); if (res < 0) goto err; } if (fds[1].revents & POLLIN) { res = timeout(timer_fd); if (res < 0) goto err; } } return 0; err: close(sk_fd); close(timer_fd); return 1; } libavtp-0.2.0/examples/aaf-talker.c000066400000000000000000000151411420102630700171400ustar00rootroot00000000000000/* * Copyright (c) 2017, Intel Corporation * * 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 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. */ /* AAF Talker example. * * This example implements a very simple AAF talker application which reads * a PCM stream from stdin, creates AAF packets and transmit them via the * network. * * For simplicity, the example supports only one set of PCM parameters: * - Sample format: 16-bit little endian * - Sample rate: 48 kHz * - Number of channels: 2 (stereo) * * TSN stream parameters (e.g. destination mac address, traffic priority) are * passed via command-line arguments. Run 'aaf-talker --help' for more * information. * * In order to have this example working properly, make sure you have * configured FQTSS feature from your NIC according (for further information * see tc-cbs(8)). Also, this example relies on system clock to set the AVTP * timestamp so make sure it is synchronized with the PTP Hardware Clock (PHC) * from your NIC and that the PHC is synchronized with the network clock. For * further information see ptp4l(8) and phc2sys(8). * * The easiest way to use this example is combining it with 'arecord' tool * provided by alsa-utils. 'arecord' reads the PCM stream from a capture ALSA * device (e.g. your microphone) and writes it to stdout. So to stream Audio * captured from your mic to a TSN network you should do something like this: * * $ arecord -f dat -t raw -D | aaf-talker */ #include #include #include #include #include #include #include #include #include "avtp.h" #include "avtp_aaf.h" #include "examples/common.h" #define STREAM_ID 0xAABBCCDDEEFF0001 #define SAMPLE_SIZE 2 /* Sample size in bytes. */ #define NUM_CHANNELS 2 #define DATA_LEN (SAMPLE_SIZE * NUM_CHANNELS) #define PDU_SIZE (sizeof(struct avtp_stream_pdu) + DATA_LEN) #define NSEC_PER_SEC 1000000000ULL #define NSEC_PER_MSEC 1000000ULL static char ifname[IFNAMSIZ]; static uint8_t macaddr[ETH_ALEN]; static int priority = -1; static int max_transit_time; static struct argp_option options[] = { {"dst-addr", 'd', "MACADDR", 0, "Stream Destination MAC address" }, {"ifname", 'i', "IFNAME", 0, "Network Interface" }, {"max-transit-time", 'm', "MSEC", 0, "Maximum Transit Time in ms" }, {"prio", 'p', "NUM", 0, "SO_PRIORITY to be set in socket" }, { 0 } }; static error_t parser(int key, char *arg, struct argp_state *state) { int res; switch (key) { case 'd': res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], &macaddr[5]); if (res != 6) { fprintf(stderr, "Invalid address\n"); exit(EXIT_FAILURE); } break; case 'i': strncpy(ifname, arg, sizeof(ifname) - 1); break; case 'm': max_transit_time = atoi(arg); break; case 'p': priority = atoi(arg); break; } return 0; } static struct argp argp = { options, parser }; static int init_pdu(struct avtp_stream_pdu *pdu) { int res; res = avtp_aaf_pdu_init(pdu); if (res < 0) return -1; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_TV, 1); if (res < 0) return -1; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_STREAM_ID, STREAM_ID); if (res < 0) return -1; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_FORMAT, AVTP_AAF_FORMAT_INT_16BIT); if (res < 0) return -1; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_NSR, AVTP_AAF_PCM_NSR_48KHZ); if (res < 0) return -1; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_CHAN_PER_FRAME, NUM_CHANNELS); if (res < 0) return -1; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_BIT_DEPTH, 16); if (res < 0) return -1; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_STREAM_DATA_LEN, DATA_LEN); if (res < 0) return -1; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_SP, AVTP_AAF_PCM_SP_NORMAL); if (res < 0) return -1; return 0; } int main(int argc, char *argv[]) { int fd, res; struct sockaddr_ll sk_addr; struct avtp_stream_pdu *pdu = alloca(PDU_SIZE); uint8_t seq_num = 0; argp_parse(&argp, argc, argv, 0, NULL, NULL); fd = create_talker_socket(priority); if (fd < 0) return 1; res = setup_socket_address(fd, ifname, macaddr, ETH_P_TSN, &sk_addr); if (res < 0) goto err; res = init_pdu(pdu); if (res < 0) goto err; while (1) { ssize_t n; uint32_t avtp_time; memset(pdu->avtp_payload, 0, DATA_LEN); n = read(STDIN_FILENO, pdu->avtp_payload, DATA_LEN); if (n == 0) break; if (n != DATA_LEN) { fprintf(stderr, "read %zd bytes, expected %d\n", n, DATA_LEN); } res = calculate_avtp_time(&avtp_time, max_transit_time); if (res < 0) { fprintf(stderr, "Failed to calculate avtp time\n"); goto err; } res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_TIMESTAMP, avtp_time); if (res < 0) goto err; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_SEQ_NUM, seq_num++); if (res < 0) goto err; n = sendto(fd, pdu, PDU_SIZE, 0, (struct sockaddr *) &sk_addr, sizeof(sk_addr)); if (n < 0) { perror("Failed to send data"); goto err; } if (n != PDU_SIZE) { fprintf(stderr, "wrote %zd bytes, expected %zd\n", n, PDU_SIZE); } } close(fd); return 0; err: close(fd); return 1; } libavtp-0.2.0/examples/common.c000066400000000000000000000125361420102630700164260ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation * * 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 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 #include #include #include #include #include #include #include #include #include #include #include #include "examples/common.h" #define NSEC_PER_SEC 1000000000ULL #define NSEC_PER_MSEC 1000000ULL int calculate_avtp_time(uint32_t *avtp_time, uint32_t max_transit_time) { int res; struct timespec tspec; uint64_t ptime; res = clock_gettime(CLOCK_REALTIME, &tspec); if (res < 0) { perror("Failed to get time"); return -1; } ptime = (tspec.tv_sec * NSEC_PER_SEC) + (max_transit_time * NSEC_PER_MSEC) + tspec.tv_nsec; *avtp_time = ptime % (1ULL << 32); return 0; } int get_presentation_time(uint64_t avtp_time, struct timespec *tspec) { int res; uint64_t ptime, now; res = clock_gettime(CLOCK_REALTIME, tspec); if (res < 0) { perror("Failed to get time from PHC"); return -1; } now = (tspec->tv_sec * NSEC_PER_SEC) + tspec->tv_nsec; /* The avtp_timestamp within AAF packet is the lower part (32 * less-significant bits) from presentation time calculated by the * talker. */ ptime = (now & 0xFFFFFFFF00000000ULL) | avtp_time; /* If 'ptime' is less than the 'now', it means the higher part * from 'ptime' needs to be incremented by 1 in order to recover the * presentation time set by the talker. */ if (ptime < now) ptime += (1ULL << 32); tspec->tv_sec = ptime / NSEC_PER_SEC; tspec->tv_nsec = ptime % NSEC_PER_SEC; return 0; } int setup_socket_address(int fd, const char *ifname, uint8_t macaddr[], int protocol, struct sockaddr_ll *sk_addr) { int res; struct ifreq req; snprintf(req.ifr_name, sizeof(req.ifr_name), "%s", ifname); res = ioctl(fd, SIOCGIFINDEX, &req); if (res < 0) { perror("Failed to get interface index"); return -1; } sk_addr->sll_family = AF_PACKET; sk_addr->sll_protocol = htons(protocol); sk_addr->sll_halen = ETH_ALEN; sk_addr->sll_ifindex = req.ifr_ifindex; memcpy(sk_addr->sll_addr, macaddr, ETH_ALEN); return 0; } int create_talker_socket(int priority) { int fd, res; fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_TSN)); if (fd < 0) { perror("Failed to open socket"); return -1; } if (priority != -1) { res = setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)); if (res < 0) { perror("Failed to set priority"); goto err; } } return fd; err: close(fd); return -1; } int create_listener_socket(char *ifname, uint8_t macaddr[], int protocol) { int fd, res; struct packet_mreq mreq; struct sockaddr_ll sk_addr; fd = socket(AF_PACKET, SOCK_DGRAM, htons(protocol)); if (fd < 0) { perror("Failed to open socket"); return -1; } res = setup_socket_address(fd, ifname, macaddr, protocol, &sk_addr); if (res < 0) goto err; res = bind(fd, (struct sockaddr *) &sk_addr, sizeof(sk_addr)); if (res < 0) { perror("Couldn't bind() to interface"); goto err; } mreq.mr_ifindex = sk_addr.sll_ifindex; mreq.mr_type = PACKET_MR_MULTICAST; mreq.mr_alen = ETH_ALEN; memcpy(&mreq.mr_address, macaddr, ETH_ALEN); res = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(struct packet_mreq)); if (res < 0) { perror("Couldn't set PACKET_ADD_MEMBERSHIP"); goto err; } return fd; err: close(fd); return -1; } int arm_timer(int fd, struct timespec *tspec) { int res; struct itimerspec timer_spec = { 0 }; timer_spec.it_value.tv_sec = tspec->tv_sec; timer_spec.it_value.tv_nsec = tspec->tv_nsec; res = timerfd_settime(fd, TFD_TIMER_ABSTIME, &timer_spec, NULL); if (res < 0) { perror("Failed to set timer"); return -1; } return 0; } int present_data(uint8_t *data, size_t len) { ssize_t n; n = write(STDOUT_FILENO, data, len); if (n < 0 || n != len) { perror("Failed to write()"); return -1; } return 0; } libavtp-0.2.0/examples/common.h000066400000000000000000000077231420102630700164350ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation * * 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 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 /* Calculate AVTP presentation time based on current time and informed * max_transit_time. * @avtp_time: Pointer to variable which the calculated time should be saved. * @max_transit_time: Max transit time for the network * * Returns: * 0: Success. * -1: If could not get current time. */ int calculate_avtp_time(uint32_t *avtp_time, uint32_t max_transit_time); /* Given an AVTP presentation time, retrieve correspondent time on * CLOCK_REALTIME. * @avtp_time: AVTP presentation time to be converted. * @ts: Pointer to struct timespec where obtained time should be saved. * * Returns: * 0: Success. * -1: If could not get CLOCK_REALTIME. */ int get_presentation_time(uint64_t avtp_time, struct timespec *tspec); /* Create TSN socket to listen for incomimg packets. * @ifname: Network interface name where to create the socket. * @macaddr: Stream destination MAC address. * @protocol: Protocol to listen to. * * Returns: * >= 0: Socket file descriptor. Should be closed with close() when done. * -1: Could not create socket. */ int create_listener_socket(char *ifname, uint8_t macaddr[], int protocol); /* Create TSN socket to send packets. * @priority: SO_PRIORITY to be set in socket. * * Returns: * >= 0: Socket file descriptor. Should be closed with close() when done. * -1: Could not create socket. */ int create_talker_socket(int priority); /* Set struct sockaddr_ll with TSN and socket parameters, so it can be used * later on sendo() or bind() calls. * @fd: Socket file descriptor. * @ifname: Network interface name where to create the socket. * @macaddr: Stream destination MAC address. * @sk_addr: Pointer to struct sockaddr_ll to be set up. * @protocol: Protocol used. * * Returns: * 0: Success. * -1: Could not get interface index. */ int setup_socket_address(int fd, const char *ifname, uint8_t macaddr[], int protocol, struct sockaddr_ll *sk_addr); /* Write data to standard output. * @data: Data to be written. * @len: Number of bytes to be written. * * Returns: * 0: Success. It's only reported when all data is successfully written. * -1: Could not write all data. */ int present_data(uint8_t *data, size_t len); /* Arm a timerfd to go off on informed time. * @fd: File descriptor of the timer. * @tspec: When the time should go off. * * Returns: * 0: Success. * -1: Could not arm timer. */ int arm_timer(int fd, struct timespec *tspec); libavtp-0.2.0/examples/crf-listener.c000066400000000000000000000622421420102630700175320ustar00rootroot00000000000000/* * Copyright (c) 2018, Intel Corporation * * 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 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. */ /* CRF Listener example. * * This example implements a very simple CRF listener application which receives * CRF packets from the network and recovers media clock. * Additionally, it operates as AAF listener or AAF talker according to the * operation mode option passed via command-line argument. * * When operating as AAF talker, it sends dummy AAF packets with presentation * time that align with the reference clock. AAF packets are sent only after * the first CRF packet is received. * * When operating as AAF listener, it receives AAF packets and checks if their * presentation time is aligned with the clock reference provided by the CRF * stream. * * Note that the application running on AAF listener mode should be started * before the application running on AAF talker mode so the former is able to * recover the media clock and check for AAF stream alignment. * * TSN stream parameters (e.g. destination mac address and mode) are passed * via command-line arguments. Run 'crf-listener --help' for more information. * * This example relies on the system clock to keep the transmission interval * when operating in AAF talker mode. So make sure the system clock is * synchronized with PTP time. For further information on how to synchronize * those clocks see ptp4l(8) and phc2sys(8) man pages. Additionally, make sure * you have configured FQTSS feature from your NIC according (for further * information see tc-cbs(8)). * * Below we provide an example to setup ptp4l, phc2sys and to configure * the qdiscs to transmit an AAF stream with 48 kHz sampling rate, 16-bit * sample size, stereo. * * On PTP slave host: Replace $IFNAME by your PTP capable NIC name. The * gPTP.cfg file mentioned below can be found in /usr/share/doc/linuxptp/ * (depending on your distro). * $ ptp4l -f gPTP.cfg -i $IFNAME -s * $ phc2sys -f gPTP.cfg -a -r * * Configure mpqrio (replace $HANDLE_ID by an unused handle ID): * $ tc qdisc add dev $IFNAME parent root handle $HANDLE_ID mqprio \ * num_tc 3 map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 \ * queues 1@0 1@1 2@2 hw 0 * * Configure cbs: * $ tc qdisc replace dev $IFNAME parent $HANDLE_ID:1 cbs idleslope 5760 \ * sendslope -994240 hicredit 9 locredit -89 offload 1 * * Finally, the AAF listener mode implemented by this example application is * limited and doesn't work with multiple AAF talkers. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "avtp.h" #include "avtp_crf.h" #include "avtp_aaf.h" #include "examples/common.h" #define AAF_STREAM_ID 0xAABBCCDDEEFF0001 #define AAF_NUM_SAMPLES 6 /* Number of samples per packet. */ #define AAF_SAMPLE_SIZE 2 /* Sample size in bytes. */ #define AAF_NUM_CHANNELS 2 /* Number of channels per frame */ #define AAF_DATA_LEN (AAF_NUM_SAMPLES * AAF_SAMPLE_SIZE * AAF_NUM_CHANNELS) #define AAF_PDU_SIZE (sizeof(struct avtp_stream_pdu) + AAF_DATA_LEN) #define AAF_SAMPLE_RATE 48000 #define CRF_STREAM_ID 0xAABBCCDDEEFF0002 /* Values based on Spec 1722 Table 28 recommendation. */ #define CRF_SAMPLE_RATE 48000 #define CRF_TIMESTAMPS_PER_SEC 300 #define TIMESTAMPS_PER_PKT 6 #define CRF_DATA_LEN (sizeof(uint64_t) * TIMESTAMPS_PER_PKT) #define CRF_PDU_SIZE (sizeof(struct avtp_crf_pdu) + CRF_DATA_LEN) #define MAX_PDU_SIZE MAX(AAF_PDU_SIZE, CRF_PDU_SIZE) #define TIME_PERIOD_NS ((double)NSEC_PER_SEC / CRF_SAMPLE_RATE) #define AAF_PERIOD (NSEC_PER_SEC * AAF_NUM_SAMPLES / AAF_SAMPLE_RATE) #define MCLK_PERIOD AAF_PERIOD #define MCLKLIST_TS_PER_CRF (CRF_SAMPLE_RATE / CRF_TIMESTAMPS_PER_SEC) #define NSEC_PER_SEC 1000000000ULL #define NSEC_PER_MSEC 1000000ULL struct media_clock_entry { STAILQ_ENTRY(media_clock_entry) mclk_entries; uint64_t timestamp; }; static enum { MODE_TALKER, MODE_LISTENER, } mode; static char ifname[IFNAMSIZ]; static uint8_t crf_macaddr[ETH_ALEN]; static uint8_t aaf_macaddr[ETH_ALEN]; static int priority = -1; static int mtt; static bool prev_state; static bool first_aaf_pdu = true; static bool need_mclk_lookup = true; static uint8_t crf_seq_num; static uint8_t aaf_seq_num; static uint64_t prev_mclk_timestamp, rounded_mtt; static STAILQ_HEAD(timestamp_queue, media_clock_entry) mclk_timestamps; static struct argp_option options[] = { {"crf-addr", 'c', "MACADDR", 0, "CRF Stream Destination MAC address" }, {"aaf-addr", 'a', "MACADDR", 0, "AAF Stream Destination MAC address" }, {"ifname", 'i', "IFNAME", 0, "Network Interface" }, {"prio", 'p', "NUM", 0, "SO_PRIORITY to be set in AAF stream" }, {"mtt", 'm', "MSEC", 0, "Max Transit time from AAF stream (in ms)" }, {"mode", 'o', "talker|listener", 0, "AAF operation mode"}, { 0 } }; static error_t parser(int key, char *arg, struct argp_state *state) { int res; switch (key) { case 'c': res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &crf_macaddr[0], &crf_macaddr[1], &crf_macaddr[2], &crf_macaddr[3], &crf_macaddr[4], &crf_macaddr[5]); if (res != 6) { fprintf(stderr, "Invalid CRF address\n"); exit(EXIT_FAILURE); } break; case 'a': res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &aaf_macaddr[0], &aaf_macaddr[1], &aaf_macaddr[2], &aaf_macaddr[3], &aaf_macaddr[4], &aaf_macaddr[5]); if (res != 6) { fprintf(stderr, "Invalid AAF address\n"); exit(EXIT_FAILURE); } break; case 'm': mtt = atoi(arg) * NSEC_PER_MSEC; break; case 'i': strncpy(ifname, arg, sizeof(ifname) - 1); break; case 'p': priority = atoi(arg); break; case 'o': if (strcmp(arg, "talker") == 0) mode = MODE_TALKER; else if (strcmp(arg, "listener") == 0) mode = MODE_LISTENER; else { fprintf(stderr, "Invalid mode\n"); exit(EXIT_FAILURE); } break; } return 0; } static struct argp argp = { options, parser }; static uint64_t mclk_dequeue_ts(void) { uint64_t mclk_timestamp; struct media_clock_entry *mclk_entry; mclk_entry = STAILQ_FIRST(&mclk_timestamps); mclk_timestamp = mclk_entry->timestamp; STAILQ_REMOVE_HEAD(&mclk_timestamps, mclk_entries); free(mclk_entry); return mclk_timestamp; } static int mclk_enqueue_ts(uint64_t ts) { struct media_clock_entry *mclk_entry; mclk_entry = malloc(sizeof(*mclk_entry)); if (!mclk_entry) { fprintf(stderr, "Failed to allocate memory\n"); return -1; } mclk_entry->timestamp = ts; STAILQ_INSERT_TAIL(&mclk_timestamps, mclk_entry, mclk_entries); return 0; } static uint64_t get_next_mclk_timestamp(void) { uint64_t mclk_timestamp; if (STAILQ_EMPTY(&mclk_timestamps)) { mclk_timestamp = prev_mclk_timestamp + MCLK_PERIOD; need_mclk_lookup = true; } else { mclk_timestamp = mclk_dequeue_ts(); } prev_mclk_timestamp = mclk_timestamp; return mclk_timestamp; } static uint64_t mclk_lookup(uint32_t avtp_time) { uint64_t mclk_timestamp = get_next_mclk_timestamp(); while (mclk_timestamp % (1ULL << 32) != avtp_time) mclk_timestamp = get_next_mclk_timestamp(); return mclk_timestamp; } static bool is_valid_crf_pdu(struct avtp_crf_pdu *pdu) { int res; uint32_t val32; uint64_t val64; struct avtp_common_pdu *common = (struct avtp_common_pdu *) pdu; res = avtp_pdu_get(common, AVTP_FIELD_SUBTYPE, &val32); if (res < 0) { fprintf(stderr, "Failed to get CRF subtype field: %d\n", res); return false; } if (val32 != AVTP_SUBTYPE_CRF) return false; res = avtp_pdu_get(common, AVTP_FIELD_VERSION, &val32); if (res < 0) { fprintf(stderr, "Failed to get CRF version field: %d\n", res); return false; } if (val32 != 0) { fprintf(stderr, "CRF: Version mismatch: expected %u, got %u\n", 0, val32); return false; } res = avtp_crf_pdu_get(pdu, AVTP_CRF_FIELD_SV, &val64); if (res < 0) { fprintf(stderr, "Failed to get CRF sv field: %d\n", res); return false; } if (val64 != 1) { fprintf(stderr, "CRF: sv mismatch: expected %u, got %" PRIu64 "\n", 1, val64); return false; } res = avtp_crf_pdu_get(pdu, AVTP_CRF_FIELD_FS, &val64); if (res < 0) { fprintf(stderr, "Failed to get CRF fs field: %d\n", res); return false; } if (val64 != 0) { fprintf(stderr, "CRF: fs mismatch: expected %u, got %" PRIu64 "\n", 0, val64); return false; } res = avtp_crf_pdu_get(pdu, AVTP_CRF_FIELD_SEQ_NUM, &val64); if (res < 0) { fprintf(stderr, "Failed to get CRF sequence num field: %d\n", res); return false; } if (val64 != crf_seq_num) { /* If we have a sequence number mismatch, we simply log the * issue and continue to process the packet. We don't want to * invalidate it since it is a valid packet after all. */ fprintf(stderr, "CRF: Sequence number mismatch: expected %u, got %" PRIu64 "\n", crf_seq_num, val64); crf_seq_num = val64; } crf_seq_num++; res = avtp_crf_pdu_get(pdu, AVTP_CRF_FIELD_TYPE, &val64); if (res < 0) { fprintf(stderr, "Failed to get CRF format field: %d\n", res); return false; } if (val64 != AVTP_CRF_TYPE_AUDIO_SAMPLE) { fprintf(stderr, "CRF: Format mismatch: expected %u, got %" PRIu64 "\n", AVTP_CRF_TYPE_AUDIO_SAMPLE, val64); return false; } res = avtp_crf_pdu_get(pdu, AVTP_CRF_FIELD_STREAM_ID, &val64); if (res < 0) { fprintf(stderr, "Failed to get CRF stream ID field: %d\n", res); return false; } if (val64 != CRF_STREAM_ID) { fprintf(stderr, "CRF: Stream ID mismatch: expected %" PRIu64 ", got %" PRIu64 "\n", CRF_STREAM_ID, val64); return false; } res = avtp_crf_pdu_get(pdu, AVTP_CRF_FIELD_PULL, &val64); if (res < 0) { fprintf(stderr, "Failed to get CRF multiplier modifier field: %d\n", res); return false; } if (val64 != AVTP_CRF_PULL_MULT_BY_1) { fprintf(stderr, "CRF Pull mismatch: expected %u, got %" PRIu64 "\n", AVTP_CRF_PULL_MULT_BY_1, val64); return false; } res = avtp_crf_pdu_get(pdu, AVTP_CRF_FIELD_BASE_FREQ, &val64); if (res < 0) { fprintf(stderr, "Failed to get CRF base frequency field: %d\n", res); return false; } if (val64 != CRF_SAMPLE_RATE) { fprintf(stderr, "CRF Base frequency: expected %u, got %" PRIu64 "\n", CRF_SAMPLE_RATE, val64); return false; } res = avtp_crf_pdu_get(pdu, AVTP_CRF_FIELD_CRF_DATA_LEN, &val64); if (res < 0) { fprintf(stderr, "Failed to get CRF data length field: %d\n", res); return false; } if (val64 != CRF_DATA_LEN) { fprintf(stderr, "CRF Data length mismatch: expected %zu, got %" PRIu64 "\n", CRF_DATA_LEN, val64); return false; } return true; } static bool is_valid_aaf_pdu(struct avtp_stream_pdu *pdu) { struct avtp_common_pdu *common = (struct avtp_common_pdu *) pdu; uint64_t val64; uint32_t val32; int res; res = avtp_pdu_get(common, AVTP_FIELD_VERSION, &val32); if (res < 0) { fprintf(stderr, "AAF: Failed to get version field: %d\n", res); return false; } if (val32 != 0) { fprintf(stderr, "AAF: Version mismatch: expected %u, got %u\n", 0, val32); return false; } res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_TV, &val64); if (res < 0) { fprintf(stderr, "AAF: Failed to get tv field: %d\n", res); return false; } if (val64 != 1) { fprintf(stderr, "AAF: tv mismatch: expected %u, got %" PRIu64 "\n", 1, val64); return false; } res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_SP, &val64); if (res < 0) { fprintf(stderr, "AAF: Failed to get sp field: %d\n", res); return false; } if (val64 != AVTP_AAF_PCM_SP_NORMAL) { fprintf(stderr, "AAF: tv mismatch: expected %u, got %" PRIu64 "\n", 1, val64); return false; } res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_STREAM_ID, &val64); if (res < 0) { fprintf(stderr, "AAF: Failed to get stream ID field: %d\n", res); return false; } if (val64 != AAF_STREAM_ID) { fprintf(stderr, "AAF: Stream ID mismatch: expected %" PRIu64 ", got %" PRIu64 "\n", AAF_STREAM_ID, val64); return false; } res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_SEQ_NUM, &val64); if (res < 0) { fprintf(stderr, "AAF: Failed to get sequence num field: %d\n", res); return false; } if (val64 != aaf_seq_num) { /* If we have a sequence number mismatch, we simply log the * issue and continue to process the packet. We don't want to * invalidate it since it is a valid packet after all. */ fprintf(stderr, "AAF Sequence number mismatch: expected %u, got %" PRIu64 "\n", aaf_seq_num, val64); aaf_seq_num = val64; } aaf_seq_num++; res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_FORMAT, &val64); if (res < 0) { fprintf(stderr, "AAF: Failed to get format field: %d\n", res); return false; } if (val64 != AVTP_AAF_FORMAT_INT_16BIT) { fprintf(stderr, "AAF: Format mismatch: expected %u, got %" PRIu64 "\n", AVTP_AAF_FORMAT_INT_16BIT, val64); return false; } res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_NSR, &val64); if (res < 0) { fprintf(stderr, "AAF: Failed to get sample rate field: %d\n", res); return false; } if (val64 != AVTP_AAF_PCM_NSR_48KHZ) { fprintf(stderr, "AAF: Sample rate mismatch: expected %u, got %" PRIu64 "\n", AVTP_AAF_PCM_NSR_48KHZ, val64); return false; } res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_CHAN_PER_FRAME, &val64); if (res < 0) { fprintf(stderr, "AAF: Failed to get channels field: %d\n", res); return false; } if (val64 != AAF_NUM_CHANNELS) { fprintf(stderr, "AAF: Channels mismatch: expected %u, got %" PRIu64 "\n", AAF_NUM_CHANNELS, val64); return false; } res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_BIT_DEPTH, &val64); if (res < 0) { fprintf(stderr, "AAF: Failed to get depth field: %d\n", res); return false; } if (val64 != 16) { fprintf(stderr, "AAF: Depth mismatch: expected %u, got %" PRIu64 "\n", 16, val64); return false; } res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_STREAM_DATA_LEN, &val64); if (res < 0) { fprintf(stderr, "AAF: Failed to get data_len field: %d\n", res); return false; } if (val64 != AAF_DATA_LEN) { fprintf(stderr, "AAF: Data len mismatch: expected %u, got %" PRIu64 "\n", AAF_DATA_LEN, val64); return false; } return true; } static int init_aaf_pdu(struct avtp_stream_pdu *pdu) { int res; res = avtp_aaf_pdu_init(pdu); if (res < 0) return -1; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_TV, 1); if (res < 0) return -1; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_STREAM_ID, AAF_STREAM_ID); if (res < 0) return -1; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_FORMAT, AVTP_AAF_FORMAT_INT_16BIT); if (res < 0) return -1; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_NSR, AVTP_AAF_PCM_NSR_48KHZ); if (res < 0) return -1; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_CHAN_PER_FRAME, AAF_NUM_CHANNELS); if (res < 0) return -1; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_BIT_DEPTH, 16); if (res < 0) return -1; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_STREAM_DATA_LEN, AAF_DATA_LEN); if (res < 0) return -1; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_SP, AVTP_AAF_PCM_SP_NORMAL); if (res < 0) return -1; return 0; } static int aaf_talker_tx_timeout(int fd_timer, int fd_sk, const struct sockaddr_ll *addr, struct avtp_stream_pdu *pdu) { int res; ssize_t n; uint64_t expirations; uint32_t avtp_time = 0; n = read(fd_timer, &expirations, sizeof(uint64_t)); if (n < 0) { perror("Failed to read timerfd"); return -1; } while (expirations--) { avtp_time = get_next_mclk_timestamp(); res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_TIMESTAMP, avtp_time); if (res < 0) return res; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_SEQ_NUM, aaf_seq_num++); if (res < 0) return res; n = sendto(fd_sk, pdu, AAF_PDU_SIZE, 0, (struct sockaddr *) addr, sizeof(*addr)); if (n < 0) { perror("Failed to send data"); return -1; } if (n != AAF_PDU_SIZE) { fprintf(stderr, "AAF: wrote %zd bytes, expected %zd\n", n, AAF_PDU_SIZE); } } return 0; } /* This routine generates media clock timestamps using timestamps from CRF * stream. */ static int recover_mclk(struct avtp_crf_pdu *pdu) { int res, idx; uint64_t ts_mclk, ts_crf; /* For simplicity's sake, we consider only the first timestamp from * CRF PDU to recover the media clock. */ ts_crf = be64toh(pdu->crf_data[0]); for (idx = 0; idx < MCLKLIST_TS_PER_CRF; idx++) { ts_mclk = ts_crf + (idx * MCLK_PERIOD); if (mode == MODE_TALKER) { /* If we are operating in talker mode, the max transit * time is added to the recovered timestamp, rounding * it up to the nearest multiple fo the media clock. */ ts_mclk += rounded_mtt; } if (ts_mclk <= prev_mclk_timestamp) /* If the recovered timestamp is less than the * timestamp from the last AAF pdu received, we discard * it. This situation happens when the CRF pdu is * received late and the media clock has already * freewheeled. */ continue; res = mclk_enqueue_ts(ts_mclk); if (res < 0) return res; } return 0; } static int is_ts_aligned(uint32_t mclk_ts, uint32_t avtp_ts) { int n = 0; int t_offset, delta_ll, delta_hl; t_offset = avtp_ts - mclk_ts; delta_ll = (n * TIME_PERIOD_NS) - (TIME_PERIOD_NS/4); delta_hl = (n * TIME_PERIOD_NS) + (TIME_PERIOD_NS/4); /* Equation 16 defined in spec 1722: * ((n * Ps) - Ps/4) < Toffset < ((n * Ps) + Ps/4) * Toffset: timestamp offset in nanoseconds between the AVTP Presentation Timestamp of the media stream and the timestamp of the CRF stream * n : positive integer chosen for the implementation * Ps : the sample period of the CRF stream in nanoseconds */ if (delta_ll > t_offset || t_offset > delta_hl) return false; return true; } static int handle_crf_pdu(struct avtp_crf_pdu *pdu) { if (!is_valid_crf_pdu(pdu)) return 0; return recover_mclk(pdu); } static int handle_aaf_pdu(struct avtp_stream_pdu *pdu) { int res; bool state; uint64_t val; uint32_t avtp_time, mclk_time; if (!is_valid_aaf_pdu(pdu)) return 0; res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_TIMESTAMP, &val); if (res < 0) { fprintf(stderr, "Failed to get AVTP time from PDU\n"); return res; } avtp_time = val; if (need_mclk_lookup) { mclk_time = mclk_lookup(avtp_time); need_mclk_lookup = false; } else { mclk_time = get_next_mclk_timestamp(); } state = is_ts_aligned(mclk_time, avtp_time); if (prev_state != state) { if (state) printf("AAF Stream is aligned with common media clock\n"); else printf("AAF Stream is not aligned with common media clock\n"); } prev_state = state; return 0; } static int aaf_talker_recv_pdu(int fd_sk, int fd_timer) { int res; ssize_t n; struct avtp_crf_pdu *pdu = alloca(CRF_PDU_SIZE); memset(pdu, 0, CRF_PDU_SIZE); n = recv(fd_sk, pdu, CRF_PDU_SIZE, 0); if (n < 0) { perror("Failed to receive data"); return -1; } /* The protocol type from rx socket is set to ETH_P_ALL so we receive * non-AVTP packets as well. In order to filter out those packets, we * check the number of bytes received. If it doesn't match the CRF pdu * size we drop the packet. */ if (n != CRF_PDU_SIZE) return 0; res = handle_crf_pdu(pdu); if (res < 0) return -1; /* Arm the timer for the first time to start sending AAF stream. */ if (first_aaf_pdu) { struct itimerspec itspec = { 0 }; uint64_t ts = mclk_dequeue_ts(); first_aaf_pdu = false; itspec.it_value.tv_sec = ts / NSEC_PER_SEC; itspec.it_value.tv_nsec = ts % NSEC_PER_SEC; itspec.it_interval.tv_sec = 0; itspec.it_interval.tv_nsec = AAF_PERIOD; res = timerfd_settime(fd_timer, TFD_TIMER_ABSTIME, &itspec, NULL); if (res < 0) { perror("Failed to set timer"); return -1; } } return 0; } static int aaf_listener_recv_pdu(int fd) { int res; ssize_t n; uint32_t val; void *pdu = alloca(MAX_PDU_SIZE); struct avtp_common_pdu *common = (struct avtp_common_pdu *) pdu; memset(pdu, 0, MAX_PDU_SIZE); n = recv(fd, pdu, MAX_PDU_SIZE, 0); if (n < 0) { perror("Failed to receive data"); return -1; } /* The protocol type from rx socket is set to ETH_P_ALL so we receive * non-AVTP packets as well. In order to filter out those packets, we * check the number of bytes received. If it doesn't match the CRF or * AAF pdu size we drop the packet. */ if (n != AAF_PDU_SIZE && n != CRF_PDU_SIZE) return 0; res = avtp_pdu_get(common, AVTP_FIELD_SUBTYPE, &val); if (res < 0) { fprintf(stderr, "Failed to get subtype field: %d\n", res); return -1; } switch (val) { case AVTP_SUBTYPE_CRF: res = handle_crf_pdu(pdu); break; case AVTP_SUBTYPE_AAF: res = handle_aaf_pdu(pdu); break; } return res; } static int setup_rx_socket(void) { int res, fd; struct ifreq req = {0}; struct packet_mreq mreq = {0}; /* In case this example is running on the same host where crf-talker is * running, we set protocol type to ETH_P_ALL to allow CRF traffic to * loop back. */ fd = create_listener_socket(ifname, crf_macaddr, ETH_P_ALL); if (fd < 0) { perror("Failed to open socket"); return -1; } if (mode == MODE_LISTENER) { snprintf(req.ifr_name, sizeof(req.ifr_name), "%s", ifname); res = ioctl(fd, SIOCGIFINDEX, &req); if (res < 0) { perror("Failed to get interface index"); goto err; } mreq.mr_ifindex = req.ifr_ifindex; mreq.mr_type = PACKET_MR_MULTICAST; mreq.mr_alen = ETH_ALEN; memcpy(&mreq.mr_address, aaf_macaddr, ETH_ALEN); res = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(struct packet_mreq)); if (res < 0) { perror("Couldn't add membership for AAF stream"); goto err; } } return fd; err: close(fd); return -1; } static int aaf_talker(int fd_rx) { int res, fd_tx, fd_timer; struct pollfd poll_fd[2]; struct sockaddr_ll sk_addr = {0}; struct ifreq req = {0}; struct avtp_stream_pdu *pdu; fd_tx = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_TSN)); if (fd_tx < 0) { perror("Failed to open socket"); return -1; } if (priority != -1) { res = setsockopt(fd_tx, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)); if (res < 0) { perror("Failed to set priority"); goto fd_tx_close; } } snprintf(req.ifr_name, sizeof(req.ifr_name), "%s", ifname); res = ioctl(fd_tx, SIOCGIFINDEX, &req); if (res < 0) { perror("Failed to get interface index"); goto fd_tx_close; } sk_addr.sll_family = AF_PACKET; sk_addr.sll_protocol = htons(ETH_P_TSN); sk_addr.sll_halen = ETH_ALEN; sk_addr.sll_ifindex = req.ifr_ifindex; memcpy(&sk_addr.sll_addr, aaf_macaddr, ETH_ALEN); fd_timer = timerfd_create(CLOCK_REALTIME, 0); if (fd_timer < 0) goto fd_tx_close; pdu = alloca(AAF_PDU_SIZE); res = init_aaf_pdu(pdu); if (res < 0) goto fd_timer_close; memset(pdu->avtp_payload, 0, AAF_DATA_LEN); poll_fd[0].fd = fd_rx; poll_fd[0].events = POLLIN; poll_fd[1].fd = fd_timer; poll_fd[1].events = POLLIN; while (1) { res = poll(poll_fd, 2, -1); if (res < 0) { perror("Failed to poll() fds"); goto fd_timer_close; } if (poll_fd[0].revents & POLLIN) { res = aaf_talker_recv_pdu(fd_rx, fd_timer); if (res < 0) goto fd_timer_close; } if (poll_fd[1].revents & POLLIN) { res = aaf_talker_tx_timeout(fd_timer, fd_tx, &sk_addr, pdu); if (res < 0) goto fd_timer_close; } } close(fd_timer); close(fd_tx); return 0; fd_timer_close: close(fd_timer); fd_tx_close: close(fd_tx); return 1; } static int aaf_listener(int fd_rx) { int res; while (1) { res = aaf_listener_recv_pdu(fd_rx); if (res < 0) return -1; } } int main(int argc, char *argv[]) { int fd_rx; argp_parse(&argp, argc, argv, 0, NULL, NULL); STAILQ_INIT(&mclk_timestamps); rounded_mtt = ceil((double)mtt / MCLK_PERIOD) * MCLK_PERIOD; fd_rx = setup_rx_socket(); if (fd_rx < 0) return 1; switch (mode) { case MODE_LISTENER: aaf_listener(fd_rx); break; case MODE_TALKER: aaf_talker(fd_rx); break; } close(fd_rx); return 0; } libavtp-0.2.0/examples/crf-talker.c000066400000000000000000000167441420102630700171750ustar00rootroot00000000000000/* * Copyright (c) 2018, Intel Corporation * * 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 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. */ /* CRF Talker example. * * This example implements a very simple CRF talker application which reads * system clock to get current time, generates CRF timestamps, creates AVTP CRF * packets and transmit them via the network. * * TSN stream parameters (e.g. destination mac address and maximum transit * time) are passed via command-line arguments. Run 'crf-talker --help' for * more information. * * This example relies on system clock to generate CRF timestamps and to keep * transmission rate. So make sure the system clock is synchronized with the * PTP Hardware Clock (PHC) from your NIC and that the PHC is synchronized with * the PTP time from the network. For further information on how to synchronize * those clocks see ptp4l(8) and phc2sys(8) man pages. * * Here is an example to setup ptp4l and phc2sys on PTP master host. Replace * $IFNAME by your PTP capable NIC name. The gPTP.cfg file mentioned below can * be found in /usr/share/doc/linuxptp/ (depending on your distro). * $ ptp4l -f gPTP.cfg -i $IFNAME * $ phc2sys -f gPTP.cfg -c $IFNAME -s CLOCK_REALTIME -w */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "avtp.h" #include "avtp_crf.h" #include "examples/common.h" #define STREAM_ID 0xAABBCCDDEEFF0002 /* Values based on Spec 1722 Table 28 recommendation. */ #define SAMPLE_RATE 48000 #define TIMESTAMP_INTERVAL 160 #define TIMESTAMPS_PER_SEC 300 #define TIMESTAMPS_PER_PKT 6 #define NSEC_PER_SEC 1000000000ULL #define NSEC_PER_MSEC 1000000ULL #define DATA_LEN (sizeof(uint64_t) * TIMESTAMPS_PER_PKT) #define PDU_SIZE (sizeof(struct avtp_crf_pdu) + DATA_LEN) #define PDUS_PER_SEC (TIMESTAMPS_PER_SEC / TIMESTAMPS_PER_PKT) #define CRF_PERIOD (NSEC_PER_SEC / TIMESTAMPS_PER_SEC) #define NOMINAL_PERIOD (1.0 / SAMPLE_RATE) #define TX_INTERVAL (NSEC_PER_SEC / PDUS_PER_SEC) static char ifname[IFNAMSIZ]; static uint8_t macaddr[ETH_ALEN]; static int mtt; static struct argp_option options[] = { {"dst-addr", 'd', "MACADDR", 0, "Stream Destination MAC address" }, {"ifname", 'i', "IFNAME", 0, "Network Interface" }, {"max-transit-time", 'm', "MSEC", 0, "Maximum Transit Time in ms" }, { 0 } }; static error_t parser(int key, char *arg, struct argp_state *state) { int res; switch (key) { case 'd': res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], &macaddr[5]); if (res != 6) { fprintf(stderr, "Invalid address\n"); exit(EXIT_FAILURE); } break; case 'i': strncpy(ifname, arg, sizeof(ifname) - 1); break; case 'm': mtt = atoi(arg) * NSEC_PER_MSEC; break; } return 0; } static struct argp argp = { options, parser }; static uint64_t calculate_crf_timestamp(struct timespec tspec, uint64_t rounded_mtt) { uint64_t ts, crf_time; const uint64_t tc = 0; ts = (tspec.tv_sec * NSEC_PER_SEC) + tspec.tv_nsec; /* Equation 14 defined in spec 1722: * Tcrf = Ts + (ceil(TTmax/p) * p) + Tc * TCRF : CRF timestamp placed in the CRF AVTPDU * Ts : the original timestamp, sampled at the source * TTmax: the Max Transit Time value chosen for the network * P : the nominal period of the clock source * TC : the amount of time that samples spend accumulating in the * Talker’s transmit buffer */ /* Value for sample accumulating time (TC) is system specific. Since * this is a CRF talker example, for simplicity, the value for Tc * is set to 0. */ crf_time = ts + rounded_mtt + tc; return crf_time; } static int init_pdu(struct avtp_crf_pdu *pdu) { int res; res = avtp_crf_pdu_init(pdu); if (res < 0) return -1; res = avtp_crf_pdu_set(pdu, AVTP_CRF_FIELD_FS, 0); if (res < 0) return -1; res = avtp_crf_pdu_set(pdu, AVTP_CRF_FIELD_TYPE, AVTP_CRF_TYPE_AUDIO_SAMPLE); if (res < 0) return -1; res = avtp_crf_pdu_set(pdu, AVTP_CRF_FIELD_STREAM_ID, STREAM_ID); if (res < 0) return -1; res = avtp_crf_pdu_set(pdu, AVTP_CRF_FIELD_PULL, AVTP_CRF_PULL_MULT_BY_1); if (res < 0) return -1; res = avtp_crf_pdu_set(pdu, AVTP_CRF_FIELD_BASE_FREQ, SAMPLE_RATE); if (res < 0) return -1; res = avtp_crf_pdu_set(pdu, AVTP_CRF_FIELD_TIMESTAMP_INTERVAL, TIMESTAMP_INTERVAL); if (res < 0) return -1; res = avtp_crf_pdu_set(pdu, AVTP_CRF_FIELD_CRF_DATA_LEN, DATA_LEN); if (res < 0) return -1; return 0; } int main(int argc, char *argv[]) { int sk_fd, res, idx; uint8_t seq_num = 0; uint64_t crf_time, rounded_mtt; struct timespec clksrc_ts = {0}; struct sockaddr_ll sk_addr = {0}; struct avtp_crf_pdu *pdu = alloca(PDU_SIZE); argp_parse(&argp, argc, argv, 0, NULL, NULL); sk_fd = create_talker_socket(-1); if (sk_fd < 0) { return 1; } res = setup_socket_address(sk_fd, ifname, macaddr, ETH_P_TSN, &sk_addr); if (res < 0) goto err; res = init_pdu(pdu); if (res < 0) goto err; res = clock_gettime(CLOCK_REALTIME, &clksrc_ts); if (res < 0) { perror("Failed to get time"); goto err; } rounded_mtt = ceil(mtt / NOMINAL_PERIOD) * NOMINAL_PERIOD; while (1) { ssize_t n; crf_time = calculate_crf_timestamp(clksrc_ts, rounded_mtt); for (idx = 0; idx < TIMESTAMPS_PER_PKT; idx++) pdu->crf_data[idx] = htobe64(crf_time + (CRF_PERIOD * idx)); res = avtp_crf_pdu_set(pdu, AVTP_CRF_FIELD_SEQ_NUM, seq_num++); if (res < 0) goto err; n = sendto(sk_fd, pdu, PDU_SIZE, 0, (struct sockaddr *) &sk_addr, sizeof(sk_addr)); if (n < 0) { perror("Failed to send data"); goto err; } if (n != PDU_SIZE) { fprintf(stderr, "wrote %zd bytes, expected %zd\n", n, PDU_SIZE); } clksrc_ts.tv_nsec += TX_INTERVAL; if (clksrc_ts.tv_nsec >= NSEC_PER_SEC) { clksrc_ts.tv_sec++; clksrc_ts.tv_nsec -= NSEC_PER_SEC; } clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &clksrc_ts, NULL); } close(sk_fd); return 0; err: close(sk_fd); return 1; } libavtp-0.2.0/examples/cvf-listener.c000066400000000000000000000242051420102630700175330ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation * * 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 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. */ /* CVF Listener example. * * This example implements a very simple CVF listener application which * receives CVF packets from the network, retrieves video data and writes * them to stdout once the presentation time is reached. * * For simplicity, this examples accepts only CVF H.264 packets, and the H.264 * data must be composed of NAL and each NAL unit can not exceed 1400 bytes. * * The H.264 data sent to output is in H.264 byte-stream format. * * TSN stream parameters such as destination mac address are passed via * command-line arguments. Run 'cvf-listener --help' for more information. * * This example relies on the system clock to schedule video data samples for * presentation. So make sure the system clock is synchronized with the PTP * Hardware Clock (PHC) from your NIC and that the PHC is synchronized with * the PTP time from the network. For further information on how to synchronize * those clocks see ptp4l(8) and phc2sys(8) man pages. * * The easiest way to use this example is by combining it with a GStreamer * pipeline. We use GStreamer to read the H.264 byte-stream from stdin and * present it. So, to play an H.264 video from a TSN strem and show it on a X * display, you can do something like: * * $ cvf-listener | gst-launch-1.0 filesrc location=/dev/stdin \ * ! decodebin ! videoconvert ! autovideosink */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "avtp.h" #include "avtp_cvf.h" #include "examples/common.h" #define STREAM_ID 0xAABBCCDDEEFF0001 #define DATA_LEN 1400 #define AVTP_H264_HEADER_LEN (sizeof(uint32_t)) #define AVTP_FULL_HEADER_LEN (sizeof(struct avtp_stream_pdu) + AVTP_H264_HEADER_LEN) #define MAX_PDU_SIZE (AVTP_FULL_HEADER_LEN + DATA_LEN) struct nal_entry { STAILQ_ENTRY(nal_entry) entries; uint16_t len; struct timespec tspec; uint8_t nal[DATA_LEN]; }; static STAILQ_HEAD(nal_queue, nal_entry) nals; static char ifname[IFNAMSIZ]; static uint8_t macaddr[ETH_ALEN]; static uint8_t expected_seq; static struct argp_option options[] = { {"dst-addr", 'd', "MACADDR", 0, "Stream Destination MAC address" }, {"ifname", 'i', "IFNAME", 0, "Network Interface" }, { 0 } }; static error_t parser(int key, char *arg, struct argp_state *state) { int res; switch (key) { case 'd': res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], &macaddr[5]); if (res != 6) { fprintf(stderr, "Invalid address\n"); exit(EXIT_FAILURE); } break; case 'i': strncpy(ifname, arg, sizeof(ifname) - 1); break; } return 0; } static struct argp argp = { options, parser }; static int schedule_nal(int fd, struct timespec *tspec, uint8_t *nal, ssize_t len) { struct nal_entry *entry; entry = malloc(sizeof(*entry)); if (!entry) { fprintf(stderr, "Failed to allocate memory\n"); return -1; } entry->len = len; entry->tspec.tv_sec = tspec->tv_sec; entry->tspec.tv_nsec = tspec->tv_nsec; memcpy(entry->nal, nal, entry->len); STAILQ_INSERT_TAIL(&nals, entry, entries); /* If this was the first entry inserted onto the queue, we need to arm * the timer. */ if (STAILQ_FIRST(&nals) == entry) { int res; res = arm_timer(fd, tspec); if (res < 0) { STAILQ_REMOVE(&nals, entry, nal_entry, entries); free(entry); return -1; } } return 0; } static bool is_valid_packet(struct avtp_stream_pdu *pdu) { struct avtp_common_pdu *common = (struct avtp_common_pdu *) pdu; uint64_t val64; uint32_t val32; int res; res = avtp_pdu_get(common, AVTP_FIELD_SUBTYPE, &val32); if (res < 0) { fprintf(stderr, "Failed to get subtype field: %d\n", res); return false; } if (val32 != AVTP_SUBTYPE_CVF) { fprintf(stderr, "Subtype mismatch: expected %u, got %u\n", AVTP_SUBTYPE_CVF, val32); return false; } res = avtp_pdu_get(common, AVTP_FIELD_VERSION, &val32); if (res < 0) { fprintf(stderr, "Failed to get version field: %d\n", res); return false; } if (val32 != 0) { fprintf(stderr, "Version mismatch: expected %u, got %u\n", 0, val32); return false; } res = avtp_cvf_pdu_get(pdu, AVTP_CVF_FIELD_TV, &val64); if (res < 0) { fprintf(stderr, "Failed to get tv field: %d\n", res); return false; } if (val64 != 1) { fprintf(stderr, "tv mismatch: expected %u, got %lu\n", 1, val64); return false; } res = avtp_cvf_pdu_get(pdu, AVTP_CVF_FIELD_STREAM_ID, &val64); if (res < 0) { fprintf(stderr, "Failed to get stream ID field: %d\n", res); return false; } if (val64 != STREAM_ID) { fprintf(stderr, "Stream ID mismatch: expected %lu, got %lu\n", STREAM_ID, val64); return false; } res = avtp_cvf_pdu_get(pdu, AVTP_CVF_FIELD_SEQ_NUM, &val64); if (res < 0) { fprintf(stderr, "Failed to get sequence num field: %d\n", res); return false; } if (val64 != expected_seq) { /* If we have a sequence number mismatch, we simply log the * issue and continue to process the packet. We don't want to * invalidate it since it is a valid packet after all. */ fprintf(stderr, "Sequence number mismatch: expected %u, got %lu\n", expected_seq, val64); expected_seq = val64; } expected_seq++; res = avtp_cvf_pdu_get(pdu, AVTP_CVF_FIELD_FORMAT, &val64); if (res < 0) { fprintf(stderr, "Failed to get format field: %d\n", res); return false; } if (val64 != AVTP_CVF_FORMAT_RFC) { fprintf(stderr, "Format mismatch: expected %u, got %lu\n", AVTP_CVF_FORMAT_RFC, val64); return false; } res = avtp_cvf_pdu_get(pdu, AVTP_CVF_FIELD_FORMAT_SUBTYPE, &val64); if (res < 0) { fprintf(stderr, "Failed to get format subtype field: %d\n", res); return false; } if (val64 != AVTP_CVF_FORMAT_SUBTYPE_H264) { fprintf(stderr, "Format mismatch: expected %u, got %lu\n", AVTP_CVF_FORMAT_SUBTYPE_H264, val64); return false; } return true; } static int get_h264_data_len(struct avtp_stream_pdu *pdu, uint16_t *stream_data_len) { int res; uint64_t val; res = avtp_cvf_pdu_get(pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, &val); if (res < 0) { fprintf(stderr, "Failed to get data_len field\n"); return -1; } *stream_data_len = val - AVTP_H264_HEADER_LEN; return 0; } static int new_packet(int sk_fd, int timer_fd) { int res; ssize_t n; uint16_t h264_data_len; uint64_t avtp_time; struct timespec tspec; struct avtp_stream_pdu *pdu = alloca(MAX_PDU_SIZE); struct avtp_cvf_h264_payload *h264_pay = (struct avtp_cvf_h264_payload *)pdu->avtp_payload; memset(pdu, 1, MAX_PDU_SIZE); n = recv(sk_fd, pdu, MAX_PDU_SIZE, 0); if (n < 0 || n > MAX_PDU_SIZE) { perror("Failed to receive data"); return -1; } if (!is_valid_packet(pdu)) { fprintf(stderr, "Dropping packet\n"); return 0; } res = avtp_cvf_pdu_get(pdu, AVTP_CVF_FIELD_TIMESTAMP, &avtp_time); if (res < 0) { fprintf(stderr, "Failed to get AVTP time from PDU\n"); return -1; } res = get_presentation_time(avtp_time, &tspec); if (res < 0) return -1; res = get_h264_data_len(pdu, &h264_data_len); if (res < 0) return -1; res = schedule_nal(timer_fd, &tspec, h264_pay->h264_data, h264_data_len); if (res < 0) return -1; return 0; } static int timeout(int fd) { int res; ssize_t n; uint64_t expirations; struct nal_entry *entry; n = read(fd, &expirations, sizeof(uint64_t)); if (n < 0) { perror("Failed to read timerfd"); return -1; } assert(expirations == 1); entry = STAILQ_FIRST(&nals); assert(entry != NULL); res = present_data(entry->nal, entry->len); if (res < 0) return -1; STAILQ_REMOVE_HEAD(&nals, entries); free(entry); if (!STAILQ_EMPTY(&nals)) { entry = STAILQ_FIRST(&nals); res = arm_timer(fd, &entry->tspec); if (res < 0) return -1; } return 0; } int main(int argc, char *argv[]) { int sk_fd, timer_fd, res; struct pollfd fds[2]; argp_parse(&argp, argc, argv, 0, NULL, NULL); STAILQ_INIT(&nals); sk_fd = create_listener_socket(ifname, macaddr, ETH_P_TSN); if (sk_fd < 0) return 1; timer_fd = timerfd_create(CLOCK_REALTIME, 0); if (timer_fd < 0) { close(sk_fd); return 1; } fds[0].fd = sk_fd; fds[0].events = POLLIN; fds[1].fd = timer_fd; fds[1].events = POLLIN; while (1) { res = poll(fds, 2, -1); if (res < 0) { perror("Failed to poll() fds"); goto err; } if (fds[0].revents & POLLIN) { res = new_packet(sk_fd, timer_fd); if (res < 0) goto err; } if (fds[1].revents & POLLIN) { res = timeout(timer_fd); if (res < 0) goto err; } } return 0; err: close(sk_fd); close(timer_fd); return 1; } libavtp-0.2.0/examples/cvf-talker.c000066400000000000000000000216351420102630700171740ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation * * 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 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. */ /* CVF Talker example. * * This example implements a very simple CVF talker application which reads * an H.264 byte-stream from stdin, creates CVF packets and transmit them via * network. * * For simplicity, this example supports only NAL units in byte-stream format, * and each NAL unit can not exceed 1400 bytes. * * TSN stream parameters (e.g. destination mac address, traffic priority) are * passed via command-line arguments. Run 'cvf-talker --help' for more * information. * * In order to have this example working properly, make sure you have * configured FQTSS feature from your NIC according (for further information * see tc-cbs(8)). Also, this example relies on system clock to set the AVTP * timestamp so make sure it is synchronized with the PTP Hardware Clock (PHC) * from your NIC and that the PHC is synchronized with the network clock. For * further information see ptp4l(8) and phc2sys(8). * * The easiest way to use this example is by combining it with a GStreamer * pipeline. We use GStreamer to provide an H.264 stream that is sent to * stdout, from where this example reads the stream. So, to generate * an H.264 video to send via TSN network, you can do something like: * * $ gst-launch-1.0 -e -q videotestsrc pattern=ball \ * ! video/x-raw,width=192,height=144 ! x264enc \ * ! video/x-h264,stream-format=byte-stream ! filesink location=/dev/stdout \ * | cvf-talker * * Note that the `x264enc` may be changed by any other H.264 encoder * available, as long as it generates a byte-stream with NAL units no longer * than 1400 bytes. */ #include #include #include #include #include #include #include #include #include #include #include #include "avtp.h" #include "avtp_cvf.h" #include "examples/common.h" #define STREAM_ID 0xAABBCCDDEEFF0001 #define DATA_LEN 1400 #define AVTP_H264_HEADER_LEN (sizeof(uint32_t)) #define AVTP_FULL_HEADER_LEN (sizeof(struct avtp_stream_pdu) + AVTP_H264_HEADER_LEN) #define MAX_PDU_SIZE (AVTP_FULL_HEADER_LEN + DATA_LEN) static char ifname[IFNAMSIZ]; static uint8_t macaddr[ETH_ALEN]; static int priority = -1; static int max_transit_time; static char buffer[MAX_PDU_SIZE * 2]; static size_t buffer_level; static uint8_t seq_num; enum process_result {PROCESS_OK, PROCESS_NONE, PROCESS_ERROR}; static struct argp_option options[] = { {"dst-addr", 'd', "MACADDR", 0, "Stream Destination MAC address" }, {"ifname", 'i', "IFNAME", 0, "Network Interface" }, {"max-transit-time", 'm', "MSEC", 0, "Maximum Transit Time in ms" }, {"prio", 'p', "NUM", 0, "SO_PRIORITY to be set in socket" }, { 0 } }; static error_t parser(int key, char *arg, struct argp_state *state) { int res; switch (key) { case 'd': res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], &macaddr[5]); if (res != 6) { fprintf(stderr, "Invalid address\n"); exit(EXIT_FAILURE); } break; case 'i': strncpy(ifname, arg, sizeof(ifname) - 1); break; case 'm': max_transit_time = atoi(arg); break; case 'p': priority = atoi(arg); break; } return 0; } static struct argp argp = { options, parser }; static int init_pdu(struct avtp_stream_pdu *pdu) { int res; res = avtp_cvf_pdu_init(pdu, AVTP_CVF_FORMAT_SUBTYPE_H264); if (res < 0) return -1; res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_TV, 1); if (res < 0) return -1; res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_STREAM_ID, STREAM_ID); if (res < 0) return -1; /* Just state that all data is part of the frame (M=1) */ res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_M, 1); if (res < 0) return -1; /* No H.264 timestamp now */ res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, 0); if (res < 0) return -1; /* No H.264 timestamp means no PTV */ res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_H264_PTV, 0); if (res < 0) return -1; return 0; } static ssize_t fill_buffer(void) { ssize_t n; n = read(STDIN_FILENO, buffer + buffer_level, sizeof(buffer) - buffer_level); if (n < 0) { perror("Could not read from standard input"); } buffer_level += n; return n; } static ssize_t start_code_position(size_t offset) { assert(offset < buffer_level); /* Simplified Boyer-Moore, inspired by gstreamer */ while (offset < buffer_level - 2) { if (buffer[offset + 2] == 0x1) { if (buffer[offset] == 0x0 && buffer[offset + 1] == 0x0) return offset; offset += 3; } else if (buffer[offset + 2] == 0x0) { offset++; } else { offset += 3; } } return -1; } static int prepare_packet(struct avtp_stream_pdu *pdu, char *nal_data, size_t nal_data_len) { int res; uint32_t avtp_time; struct avtp_cvf_h264_payload *h264_pay = (struct avtp_cvf_h264_payload *) pdu->avtp_payload; res = calculate_avtp_time(&avtp_time, max_transit_time); if (res < 0) { fprintf(stderr, "Failed to calculate avtp time\n"); return -1; } res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_TIMESTAMP, avtp_time); if (res < 0) return -1; res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_SEQ_NUM, seq_num++); if (res < 0) return -1; /* Stream data len includes AVTP H264 header, as this is part * of the payload too*/ res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, nal_data_len + AVTP_H264_HEADER_LEN); if (res < 0) return -1; memcpy(h264_pay->h264_data, nal_data, nal_data_len); return 0; } static int process_nal(struct avtp_stream_pdu *pdu, bool process_last, size_t *nal_len) { int res; ssize_t start, end; *nal_len = 0; start = start_code_position(0); if (start == -1) { fprintf(stderr, "Unable to find NAL start\n"); return PROCESS_NONE; } /* Now, let's find where the next starts. This is where current ends */ end = start_code_position(start + 1); if (end == -1) { if (process_last == false) { return PROCESS_NONE; } else { end = buffer_level; } } *nal_len = end - start; if (*nal_len > DATA_LEN) { fprintf(stderr, "NAL length bigger than expected. Expected %u, " "found %zd\n", DATA_LEN, *nal_len); goto err; } /* Sets AVTP packet headers and content - the NAL unit */ res = prepare_packet(pdu, &buffer[start], *nal_len); if (res < 0) { goto err; } /* Finally, let's offset any remaining data on the buffer to the * beginning. Not really efficient, but keep things simple */ memmove(buffer, buffer + end, buffer_level - end); buffer_level -= end; return PROCESS_OK; err: return PROCESS_ERROR; } int main(int argc, char *argv[]) { int fd, res; struct sockaddr_ll sk_addr; struct avtp_stream_pdu *pdu = alloca(MAX_PDU_SIZE); argp_parse(&argp, argc, argv, 0, NULL, NULL); fd = create_talker_socket(priority); if (fd < 0) return 1; res = setup_socket_address(fd, ifname, macaddr, ETH_P_TSN, &sk_addr); if (res < 0) goto err; res = init_pdu(pdu); if (res < 0) goto err; while (1) { ssize_t n; bool end = false; n = fill_buffer(); if (n == 0) end = true; while (buffer_level > 0) { enum process_result pr = process_nal(pdu, end, (size_t *)&n); if (pr == PROCESS_ERROR) goto err; if (pr == PROCESS_NONE) break; n = sendto(fd, pdu, AVTP_FULL_HEADER_LEN + n, 0, (struct sockaddr *) &sk_addr, sizeof(sk_addr)); if (n < 0) { perror("Failed to send data"); goto err; } } if (end) break; } close(fd); return 0; err: close(fd); return 1; } libavtp-0.2.0/examples/ieciidc-listener.c000066400000000000000000000271771420102630700203610ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation * * 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 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. */ /* IEC 61883/IIDC Listener example. * * This example implements a very simple IEC 61883/IIDC listener application * which receives AVTP packets from the network, retrieves the MPEG-TS packets, * and writes them to stdout once the presentation time is reached. * * For simplicity, the example supports MPEG-TS streams, and expects that each * AVTP packet contains only one source packet. * * TSN stream parameters such as destination mac address are passed via * command-line arguments. Run 'ieciidc-listener --help' for more information. * * This example relies on the system clock to schedule MPEG-TS packets for * playback. So make sure the system clock is synchronized with the PTP * Hardware Clock (PHC) from your NIC and that the PHC is synchronized with * the PTP time from the network. For further information on how to synchronize * those clocks see ptp4l(8) and phc2sys(8) man pages. * * The easiest way to use this example is by combining it with a GStreamer * pipeline. We provide an MPEG-TS stream that is sent to stdout, from where * GStreameer reads the stream. So, to send the MPEG-TS stream received from * the TSN network to GStreamer, you can do something like: * * $ ieciidc-listener | gst-launch-1.0 -e -q filesrc location=/dev/stdin * ! tsdemux ! decodebin ! videoconvert ! autovideosink */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "avtp.h" #include "avtp_ieciidc.h" #include "examples/common.h" #define STREAM_ID 0xAABBCCDDEEFF0001 #define MPEG_TS_PACKET_LEN 188 #define DATA_LEN (MPEG_TS_PACKET_LEN + sizeof(uint32_t)) /* MPEG-TS size + SPH */ #define CIP_HEADER_LEN (sizeof(uint32_t) * 2) #define STREAM_DATA_LEN DATA_LEN + CIP_HEADER_LEN #define PDU_SIZE (sizeof(struct avtp_stream_pdu) + CIP_HEADER_LEN + DATA_LEN) struct packet_entry { STAILQ_ENTRY(packet_entry) entries; struct timespec tspec; uint8_t mpegts_packet[MPEG_TS_PACKET_LEN]; }; static STAILQ_HEAD(packet_queue, packet_entry) packets; static char ifname[IFNAMSIZ]; static uint8_t macaddr[ETH_ALEN]; static uint8_t expected_seq; static uint8_t expected_dbc; static struct argp_option options[] = { {"dst-addr", 'd', "MACADDR", 0, "Stream Destination MAC address" }, {"ifname", 'i', "IFNAME", 0, "Network Interface" }, { 0 } }; static error_t parser(int key, char *arg, struct argp_state *state) { int res; switch (key) { case 'd': res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], &macaddr[5]); if (res != 6) { fprintf(stderr, "Invalid address\n"); exit(EXIT_FAILURE); } break; case 'i': strncpy(ifname, arg, sizeof(ifname) - 1); break; } return 0; } static struct argp argp = { options, parser }; /* Schedule 'MPEG-TS packet' to be presented at time specified by 'tspec'. */ static int schedule_packet(int fd, struct timespec *tspec, uint8_t *mpeg_tsp) { struct packet_entry *entry; entry = malloc(sizeof(*entry)); if (!entry) { fprintf(stderr, "Failed to allocate memory\n"); return -1; } entry->tspec.tv_sec = tspec->tv_sec; entry->tspec.tv_nsec = tspec->tv_nsec; memcpy(entry->mpegts_packet, mpeg_tsp, MPEG_TS_PACKET_LEN); STAILQ_INSERT_TAIL(&packets, entry, entries); /* If this was the first entry inserted onto the queue, we need to arm * the timer. */ if (STAILQ_FIRST(&packets) == entry) { int res; res = arm_timer(fd, tspec); if (res < 0) { STAILQ_REMOVE(&packets, entry, packet_entry, entries); free(entry); return -1; } } return 0; } static bool is_valid_packet(struct avtp_stream_pdu *pdu) { struct avtp_common_pdu *common = (struct avtp_common_pdu *) pdu; uint64_t val64; uint32_t val32; int res; res = avtp_pdu_get(common, AVTP_FIELD_SUBTYPE, &val32); assert(res == 0); if (val32 != AVTP_SUBTYPE_61883_IIDC) { fprintf(stderr, "Subtype mismatch: expected %u, got %u\n", AVTP_SUBTYPE_61883_IIDC, val32); return false; } res = avtp_pdu_get(common, AVTP_FIELD_VERSION, &val32); assert(res == 0); if (val32 != 0) { fprintf(stderr, "Version mismatch: expected %u, got %u\n", 0, val32); return false; } res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_TV, &val64); assert(res == 0); if (val64 != 0) { fprintf(stderr, "tv mismatch: expected %u, got %" PRIu64 "\n", 0, val64); return false; } res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_STREAM_ID, &val64); assert(res == 0); if (val64 != STREAM_ID) { fprintf(stderr, "Stream ID mismatch: expected %" PRIu64 ", got %" PRIu64 "\n", STREAM_ID, val64); return false; } res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_SEQ_NUM, &val64); assert(res == 0); if (val64 != expected_seq) { /* If we have a sequence number mismatch, we simply log the * issue and continue to process the packet. We don't want to * invalidate it since it is a valid packet after all. */ fprintf(stderr, "Sequence number mismatch: expected %u, got %" PRIu64 "\n", expected_seq, val64); expected_seq = val64; } expected_seq++; res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_STREAM_DATA_LEN, &val64); assert(res == 0); if (val64 != STREAM_DATA_LEN) { fprintf(stderr, "Data len mismatch: expected %lu, got %" PRIu64 "\n", STREAM_DATA_LEN, val64); return false; } res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_TAG, &val64); assert(res == 0); if (val64 != AVTP_IECIIDC_TAG_CIP) { fprintf(stderr, "tag mismatch: expected %u, got %" PRIu64 "\n", AVTP_IECIIDC_TAG_CIP, val64); return false; } res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CHANNEL, &val64); assert(res == 0); if (val64 != 31) { fprintf(stderr, "channel mismatch: expected %u, got %" PRIu64 "\n", 31, val64); return false; } res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_SID, &val64); assert(res == 0); if (val64 != 63) { fprintf(stderr, "sid mismatch: expected %u, got %" PRIu64 "\n", 63, val64); return false; } res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_DBS, &val64); assert(res == 0); if (val64 != 6) { fprintf(stderr, "dbs mismatch: expected %u, got %" PRIu64 "\n", 6, val64); return false; } res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_FN, &val64); assert(res == 0); if (val64 != 3) { fprintf(stderr, "fn mismatch: expected %u, got %" PRIu64 "\n", 3, val64); return false; } res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_QPC, &val64); assert(res == 0); if (val64 != 0) { fprintf(stderr, "GV mismatch: expected %u, got %" PRIu64 "\n", 0, val64); return false; } res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_SPH, &val64); assert(res == 0); if (val64 != 1) { fprintf(stderr, "sph mismatch: expected %u, got %" PRIu64 "\n", 1, val64); return false; } res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_FMT, &val64); assert(res == 0); if (val64 != 32) { fprintf(stderr, "fmt mismatch: expected %u, got %" PRIu64 "\n", 32, val64); return false; } res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_TSF, &val64); assert(res == 0); if (val64 != 0) { fprintf(stderr, "tsf mismatch: expected %u, got %" PRIu64 "\n", 0, val64); return false; } res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_DBC, &val64); assert(res == 0); if (val64 != expected_dbc) { /* As with sequence mismatch, we'll not discard this packet, * only log that the mismatch happened */ fprintf(stderr, "dbc mismatch: expected %u, got %" PRIu64 "\n", expected_dbc, val64); } expected_dbc += 8; return true; } static int new_packet(int sk_fd, int timer_fd) { int res; ssize_t n; uint32_t avtp_time; struct timespec tspec; struct avtp_stream_pdu *pdu = alloca(PDU_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) pdu->avtp_payload; struct avtp_ieciidc_cip_source_packet *sp = (struct avtp_ieciidc_cip_source_packet *) pay->cip_data_payload; memset(pdu, 0, PDU_SIZE); n = recv(sk_fd, pdu, PDU_SIZE, 0); if (n < 0 || n != PDU_SIZE) { perror("Failed to receive data"); return -1; } if (!is_valid_packet(pdu)) { fprintf(stderr, "Dropping packet\n"); return 0; } /* There are no helpers for payload fields, so one must remember * of byte ordering */ avtp_time = ntohl(sp->avtp_source_packet_header_timestamp); res = get_presentation_time(avtp_time, &tspec); if (res < 0) return -1; res = schedule_packet(timer_fd, &tspec, sp->cip_with_sph_payload); if (res < 0) return -1; return 0; } static int timeout(int fd) { int res; ssize_t n; uint64_t expirations; struct packet_entry *entry; n = read(fd, &expirations, sizeof(uint64_t)); if (n < 0) { perror("Failed to read timerfd"); return -1; } assert(expirations == 1); entry = STAILQ_FIRST(&packets); assert(entry != NULL); res = present_data(entry->mpegts_packet, MPEG_TS_PACKET_LEN); if (res < 0) return -1; STAILQ_REMOVE_HEAD(&packets, entries); free(entry); if (!STAILQ_EMPTY(&packets)) { entry = STAILQ_FIRST(&packets); res = arm_timer(fd, &entry->tspec); if (res < 0) return -1; } return 0; } int main(int argc, char *argv[]) { int sk_fd, timer_fd, res; struct pollfd fds[2]; argp_parse(&argp, argc, argv, 0, NULL, NULL); STAILQ_INIT(&packets); sk_fd = create_listener_socket(ifname, macaddr, ETH_P_TSN); if (sk_fd < 0) return 1; timer_fd = timerfd_create(CLOCK_REALTIME, 0); if (timer_fd < 0) { close(sk_fd); return 1; } fds[0].fd = sk_fd; fds[0].events = POLLIN; fds[1].fd = timer_fd; fds[1].events = POLLIN; while (1) { res = poll(fds, 2, -1); if (res < 0) { perror("Failed to poll() fds"); goto err; } if (fds[0].revents & POLLIN) { res = new_packet(sk_fd, timer_fd); if (res < 0) goto err; } if (fds[1].revents & POLLIN) { res = timeout(timer_fd); if (res < 0) goto err; } } return 0; err: close(sk_fd); close(timer_fd); return 1; } libavtp-0.2.0/examples/ieciidc-talker.c000066400000000000000000000175301420102630700200060ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation * * 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 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. */ /* IEC 61883/IIDC Talker example. * * This example implements a very simple IEC 61883 talker application which * reads an MPEG-TS stream from stdin, creates AVTP IEC 61883/IIDC packets and * transmits them via the network. * * For simplicity, the example supports only MPEG-TS streams, and only one * source packet is packed into each AVTP packet sent. * * TSN stream parameters (e.g. destination mac address, traffic priority) are * passed via command-line arguments. Run 'ieciidc-talker --help' for more * information. * * In order to have this example working properly, make sure you have * configured FQTSS feature from your NIC according (for further information * see tc-cbs(8)). Also, this example relies on system clock to set the AVTP * timestamp so make sure it is synchronized with the PTP Hardware Clock (PHC) * from your NIC and that the PHC is synchronized with the network clock. For * further information see ptp4l(8) and phc2sys(8). * * The easiest way to use this example is by combining it with a GStreamer * pipeline. We use GStreamer to provide an MPEG-TS stream that is sent to * stdout, from where this example reads the stream. So, to generate * an MPEG-TS video to send via TSN network, you can do something like: * * $ gst-launch-1.0 -e -q videotestsrc pattern=ball ! x264enc * ! mpegtsmux ! filesink location=/dev/stdout * | ieciidc-talker * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "avtp.h" #include "avtp_ieciidc.h" #include "examples/common.h" #define STREAM_ID 0xAABBCCDDEEFF0001 #define MPEG_TS_PACKET_LEN 188 #define DATA_LEN (MPEG_TS_PACKET_LEN + sizeof(uint32_t)) /* MPEG-TS size + SPH */ #define CIP_HEADER_LEN (sizeof(uint32_t) * 2) #define STREAM_DATA_LEN DATA_LEN + CIP_HEADER_LEN #define PDU_SIZE (sizeof(struct avtp_stream_pdu) + CIP_HEADER_LEN + DATA_LEN) static char ifname[IFNAMSIZ]; static uint8_t macaddr[ETH_ALEN]; static int priority = -1; static int max_transit_time; static struct argp_option options[] = { {"dst-addr", 'd', "MACADDR", 0, "Stream Destination MAC address" }, {"ifname", 'i', "IFNAME", 0, "Network Interface" }, {"max-transit-time", 'm', "MSEC", 0, "Maximum Transit Time in ms" }, {"prio", 'p', "NUM", 0, "SO_PRIORITY to be set in socket" }, { 0 } }; static error_t parser(int key, char *arg, struct argp_state *state) { int res; switch (key) { case 'd': res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], &macaddr[5]); if (res != 6) { fprintf(stderr, "Invalid address\n"); exit(EXIT_FAILURE); } break; case 'i': strncpy(ifname, arg, sizeof(ifname) - 1); break; case 'm': max_transit_time = atoi(arg); break; case 'p': priority = atoi(arg); break; } return 0; } static struct argp argp = { options, parser }; static void init_pdu(struct avtp_stream_pdu *pdu) { int res; res = avtp_ieciidc_pdu_init(pdu, AVTP_IECIIDC_TAG_CIP); assert(res == 0); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_TV, 0); assert(res == 0); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_STREAM_ID, STREAM_ID); assert(res == 0); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_STREAM_DATA_LEN, STREAM_DATA_LEN); assert(res == 0); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_GV, 0); assert(res == 0); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_GATEWAY_INFO, 0); assert(res == 0); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CHANNEL, 31); assert(res == 0); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_QI_1, 0); assert(res == 0); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_SID, 63); assert(res == 0); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_DBS, 6); assert(res == 0); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_FN, 3); assert(res == 0); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_QPC, 0); assert(res == 0); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_SPH, 1); assert(res == 0); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_QI_2, 2); assert(res == 0); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_FMT, 32); assert(res == 0); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_TSF, 0); assert(res == 0); } int main(int argc, char *argv[]) { int fd, res; struct sockaddr_ll sk_addr; struct avtp_stream_pdu *pdu = alloca(PDU_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *)pdu->avtp_payload; uint8_t seq_num = 0; uint8_t dbc = 0; argp_parse(&argp, argc, argv, 0, NULL, NULL); fd = create_talker_socket(priority); if (fd < 0) return 1; res = setup_socket_address(fd, ifname, macaddr, ETH_P_TSN, &sk_addr); if (res < 0) goto err; init_pdu(pdu); while (1) { ssize_t n; uint32_t avtp_time; struct avtp_ieciidc_cip_source_packet *sp; memset(pay->cip_data_payload, 0, DATA_LEN); sp = (struct avtp_ieciidc_cip_source_packet *) pay->cip_data_payload; n = read(STDIN_FILENO, sp->cip_with_sph_payload, MPEG_TS_PACKET_LEN); if (n == 0) break; if (n != MPEG_TS_PACKET_LEN) { fprintf(stderr, "read %zd bytes, expected %d\n", n, MPEG_TS_PACKET_LEN); } res = calculate_avtp_time(&avtp_time, max_transit_time); if (res < 0) { fprintf(stderr, "Failed to calculate avtp time\n"); goto err; } /* There are no helpers for payload fields, so one must remember * of byte ordering */ sp->avtp_source_packet_header_timestamp = htonl(avtp_time); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_SEQ_NUM, seq_num++); assert(res == 0); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_DBC, dbc); assert(res == 0); /* We just send one MPEG-TS packet per AVTP packet, so we * increase dbc by the number of blocks on one MPEG-TS packet */ dbc += 8; n = sendto(fd, pdu, PDU_SIZE, 0, (struct sockaddr *) &sk_addr, sizeof(sk_addr)); if (n < 0) { perror("Failed to send data"); goto err; } if (n != PDU_SIZE) { fprintf(stderr, "wrote %zd bytes, expected %zd\n", n, PDU_SIZE); } } close(fd); return 0; err: close(fd); return 1; } libavtp-0.2.0/include/000077500000000000000000000000001420102630700145705ustar00rootroot00000000000000libavtp-0.2.0/include/avtp.h000066400000000000000000000075151420102630700157230ustar00rootroot00000000000000/* * Copyright (c) 2017, Intel Corporation * * 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 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. */ #pragma once #include #include #ifdef __cplusplus extern "C" { #endif /* AVTP subtypes values. For further information refer to section 4.4.3.2 from * IEEE 1722-2016 spec. */ #define AVTP_SUBTYPE_61883_IIDC 0x00 #define AVTP_SUBTYPE_MMA_STREAM 0x01 #define AVTP_SUBTYPE_AAF 0x02 #define AVTP_SUBTYPE_CVF 0x03 #define AVTP_SUBTYPE_CRF 0x04 #define AVTP_SUBTYPE_TSCF 0x05 #define AVTP_SUBTYPE_SVF 0x06 #define AVTP_SUBTYPE_RVF 0x07 #define AVTP_SUBTYPE_AEF_CONTINUOUS 0x6E #define AVTP_SUBTYPE_VSF_STREAM 0x6F #define AVTP_SUBTYPE_EF_STREAM 0x7F #define AVTP_SUBTYPE_NTSCF 0x82 #define AVTP_SUBTYPE_ESCF 0xEC #define AVTP_SUBTYPE_EECF 0xED #define AVTP_SUBTYPE_AEF_DISCRETE 0xEE #define AVTP_SUBTYPE_ADP 0xFA #define AVTP_SUBTYPE_AECP 0xFB #define AVTP_SUBTYPE_ACMP 0xFC #define AVTP_SUBTYPE_MAAP 0xFE #define AVTP_SUBTYPE_EF_CONTROL 0xFF /* XXX: Fields from PDU structs should not be read or written directly since * they are encoded in Network order which may be different from the Host * order (see section 3.4.1 from IEEE 1722-2016 spec for further information). * * Any read or write operation with PDU structs should be done via getter and * setter APIs which handle byte order conversion. */ struct avtp_common_pdu { uint32_t subtype_data; uint8_t pdu_specific[0]; } __attribute__ ((__packed__)); struct avtp_stream_pdu { uint32_t subtype_data; uint64_t stream_id; uint32_t avtp_time; uint32_t format_specific; uint32_t packet_info; uint8_t avtp_payload[0]; } __attribute__ ((__packed__)); enum avtp_field { AVTP_FIELD_SUBTYPE, AVTP_FIELD_VERSION, AVTP_FIELD_MAX, }; /* Get value from Common AVTPDU field. * @pdu: Pointer to PDU struct. * @field: PDU field to be retrieved. * @val: Pointer to variable which the retrieved value should be saved. * * Returns: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_pdu_get(const struct avtp_common_pdu *pdu, enum avtp_field field, uint32_t *val); /* Set value from Common AVTPDU field. * @pdu: Pointer to PDU struct. * @field: PDU field to be set. * @val: Value to be set. * * Returns: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_pdu_set(struct avtp_common_pdu *pdu, enum avtp_field field, uint32_t val); #ifdef __cplusplus } #endif libavtp-0.2.0/include/avtp_aaf.h000066400000000000000000000075621420102630700165340ustar00rootroot00000000000000/* * Copyright (c) 2017, Intel Corporation * * 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 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. */ #pragma once #include #include #ifdef __cplusplus extern "C" { #endif /* AAF PCM 'format' field values. */ #define AVTP_AAF_FORMAT_USER 0x00 #define AVTP_AAF_FORMAT_FLOAT_32BIT 0x01 #define AVTP_AAF_FORMAT_INT_32BIT 0x02 #define AVTP_AAF_FORMAT_INT_24BIT 0x03 #define AVTP_AAF_FORMAT_INT_16BIT 0x04 #define AVTP_AAF_FORMAT_AES3_32BIT 0x05 /* AAF PCM 'nsr' (nominal sample rate) field values. */ #define AVTP_AAF_PCM_NSR_USER 0x00 #define AVTP_AAF_PCM_NSR_8KHZ 0x01 #define AVTP_AAF_PCM_NSR_16KHZ 0x02 #define AVTP_AAF_PCM_NSR_32KHZ 0x03 #define AVTP_AAF_PCM_NSR_44_1KHZ 0x04 #define AVTP_AAF_PCM_NSR_48KHZ 0x05 #define AVTP_AAF_PCM_NSR_88_2KHZ 0x06 #define AVTP_AAF_PCM_NSR_96KHZ 0x07 #define AVTP_AAF_PCM_NSR_176_4KHZ 0x08 #define AVTP_AAF_PCM_NSR_192KHZ 0x09 #define AVTP_AAF_PCM_NSR_24KHZ 0x0A /* AAF PCM 'sp' (sparse timestamp) field values. */ #define AVTP_AAF_PCM_SP_NORMAL 0x00 #define AVTP_AAF_PCM_SP_SPARSE 0x01 enum avtp_aaf_field { AVTP_AAF_FIELD_SV, AVTP_AAF_FIELD_MR, AVTP_AAF_FIELD_TV, AVTP_AAF_FIELD_SEQ_NUM, AVTP_AAF_FIELD_TU, AVTP_AAF_FIELD_STREAM_ID, AVTP_AAF_FIELD_TIMESTAMP, AVTP_AAF_FIELD_STREAM_DATA_LEN, AVTP_AAF_FIELD_FORMAT, AVTP_AAF_FIELD_NSR, AVTP_AAF_FIELD_CHAN_PER_FRAME, AVTP_AAF_FIELD_BIT_DEPTH, AVTP_AAF_FIELD_SP, AVTP_AAF_FIELD_EVT, AVTP_AAF_FIELD_MAX, }; /* Get value from AAF AVTPDU field. * @pdu: Pointer to PDU struct. * @field: PDU field to be retrieved. * @val: Pointer to variable which the retrieved value should be saved. * * Returns: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_aaf_pdu_get(const struct avtp_stream_pdu *pdu, enum avtp_aaf_field field, uint64_t *val); /* Set value from AAF AVTPDU field. * @pdu: Pointer to PDU struct. * @field: PDU field to be set. * @val: Value to be set. * * Returns: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_aaf_pdu_set(struct avtp_stream_pdu *pdu, enum avtp_aaf_field field, uint64_t val); /* Initialize AAF AVTPDU. All AVTPDU fields are initialized with zero except * 'subtype' (which is set to AVTP_SUBTYPE_AAF) and 'sv' (which is set to 1). * @pdu: Pointer to PDU struct. * * Return values: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_aaf_pdu_init(struct avtp_stream_pdu *pdu); #ifdef __cplusplus } #endif libavtp-0.2.0/include/avtp_crf.h000066400000000000000000000071211420102630700165460ustar00rootroot00000000000000/* * Copyright (c) 2018, Intel Corporation * * 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 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. */ #pragma once #include #include #ifdef __cplusplus extern "C" { #endif /* CRF 'type' field values. */ #define AVTP_CRF_TYPE_USER 0x00 #define AVTP_CRF_TYPE_AUDIO_SAMPLE 0x01 #define AVTP_CRF_TYPE_VIDEO_FRAME 0x02 #define AVTP_CRF_TYPE_VIDEO_LINE 0x03 #define AVTP_CRF_TYPE_MACHINE_CYCLE 0x04 /* CRF 'pull' field values. */ #define AVTP_CRF_PULL_MULT_BY_1 0x00 #define AVTP_CRF_PULL_MULT_BY_1_OVER_1_001 0x01 #define AVTP_CRF_PULL_MULT_BY_1_001 0x02 #define AVTP_CRF_PULL_MULT_BY_24_OVER_25 0x03 #define AVTP_CRF_PULL_MULT_BY_25_OVER_24 0x04 #define AVTP_CRF_PULL_MULT_BY_1_OVER_8 0x05 struct avtp_crf_pdu { uint32_t subtype_data; uint64_t stream_id; uint64_t packet_info; uint64_t crf_data[0]; } __attribute__ ((__packed__)); enum avtp_crf_field { AVTP_CRF_FIELD_SV, AVTP_CRF_FIELD_MR, AVTP_CRF_FIELD_FS, AVTP_CRF_FIELD_TU, AVTP_CRF_FIELD_SEQ_NUM, AVTP_CRF_FIELD_TYPE, AVTP_CRF_FIELD_STREAM_ID, AVTP_CRF_FIELD_PULL, AVTP_CRF_FIELD_BASE_FREQ, AVTP_CRF_FIELD_CRF_DATA_LEN, AVTP_CRF_FIELD_TIMESTAMP_INTERVAL, AVTP_CRF_FIELD_MAX, }; /* Get value from CRF AVTPDU field. * @pdu: Pointer to PDU struct. * @field: PDU field to be retrieved. * @val: Pointer to variable which the retrieved value should be saved. * * Returns: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_crf_pdu_get(const struct avtp_crf_pdu *pdu, enum avtp_crf_field field, uint64_t *val); /* Set value from CRF AVTPDU field. * @pdu: Pointer to PDU struct. * @field: PDU field to be set. * @val: Value to be set. * * Returns: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_crf_pdu_set(struct avtp_crf_pdu *pdu, enum avtp_crf_field field, uint64_t val); /* Initialize CRF AVTPDU. All AVTPDU fields are initialized with zero except * 'subtype' (which is set to AVTP_SUBTYPE_CRF) and 'sv' (which is set to 1). * @pdu: Pointer to PDU struct. * * Return values: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_crf_pdu_init(struct avtp_crf_pdu *pdu); #ifdef __cplusplus } #endif libavtp-0.2.0/include/avtp_cvf.h000066400000000000000000000070371420102630700165600ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation * * 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 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. */ #pragma once #include #include #ifdef __cplusplus extern "C" { #endif /* CVF 'format' field values. */ #define AVTP_CVF_FORMAT_RFC 0x02 /* CVF 'format subtype' field values. */ #define AVTP_CVF_FORMAT_SUBTYPE_MJPEG 0x00 #define AVTP_CVF_FORMAT_SUBTYPE_H264 0x01 #define AVTP_CVF_FORMAT_SUBTYPE_JPEG2000 0x02 enum avtp_cvf_field { AVTP_CVF_FIELD_SV, AVTP_CVF_FIELD_MR, AVTP_CVF_FIELD_TV, AVTP_CVF_FIELD_SEQ_NUM, AVTP_CVF_FIELD_TU, AVTP_CVF_FIELD_STREAM_ID, AVTP_CVF_FIELD_TIMESTAMP, AVTP_CVF_FIELD_STREAM_DATA_LEN, AVTP_CVF_FIELD_FORMAT, AVTP_CVF_FIELD_FORMAT_SUBTYPE, AVTP_CVF_FIELD_M, AVTP_CVF_FIELD_EVT, AVTP_CVF_FIELD_H264_PTV, AVTP_CVF_FIELD_H264_TIMESTAMP, AVTP_CVF_FIELD_MAX, }; struct avtp_cvf_h264_payload { uint32_t h264_header; uint8_t h264_data[0]; } __attribute__((__packed__)); /* Get value of CVF AVTPDU field. * @pdu: Pointer to PDU struct. * @field: PDU field to be retrieved. * @val: Pointer to variable which the retrieved value should be saved. * * Returns: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_cvf_pdu_get(const struct avtp_stream_pdu *pdu, enum avtp_cvf_field field, uint64_t *val); /* Set value of CVF AVTPDU field. * @pdu: Pointer to PDU struct. * @field: PDU field to be set. * @val: Value to be set. * * Returns: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_cvf_pdu_set(struct avtp_stream_pdu *pdu, enum avtp_cvf_field field, uint64_t val); /* Initialize CVF AVTPDU. All AVTPDU fields are initialized with zero except * 'subtype' (which is set to AVTP_SUBTYPE_CVF), 'sv' (which is set to 1), * 'format' (which is set to AVTP_CVF_FORMAT_RFC) and 'format_subtype' * (which is set to the `subtype` specified). * @pdu: Pointer to PDU struct. * @subtype: AVTP CVF Format Subtype of this AVTPDU. * * Return values: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_cvf_pdu_init(struct avtp_stream_pdu *pdu, uint8_t subtype); #ifdef __cplusplus } #endif libavtp-0.2.0/include/avtp_ieciidc.h000066400000000000000000000114561420102630700173730ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation * * 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 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. */ #pragma once #include #include #ifdef __cplusplus extern "C" { #endif #define AVTP_IECIIDC_TAG_NO_CIP 0x00 #define AVTP_IECIIDC_TAG_CIP 0x01 enum avtp_ieciidc_field { AVTP_IECIIDC_FIELD_SV, AVTP_IECIIDC_FIELD_MR, AVTP_IECIIDC_FIELD_TV, AVTP_IECIIDC_FIELD_SEQ_NUM, AVTP_IECIIDC_FIELD_TU, AVTP_IECIIDC_FIELD_STREAM_ID, AVTP_IECIIDC_FIELD_TIMESTAMP, AVTP_IECIIDC_FIELD_STREAM_DATA_LEN, AVTP_IECIIDC_FIELD_GV, AVTP_IECIIDC_FIELD_GATEWAY_INFO, AVTP_IECIIDC_FIELD_TAG, AVTP_IECIIDC_FIELD_CHANNEL, AVTP_IECIIDC_FIELD_TCODE, AVTP_IECIIDC_FIELD_SY, AVTP_IECIIDC_FIELD_CIP_QI_1, AVTP_IECIIDC_FIELD_CIP_QI_2, AVTP_IECIIDC_FIELD_CIP_SID, AVTP_IECIIDC_FIELD_CIP_DBS, AVTP_IECIIDC_FIELD_CIP_FN, AVTP_IECIIDC_FIELD_CIP_QPC, AVTP_IECIIDC_FIELD_CIP_SPH, AVTP_IECIIDC_FIELD_CIP_DBC, AVTP_IECIIDC_FIELD_CIP_FMT, AVTP_IECIIDC_FIELD_CIP_SYT, /* Fields defined below are the FDF - Format Dependent Field - fields. * As they are poorly described in the IEEE 1722 - it usually refers to * the IEC 61883-1, which in turn refers to each relevant IEC 61883 * part, this comment is an attempt to summarize the description of * those fields, as described in IEC 61883. * * Note that FDF is the one defined on Figure 23 of IEEE 1722-2016, and * FDF_3 is the one with 3 octets, seen on Figure 24 of the same * standard. * * - IEC 61883-4 uses FDF_3, with fields: * - TSF (Bit 0) * * - IEC 61883-6 uses FDF, with fields: * - EVT (Bits 2-3) * - SFC (Bits 5-7) * - N (Bit 4) * - NO-DATA (All 8 bits set to 1) * * - IEC 61883-7 uses FDF_3, with fields: * - TSF (Bit 0) * * - IEC 61883-8 uses FDF, with fields: * - ND (Bit 0) */ AVTP_IECIIDC_FIELD_CIP_TSF, AVTP_IECIIDC_FIELD_CIP_EVT, AVTP_IECIIDC_FIELD_CIP_SFC, AVTP_IECIIDC_FIELD_CIP_N, AVTP_IECIIDC_FIELD_CIP_ND, AVTP_IECIIDC_FIELD_CIP_NO_DATA, AVTP_IECIIDC_FIELD_MAX, }; struct avtp_ieciidc_cip_payload { uint32_t cip_1; uint32_t cip_2; uint8_t cip_data_payload[0]; }; struct avtp_ieciidc_cip_source_packet { uint32_t avtp_source_packet_header_timestamp; uint8_t cip_with_sph_payload[0]; }; /* Get value from IEC 61883/IIDC AVTPDU field. * @pdu: Pointer to PDU struct. * @field: PDU field to be retrieved. * @val: Pointer to variable which the retrieved value should be saved. * * Returns: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_ieciidc_pdu_get(const struct avtp_stream_pdu *pdu, enum avtp_ieciidc_field field, uint64_t *val); /* Set value from IEC 61883/IIDC AVTPDU field. * @pdu: Pointer to PDU struct. * @field: PDU field to be set. * @val: Value to be set. * * Returns: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_ieciidc_pdu_set(struct avtp_stream_pdu *pdu, enum avtp_ieciidc_field field, uint64_t val); /* Initialize IEC 61883/IIDC AVTPDU. The following fields are pre-initialised: * 'subtype' -> AVTP_SUBTYPE_61883_IIDC * 'sv' -> 0x01 * 'tcode' -> 0x0A * 'tag' -> tag informed on parameter * All other fields are set to zero. * @pdu: Pointer to PDU struct. * @tag: Value of AVTP_IECIIDC_FIELD_TAG. * * Return values: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_ieciidc_pdu_init(struct avtp_stream_pdu *pdu, uint8_t tag); #ifdef __cplusplus } #endif libavtp-0.2.0/include/avtp_rvf.h000066400000000000000000000127011420102630700165710ustar00rootroot00000000000000/* * Copyright (c) 2021, Fastree3D * Adrian Fiergolski * * 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 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. */ #pragma once #include #include #ifdef __cplusplus extern "C" { #endif /* RVF 'pixel depth' field values. */ #define AVTP_RVF_PIXEL_DEPTH_8 0x01 #define AVTP_RVF_PIXEL_DEPTH_10 0x02 #define AVTP_RVF_PIXEL_DEPTH_12 0x03 #define AVTP_RVF_PIXEL_DEPTH_16 0x04 #define AVTP_RVF_PIXEL_DEPTH_USER 0x0F /* RVF 'pixel format' field values. */ #define AVTP_RVF_PIXEL_FORMAT_MONO 0x00 #define AVTP_RVF_PIXEL_FORMAT_411 0x01 #define AVTP_RVF_PIXEL_FORMAT_420 0x02 #define AVTP_RVF_PIXEL_FORMAT_422 0x03 #define AVTP_RVF_PIXEL_FORMAT_444 0x04 #define AVTP_RVF_PIXEL_FORMAT_4224 0x06 #define AVTP_RVF_PIXEL_FORMAT_4444 0x07 #define AVTP_RVF_PIXEL_FORMAT_BAYER_GRBG 0x08 #define AVTP_RVF_PIXEL_FORMAT_BAYER_RGGB 0x09 #define AVTP_RVF_PIXEL_FORMAT_BAYER_BGGR 0x0A #define AVTP_RVF_PIXEL_FORMAT_BAYER_GBRG 0x0B #define AVTP_RVF_PIXEL_FORMAT_USER 0x0F /* RVF 'frame rate' field values. */ #define AVTP_RVF_FRAME_RATE_1 0x01 #define AVTP_RVF_FRAME_RATE_2 0x02 #define AVTP_RVF_FRAME_RATE_5 0x03 #define AVTP_RVF_FRAME_RATE_10 0x10 #define AVTP_RVF_FRAME_RATE_15 0x11 #define AVTP_RVF_FRAME_RATE_20 0x12 #define AVTP_RVF_FRAME_RATE_24 0x13 #define AVTP_RVF_FRAME_RATE_25 0x14 #define AVTP_RVF_FRAME_RATE_30 0x15 #define AVTP_RVF_FRAME_RATE_48 0x16 #define AVTP_RVF_FRAME_RATE_50 0x17 #define AVTP_RVF_FRAME_RATE_60 0x18 #define AVTP_RVF_FRAME_RATE_72 0x19 #define AVTP_RVF_FRAME_RATE_85 0x1A #define AVTP_RVF_FRAME_RATE_100 0x30 #define AVTP_RVF_FRAME_RATE_120 0x31 #define AVTP_RVF_FRAME_RATE_150 0x32 #define AVTP_RVF_FRAME_RATE_200 0x33 #define AVTP_RVF_FRAME_RATE_240 0x34 #define AVTP_RVF_FRAME_RATE_300 0x35 #define AVTP_RVF_FRAME_RATE_USER 0x0F /* RVF 'colorspace' field values. */ #define AVTP_RVF_COLORSPACE_YCbCr 0x01 #define AVTP_RVF_COLORSPACE_SRGB 0x02 #define AVTP_RVF_COLORSPACE_YCgCo 0x03 #define AVTP_RVF_COLORSPACE_GRAY 0x04 #define AVTP_RVF_COLORSPACE_XYZ 0x05 #define AVTP_RVF_COLORSPACE_YCM 0x06 #define AVTP_RVF_COLORSPACE_BT_601 0x07 #define AVTP_RVF_COLORSPACE_BT_709 0x08 #define AVTP_RVF_COLORSPACE_ITU_BT 0x09 #define AVTP_RVF_COLORSPACE_USER 0x0F enum avtp_rvf_field { AVTP_RVF_FIELD_SV, AVTP_RVF_FIELD_MR, AVTP_RVF_FIELD_TV, AVTP_RVF_FIELD_SEQ_NUM, AVTP_RVF_FIELD_TU, AVTP_RVF_FIELD_STREAM_ID, AVTP_RVF_FIELD_TIMESTAMP, AVTP_RVF_FIELD_STREAM_DATA_LEN, AVTP_RVF_FIELD_ACTIVE_PIXELS, AVTP_RVF_FIELD_TOTAL_LINES, AVTP_RVF_FIELD_AP, AVTP_RVF_FIELD_F, AVTP_RVF_FIELD_EF, AVTP_RVF_FIELD_EVT, AVTP_RVF_FIELD_PD, AVTP_RVF_FIELD_I, AVTP_RVF_FIELD_RAW_PIXEL_DEPTH, AVTP_RVF_FIELD_RAW_PIXEL_FORMAT, AVTP_RVF_FIELD_RAW_FRAME_RATE, AVTP_RVF_FIELD_RAW_COLORSPACE, AVTP_RVF_FIELD_RAW_NUM_LINES, AVTP_RVF_FIELD_RAW_I_SEQ_NUM, AVTP_RVF_FIELD_RAW_LINE_NUMBER, AVTP_RVF_FIELD_MAX, }; struct avtp_rvf_payload { uint64_t raw_header; uint8_t raw_data[0]; } __attribute__((__packed__)); /* Get value of RVF AVTPDU field. * @pdu: Pointer to PDU struct. * @field: PDU field to be retrieved. * @val: Pointer to variable which the retrieved value should be saved. * * Returns: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_rvf_pdu_get(const struct avtp_stream_pdu *pdu, enum avtp_rvf_field field, uint64_t *val); /* Set value of RVF AVTPDU field. * @pdu: Pointer to PDU struct. * @field: PDU field to be set. * @val: Value to be set. * * Returns: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_rvf_pdu_set(struct avtp_stream_pdu *pdu, enum avtp_rvf_field field, uint64_t val); /* Initialize RVF AVTPDU. All AVTPDU fields are initialized with zero except * 'subtype' (which is set to AVTP_SUBTYPE_RVF), 'sv' (which is set to 1), * @pdu: Pointer to PDU struct. * @subtype: AVTP CVF Format Subtype of this AVTPDU. * * Return values: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_rvf_pdu_init(struct avtp_stream_pdu *pdu); #ifdef __cplusplus } #endif libavtp-0.2.0/meson.build000066400000000000000000000100751420102630700153120ustar00rootroot00000000000000project( 'libavtp', 'c', version: '0.2.0', license: 'BSD-3-Clause', meson_version: '>=0.46.0', ) avtp_lib = library( 'avtp', [ 'src/avtp.c', 'src/avtp_aaf.c', 'src/avtp_crf.c', 'src/avtp_cvf.c', 'src/avtp_rvf.c', 'src/avtp_ieciidc.c', 'src/avtp_stream.c', ], version: meson.project_version(), include_directories: include_directories('include'), install: true, ) avtp_dep = declare_dependency( link_with: avtp_lib, include_directories: include_directories('include'), ) install_headers( 'include/avtp.h', 'include/avtp_aaf.h', 'include/avtp_crf.h', 'include/avtp_cvf.h', 'include/avtp_rvf.h', 'include/avtp_ieciidc.h', ) pkg = import('pkgconfig') pkg.generate(avtp_lib, description: 'AVTP packetization library', url: 'github.com/AVnu/libavtp', ) if get_option('tests') == 'disabled' cmocka = disabler() else cmocka = dependency('cmocka', required: get_option('tests') == 'enabled') endif if cmocka.found() test_avtp = executable( 'test-avtp', 'unit/test-avtp.c', include_directories: include_directories('include'), link_with: avtp_lib, dependencies: cmocka, build_by_default: false, ) test_aaf = executable( 'test-aaf', 'unit/test-aaf.c', include_directories: include_directories('include'), link_with: avtp_lib, dependencies: cmocka, build_by_default: false, ) test_crf = executable( 'test-crf', 'unit/test-crf.c', include_directories: include_directories('include'), link_with: avtp_lib, dependencies: cmocka, build_by_default: false, ) test_stream = executable( 'test-stream', 'unit/test-stream.c', 'src/avtp_stream.c', include_directories: include_directories('include', 'src'), link_with: avtp_lib, dependencies: cmocka, build_by_default: false, ) test_cvf = executable( 'test-cvf', 'unit/test-cvf.c', include_directories: include_directories('include'), link_with: avtp_lib, dependencies: cmocka, build_by_default: false, ) test_rvf = executable( 'test-rvf', 'unit/test-rvf.c', include_directories: include_directories('include'), link_with: avtp_lib, dependencies: cmocka, build_by_default: false, ) test_ieciidc = executable( 'test-ieciidc', 'unit/test-ieciidc.c', include_directories: include_directories('include'), link_with: avtp_lib, dependencies: cmocka, build_by_default: false, ) test('AVTP API', test_avtp) test('Stream API', test_stream) test('AAF API', test_aaf) test('CRF API', test_crf) test('CVF API', test_cvf) test('RVF API', test_rvf) test('IEC61883/IIDC API', test_ieciidc) endif cc = meson.get_compiler('c') mdep = cc.find_library('m', required : false) executable( 'aaf-talker', 'examples/aaf-talker.c', 'examples/common.c', include_directories: include_directories('include'), link_with: avtp_lib, build_by_default: false, ) executable( 'aaf-listener', 'examples/aaf-listener.c', 'examples/common.c', include_directories: include_directories('include'), link_with: avtp_lib, build_by_default: false, ) executable( 'crf-talker', 'examples/crf-talker.c', 'examples/common.c', include_directories: include_directories('include'), link_with: avtp_lib, dependencies : mdep, build_by_default: false, ) executable( 'crf-listener', 'examples/crf-listener.c', 'examples/common.c', include_directories: include_directories('include'), link_with: avtp_lib, dependencies : mdep, build_by_default: false, ) executable( 'cvf-talker', 'examples/cvf-talker.c', 'examples/common.c', include_directories: include_directories('include'), link_with: avtp_lib, build_by_default: false, ) executable( 'cvf-listener', 'examples/cvf-listener.c', 'examples/common.c', include_directories: include_directories('include'), link_with: avtp_lib, build_by_default: false, ) executable( 'ieciidc-talker', 'examples/ieciidc-talker.c', 'examples/common.c', include_directories: include_directories('include'), link_with: avtp_lib, build_by_default: false, ) executable( 'ieciidc-listener', 'examples/ieciidc-listener.c', 'examples/common.c', include_directories: include_directories('include'), link_with: avtp_lib, build_by_default: false, ) libavtp-0.2.0/meson_options.txt000066400000000000000000000003161420102630700166020ustar00rootroot00000000000000# Port to 'feature' once we depend on meson 0.47.0 option( 'tests', type : 'combo', value : 'auto', choices : ['enabled', 'disabled', 'auto'], description : 'Build unit test libraries') libavtp-0.2.0/src/000077500000000000000000000000001420102630700137345ustar00rootroot00000000000000libavtp-0.2.0/src/avtp.c000066400000000000000000000054241420102630700150570ustar00rootroot00000000000000/* * Copyright (c) 2017, Intel Corporation * * 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 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 #include #include "avtp.h" #include "util.h" #define SHIFT_SUBTYPE (31 - 7) #define SHIFT_VERSION (31 - 11) #define MASK_SUBTYPE (BITMASK(8) << SHIFT_SUBTYPE) #define MASK_VERSION (BITMASK(3) << SHIFT_VERSION) int avtp_pdu_get(const struct avtp_common_pdu *pdu, enum avtp_field field, uint32_t *val) { uint32_t bitmap, mask; uint8_t shift; if (!pdu || !val) return -EINVAL; switch (field) { case AVTP_FIELD_SUBTYPE: mask = MASK_SUBTYPE; shift = SHIFT_SUBTYPE; break; case AVTP_FIELD_VERSION: mask = MASK_VERSION; shift = SHIFT_VERSION; break; default: return -EINVAL; } bitmap = ntohl(pdu->subtype_data); *val = BITMAP_GET_VALUE(bitmap, mask, shift); return 0; } int avtp_pdu_set(struct avtp_common_pdu *pdu, enum avtp_field field, uint32_t value) { uint32_t bitmap, mask; uint8_t shift; if (!pdu) return -EINVAL; switch (field) { case AVTP_FIELD_SUBTYPE: mask = MASK_SUBTYPE; shift = SHIFT_SUBTYPE; break; case AVTP_FIELD_VERSION: mask = MASK_VERSION; shift = SHIFT_VERSION; break; default: return -EINVAL; } bitmap = ntohl(pdu->subtype_data); BITMAP_SET_VALUE(bitmap, value, mask, shift); pdu->subtype_data = htonl(bitmap); return 0; } libavtp-0.2.0/src/avtp_aaf.c000066400000000000000000000136411420102630700156660ustar00rootroot00000000000000/* * Copyright (c) 2017, Intel Corporation * * 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 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 #include #include "avtp.h" #include "avtp_aaf.h" #include "avtp_stream.h" #include "util.h" #define SHIFT_FORMAT (31 - 7) #define SHIFT_NSR (31 - 11) #define SHIFT_CHAN_PER_FRAME (31 - 23) #define SHIFT_SP (31 - 19) #define SHIFT_EVT (31 - 23) #define MASK_FORMAT (BITMASK(8) << SHIFT_FORMAT) #define MASK_NSR (BITMASK(4) << SHIFT_NSR) #define MASK_CHAN_PER_FRAME (BITMASK(10) << SHIFT_CHAN_PER_FRAME) #define MASK_BIT_DEPTH (BITMASK(8)) #define MASK_SP (BITMASK(1) << SHIFT_SP) #define MASK_EVT (BITMASK(4) << SHIFT_EVT) static int get_field_value(const struct avtp_stream_pdu *pdu, enum avtp_aaf_field field, uint64_t *val) { uint32_t bitmap, mask; uint8_t shift; switch (field) { case AVTP_AAF_FIELD_FORMAT: mask = MASK_FORMAT; shift = SHIFT_FORMAT; bitmap = ntohl(pdu->format_specific); break; case AVTP_AAF_FIELD_NSR: mask = MASK_NSR; shift = SHIFT_NSR; bitmap = ntohl(pdu->format_specific); break; case AVTP_AAF_FIELD_CHAN_PER_FRAME: mask = MASK_CHAN_PER_FRAME; shift = SHIFT_CHAN_PER_FRAME; bitmap = ntohl(pdu->format_specific); break; case AVTP_AAF_FIELD_BIT_DEPTH: mask = MASK_BIT_DEPTH; shift = 0; bitmap = ntohl(pdu->format_specific); break; case AVTP_AAF_FIELD_SP: mask = MASK_SP; shift = SHIFT_SP; bitmap = ntohl(pdu->packet_info); break; case AVTP_AAF_FIELD_EVT: mask = MASK_EVT; shift = SHIFT_EVT; bitmap = ntohl(pdu->packet_info); break; default: return -EINVAL; } *val = BITMAP_GET_VALUE(bitmap, mask, shift); return 0; } int avtp_aaf_pdu_get(const struct avtp_stream_pdu *pdu, enum avtp_aaf_field field, uint64_t *val) { int res; if (!pdu || !val) return -EINVAL; switch (field) { case AVTP_AAF_FIELD_SV: case AVTP_AAF_FIELD_MR: case AVTP_AAF_FIELD_TV: case AVTP_AAF_FIELD_SEQ_NUM: case AVTP_AAF_FIELD_TU: case AVTP_AAF_FIELD_STREAM_DATA_LEN: case AVTP_AAF_FIELD_TIMESTAMP: case AVTP_AAF_FIELD_STREAM_ID: res = avtp_stream_pdu_get(pdu, (enum avtp_stream_field) field, val); break; case AVTP_AAF_FIELD_FORMAT: case AVTP_AAF_FIELD_NSR: case AVTP_AAF_FIELD_CHAN_PER_FRAME: case AVTP_AAF_FIELD_BIT_DEPTH: case AVTP_AAF_FIELD_SP: case AVTP_AAF_FIELD_EVT: res = get_field_value(pdu, field, val); break; default: res = -EINVAL; break; } return res; } static int set_field_value(struct avtp_stream_pdu *pdu, enum avtp_aaf_field field, uint32_t val) { uint32_t bitmap, mask; uint8_t shift; void *ptr; switch (field) { case AVTP_AAF_FIELD_FORMAT: mask = MASK_FORMAT; shift = SHIFT_FORMAT; ptr = &pdu->format_specific; break; case AVTP_AAF_FIELD_NSR: mask = MASK_NSR; shift = SHIFT_NSR; ptr = &pdu->format_specific; break; case AVTP_AAF_FIELD_CHAN_PER_FRAME: mask = MASK_CHAN_PER_FRAME; shift = SHIFT_CHAN_PER_FRAME; ptr = &pdu->format_specific; break; case AVTP_AAF_FIELD_BIT_DEPTH: mask = MASK_BIT_DEPTH; shift = 0; ptr = &pdu->format_specific; break; case AVTP_AAF_FIELD_SP: mask = MASK_SP; shift = SHIFT_SP; ptr = &pdu->packet_info; break; case AVTP_AAF_FIELD_EVT: mask = MASK_EVT; shift = SHIFT_EVT; ptr = &pdu->packet_info; break; default: return -EINVAL; } bitmap = get_unaligned_be32(ptr); BITMAP_SET_VALUE(bitmap, val, mask, shift); put_unaligned_be32(bitmap, ptr); return 0; } int avtp_aaf_pdu_set(struct avtp_stream_pdu *pdu, enum avtp_aaf_field field, uint64_t val) { int res; if (!pdu) return -EINVAL; switch (field) { case AVTP_AAF_FIELD_SV: case AVTP_AAF_FIELD_MR: case AVTP_AAF_FIELD_TV: case AVTP_AAF_FIELD_SEQ_NUM: case AVTP_AAF_FIELD_TU: case AVTP_AAF_FIELD_STREAM_DATA_LEN: case AVTP_AAF_FIELD_TIMESTAMP: case AVTP_AAF_FIELD_STREAM_ID: res = avtp_stream_pdu_set(pdu, (enum avtp_stream_field) field, val); break; case AVTP_AAF_FIELD_FORMAT: case AVTP_AAF_FIELD_NSR: case AVTP_AAF_FIELD_CHAN_PER_FRAME: case AVTP_AAF_FIELD_BIT_DEPTH: case AVTP_AAF_FIELD_SP: case AVTP_AAF_FIELD_EVT: res = set_field_value(pdu, field, val); break; default: res = -EINVAL; break; } return res; } int avtp_aaf_pdu_init(struct avtp_stream_pdu *pdu) { int res; if (!pdu) return -EINVAL; memset(pdu, 0, sizeof(struct avtp_stream_pdu)); res = avtp_pdu_set((struct avtp_common_pdu *) pdu, AVTP_FIELD_SUBTYPE, AVTP_SUBTYPE_AAF); if (res < 0) return res; res = avtp_aaf_pdu_set(pdu, AVTP_AAF_FIELD_SV, 1); if (res < 0) return res; return 0; }; libavtp-0.2.0/src/avtp_crf.c000066400000000000000000000156051420102630700157130ustar00rootroot00000000000000/* * Copyright (c) 2018, Intel Corporation * * 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 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 #include #include #include "avtp.h" #include "avtp_crf.h" #include "util.h" #define SHIFT_SV (31 - 8) #define SHIFT_MR (31 - 12) #define SHIFT_FS (31 - 14) #define SHIFT_TU (31 - 15) #define SHIFT_SEQ_NUM (31 - 23) #define SHIFT_PULL (63 - 2) #define SHIFT_BASE_FREQ (63 - 31) #define SHIFT_CRF_DATA_LEN (63 - 47) #define MASK_SV (BITMASK(1) << SHIFT_SV) #define MASK_MR (BITMASK(1) << SHIFT_MR) #define MASK_FS (BITMASK(1) << SHIFT_FS) #define MASK_TU (BITMASK(1) << SHIFT_TU) #define MASK_SEQ_NUM (BITMASK(8) << SHIFT_SEQ_NUM) #define MASK_TYPE (BITMASK(8)) #define MASK_PULL (BITMASK(3) << SHIFT_PULL) #define MASK_BASE_FREQ (BITMASK(29) << SHIFT_BASE_FREQ) #define MASK_CRF_DATA_LEN (BITMASK(16) << SHIFT_CRF_DATA_LEN) #define MASK_TIMESTAMP_INTERVAL (BITMASK(16)) static int get_field_value(const struct avtp_crf_pdu *pdu, enum avtp_crf_field field, uint64_t *val) { uint64_t bitmap, mask; uint8_t shift; switch (field) { case AVTP_CRF_FIELD_SV: mask = MASK_SV; shift = SHIFT_SV; bitmap = ntohl(pdu->subtype_data); break; case AVTP_CRF_FIELD_MR: mask = MASK_MR; shift = SHIFT_MR; bitmap = ntohl(pdu->subtype_data); break; case AVTP_CRF_FIELD_FS: mask = MASK_FS; shift = SHIFT_FS; bitmap = ntohl(pdu->subtype_data); break; case AVTP_CRF_FIELD_TU: mask = MASK_TU; shift = SHIFT_TU; bitmap = ntohl(pdu->subtype_data); break; case AVTP_CRF_FIELD_SEQ_NUM: mask = MASK_SEQ_NUM; shift = SHIFT_SEQ_NUM; bitmap = ntohl(pdu->subtype_data); break; case AVTP_CRF_FIELD_TYPE: mask = MASK_TYPE; shift = 0; bitmap = ntohl(pdu->subtype_data); break; case AVTP_CRF_FIELD_PULL: mask = MASK_PULL; shift = SHIFT_PULL; bitmap = be64toh(pdu->packet_info); break; case AVTP_CRF_FIELD_BASE_FREQ: mask = MASK_BASE_FREQ; shift = SHIFT_BASE_FREQ; bitmap = be64toh(pdu->packet_info); break; case AVTP_CRF_FIELD_CRF_DATA_LEN: mask = MASK_CRF_DATA_LEN; shift = SHIFT_CRF_DATA_LEN; bitmap = be64toh(pdu->packet_info); break; case AVTP_CRF_FIELD_TIMESTAMP_INTERVAL: mask = MASK_TIMESTAMP_INTERVAL; shift = 0; bitmap = be64toh(pdu->packet_info); break; default: return -EINVAL; } *val = BITMAP_GET_VALUE(bitmap, mask, shift); return 0; } int avtp_crf_pdu_get(const struct avtp_crf_pdu *pdu, enum avtp_crf_field field, uint64_t *val) { int res; if (!pdu || !val) return -EINVAL; switch (field) { case AVTP_CRF_FIELD_SV: case AVTP_CRF_FIELD_MR: case AVTP_CRF_FIELD_FS: case AVTP_CRF_FIELD_TU: case AVTP_CRF_FIELD_SEQ_NUM: case AVTP_CRF_FIELD_TYPE: case AVTP_CRF_FIELD_PULL: case AVTP_CRF_FIELD_BASE_FREQ: case AVTP_CRF_FIELD_CRF_DATA_LEN: case AVTP_CRF_FIELD_TIMESTAMP_INTERVAL: res = get_field_value(pdu, field, val); break; case AVTP_CRF_FIELD_STREAM_ID: *val = be64toh(pdu->stream_id); res = 0; break; default: res = -EINVAL; break; } return res; } static int set_field_value_32(struct avtp_crf_pdu *pdu, enum avtp_crf_field field, uint64_t val) { uint32_t bitmap, mask; uint8_t shift; switch (field) { case AVTP_CRF_FIELD_SV: mask = MASK_SV; shift = SHIFT_SV; break; case AVTP_CRF_FIELD_MR: mask = MASK_MR; shift = SHIFT_MR; break; case AVTP_CRF_FIELD_FS: mask = MASK_FS; shift = SHIFT_FS; break; case AVTP_CRF_FIELD_TU: mask = MASK_TU; shift = SHIFT_TU; break; case AVTP_CRF_FIELD_SEQ_NUM: mask = MASK_SEQ_NUM; shift = SHIFT_SEQ_NUM; break; case AVTP_CRF_FIELD_TYPE: mask = MASK_TYPE; shift = 0; break; default: return -EINVAL; } bitmap = ntohl(pdu->subtype_data); BITMAP_SET_VALUE(bitmap, val, mask, shift); pdu->subtype_data = htonl(bitmap); return 0; } static int set_field_value_64(struct avtp_crf_pdu *pdu, enum avtp_crf_field field, uint64_t val) { uint64_t bitmap, mask; uint8_t shift; switch (field) { case AVTP_CRF_FIELD_PULL: mask = MASK_PULL; shift = SHIFT_PULL; break; case AVTP_CRF_FIELD_BASE_FREQ: mask = MASK_BASE_FREQ; shift = SHIFT_BASE_FREQ; break; case AVTP_CRF_FIELD_CRF_DATA_LEN: mask = MASK_CRF_DATA_LEN; shift = SHIFT_CRF_DATA_LEN; break; case AVTP_CRF_FIELD_TIMESTAMP_INTERVAL: mask = MASK_TIMESTAMP_INTERVAL; shift = 0; break; default: return -EINVAL; } bitmap = be64toh(pdu->packet_info); BITMAP_SET_VALUE(bitmap, val, mask, shift); pdu->packet_info = htobe64(bitmap); return 0; } int avtp_crf_pdu_set(struct avtp_crf_pdu *pdu, enum avtp_crf_field field, uint64_t val) { int res; if (!pdu) return -EINVAL; switch (field) { case AVTP_CRF_FIELD_SV: case AVTP_CRF_FIELD_MR: case AVTP_CRF_FIELD_FS: case AVTP_CRF_FIELD_TU: case AVTP_CRF_FIELD_SEQ_NUM: case AVTP_CRF_FIELD_TYPE: res = set_field_value_32(pdu, field, val); break; case AVTP_CRF_FIELD_PULL: case AVTP_CRF_FIELD_BASE_FREQ: case AVTP_CRF_FIELD_CRF_DATA_LEN: case AVTP_CRF_FIELD_TIMESTAMP_INTERVAL: res = set_field_value_64(pdu, field, val); break; case AVTP_CRF_FIELD_STREAM_ID: pdu->stream_id = htobe64(val); res = 0; break; default: res = -EINVAL; } return res; } int avtp_crf_pdu_init(struct avtp_crf_pdu *pdu) { int res; if (!pdu) return -EINVAL; memset(pdu, 0, sizeof(struct avtp_crf_pdu)); res = avtp_pdu_set((struct avtp_common_pdu *) pdu, AVTP_FIELD_SUBTYPE, AVTP_SUBTYPE_CRF); if (res < 0) return res; res = avtp_crf_pdu_set(pdu, AVTP_CRF_FIELD_SV, 1); if (res < 0) return res; return 0; } libavtp-0.2.0/src/avtp_cvf.c000066400000000000000000000145401420102630700157140ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation * * 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 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 #include #include "avtp.h" #include "avtp_cvf.h" #include "avtp_stream.h" #include "util.h" #define SHIFT_FORMAT (31 - 7) #define SHIFT_FORMAT_SUBTYPE (31 - 15) #define SHIFT_M (31 - 19) #define SHIFT_EVT (31 - 23) #define SHIFT_PTV (31 - 18) #define MASK_FORMAT (BITMASK(8) << SHIFT_FORMAT) #define MASK_FORMAT_SUBTYPE (BITMASK(8) << SHIFT_FORMAT_SUBTYPE) #define MASK_M (BITMASK(1) << SHIFT_M) #define MASK_EVT (BITMASK(4) << SHIFT_EVT) #define MASK_PTV (BITMASK(1) << SHIFT_PTV) static int get_field_value(const struct avtp_stream_pdu *pdu, enum avtp_cvf_field field, uint64_t *val) { uint32_t bitmap, mask; uint8_t shift; switch (field) { case AVTP_CVF_FIELD_FORMAT: mask = MASK_FORMAT; shift = SHIFT_FORMAT; bitmap = ntohl(pdu->format_specific); break; case AVTP_CVF_FIELD_FORMAT_SUBTYPE: mask = MASK_FORMAT_SUBTYPE; shift = SHIFT_FORMAT_SUBTYPE; bitmap = ntohl(pdu->format_specific); break; case AVTP_CVF_FIELD_M: mask = MASK_M; shift = SHIFT_M; bitmap = ntohl(pdu->packet_info); break; case AVTP_CVF_FIELD_EVT: mask = MASK_EVT; shift = SHIFT_EVT; bitmap = ntohl(pdu->packet_info); break; case AVTP_CVF_FIELD_H264_PTV: mask = MASK_PTV; shift = SHIFT_PTV; bitmap = ntohl(pdu->packet_info); break; default: return -EINVAL; } *val = BITMAP_GET_VALUE(bitmap, mask, shift); return 0; } int avtp_cvf_pdu_get(const struct avtp_stream_pdu *pdu, enum avtp_cvf_field field, uint64_t *val) { int res; if (!pdu || !val) return -EINVAL; switch (field) { case AVTP_CVF_FIELD_SV: case AVTP_CVF_FIELD_MR: case AVTP_CVF_FIELD_TV: case AVTP_CVF_FIELD_SEQ_NUM: case AVTP_CVF_FIELD_TU: case AVTP_CVF_FIELD_STREAM_DATA_LEN: case AVTP_CVF_FIELD_TIMESTAMP: case AVTP_CVF_FIELD_STREAM_ID: res = avtp_stream_pdu_get(pdu, (enum avtp_stream_field) field, val); break; case AVTP_CVF_FIELD_FORMAT: case AVTP_CVF_FIELD_FORMAT_SUBTYPE: case AVTP_CVF_FIELD_M: case AVTP_CVF_FIELD_EVT: case AVTP_CVF_FIELD_H264_PTV: res = get_field_value(pdu, field, val); break; case AVTP_CVF_FIELD_H264_TIMESTAMP: { /* This field lives on H.264 header, inside avtp_payload */ struct avtp_cvf_h264_payload *pay = (struct avtp_cvf_h264_payload *)pdu->avtp_payload; *val = ntohl(pay->h264_header); res = 0; break; } default: res = -EINVAL; break; } return res; } static int set_field_value(struct avtp_stream_pdu *pdu, enum avtp_cvf_field field, uint32_t val) { uint32_t bitmap, mask; uint8_t shift; void *ptr; switch (field) { case AVTP_CVF_FIELD_FORMAT: mask = MASK_FORMAT; shift = SHIFT_FORMAT; ptr = &pdu->format_specific; break; case AVTP_CVF_FIELD_FORMAT_SUBTYPE: mask = MASK_FORMAT_SUBTYPE; shift = SHIFT_FORMAT_SUBTYPE; ptr = &pdu->format_specific; break; case AVTP_CVF_FIELD_M: mask = MASK_M; shift = SHIFT_M; ptr = &pdu->packet_info; break; case AVTP_CVF_FIELD_EVT: mask = MASK_EVT; shift = SHIFT_EVT; ptr = &pdu->packet_info; break; case AVTP_CVF_FIELD_H264_PTV: mask = MASK_PTV; shift = SHIFT_PTV; ptr = &pdu->packet_info; break; default: return -EINVAL; } bitmap = get_unaligned_be32(ptr); BITMAP_SET_VALUE(bitmap, val, mask, shift); put_unaligned_be32(bitmap, ptr); return 0; } int avtp_cvf_pdu_set(struct avtp_stream_pdu *pdu, enum avtp_cvf_field field, uint64_t val) { int res; if (!pdu) return -EINVAL; switch (field) { case AVTP_CVF_FIELD_SV: case AVTP_CVF_FIELD_MR: case AVTP_CVF_FIELD_TV: case AVTP_CVF_FIELD_SEQ_NUM: case AVTP_CVF_FIELD_TU: case AVTP_CVF_FIELD_STREAM_DATA_LEN: case AVTP_CVF_FIELD_TIMESTAMP: case AVTP_CVF_FIELD_STREAM_ID: res = avtp_stream_pdu_set(pdu, (enum avtp_stream_field) field, val); break; case AVTP_CVF_FIELD_FORMAT: case AVTP_CVF_FIELD_FORMAT_SUBTYPE: case AVTP_CVF_FIELD_M: case AVTP_CVF_FIELD_EVT: case AVTP_CVF_FIELD_H264_PTV: res = set_field_value(pdu, field, val); break; case AVTP_CVF_FIELD_H264_TIMESTAMP: { /* This field lives on H.264 header, inside avtp_payload */ struct avtp_cvf_h264_payload *pay = (struct avtp_cvf_h264_payload *)pdu->avtp_payload; pay->h264_header = htonl(val); res = 0; break; } default: res = -EINVAL; break; } return res; } int avtp_cvf_pdu_init(struct avtp_stream_pdu *pdu, uint8_t subtype) { int res; if (!pdu) return -EINVAL; if (subtype > AVTP_CVF_FORMAT_SUBTYPE_JPEG2000) return -EINVAL; memset(pdu, 0, sizeof(struct avtp_stream_pdu)); res = avtp_pdu_set((struct avtp_common_pdu *) pdu, AVTP_FIELD_SUBTYPE, AVTP_SUBTYPE_CVF); if (res < 0) return res; res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_SV, 1); if (res < 0) return res; res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_FORMAT, AVTP_CVF_FORMAT_RFC); if (res < 0) return res; res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_FORMAT_SUBTYPE, subtype); if (res < 0) return res; return 0; } libavtp-0.2.0/src/avtp_ieciidc.c000066400000000000000000000274711420102630700165360ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation * * 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 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 #include #include #include "avtp.h" #include "avtp_ieciidc.h" #include "avtp_stream.h" #include "util.h" #define SHIFT_GV (31 - 14) #define SHIFT_TAG (31 - 17) #define SHIFT_CHANNEL (31 - 23) #define SHIFT_TCODE (31 - 27) #define SHIFT_QI_1 (31 - 1) #define SHIFT_QI_2 (31 - 1) #define SHIFT_SID (31 - 7) #define SHIFT_DBS (31 - 15) #define SHIFT_FN (31 - 17) #define SHIFT_QPC (31 - 20) #define SHIFT_SPH (31 - 21) #define SHIFT_SPH (31 - 21) #define SHIFT_FMT (31 - 7) #define SHIFT_TSF (31 - 8) #define SHIFT_EVT (31 - 11) #define SHIFT_SFC (31 - 15) #define SHIFT_N (31 - 12) #define SHIFT_NO_DATA (31 - 15) #define SHIFT_ND (31 - 8) #define MASK_GV (BITMASK(1) << SHIFT_GV) #define MASK_TAG (BITMASK(2) << SHIFT_TAG) #define MASK_CHANNEL (BITMASK(6) << SHIFT_CHANNEL) #define MASK_TCODE (BITMASK(4) << SHIFT_TCODE) #define MASK_SY (BITMASK(4)) #define MASK_QI_1 (BITMASK(2) << SHIFT_QI_1) #define MASK_QI_2 (BITMASK(2) << SHIFT_QI_2) #define MASK_SID (BITMASK(6) << SHIFT_SID) #define MASK_DBS (BITMASK(8) << SHIFT_DBS) #define MASK_FN (BITMASK(2) << SHIFT_FN) #define MASK_QPC (BITMASK(3) << SHIFT_QPC) #define MASK_SPH (BITMASK(1) << SHIFT_SPH) #define MASK_DBC (BITMASK(8)) #define MASK_FMT (BITMASK(6) << SHIFT_FMT) #define MASK_SYT (BITMASK(16)) #define MASK_TSF (BITMASK(1) << SHIFT_TSF) #define MASK_EVT (BITMASK(2) << SHIFT_EVT) #define MASK_SFC (BITMASK(3) << SHIFT_SFC) #define MASK_N (BITMASK(1) << SHIFT_N) #define MASK_NO_DATA (BITMASK(8) << SHIFT_NO_DATA) #define MASK_ND (BITMASK(1) << SHIFT_ND) static int get_field_value(const struct avtp_stream_pdu *pdu, enum avtp_ieciidc_field field, uint64_t *val) { uint32_t bitmap, mask; uint8_t shift; struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) pdu->avtp_payload; switch (field) { case AVTP_IECIIDC_FIELD_GV: mask = MASK_GV; shift = SHIFT_GV; bitmap = ntohl(pdu->subtype_data); break; case AVTP_IECIIDC_FIELD_TAG: mask = MASK_TAG; shift = SHIFT_TAG; bitmap = ntohl(pdu->packet_info); break; case AVTP_IECIIDC_FIELD_CHANNEL: mask = MASK_CHANNEL; shift = SHIFT_CHANNEL; bitmap = ntohl(pdu->packet_info); break; case AVTP_IECIIDC_FIELD_TCODE: mask = MASK_TCODE; shift = SHIFT_TCODE; bitmap = ntohl(pdu->packet_info); break; case AVTP_IECIIDC_FIELD_SY: mask = MASK_SY; shift = 0; bitmap = ntohl(pdu->packet_info); break; case AVTP_IECIIDC_FIELD_CIP_QI_1: mask = MASK_QI_1; shift = SHIFT_QI_1; bitmap = ntohl(pay->cip_1); break; case AVTP_IECIIDC_FIELD_CIP_QI_2: mask = MASK_QI_2; shift = SHIFT_QI_2; bitmap = ntohl(pay->cip_2); break; case AVTP_IECIIDC_FIELD_CIP_SID: mask = MASK_SID; shift = SHIFT_SID; bitmap = ntohl(pay->cip_1); break; case AVTP_IECIIDC_FIELD_CIP_DBS: mask = MASK_DBS; shift = SHIFT_DBS; bitmap = ntohl(pay->cip_1); break; case AVTP_IECIIDC_FIELD_CIP_FN: mask = MASK_FN; shift = SHIFT_FN; bitmap = ntohl(pay->cip_1); break; case AVTP_IECIIDC_FIELD_CIP_QPC: mask = MASK_QPC; shift = SHIFT_QPC; bitmap = ntohl(pay->cip_1); break; case AVTP_IECIIDC_FIELD_CIP_SPH: mask = MASK_SPH; shift = SHIFT_SPH; bitmap = ntohl(pay->cip_1); break; case AVTP_IECIIDC_FIELD_CIP_DBC: mask = MASK_DBC; shift = 0; bitmap = ntohl(pay->cip_1); break; case AVTP_IECIIDC_FIELD_CIP_FMT: mask = MASK_FMT; shift = SHIFT_FMT; bitmap = ntohl(pay->cip_2); break; case AVTP_IECIIDC_FIELD_CIP_TSF: mask = MASK_TSF; shift = SHIFT_TSF; bitmap = ntohl(pay->cip_2); break; case AVTP_IECIIDC_FIELD_CIP_EVT: mask = MASK_EVT; shift = SHIFT_EVT; bitmap = ntohl(pay->cip_2); break; case AVTP_IECIIDC_FIELD_CIP_SFC: mask = MASK_SFC; shift = SHIFT_SFC; bitmap = ntohl(pay->cip_2); break; case AVTP_IECIIDC_FIELD_CIP_N: mask = MASK_N; shift = SHIFT_N; bitmap = ntohl(pay->cip_2); break; case AVTP_IECIIDC_FIELD_CIP_ND: mask = MASK_ND; shift = SHIFT_ND; bitmap = ntohl(pay->cip_2); break; case AVTP_IECIIDC_FIELD_CIP_NO_DATA: mask = MASK_NO_DATA; shift = SHIFT_NO_DATA; bitmap = ntohl(pay->cip_2); break; case AVTP_IECIIDC_FIELD_CIP_SYT: mask = MASK_SYT; shift = 0; bitmap = ntohl(pay->cip_2); break; default: return -EINVAL; } *val = BITMAP_GET_VALUE(bitmap, mask, shift); return 0; } int avtp_ieciidc_pdu_get(const struct avtp_stream_pdu *pdu, enum avtp_ieciidc_field field, uint64_t *val) { int res; if (!pdu || !val) return -EINVAL; switch (field) { case AVTP_IECIIDC_FIELD_SV: case AVTP_IECIIDC_FIELD_MR: case AVTP_IECIIDC_FIELD_TV: case AVTP_IECIIDC_FIELD_SEQ_NUM: case AVTP_IECIIDC_FIELD_TU: case AVTP_IECIIDC_FIELD_STREAM_DATA_LEN: case AVTP_IECIIDC_FIELD_TIMESTAMP: case AVTP_IECIIDC_FIELD_STREAM_ID: res = avtp_stream_pdu_get(pdu, (enum avtp_stream_field) field, val); break; case AVTP_IECIIDC_FIELD_GV: case AVTP_IECIIDC_FIELD_TAG: case AVTP_IECIIDC_FIELD_CHANNEL: case AVTP_IECIIDC_FIELD_TCODE: case AVTP_IECIIDC_FIELD_SY: case AVTP_IECIIDC_FIELD_CIP_QI_1: case AVTP_IECIIDC_FIELD_CIP_QI_2: case AVTP_IECIIDC_FIELD_CIP_SID: case AVTP_IECIIDC_FIELD_CIP_DBS: case AVTP_IECIIDC_FIELD_CIP_FN: case AVTP_IECIIDC_FIELD_CIP_QPC: case AVTP_IECIIDC_FIELD_CIP_SPH: case AVTP_IECIIDC_FIELD_CIP_DBC: case AVTP_IECIIDC_FIELD_CIP_FMT: case AVTP_IECIIDC_FIELD_CIP_TSF: case AVTP_IECIIDC_FIELD_CIP_EVT: case AVTP_IECIIDC_FIELD_CIP_SFC: case AVTP_IECIIDC_FIELD_CIP_N: case AVTP_IECIIDC_FIELD_CIP_ND: case AVTP_IECIIDC_FIELD_CIP_NO_DATA: case AVTP_IECIIDC_FIELD_CIP_SYT: res = get_field_value(pdu, field, val); break; case AVTP_IECIIDC_FIELD_GATEWAY_INFO: *val = ntohl(pdu->format_specific); res = 0; break; default: res = -EINVAL; break; } return res; } static int set_field_value(struct avtp_stream_pdu *pdu, enum avtp_ieciidc_field field, uint64_t value) { uint32_t bitmap, mask; uint8_t shift; void *ptr; struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) pdu->avtp_payload; switch (field) { case AVTP_IECIIDC_FIELD_GV: mask = MASK_GV; shift = SHIFT_GV; ptr = &pdu->subtype_data; break; case AVTP_IECIIDC_FIELD_TAG: mask = MASK_TAG; shift = SHIFT_TAG; ptr = &pdu->packet_info; break; case AVTP_IECIIDC_FIELD_CHANNEL: mask = MASK_CHANNEL; shift = SHIFT_CHANNEL; ptr = &pdu->packet_info; break; case AVTP_IECIIDC_FIELD_TCODE: mask = MASK_TCODE; shift = SHIFT_TCODE; ptr = &pdu->packet_info; break; case AVTP_IECIIDC_FIELD_SY: mask = MASK_SY; shift = 0; ptr = &pdu->packet_info; break; case AVTP_IECIIDC_FIELD_CIP_QI_1: mask = MASK_QI_1; shift = SHIFT_QI_1; ptr = &pay->cip_1; break; case AVTP_IECIIDC_FIELD_CIP_QI_2: mask = MASK_QI_2; shift = SHIFT_QI_2; ptr = &pay->cip_2; break; case AVTP_IECIIDC_FIELD_CIP_SID: mask = MASK_SID; shift = SHIFT_SID; ptr = &pay->cip_1; break; case AVTP_IECIIDC_FIELD_CIP_DBS: mask = MASK_DBS; shift = SHIFT_DBS; ptr = &pay->cip_1; break; case AVTP_IECIIDC_FIELD_CIP_FN: mask = MASK_FN; shift = SHIFT_FN; ptr = &pay->cip_1; break; case AVTP_IECIIDC_FIELD_CIP_QPC: mask = MASK_QPC; shift = SHIFT_QPC; ptr = &pay->cip_1; break; case AVTP_IECIIDC_FIELD_CIP_SPH: mask = MASK_SPH; shift = SHIFT_SPH; ptr = &pay->cip_1; break; case AVTP_IECIIDC_FIELD_CIP_DBC: mask = MASK_DBC; shift = 0; ptr = &pay->cip_1; break; case AVTP_IECIIDC_FIELD_CIP_FMT: mask = MASK_FMT; shift = SHIFT_FMT; ptr = &pay->cip_2; break; case AVTP_IECIIDC_FIELD_CIP_TSF: mask = MASK_TSF; shift = SHIFT_TSF; ptr = &pay->cip_2; break; case AVTP_IECIIDC_FIELD_CIP_EVT: mask = MASK_EVT; shift = SHIFT_EVT; ptr = &pay->cip_2; break; case AVTP_IECIIDC_FIELD_CIP_SFC: mask = MASK_SFC; shift = SHIFT_SFC; ptr = &pay->cip_2; break; case AVTP_IECIIDC_FIELD_CIP_N: mask = MASK_N; shift = SHIFT_N; ptr = &pay->cip_2; break; case AVTP_IECIIDC_FIELD_CIP_ND: mask = MASK_ND; shift = SHIFT_ND; ptr = &pay->cip_2; break; case AVTP_IECIIDC_FIELD_CIP_NO_DATA: mask = MASK_NO_DATA; shift = SHIFT_NO_DATA; ptr = &pay->cip_2; break; case AVTP_IECIIDC_FIELD_CIP_SYT: mask = MASK_SYT; shift = 0; ptr = &pay->cip_2; break; default: return -EINVAL; } bitmap = get_unaligned_be32(ptr); BITMAP_SET_VALUE(bitmap, value, mask, shift); put_unaligned_be32(bitmap, ptr); return 0; } int avtp_ieciidc_pdu_set(struct avtp_stream_pdu *pdu, enum avtp_ieciidc_field field, uint64_t value) { int res; if (!pdu) return -EINVAL; switch (field) { case AVTP_IECIIDC_FIELD_SV: case AVTP_IECIIDC_FIELD_MR: case AVTP_IECIIDC_FIELD_TV: case AVTP_IECIIDC_FIELD_SEQ_NUM: case AVTP_IECIIDC_FIELD_TU: case AVTP_IECIIDC_FIELD_STREAM_DATA_LEN: case AVTP_IECIIDC_FIELD_TIMESTAMP: case AVTP_IECIIDC_FIELD_STREAM_ID: res = avtp_stream_pdu_set(pdu, (enum avtp_stream_field) field, value); break; case AVTP_IECIIDC_FIELD_GV: case AVTP_IECIIDC_FIELD_TAG: case AVTP_IECIIDC_FIELD_CHANNEL: case AVTP_IECIIDC_FIELD_TCODE: case AVTP_IECIIDC_FIELD_SY: case AVTP_IECIIDC_FIELD_CIP_QI_1: case AVTP_IECIIDC_FIELD_CIP_QI_2: case AVTP_IECIIDC_FIELD_CIP_SID: case AVTP_IECIIDC_FIELD_CIP_DBS: case AVTP_IECIIDC_FIELD_CIP_FN: case AVTP_IECIIDC_FIELD_CIP_QPC: case AVTP_IECIIDC_FIELD_CIP_SPH: case AVTP_IECIIDC_FIELD_CIP_DBC: case AVTP_IECIIDC_FIELD_CIP_FMT: case AVTP_IECIIDC_FIELD_CIP_TSF: case AVTP_IECIIDC_FIELD_CIP_EVT: case AVTP_IECIIDC_FIELD_CIP_SFC: case AVTP_IECIIDC_FIELD_CIP_N: case AVTP_IECIIDC_FIELD_CIP_ND: case AVTP_IECIIDC_FIELD_CIP_NO_DATA: case AVTP_IECIIDC_FIELD_CIP_SYT: res = set_field_value(pdu, field, value); break; case AVTP_IECIIDC_FIELD_GATEWAY_INFO: pdu->format_specific = htonl(value); res = 0; break; default: res = -EINVAL; break; } return res; } int avtp_ieciidc_pdu_init(struct avtp_stream_pdu *pdu, uint8_t tag) { int res; if (!pdu || tag > 0x01) return -EINVAL; memset(pdu, 0, sizeof(struct avtp_stream_pdu)); res = avtp_pdu_set((struct avtp_common_pdu *) pdu, AVTP_FIELD_SUBTYPE, AVTP_SUBTYPE_61883_IIDC); if (res < 0) return res; res = avtp_stream_pdu_set((struct avtp_stream_pdu *) pdu, AVTP_STREAM_FIELD_SV, 1); if (res < 0) return res; res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_TCODE, 0x0A); if (res < 0) return res; res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_TAG, tag); if (res < 0) return res; return 0; } libavtp-0.2.0/src/avtp_rvf.c000066400000000000000000000245701420102630700157370ustar00rootroot00000000000000/* * Copyright (c) 2021, Fastree3D * Adrian Fiergolski * * 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 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 #include #include "avtp.h" #include "avtp_rvf.h" #include "avtp_stream.h" #include "util.h" #define SHIFT_ACTIVE_PIXELS (31 - 15) #define SHIFT_TOTAL_LINES (31 - 31) #define SHIFT_AP (31 - 16) #define SHIFT_F (31 - 18) #define SHIFT_EF (31 - 19) #define SHIFT_EVT (31 - 23) #define SHIFT_PD (31 - 24) #define SHIFT_I (31 - 25) #define SHIFT_RAW_PIXEL_DEPTH (63 - 11) #define SHIFT_RAW_PIXEL_FORMAT (63 - 15) #define SHIFT_RAW_FRAME_RATE (63 - 23) #define SHIFT_RAW_COLORSPACE (63 - 27) #define SHIFT_RAW_NUM_LINES (63 - 31) #define SHIFT_RAW_I_SEQ_NUM (63 - 47) #define SHIFT_RAW_LINE_NUMBER (63 - 63) #define MASK_ACTIVE_PIXELS (BITMASK(16) << SHIFT_ACTIVE_PIXELS) #define MASK_TOTAL_LINES (BITMASK(16) << SHIFT_TOTAL_LINES) #define MASK_AP (BITMASK(1) << SHIFT_AP) #define MASK_F (BITMASK(1) << SHIFT_F) #define MASK_EF (BITMASK(1) << SHIFT_EF) #define MASK_EVT (BITMASK(4) << SHIFT_EVT) #define MASK_PD (BITMASK(1) << SHIFT_PD) #define MASK_I (BITMASK(1) << SHIFT_I) #define MASK_RAW_PIXEL_DEPTH (BITMASK(4) << SHIFT_RAW_PIXEL_DEPTH) #define MASK_RAW_PIXEL_FORMAT (BITMASK(4) << SHIFT_RAW_PIXEL_FORMAT) #define MASK_RAW_FRAME_RATE (BITMASK(8) << SHIFT_RAW_FRAME_RATE) #define MASK_RAW_COLORSPACE (BITMASK(4) << SHIFT_RAW_COLORSPACE) #define MASK_RAW_NUM_LINES (BITMASK(4) << SHIFT_RAW_NUM_LINES) #define MASK_RAW_I_SEQ_NUM (BITMASK(8) << SHIFT_RAW_I_SEQ_NUM) #define MASK_RAW_LINE_NUMBER (BITMASK(16) << SHIFT_RAW_LINE_NUMBER) static int get_field_value(const struct avtp_stream_pdu *pdu, enum avtp_rvf_field field, uint64_t *val) { uint32_t bitmap, mask; uint8_t shift; switch (field) { case AVTP_RVF_FIELD_ACTIVE_PIXELS: mask = MASK_ACTIVE_PIXELS; shift = SHIFT_ACTIVE_PIXELS; bitmap = ntohl(pdu->format_specific); break; case AVTP_RVF_FIELD_TOTAL_LINES: mask = MASK_TOTAL_LINES; shift = SHIFT_TOTAL_LINES; bitmap = ntohl(pdu->format_specific); break; case AVTP_RVF_FIELD_AP: mask = MASK_AP; shift = SHIFT_AP; bitmap = ntohl(pdu->packet_info); break; case AVTP_RVF_FIELD_F: mask = MASK_F; shift = SHIFT_F; bitmap = ntohl(pdu->packet_info); break; case AVTP_RVF_FIELD_EF: mask = MASK_EF; shift = SHIFT_EF; bitmap = ntohl(pdu->packet_info); break; case AVTP_RVF_FIELD_EVT: mask = MASK_EVT; shift = SHIFT_EVT; bitmap = ntohl(pdu->packet_info); break; case AVTP_RVF_FIELD_PD: mask = MASK_PD; shift = SHIFT_PD; bitmap = ntohl(pdu->packet_info); break; case AVTP_RVF_FIELD_I: mask = MASK_I; shift = SHIFT_I; bitmap = ntohl(pdu->packet_info); break; default: return -EINVAL; } *val = BITMAP_GET_VALUE(bitmap, mask, shift); return 0; } static int get_raw_field_value(const uint64_t bitmap, enum avtp_rvf_field field, uint64_t *val) { uint64_t mask; uint8_t shift; switch (field) { case AVTP_RVF_FIELD_RAW_PIXEL_DEPTH: mask = MASK_RAW_PIXEL_DEPTH; shift = SHIFT_RAW_PIXEL_DEPTH; break; case AVTP_RVF_FIELD_RAW_PIXEL_FORMAT: mask = MASK_RAW_PIXEL_FORMAT; shift = SHIFT_RAW_PIXEL_FORMAT; break; case AVTP_RVF_FIELD_RAW_FRAME_RATE: mask = MASK_RAW_FRAME_RATE; shift = SHIFT_RAW_FRAME_RATE; break; case AVTP_RVF_FIELD_RAW_COLORSPACE: mask = MASK_RAW_COLORSPACE; shift = SHIFT_RAW_COLORSPACE; break; case AVTP_RVF_FIELD_RAW_NUM_LINES: mask = MASK_RAW_NUM_LINES; shift = SHIFT_RAW_NUM_LINES; break; case AVTP_RVF_FIELD_RAW_I_SEQ_NUM: mask = MASK_RAW_I_SEQ_NUM; shift = SHIFT_RAW_I_SEQ_NUM; break; case AVTP_RVF_FIELD_RAW_LINE_NUMBER: mask = MASK_RAW_LINE_NUMBER; shift = SHIFT_RAW_LINE_NUMBER; break; default: return -EINVAL; } *val = BITMAP_GET_VALUE(bitmap, mask, shift); return 0; } int avtp_rvf_pdu_get(const struct avtp_stream_pdu *pdu, enum avtp_rvf_field field, uint64_t *val) { int res; if (!pdu || !val) return -EINVAL; switch (field) { case AVTP_RVF_FIELD_SV: case AVTP_RVF_FIELD_MR: case AVTP_RVF_FIELD_TV: case AVTP_RVF_FIELD_SEQ_NUM: case AVTP_RVF_FIELD_TU: case AVTP_RVF_FIELD_STREAM_DATA_LEN: case AVTP_RVF_FIELD_TIMESTAMP: case AVTP_RVF_FIELD_STREAM_ID: res = avtp_stream_pdu_get(pdu, (enum avtp_stream_field)field, val); break; case AVTP_RVF_FIELD_ACTIVE_PIXELS: case AVTP_RVF_FIELD_TOTAL_LINES: case AVTP_RVF_FIELD_AP: case AVTP_RVF_FIELD_F: case AVTP_RVF_FIELD_EF: case AVTP_RVF_FIELD_EVT: case AVTP_RVF_FIELD_PD: case AVTP_RVF_FIELD_I: res = get_field_value(pdu, field, val); break; case AVTP_RVF_FIELD_RAW_PIXEL_DEPTH: case AVTP_RVF_FIELD_RAW_PIXEL_FORMAT: case AVTP_RVF_FIELD_RAW_FRAME_RATE: case AVTP_RVF_FIELD_RAW_COLORSPACE: case AVTP_RVF_FIELD_RAW_NUM_LINES: case AVTP_RVF_FIELD_RAW_I_SEQ_NUM: case AVTP_RVF_FIELD_RAW_LINE_NUMBER: { /* These fields lives on RAW header, inside avtp_payload */ struct avtp_rvf_payload *pay = (struct avtp_rvf_payload *)pdu->avtp_payload; res = get_raw_field_value(be64toh(pay->raw_header), field, val); break; } default: res = -EINVAL; break; } return res; } static int set_field_value(struct avtp_stream_pdu *pdu, enum avtp_rvf_field field, uint32_t val) { uint32_t bitmap, mask; uint8_t shift; void *ptr; switch (field) { case AVTP_RVF_FIELD_ACTIVE_PIXELS: mask = MASK_ACTIVE_PIXELS; shift = SHIFT_ACTIVE_PIXELS; ptr = &pdu->format_specific; break; case AVTP_RVF_FIELD_TOTAL_LINES: mask = MASK_TOTAL_LINES; shift = SHIFT_TOTAL_LINES; ptr = &pdu->format_specific; break; case AVTP_RVF_FIELD_AP: mask = MASK_AP; shift = SHIFT_AP; ptr = &pdu->packet_info; break; case AVTP_RVF_FIELD_F: mask = MASK_F; shift = SHIFT_F; ptr = &pdu->packet_info; break; case AVTP_RVF_FIELD_EF: mask = MASK_EF; shift = SHIFT_EF; ptr = &pdu->packet_info; break; case AVTP_RVF_FIELD_EVT: mask = MASK_EVT; shift = SHIFT_EVT; ptr = &pdu->packet_info; break; case AVTP_RVF_FIELD_PD: mask = MASK_PD; shift = SHIFT_PD; ptr = &pdu->packet_info; break; case AVTP_RVF_FIELD_I: mask = MASK_I; shift = SHIFT_I; ptr = &pdu->packet_info; break; default: return -EINVAL; } bitmap = get_unaligned_be32(ptr); BITMAP_SET_VALUE(bitmap, val, mask, shift); put_unaligned_be32(bitmap, ptr); return 0; } static int set_raw_field_value(struct avtp_rvf_payload *pay, enum avtp_rvf_field field, uint64_t val) { uint64_t bitmap, mask; uint8_t shift; switch (field) { case AVTP_RVF_FIELD_RAW_PIXEL_DEPTH: mask = MASK_RAW_PIXEL_DEPTH; shift = SHIFT_RAW_PIXEL_DEPTH; break; case AVTP_RVF_FIELD_RAW_PIXEL_FORMAT: mask = MASK_RAW_PIXEL_FORMAT; shift = SHIFT_RAW_PIXEL_FORMAT; break; case AVTP_RVF_FIELD_RAW_FRAME_RATE: mask = MASK_RAW_FRAME_RATE; shift = SHIFT_RAW_FRAME_RATE; break; case AVTP_RVF_FIELD_RAW_COLORSPACE: mask = MASK_RAW_COLORSPACE; shift = SHIFT_RAW_COLORSPACE; break; case AVTP_RVF_FIELD_RAW_NUM_LINES: mask = MASK_RAW_NUM_LINES; shift = SHIFT_RAW_NUM_LINES; break; case AVTP_RVF_FIELD_RAW_I_SEQ_NUM: mask = MASK_RAW_I_SEQ_NUM; shift = SHIFT_RAW_I_SEQ_NUM; break; case AVTP_RVF_FIELD_RAW_LINE_NUMBER: mask = MASK_RAW_LINE_NUMBER; shift = SHIFT_RAW_LINE_NUMBER; break; default: return -EINVAL; } bitmap = be64toh(pay->raw_header); BITMAP_SET_VALUE(bitmap, val, mask, shift); pay->raw_header = htobe64(bitmap); return 0; } int avtp_rvf_pdu_set(struct avtp_stream_pdu *pdu, enum avtp_rvf_field field, uint64_t val) { int res; if (!pdu) return -EINVAL; switch (field) { case AVTP_RVF_FIELD_SV: case AVTP_RVF_FIELD_MR: case AVTP_RVF_FIELD_TV: case AVTP_RVF_FIELD_SEQ_NUM: case AVTP_RVF_FIELD_TU: case AVTP_RVF_FIELD_STREAM_DATA_LEN: case AVTP_RVF_FIELD_TIMESTAMP: case AVTP_RVF_FIELD_STREAM_ID: res = avtp_stream_pdu_set(pdu, (enum avtp_stream_field)field, val); break; case AVTP_RVF_FIELD_ACTIVE_PIXELS: case AVTP_RVF_FIELD_TOTAL_LINES: case AVTP_RVF_FIELD_AP: case AVTP_RVF_FIELD_F: case AVTP_RVF_FIELD_EF: case AVTP_RVF_FIELD_EVT: case AVTP_RVF_FIELD_PD: case AVTP_RVF_FIELD_I: res = set_field_value(pdu, field, val); break; case AVTP_RVF_FIELD_RAW_PIXEL_DEPTH: case AVTP_RVF_FIELD_RAW_PIXEL_FORMAT: case AVTP_RVF_FIELD_RAW_FRAME_RATE: case AVTP_RVF_FIELD_RAW_COLORSPACE: case AVTP_RVF_FIELD_RAW_NUM_LINES: case AVTP_RVF_FIELD_RAW_I_SEQ_NUM: case AVTP_RVF_FIELD_RAW_LINE_NUMBER: { /* These fields lives on RAW header, inside avtp_payload */ res = set_raw_field_value( (struct avtp_rvf_payload *)pdu->avtp_payload, field, val); break; } default: res = -EINVAL; break; } return res; } int avtp_rvf_pdu_init(struct avtp_stream_pdu *pdu) { int res; if (!pdu) return -EINVAL; memset(pdu, 0, sizeof(struct avtp_stream_pdu)); res = avtp_pdu_set((struct avtp_common_pdu *)pdu, AVTP_FIELD_SUBTYPE, AVTP_SUBTYPE_RVF); if (res < 0) return res; res = avtp_rvf_pdu_set(pdu, AVTP_RVF_FIELD_SV, 1); if (res < 0) return res; return 0; } libavtp-0.2.0/src/avtp_stream.c000066400000000000000000000124021420102630700164240ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation * * 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 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 #include #include "avtp.h" #include "avtp_stream.h" #include "util.h" #define SHIFT_SV (31 - 8) #define SHIFT_MR (31 - 12) #define SHIFT_TV (31 - 15) #define SHIFT_SEQ_NUM (31 - 23) #define SHIFT_STREAM_DATA_LEN (31 - 15) #define MASK_SV (BITMASK(1) << SHIFT_SV) #define MASK_MR (BITMASK(1) << SHIFT_MR) #define MASK_TV (BITMASK(1) << SHIFT_TV) #define MASK_SEQ_NUM (BITMASK(8) << SHIFT_SEQ_NUM) #define MASK_TU (BITMASK(1)) #define MASK_STREAM_DATA_LEN (BITMASK(16) << SHIFT_STREAM_DATA_LEN) static int get_field_value(const struct avtp_stream_pdu *pdu, enum avtp_stream_field field, uint64_t *val) { uint32_t bitmap, mask; uint8_t shift; switch (field) { case AVTP_STREAM_FIELD_SV: mask = MASK_SV; shift = SHIFT_SV; bitmap = ntohl(pdu->subtype_data); break; case AVTP_STREAM_FIELD_MR: mask = MASK_MR; shift = SHIFT_MR; bitmap = ntohl(pdu->subtype_data); break; case AVTP_STREAM_FIELD_TV: mask = MASK_TV; shift = SHIFT_TV; bitmap = ntohl(pdu->subtype_data); break; case AVTP_STREAM_FIELD_SEQ_NUM: mask = MASK_SEQ_NUM; shift = SHIFT_SEQ_NUM; bitmap = ntohl(pdu->subtype_data); break; case AVTP_STREAM_FIELD_TU: mask = MASK_TU; shift = 0; bitmap = ntohl(pdu->subtype_data); break; case AVTP_STREAM_FIELD_STREAM_DATA_LEN: mask = MASK_STREAM_DATA_LEN; shift = SHIFT_STREAM_DATA_LEN; bitmap = ntohl(pdu->packet_info); break; default: return -EINVAL; } *val = BITMAP_GET_VALUE(bitmap, mask, shift); return 0; } int avtp_stream_pdu_get(const struct avtp_stream_pdu *pdu, enum avtp_stream_field field, uint64_t *val) { int res; if (!pdu || !val) return -EINVAL; switch (field) { case AVTP_STREAM_FIELD_SV: case AVTP_STREAM_FIELD_MR: case AVTP_STREAM_FIELD_TV: case AVTP_STREAM_FIELD_SEQ_NUM: case AVTP_STREAM_FIELD_TU: case AVTP_STREAM_FIELD_STREAM_DATA_LEN: res = get_field_value(pdu, field, val); break; case AVTP_STREAM_FIELD_TIMESTAMP: *val = ntohl(pdu->avtp_time); res = 0; break; case AVTP_STREAM_FIELD_STREAM_ID: *val = be64toh(pdu->stream_id); res = 0; break; default: return -EINVAL; } return res; } static int set_field_value(struct avtp_stream_pdu *pdu, enum avtp_stream_field field, uint64_t val) { uint32_t bitmap, mask; uint8_t shift; void *ptr; switch (field) { case AVTP_STREAM_FIELD_SV: mask = MASK_SV; shift = SHIFT_SV; ptr = &pdu->subtype_data; break; case AVTP_STREAM_FIELD_MR: mask = MASK_MR; shift = SHIFT_MR; ptr = &pdu->subtype_data; break; case AVTP_STREAM_FIELD_TV: mask = MASK_TV; shift = SHIFT_TV; ptr = &pdu->subtype_data; break; case AVTP_STREAM_FIELD_SEQ_NUM: mask = MASK_SEQ_NUM; shift = SHIFT_SEQ_NUM; ptr = &pdu->subtype_data; break; case AVTP_STREAM_FIELD_TU: mask = MASK_TU; shift = 0; ptr = &pdu->subtype_data; break; case AVTP_STREAM_FIELD_STREAM_DATA_LEN: mask = MASK_STREAM_DATA_LEN; shift = SHIFT_STREAM_DATA_LEN; ptr = &pdu->packet_info; break; default: return -EINVAL; } bitmap = get_unaligned_be32(ptr); BITMAP_SET_VALUE(bitmap, val, mask, shift); put_unaligned_be32(bitmap, ptr); return 0; } int avtp_stream_pdu_set(struct avtp_stream_pdu *pdu, enum avtp_stream_field field, uint64_t value) { int res; if (!pdu) return -EINVAL; switch (field) { case AVTP_STREAM_FIELD_SV: case AVTP_STREAM_FIELD_MR: case AVTP_STREAM_FIELD_TV: case AVTP_STREAM_FIELD_SEQ_NUM: case AVTP_STREAM_FIELD_TU: case AVTP_STREAM_FIELD_STREAM_DATA_LEN: res = set_field_value(pdu, field, value); break; case AVTP_STREAM_FIELD_TIMESTAMP: pdu->avtp_time = htonl(value); res = 0; break; case AVTP_STREAM_FIELD_STREAM_ID: pdu->stream_id = htobe64(value); res = 0; break; default: return -EINVAL; } return res; } libavtp-0.2.0/src/avtp_stream.h000066400000000000000000000066431420102630700164430ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation * * 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 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. */ #pragma once #include #include #pragma GCC visibility push(hidden) #ifdef __cplusplus extern "C" { #endif /* XXX: To be able to use the functions provided by this header, * without needing to direct "translate" enum values, it is necessary * that any format specific enum have the following fields (excluding * AVTP_STREAM_FIELD_MAX) in the same order as below. For instance, * some `enum avtp_newformat_field` would start like: * * enum avtp_newformat_field { * AVTP_NEWFORMAT_FIELD_SV, * AVTP_NEWFORMAT_FIELD_MR, * // (other stream fields here) * AVTP_NEWFORMAT_FIELD_XYZ, * // (other newformat specific fields here) * } * * This way, one can simply cast enums when calling functions from this * header: * * avtp_stream_pdu_get(pdu, (enum avtp_stream_field) field, val); * * Otherwise, the mapping step would be necessary before the calls. */ enum avtp_stream_field { AVTP_STREAM_FIELD_SV, AVTP_STREAM_FIELD_MR, AVTP_STREAM_FIELD_TV, AVTP_STREAM_FIELD_SEQ_NUM, AVTP_STREAM_FIELD_TU, AVTP_STREAM_FIELD_STREAM_ID, AVTP_STREAM_FIELD_TIMESTAMP, AVTP_STREAM_FIELD_STREAM_DATA_LEN, AVTP_STREAM_FIELD_MAX }; /* Get value from Stream AVTPDU field. * @pdu: Pointer to PDU struct. * @field: PDU field to be retrieved. * @val: Pointer to variable which the retrieved value should be saved. * * Returns: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_stream_pdu_get(const struct avtp_stream_pdu *pdu, enum avtp_stream_field field, uint64_t *val); /* Set value from Stream AVTPDU field. * @pdu: Pointer to PDU struct. * @field: PDU field to be set. * @val: Value to be set. * * Returns: * 0: Success. * -EINVAL: If any argument is invalid. */ int avtp_stream_pdu_set(struct avtp_stream_pdu *pdu, enum avtp_stream_field field, uint64_t val); #ifdef __cplusplus } #endif #pragma GCC visibility pop libavtp-0.2.0/src/util.h000066400000000000000000000046771420102630700151000ustar00rootroot00000000000000/* * Copyright (c) 2017, Intel Corporation * * 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 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. */ #pragma once #define BIT(n) (1ULL << n) #define BITMASK(len) (BIT(len) - 1) /* Get value from the bits within 'bitmap' represented by 'mask'. The 'mask' * parameter must be a continuous bit mask (e.g. 0b00111000). This macro * doesn't work with non-continuous bit masks (e.g. 0b00101001). */ #define BITMAP_GET_VALUE(bitmap, mask, shift) \ ((bitmap & mask) >> shift) /* Set the value 'val' in the 'bitmap' variable at the position represented by * 'mask'. */ #define BITMAP_SET_VALUE(bitmap, val, mask, shift) \ (bitmap = (bitmap & ~mask) | ((val << shift) & mask)) struct __una_u32 { uint32_t x; } __attribute__((packed)); static inline uint32_t get_unaligned_be32(const void *p) { const struct __una_u32 *ptr = (const struct __una_u32 *)p; return ntohl(ptr->x); } static inline void put_unaligned_be32(uint32_t val, void *p) { struct __una_u32 *ptr = (struct __una_u32 *)p; ptr->x = htonl(val); } libavtp-0.2.0/travis.sh000077500000000000000000000003441420102630700150150ustar00rootroot00000000000000#!/bin/bash set -ev mkdir build CFLAGS=-Wno-missing-braces meson . build ninja -C build/ \ test \ aaf-talker \ aaf-listener \ crf-talker \ crf-listener \ cvf-talker \ cvf-listener \ ieciidc-talker \ ieciidc-listener libavtp-0.2.0/unit/000077500000000000000000000000001420102630700141245ustar00rootroot00000000000000libavtp-0.2.0/unit/test-aaf.c000066400000000000000000000343041420102630700160000ustar00rootroot00000000000000/* * Copyright (c) 2017, Intel Corporation * * 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 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 #include #include #include #include #include "avtp.h" #include "avtp_aaf.h" static void aaf_get_field_null_pdu(void **state) { int res; uint64_t val = 1; res = avtp_aaf_pdu_get(NULL, AVTP_AAF_FIELD_SV, &val); assert_int_equal(res, -EINVAL); } static void aaf_get_field_null_val(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_aaf_pdu_get(&pdu, AVTP_AAF_FIELD_SV, NULL); assert_int_equal(res, -EINVAL); } static void aaf_get_field_invalid_field(void **state) { int res; uint64_t val = 1; struct avtp_stream_pdu pdu = { 0 }; res = avtp_aaf_pdu_get(&pdu, AVTP_AAF_FIELD_MAX, &val); assert_int_equal(res, -EINVAL); } static void aaf_get_field_sv(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'sv' field to 1. */ pdu.subtype_data = htonl(0x00800000); res = avtp_aaf_pdu_get(&pdu, AVTP_AAF_FIELD_SV, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void aaf_get_field_mr(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'mr' field to 1. */ pdu.subtype_data = htonl(0x00080000); res = avtp_aaf_pdu_get(&pdu, AVTP_AAF_FIELD_MR, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void aaf_get_field_tv(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'tv' field to 1. */ pdu.subtype_data = htonl(0x00010000); res = avtp_aaf_pdu_get(&pdu, AVTP_AAF_FIELD_TV, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void aaf_get_field_seq_num(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'sequence_num' field to 0x55. */ pdu.subtype_data = htonl(0x00005500); res = avtp_aaf_pdu_get(&pdu, AVTP_AAF_FIELD_SEQ_NUM, &val); assert_int_equal(res, 0); assert_true(val == 0x55); } static void aaf_get_field_tu(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'tu' field to 1. */ pdu.subtype_data = htonl(0x00000001); res = avtp_aaf_pdu_get(&pdu, AVTP_AAF_FIELD_TU, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void aaf_get_field_stream_id(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'stream_id' field to 0xAABBCCDDEEFF0001. */ pdu.stream_id = htobe64(0xAABBCCDDEEFF0001); res = avtp_aaf_pdu_get(&pdu, AVTP_AAF_FIELD_STREAM_ID, &val); assert_int_equal(res, 0); assert_true(val == 0xAABBCCDDEEFF0001); } static void aaf_get_field_timestamp(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'avtp_timestamp' field to 0x80C0FFEE. */ pdu.avtp_time = htonl(0x80C0FFEE); res = avtp_aaf_pdu_get(&pdu, AVTP_AAF_FIELD_TIMESTAMP, &val); assert_int_equal(res, 0); assert_true(val == 0x80C0FFEE); } static void aaf_get_field_format(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'format' field to AVTP_AAF_FORMAT_INT_16BIT. */ pdu.format_specific = htonl(0x04000000); res = avtp_aaf_pdu_get(&pdu, AVTP_AAF_FIELD_FORMAT, &val); assert_int_equal(res, 0); assert_true(val == AVTP_AAF_FORMAT_INT_16BIT); } static void aaf_get_field_nsr(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'nsr' field to AVTP_AAF_PCM_NSR_48KHZ. */ pdu.format_specific = htonl(0x00500000); res = avtp_aaf_pdu_get(&pdu, AVTP_AAF_FIELD_NSR, &val); assert_int_equal(res, 0); assert_true(val == AVTP_AAF_PCM_NSR_48KHZ); } static void aaf_get_field_chan(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'channels_per_frame' field to 0x2AA. */ pdu.format_specific = htonl(0x0002AA00); res = avtp_aaf_pdu_get(&pdu, AVTP_AAF_FIELD_CHAN_PER_FRAME, &val); assert_int_equal(res, 0); assert_true(val == 0x2AA); } static void aaf_get_field_depth(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'bit_depth' field to 0xA5. */ pdu.format_specific = htonl(0x000000A5); res = avtp_aaf_pdu_get(&pdu, AVTP_AAF_FIELD_BIT_DEPTH, &val); assert_int_equal(res, 0); assert_true(val == 0xA5); } static void aaf_get_field_data_len(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'stream_data_length' field to 0xAAAA. */ pdu.packet_info = htonl(0xAAAA0000); res = avtp_aaf_pdu_get(&pdu, AVTP_AAF_FIELD_STREAM_DATA_LEN, &val); assert_int_equal(res, 0); assert_true(val == 0xAAAA); } static void aaf_get_field_sp(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'sp' field to AVTP_AAF_PCM_SP_SPARSE. */ pdu.packet_info = htonl(0x00001000); res = avtp_aaf_pdu_get(&pdu, AVTP_AAF_FIELD_SP, &val); assert_int_equal(res, 0); assert_true(val == AVTP_AAF_PCM_SP_SPARSE); } static void aaf_get_field_evt(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'evt' field to 0xA. */ pdu.packet_info = htonl(0x00000A00); res = avtp_aaf_pdu_get(&pdu, AVTP_AAF_FIELD_EVT, &val); assert_int_equal(res, 0); assert_true(val == 0xA); } static void aaf_set_field_null_pdu(void **state) { int res; res = avtp_aaf_pdu_set(NULL, AVTP_AAF_FIELD_SV, 1); assert_int_equal(res, -EINVAL); } static void aaf_set_field_invalid_field(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_aaf_pdu_set(&pdu, AVTP_AAF_FIELD_MAX, 1); assert_int_equal(res, -EINVAL); } static void aaf_set_field_sv(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_aaf_pdu_set(&pdu, AVTP_AAF_FIELD_SV, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00800000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void aaf_set_field_mr(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_aaf_pdu_set(&pdu, AVTP_AAF_FIELD_MR, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00080000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void aaf_set_field_tv(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_aaf_pdu_set(&pdu, AVTP_AAF_FIELD_TV, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00010000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void aaf_set_field_seq_num(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_aaf_pdu_set(&pdu, AVTP_AAF_FIELD_SEQ_NUM, 0x55); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00005500); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void aaf_set_field_tu(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_aaf_pdu_set(&pdu, AVTP_AAF_FIELD_TU, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00000001); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void aaf_set_field_stream_id(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_aaf_pdu_set(&pdu, AVTP_AAF_FIELD_STREAM_ID, 0xAABBCCDDEEFF0001); assert_int_equal(res, 0); assert_true(be64toh(pdu.stream_id) == 0xAABBCCDDEEFF0001); assert_true(pdu.subtype_data == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void aaf_set_field_timestamp(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_aaf_pdu_set(&pdu, AVTP_AAF_FIELD_TIMESTAMP, 0x80C0FFEE); assert_int_equal(res, 0); assert_true(ntohl(pdu.avtp_time) == 0x80C0FFEE); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void aaf_set_field_format(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_aaf_pdu_set(&pdu, AVTP_AAF_FIELD_FORMAT, AVTP_AAF_FORMAT_INT_16BIT); assert_int_equal(res, 0); assert_true(ntohl(pdu.format_specific) == 0x04000000); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.packet_info == 0); } static void aaf_set_field_nsr(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_aaf_pdu_set(&pdu, AVTP_AAF_FIELD_NSR, AVTP_AAF_PCM_NSR_48KHZ); assert_int_equal(res, 0); assert_true(ntohl(pdu.format_specific) == 0x00500000); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.packet_info == 0); } static void aaf_set_field_chan(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_aaf_pdu_set(&pdu, AVTP_AAF_FIELD_CHAN_PER_FRAME, 0x2AA); assert_int_equal(res, 0); assert_true(ntohl(pdu.format_specific) == 0x0002AA00); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.packet_info == 0); } static void aaf_set_field_depth(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_aaf_pdu_set(&pdu, AVTP_AAF_FIELD_BIT_DEPTH, 0xA5); assert_int_equal(res, 0); assert_true(ntohl(pdu.format_specific) == 0x000000A5); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.packet_info == 0); } static void aaf_set_field_data_len(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_aaf_pdu_set(&pdu, AVTP_AAF_FIELD_STREAM_DATA_LEN, 0xAAAA); assert_int_equal(res, 0); assert_true(ntohl(pdu.packet_info) == 0xAAAA0000); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); } static void aaf_set_field_sp(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_aaf_pdu_set(&pdu, AVTP_AAF_FIELD_SP, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.packet_info) == 0x00001000); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); } static void aaf_set_field_evt(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_aaf_pdu_set(&pdu, AVTP_AAF_FIELD_EVT, 0xA); assert_int_equal(res, 0); assert_true(ntohl(pdu.packet_info) == 0x00000A00); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); } static void aaf_pdu_init_null_pdu(void **state) { int res; res = avtp_aaf_pdu_init(NULL); assert_int_equal(res, -EINVAL); } static void aaf_pdu_init(void **state) { int res; struct avtp_stream_pdu pdu; res = avtp_aaf_pdu_init(&pdu); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x02800000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(aaf_get_field_null_pdu), cmocka_unit_test(aaf_get_field_null_val), cmocka_unit_test(aaf_get_field_invalid_field), cmocka_unit_test(aaf_get_field_sv), cmocka_unit_test(aaf_get_field_mr), cmocka_unit_test(aaf_get_field_tv), cmocka_unit_test(aaf_get_field_seq_num), cmocka_unit_test(aaf_get_field_tu), cmocka_unit_test(aaf_get_field_stream_id), cmocka_unit_test(aaf_get_field_timestamp), cmocka_unit_test(aaf_get_field_format), cmocka_unit_test(aaf_get_field_nsr), cmocka_unit_test(aaf_get_field_chan), cmocka_unit_test(aaf_get_field_depth), cmocka_unit_test(aaf_get_field_data_len), cmocka_unit_test(aaf_get_field_sp), cmocka_unit_test(aaf_get_field_evt), cmocka_unit_test(aaf_set_field_null_pdu), cmocka_unit_test(aaf_set_field_invalid_field), cmocka_unit_test(aaf_set_field_sv), cmocka_unit_test(aaf_set_field_mr), cmocka_unit_test(aaf_set_field_tv), cmocka_unit_test(aaf_set_field_seq_num), cmocka_unit_test(aaf_set_field_tu), cmocka_unit_test(aaf_set_field_stream_id), cmocka_unit_test(aaf_set_field_timestamp), cmocka_unit_test(aaf_set_field_format), cmocka_unit_test(aaf_set_field_nsr), cmocka_unit_test(aaf_set_field_chan), cmocka_unit_test(aaf_set_field_depth), cmocka_unit_test(aaf_set_field_data_len), cmocka_unit_test(aaf_set_field_sp), cmocka_unit_test(aaf_set_field_evt), cmocka_unit_test(aaf_pdu_init_null_pdu), cmocka_unit_test(aaf_pdu_init), }; return cmocka_run_group_tests(tests, NULL, NULL); } libavtp-0.2.0/unit/test-avtp.c000066400000000000000000000101421420102630700162150ustar00rootroot00000000000000/* * Copyright (c) 2017, Intel Corporation * * 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 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 #include #include #include #include #include "avtp.h" static void get_field_null_pdu(void **state) { int res; uint32_t val = AVTP_SUBTYPE_MAAP; res = avtp_pdu_get(NULL, AVTP_FIELD_SUBTYPE, &val); assert_int_equal(res, -EINVAL); } static void get_field_null_val(void **state) { int res; struct avtp_common_pdu pdu = { 0 }; res = avtp_pdu_get(&pdu, AVTP_FIELD_SUBTYPE, NULL); assert_int_equal(res, -EINVAL); } static void get_field_invalid_field(void **state) { int res; uint32_t val = AVTP_SUBTYPE_MAAP; struct avtp_common_pdu pdu = { 0 }; res = avtp_pdu_get(&pdu, AVTP_FIELD_MAX, &val); assert_int_equal(res, -EINVAL); } static void get_field_subtype(void **state) { int res; uint32_t val; struct avtp_common_pdu pdu = { 0 }; /* Set 'subtype' field to 0xFE (AVTP_SUBTYPE_MAAP). */ pdu.subtype_data = htonl(0xFE000000); res = avtp_pdu_get(&pdu, AVTP_FIELD_SUBTYPE, &val); assert_int_equal(res, 0); assert_true(val == AVTP_SUBTYPE_MAAP); } static void get_field_version(void **state) { int res; uint32_t val; struct avtp_common_pdu pdu = { 0 }; /* Set 'version' field to 5. */ pdu.subtype_data = htonl(0x00500000); res = avtp_pdu_get(&pdu, AVTP_FIELD_VERSION, &val); assert_int_equal(res, 0); assert_true(val == 5); } static void set_field_null_pdu(void **state) { int res; res = avtp_pdu_set(NULL, AVTP_FIELD_SUBTYPE, AVTP_SUBTYPE_MAAP); assert_int_equal(res, -EINVAL); } static void set_field_invalid_field(void **state) { int res; struct avtp_common_pdu pdu = { 0 }; res = avtp_pdu_set(&pdu, AVTP_FIELD_MAX, 1); assert_int_equal(res, -EINVAL); } static void set_field_subtype(void **state) { int res; struct avtp_common_pdu pdu = { 0 }; res = avtp_pdu_set(&pdu, AVTP_FIELD_SUBTYPE, AVTP_SUBTYPE_MAAP); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0xFE000000); } static void set_field_version(void **state) { int res; struct avtp_common_pdu pdu = { 0 }; res = avtp_pdu_set(&pdu, AVTP_FIELD_VERSION, 5); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00500000); } int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(get_field_null_pdu), cmocka_unit_test(get_field_null_val), cmocka_unit_test(get_field_invalid_field), cmocka_unit_test(get_field_subtype), cmocka_unit_test(get_field_version), cmocka_unit_test(set_field_null_pdu), cmocka_unit_test(set_field_invalid_field), cmocka_unit_test(set_field_subtype), cmocka_unit_test(set_field_version), }; return cmocka_run_group_tests(tests, NULL, NULL); } libavtp-0.2.0/unit/test-crf.c000066400000000000000000000262461420102630700160310ustar00rootroot00000000000000/* * Copyright (c) 2018, Intel Corporation * * 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 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 #include #include #include #include #include "avtp.h" #include "avtp_crf.h" static void crf_get_field_null_pdu(void **state) { int res; uint64_t val; res = avtp_crf_pdu_get(NULL, AVTP_CRF_FIELD_SV, &val); assert_int_equal(res, -EINVAL); } static void crf_get_field_null_val(void **state) { int res; struct avtp_crf_pdu pdu = { 0 }; res = avtp_crf_pdu_get(&pdu, AVTP_CRF_FIELD_SV, NULL); assert_int_equal(res, -EINVAL); } static void crf_get_field_invalid_field(void **state) { int res; uint64_t val; struct avtp_crf_pdu pdu = { 0 }; res = avtp_crf_pdu_get(&pdu, AVTP_CRF_FIELD_MAX, &val); assert_int_equal(res, -EINVAL); } static void crf_get_field_sv(void **state) { int res; uint64_t val; struct avtp_crf_pdu pdu = { 0 }; /* Set the 'sv' field to 1 */ pdu.subtype_data = htonl(0x00800000); res = avtp_crf_pdu_get(&pdu, AVTP_CRF_FIELD_SV, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void crf_get_field_mr(void **state) { int res; uint64_t val; struct avtp_crf_pdu pdu = { 0 }; /* Set the 'mr' field to 1 */ pdu.subtype_data = htonl(0x00080000); res = avtp_crf_pdu_get(&pdu, AVTP_CRF_FIELD_MR, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void ctf_get_field_fs(void **state) { int res; uint64_t val; struct avtp_crf_pdu pdu = { 0 }; /* Set the 'fs' field to 1 */ pdu.subtype_data = htonl(0x00020000); res = avtp_crf_pdu_get(&pdu, AVTP_CRF_FIELD_FS, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void crf_get_field_tu(void **state) { int res; uint64_t val; struct avtp_crf_pdu pdu = { 0 }; /* Set the 'tu' field to 1 */ pdu.subtype_data = htonl(0x00010000); res = avtp_crf_pdu_get(&pdu, AVTP_CRF_FIELD_TU, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void crf_get_field_seq_num(void **state) { int res; uint64_t val; struct avtp_crf_pdu pdu = { 0 }; /* Set the 'seq_num' field to 0xBB */ pdu.subtype_data = htonl(0x0000BB00); res = avtp_crf_pdu_get(&pdu, AVTP_CRF_FIELD_SEQ_NUM, &val); assert_int_equal(res, 0); assert_true(val == 0xBB); } static void crf_get_field_type(void **state) { int res; uint64_t val; struct avtp_crf_pdu pdu = { 0 }; /* Set the 'type' field to AVTP_CRF_TYPE_VIDEO_LINE */ pdu.subtype_data = htonl(0x00000003); res = avtp_crf_pdu_get(&pdu, AVTP_CRF_FIELD_TYPE, &val); assert_int_equal(res, 0); assert_true(val == AVTP_CRF_TYPE_VIDEO_LINE); } static void crf_get_field_stream_id(void **state) { int res; uint64_t val; struct avtp_crf_pdu pdu = { 0 }; /* Set the 'stream_id' field to 0xAABBCCDDEEFF0002 */ pdu.stream_id = htobe64(0xAABBCCDDEEFF0002); res = avtp_crf_pdu_get(&pdu, AVTP_CRF_FIELD_STREAM_ID, &val); assert_int_equal(res, 0); assert_true(val == 0xAABBCCDDEEFF0002); } static void crf_get_field_pull(void **state) { int res; uint64_t val; struct avtp_crf_pdu pdu = { 0 }; /* Set the 'pull' field to AVTP_CRF_PULL_MULT_BY_1_001 */ pdu.packet_info = htobe64(0x4000000000000000); res = avtp_crf_pdu_get(&pdu, AVTP_CRF_FIELD_PULL, &val); assert_int_equal(res, 0); assert_true(val == AVTP_CRF_PULL_MULT_BY_1_001); } static void crf_get_field_base_freq(void **state) { int res; uint64_t val; struct avtp_crf_pdu pdu = { 0 }; /* Set the 'base_freq' field to 0x1FFFFFFF */ pdu.packet_info = htobe64(0x1FFFFFFF00000000); res = avtp_crf_pdu_get(&pdu, AVTP_CRF_FIELD_BASE_FREQ, &val); assert_int_equal(res, 0); assert_true(val == 0x1FFFFFFF); } static void crf_get_field_crf_data_len(void **state) { int res; uint64_t val; struct avtp_crf_pdu pdu = { 0 }; /* Set the 'crf_data_len' field to 0xABCD */ pdu.packet_info = htobe64(0x00000000ABCD0000); res = avtp_crf_pdu_get(&pdu, AVTP_CRF_FIELD_CRF_DATA_LEN, &val); assert_int_equal(res, 0); assert_true(val == 0xABCD); } static void crf_get_field_timestamp_interval(void **state) { int res; uint64_t val; struct avtp_crf_pdu pdu = { 0 }; /* Set the 'timestamp_interval' field to 0xABCD */ pdu.packet_info = htobe64(0x000000000000ABCD); res = avtp_crf_pdu_get(&pdu, AVTP_CRF_FIELD_TIMESTAMP_INTERVAL, &val); assert_int_equal(res, 0); assert_true(val == 0xABCD); } static void crf_set_field_null_pdu(void **state) { int res; res = avtp_crf_pdu_set(NULL, AVTP_CRF_FIELD_SV, 1); assert_int_equal(res, -EINVAL); } static void crf_set_field_invalid_field(void **state) { int res; struct avtp_crf_pdu pdu = { 0 }; res = avtp_crf_pdu_set(&pdu, AVTP_CRF_FIELD_MAX, 1); assert_int_equal(res, -EINVAL); } static void crf_set_field_sv(void **state) { int res; struct avtp_crf_pdu pdu = { 0 }; res = avtp_crf_pdu_set(&pdu, AVTP_CRF_FIELD_SV, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00800000); assert_true(pdu.stream_id == 0); assert_true(pdu.packet_info == 0); } static void crf_set_field_mr(void **state) { int res; struct avtp_crf_pdu pdu = { 0 }; res = avtp_crf_pdu_set(&pdu, AVTP_CRF_FIELD_MR, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00080000); assert_true(pdu.stream_id == 0); assert_true(pdu.packet_info == 0); } static void crf_set_field_fs(void **state) { int res; struct avtp_crf_pdu pdu = { 0 }; res = avtp_crf_pdu_set(&pdu, AVTP_CRF_FIELD_FS, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00020000); assert_true(pdu.stream_id == 0); assert_true(pdu.packet_info == 0); } static void crf_set_field_tu(void **state) { int res; struct avtp_crf_pdu pdu = { 0 }; res = avtp_crf_pdu_set(&pdu, AVTP_CRF_FIELD_TU, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00010000); assert_true(pdu.stream_id == 0); assert_true(pdu.packet_info == 0); } static void crf_set_field_seq_num(void **state) { int res; struct avtp_crf_pdu pdu = { 0 }; res = avtp_crf_pdu_set(&pdu, AVTP_CRF_FIELD_SEQ_NUM, 0xAA); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x0000AA00); assert_true(pdu.stream_id == 0); assert_true(pdu.packet_info == 0); } static void crf_set_field_type(void **state) { int res; struct avtp_crf_pdu pdu = { 0 }; res = avtp_crf_pdu_set(&pdu, AVTP_CRF_FIELD_TYPE, AVTP_CRF_TYPE_AUDIO_SAMPLE); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00000001); assert_true(pdu.stream_id == 0); assert_true(pdu.packet_info == 0); } static void crf_set_field_stream_id(void **state) { int res; struct avtp_crf_pdu pdu = { 0 }; res = avtp_crf_pdu_set(&pdu, AVTP_CRF_FIELD_STREAM_ID, 0xAABBCCDDEEFF0002); assert_int_equal(res, 0); assert_true(be64toh(pdu.stream_id) == 0xAABBCCDDEEFF0002); assert_true(pdu.subtype_data == 0); assert_true(pdu.packet_info == 0); } static void crf_set_field_pull(void **state) { int res; struct avtp_crf_pdu pdu = { 0 }; res = avtp_crf_pdu_set(&pdu, AVTP_CRF_FIELD_PULL, AVTP_CRF_PULL_MULT_BY_1_001); assert_int_equal(res, 0); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(be64toh(pdu.packet_info) == 0x4000000000000000); } static void crf_set_field_base_freq(void **state) { int res; struct avtp_crf_pdu pdu = { 0 }; res = avtp_crf_pdu_set(&pdu, AVTP_CRF_FIELD_BASE_FREQ, 0x1FFFFFFF); assert_int_equal(res, 0); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(be64toh(pdu.packet_info) == 0x1FFFFFFF00000000); } static void crf_set_field_crf_data_len(void **state) { int res; struct avtp_crf_pdu pdu = { 0 }; res = avtp_crf_pdu_set(&pdu, AVTP_CRF_FIELD_CRF_DATA_LEN, 0xABCD); assert_int_equal(res, 0); assert_true(be64toh(pdu.packet_info) == 0x00000000ABCD0000); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); } static void crf_set_field_timestamp_interval(void **state) { int res; struct avtp_crf_pdu pdu = { 0 }; res = avtp_crf_pdu_set(&pdu, AVTP_CRF_FIELD_TIMESTAMP_INTERVAL, 0xABCD); assert_int_equal(res, 0); assert_true(be64toh(pdu.packet_info) == 0x000000000000ABCD); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); } static void crf_pdu_init_null_pdu(void **state) { int res; res = avtp_crf_pdu_init(NULL); assert_int_equal(res, -EINVAL); } static void crf_pdu_init(void **state) { int res; struct avtp_crf_pdu pdu; res = avtp_crf_pdu_init(&pdu); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x04800000); assert_true(pdu.stream_id == 0); assert_true(pdu.packet_info == 0); } int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(crf_get_field_null_pdu), cmocka_unit_test(crf_get_field_null_val), cmocka_unit_test(crf_get_field_invalid_field), cmocka_unit_test(crf_get_field_sv), cmocka_unit_test(crf_get_field_mr), cmocka_unit_test(ctf_get_field_fs), cmocka_unit_test(crf_get_field_tu), cmocka_unit_test(crf_get_field_seq_num), cmocka_unit_test(crf_get_field_type), cmocka_unit_test(crf_get_field_stream_id), cmocka_unit_test(crf_get_field_pull), cmocka_unit_test(crf_get_field_base_freq), cmocka_unit_test(crf_get_field_crf_data_len), cmocka_unit_test(crf_get_field_timestamp_interval), cmocka_unit_test(crf_set_field_null_pdu), cmocka_unit_test(crf_set_field_invalid_field), cmocka_unit_test(crf_set_field_sv), cmocka_unit_test(crf_set_field_mr), cmocka_unit_test(crf_set_field_fs), cmocka_unit_test(crf_set_field_tu), cmocka_unit_test(crf_set_field_seq_num), cmocka_unit_test(crf_set_field_type), cmocka_unit_test(crf_set_field_stream_id), cmocka_unit_test(crf_set_field_pull), cmocka_unit_test(crf_set_field_base_freq), cmocka_unit_test(crf_set_field_crf_data_len), cmocka_unit_test(crf_set_field_timestamp_interval), cmocka_unit_test(crf_pdu_init_null_pdu), cmocka_unit_test(crf_pdu_init), }; return cmocka_run_group_tests(tests, NULL, NULL); } libavtp-0.2.0/unit/test-cvf.c000066400000000000000000000361141420102630700160300ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation * * 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 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 #include #include #include #include #include #include #include "avtp.h" #include "avtp_cvf.h" static void cvf_get_field_null_pdu(void **state) { int res; uint64_t val = 1; res = avtp_cvf_pdu_get(NULL, AVTP_CVF_FIELD_SV, &val); assert_int_equal(res, -EINVAL); } static void cvf_get_field_null_val(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_SV, NULL); assert_int_equal(res, -EINVAL); } static void cvf_get_field_invalid_field(void **state) { int res; uint64_t val = 1; struct avtp_stream_pdu pdu = { 0 }; res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_MAX, &val); assert_int_equal(res, -EINVAL); } static void cvf_get_field_sv(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'sv' field to 1. */ pdu.subtype_data = htonl(0x00800000); res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_SV, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void cvf_get_field_mr(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'mr' field to 1. */ pdu.subtype_data = htonl(0x00080000); res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_MR, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void cvf_get_field_tv(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'tv' field to 1. */ pdu.subtype_data = htonl(0x00010000); res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_TV, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void cvf_get_field_seq_num(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'sequence_num' field to 0x55. */ pdu.subtype_data = htonl(0x00005500); res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_SEQ_NUM, &val); assert_int_equal(res, 0); assert_true(val == 0x55); } static void cvf_get_field_tu(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'tu' field to 1. */ pdu.subtype_data = htonl(0x00000001); res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_TU, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void cvf_get_field_stream_id(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'stream_id' field to 0xAABBCCDDEEFF0001. */ pdu.stream_id = htobe64(0xAABBCCDDEEFF0001); res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_STREAM_ID, &val); assert_int_equal(res, 0); assert_true(val == 0xAABBCCDDEEFF0001); } static void cvf_get_field_timestamp(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'avtp_timestamp' field to 0x80C0FFEE. */ pdu.avtp_time = htonl(0x80C0FFEE); res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_TIMESTAMP, &val); assert_int_equal(res, 0); assert_true(val == 0x80C0FFEE); } static void cvf_get_field_format(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'format' field to AVTP_CVF_FORMAT_RFC. */ pdu.format_specific = htonl(0x02000000); res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_FORMAT, &val); assert_int_equal(res, 0); assert_true(val == AVTP_CVF_FORMAT_RFC); } static void cvf_get_field_format_subtype(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'format_subtype' field to AVTP_CVF_FORMAT_SUBTYPE_H264. */ pdu.format_specific = htonl(0x00010000); res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_FORMAT_SUBTYPE, &val); assert_int_equal(res, 0); assert_true(val == AVTP_CVF_FORMAT_SUBTYPE_H264); } static void cvf_get_field_data_len(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'stream_data_length' field to 0xAAAA. */ pdu.packet_info = htonl(0xAAAA0000); res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, &val); assert_int_equal(res, 0); assert_true(val == 0xAAAA); } static void cvf_get_field_m(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'M' field to 0x1. */ pdu.packet_info = htonl(0x00001000); res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_M, &val); assert_int_equal(res, 0); assert_true(val == 0x1); } static void cvf_get_field_evt(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'evt' field to 0xA. */ pdu.packet_info = htonl(0x00000A00); res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_EVT, &val); assert_int_equal(res, 0); assert_true(val == 0xA); } static void cvf_set_field_null_pdu(void **state) { int res; res = avtp_cvf_pdu_set(NULL, AVTP_CVF_FIELD_SV, 1); assert_int_equal(res, -EINVAL); } static void cvf_set_field_invalid_field(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_MAX, 1); assert_int_equal(res, -EINVAL); } static void cvf_set_field_sv(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_SV, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00800000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void cvf_set_field_mr(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_MR, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00080000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void cvf_set_field_tv(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_TV, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00010000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void cvf_set_field_seq_num(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_SEQ_NUM, 0x55); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00005500); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void cvf_set_field_tu(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_TU, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00000001); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void cvf_set_field_stream_id(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_STREAM_ID, 0xAABBCCDDEEFF0001); assert_int_equal(res, 0); assert_true(be64toh(pdu.stream_id) == 0xAABBCCDDEEFF0001); assert_true(pdu.subtype_data == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void cvf_set_field_timestamp(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_TIMESTAMP, 0x80C0FFEE); assert_int_equal(res, 0); assert_true(ntohl(pdu.avtp_time) == 0x80C0FFEE); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void cvf_set_field_format(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_FORMAT, AVTP_CVF_FORMAT_RFC); assert_int_equal(res, 0); assert_true(ntohl(pdu.format_specific) == 0x02000000); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.packet_info == 0); } static void cvf_set_field_format_subtype(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_FORMAT_SUBTYPE, AVTP_CVF_FORMAT_SUBTYPE_H264); assert_int_equal(res, 0); assert_true(ntohl(pdu.format_specific) == 0x10000); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.packet_info == 0); } static void cvf_set_field_data_len(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, 0xAAAA); assert_int_equal(res, 0); assert_true(ntohl(pdu.packet_info) == 0xAAAA0000); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); } static void cvf_set_field_m(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_M, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.packet_info) == 0x00001000); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); } static void cvf_set_field_evt(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_EVT, 0xA); assert_int_equal(res, 0); assert_true(ntohl(pdu.packet_info) == 0x00000A00); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); } static void cvf_pdu_init_null_pdu(void **state) { int res; res = avtp_cvf_pdu_init(NULL, AVTP_CVF_FORMAT_SUBTYPE_H264); assert_int_equal(res, -EINVAL); } static void cvf_pdu_init_invalid_subtype(void **state) { int res; struct avtp_stream_pdu pdu; res = avtp_cvf_pdu_init(&pdu, AVTP_CVF_FORMAT_SUBTYPE_JPEG2000 + 1); assert_int_equal(res, -EINVAL); } static void cvf_pdu_init(void **state) { int res; struct avtp_stream_pdu pdu; res = avtp_cvf_pdu_init(&pdu, AVTP_CVF_FORMAT_SUBTYPE_H264); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x03800000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(ntohl(pdu.format_specific) == 0x2010000); assert_true(pdu.packet_info == 0); } /**** Tests for H.264 fields ****/ static void cvf_get_field_h264_ptv(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'ptv' field to 1. */ pdu.packet_info = htonl(0x00002000); res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_H264_PTV, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void cvf_get_field_h264_timestamp(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(sizeof(struct avtp_stream_pdu) + sizeof(uint32_t)); struct avtp_cvf_h264_payload *pay = (struct avtp_cvf_h264_payload *)pdu->avtp_payload; /* Set 'h264_timestamp' field (which lives in h264_header) to * 0x80C0FFEE. */ pay->h264_header = htonl(0x80C0FFEE); res = avtp_cvf_pdu_get(pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, &val); assert_int_equal(res, 0); assert_true(val == 0x80C0FFEE); } static void cvf_set_field_h264_ptv(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_H264_PTV, 1); assert_int_equal(res, 0); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(ntohl(pdu.packet_info) == 0x00002000); } static void cvf_set_field_h264_timestamp(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(sizeof(struct avtp_stream_pdu) + sizeof(uint32_t)); struct avtp_cvf_h264_payload *pay = (struct avtp_cvf_h264_payload *)pdu->avtp_payload; memset(pdu, 0, sizeof(struct avtp_stream_pdu) + sizeof(uint32_t)); res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, 0x80C0FFEE); assert_int_equal(res, 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(ntohl(pay->h264_header) == 0x80C0FFEE); } int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(cvf_get_field_null_pdu), cmocka_unit_test(cvf_get_field_null_val), cmocka_unit_test(cvf_get_field_invalid_field), cmocka_unit_test(cvf_get_field_sv), cmocka_unit_test(cvf_get_field_mr), cmocka_unit_test(cvf_get_field_tv), cmocka_unit_test(cvf_get_field_seq_num), cmocka_unit_test(cvf_get_field_tu), cmocka_unit_test(cvf_get_field_stream_id), cmocka_unit_test(cvf_get_field_timestamp), cmocka_unit_test(cvf_get_field_format), cmocka_unit_test(cvf_get_field_format_subtype), cmocka_unit_test(cvf_get_field_data_len), cmocka_unit_test(cvf_get_field_m), cmocka_unit_test(cvf_get_field_evt), cmocka_unit_test(cvf_get_field_h264_ptv), cmocka_unit_test(cvf_get_field_h264_timestamp), cmocka_unit_test(cvf_set_field_null_pdu), cmocka_unit_test(cvf_set_field_invalid_field), cmocka_unit_test(cvf_set_field_sv), cmocka_unit_test(cvf_set_field_mr), cmocka_unit_test(cvf_set_field_tv), cmocka_unit_test(cvf_set_field_seq_num), cmocka_unit_test(cvf_set_field_tu), cmocka_unit_test(cvf_set_field_stream_id), cmocka_unit_test(cvf_set_field_timestamp), cmocka_unit_test(cvf_set_field_format), cmocka_unit_test(cvf_set_field_format_subtype), cmocka_unit_test(cvf_set_field_data_len), cmocka_unit_test(cvf_set_field_m), cmocka_unit_test(cvf_set_field_evt), cmocka_unit_test(cvf_set_field_h264_ptv), cmocka_unit_test(cvf_set_field_h264_timestamp), cmocka_unit_test(cvf_pdu_init_null_pdu), cmocka_unit_test(cvf_pdu_init_invalid_subtype), cmocka_unit_test(cvf_pdu_init), }; return cmocka_run_group_tests(tests, NULL, NULL); } libavtp-0.2.0/unit/test-ieciidc.c000066400000000000000000001031451420102630700166420ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation * * 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 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 #include #include #include #include #include #include #include "avtp.h" #include "avtp_ieciidc.h" #define IECIIDC_PDU_HEADER_SIZE (sizeof(struct avtp_stream_pdu) + \ sizeof(struct avtp_ieciidc_cip_payload)) #define IECIIDC_PDU_HEADER_SPH_SIZE (IECIIDC_PDU_HEADER_SIZE + \ sizeof(uint32_t)) static void ieciidc_get_field_null_pdu(void **state) { int res; uint64_t val = 1; res = avtp_ieciidc_pdu_get(NULL, AVTP_IECIIDC_FIELD_GV, &val); assert_int_equal(res, -EINVAL); } static void ieciidc_get_field_null_val(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_ieciidc_pdu_get(&pdu, AVTP_IECIIDC_FIELD_GV, NULL); assert_int_equal(res, -EINVAL); } static void ieciidc_get_field_invalid_field(void **state) { int res; uint64_t val = 1; struct avtp_stream_pdu pdu = { 0 }; res = avtp_ieciidc_pdu_get(&pdu, AVTP_IECIIDC_FIELD_MAX, &val); assert_int_equal(res, -EINVAL); } static void ieciidc_get_field_sv(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'sv' field to 1. */ pdu.subtype_data = htonl(0x00800000); res = avtp_ieciidc_pdu_get(&pdu, AVTP_IECIIDC_FIELD_SV, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void ieciidc_get_field_mr(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'mr' field to 1. */ pdu.subtype_data = htonl(0x00080000); res = avtp_ieciidc_pdu_get(&pdu, AVTP_IECIIDC_FIELD_MR, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void ieciidc_get_field_tv(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'tv' field to 1. */ pdu.subtype_data = htonl(0x00010000); res = avtp_ieciidc_pdu_get(&pdu, AVTP_IECIIDC_FIELD_TV, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void ieciidc_get_field_seq_num(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'sequence_num' field to 0x55. */ pdu.subtype_data = htonl(0x00005500); res = avtp_ieciidc_pdu_get(&pdu, AVTP_IECIIDC_FIELD_SEQ_NUM, &val); assert_int_equal(res, 0); assert_true(val == 0x55); } static void ieciidc_get_field_tu(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'tu' field to 1. */ pdu.subtype_data = htonl(0x00000001); res = avtp_ieciidc_pdu_get(&pdu, AVTP_IECIIDC_FIELD_TU, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void ieciidc_get_field_stream_id(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'stream_id' field to 0xAABBCCDDEEFF0001. */ pdu.stream_id = htobe64(0xAABBCCDDEEFF0001); res = avtp_ieciidc_pdu_get(&pdu, AVTP_IECIIDC_FIELD_STREAM_ID, &val); assert_int_equal(res, 0); assert_true(val == 0xAABBCCDDEEFF0001); } static void ieciidc_get_field_timestamp(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'avtp_timestamp' field to 0x80C0FFEE. */ pdu.avtp_time = htonl(0x80C0FFEE); res = avtp_ieciidc_pdu_get(&pdu, AVTP_IECIIDC_FIELD_TIMESTAMP, &val); assert_int_equal(res, 0); assert_true(val == 0x80C0FFEE); } static void ieciidc_get_field_data_len(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'stream_data_length' field to 0xAAAA. */ pdu.packet_info = htonl(0xAAAA0000); res = avtp_ieciidc_pdu_get(&pdu, AVTP_IECIIDC_FIELD_STREAM_DATA_LEN, &val); assert_int_equal(res, 0); assert_true(val == 0xAAAA); } static void ieciidc_get_field_gv(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'gv' field to 1. */ pdu.subtype_data = htonl(0x00020000); res = avtp_ieciidc_pdu_get(&pdu, AVTP_IECIIDC_FIELD_GV, &val); assert_int_equal(res, 0); assert_true(val == 0x1); } static void ieciidc_get_field_gateway_info(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'gateway info' field to 0x80C0FFEE. */ pdu.format_specific = htonl(0x80C0FFEE); res = avtp_ieciidc_pdu_get(&pdu, AVTP_IECIIDC_FIELD_GATEWAY_INFO, &val); assert_int_equal(res, 0); assert_true(val == 0x80C0FFEE); } static void ieciidc_get_field_tag(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'tag' field to 1. */ pdu.packet_info = htonl(0x00004000); res = avtp_ieciidc_pdu_get(&pdu, AVTP_IECIIDC_FIELD_TAG, &val); assert_int_equal(res, 0); assert_true(val == 0x1); } static void ieciidc_get_field_channel(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'channel' field to 42. */ pdu.packet_info = htonl(0x00002A00); res = avtp_ieciidc_pdu_get(&pdu, AVTP_IECIIDC_FIELD_CHANNEL, &val); assert_int_equal(res, 0); assert_true(val == 42); } static void ieciidc_get_field_tcode(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'tcode' field to 10. */ pdu.packet_info = htonl(0x000000A0); res = avtp_ieciidc_pdu_get(&pdu, AVTP_IECIIDC_FIELD_TCODE, &val); assert_int_equal(res, 0); assert_true(val == 10); } static void ieciidc_get_field_sy(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'sy' field to 10. */ pdu.packet_info = htonl(0x0000000A); res = avtp_ieciidc_pdu_get(&pdu, AVTP_IECIIDC_FIELD_SY, &val); assert_int_equal(res, 0); assert_true(val == 10); } static void ieciidc_get_field_qi_1(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); /* Set 'qi_1' field to 2. */ pay->cip_1 = htonl(0x80000000); res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_QI_1, &val); assert_int_equal(res, 0); assert_true(val == 2); } static void ieciidc_get_field_qi_2(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); /* Set 'qi_2' field to 2. */ pay->cip_2 = htonl(0x80000000); res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_QI_2, &val); assert_int_equal(res, 0); assert_true(val == 2); } static void ieciidc_get_field_sid(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); /* Set 'sid' field to 42. */ pay->cip_1 = htonl(0x2A000000); res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_SID, &val); assert_int_equal(res, 0); assert_true(val == 42); } static void ieciidc_get_field_dbs(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); /* Set 'dbs' field to 0xAA. */ pay->cip_1 = htonl(0x00AA0000); res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_DBS, &val); assert_int_equal(res, 0); assert_true(val == 0xAA); } static void ieciidc_get_field_fn(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); /* Set 'fn' field to 2. */ pay->cip_1 = htonl(0x00008000); res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_FN, &val); assert_int_equal(res, 0); assert_true(val == 2); } static void ieciidc_get_field_qpc(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); /* Set 'qpc' field to 5. */ pay->cip_1 = htonl(0x00002800); res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_QPC, &val); assert_int_equal(res, 0); assert_true(val == 5); } static void ieciidc_get_field_sph(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); /* Set 'sph' field to 1. */ pay->cip_1 = htonl(0x0000400); res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_SPH, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void ieciidc_get_field_dbc(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); /* Set 'dbc' field to 0xAA. */ pay->cip_1 = htonl(0x000000AA); res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_DBC, &val); assert_int_equal(res, 0); assert_true(val == 0xAA); } static void ieciidc_get_field_fmt(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); /* Set 'fmt' field to 42. */ pay->cip_2 = htonl(0x2A000000); res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_FMT, &val); assert_int_equal(res, 0); assert_true(val == 42); } static void ieciidc_get_field_syt(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); /* Set 'syt' field to 0xAAAA. */ pay->cip_2 = htonl(0x0000AAAA); res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_SYT, &val); assert_int_equal(res, 0); assert_true(val == 0xAAAA); } static void ieciidc_get_field_tsf(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); /* Set 'tsf' field to 1. */ pay->cip_2 = htonl(0x00800000); res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_TSF, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void ieciidc_get_field_evt(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); /* Set 'evt' field to 2. */ pay->cip_2 = htonl(0x00200000); res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_EVT, &val); assert_int_equal(res, 0); assert_true(val == 2); } static void ieciidc_get_field_sfc(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); /* Set 'sfc' field to 5. */ pay->cip_2 = htonl(0x00050000); res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_SFC, &val); assert_int_equal(res, 0); assert_true(val == 5); } static void ieciidc_get_field_n(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); /* Set 'n' field to 1. */ pay->cip_2 = htonl(0x00080000); res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_N, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void ieciidc_get_field_nd(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); /* Set 'nd' field to 1. */ pay->cip_2 = htonl(0x00800000); res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_ND, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void ieciidc_get_field_no_data(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); /* Set 'no_data' field to 0xFF. */ pay->cip_2 = htonl(0x00FF0000); res = avtp_ieciidc_pdu_get(pdu, AVTP_IECIIDC_FIELD_CIP_NO_DATA, &val); assert_int_equal(res, 0); assert_true(val == 0xFF); } static void ieciidc_set_field_null_pdu(void **state) { int res; res = avtp_ieciidc_pdu_set(NULL, AVTP_IECIIDC_FIELD_SV, 1); assert_int_equal(res, -EINVAL); } static void ieciidc_set_field_invalid_field(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_ieciidc_pdu_set(&pdu, AVTP_IECIIDC_FIELD_MAX, 1); assert_int_equal(res, -EINVAL); } static void ieciidc_set_field_sv(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_ieciidc_pdu_set(&pdu, AVTP_IECIIDC_FIELD_SV, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00800000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void ieciidc_set_field_mr(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_ieciidc_pdu_set(&pdu, AVTP_IECIIDC_FIELD_MR, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00080000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void ieciidc_set_field_tv(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_ieciidc_pdu_set(&pdu, AVTP_IECIIDC_FIELD_TV, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00010000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void ieciidc_set_field_seq_num(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_ieciidc_pdu_set(&pdu, AVTP_IECIIDC_FIELD_SEQ_NUM, 0x55); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00005500); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void ieciidc_set_field_tu(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_ieciidc_pdu_set(&pdu, AVTP_IECIIDC_FIELD_TU, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00000001); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void ieciidc_set_field_stream_id(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_ieciidc_pdu_set(&pdu, AVTP_IECIIDC_FIELD_STREAM_ID, 0xAABBCCDDEEFF0001); assert_int_equal(res, 0); assert_true(be64toh(pdu.stream_id) == 0xAABBCCDDEEFF0001); assert_true(pdu.subtype_data == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void ieciidc_set_field_timestamp(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_ieciidc_pdu_set(&pdu, AVTP_IECIIDC_FIELD_TIMESTAMP, 0x80C0FFEE); assert_int_equal(res, 0); assert_true(ntohl(pdu.avtp_time) == 0x80C0FFEE); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void ieciidc_set_field_data_len(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_ieciidc_pdu_set(&pdu, AVTP_IECIIDC_FIELD_STREAM_DATA_LEN, 0xAAAA); assert_int_equal(res, 0); assert_true(ntohl(pdu.packet_info) == 0xAAAA0000); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); } static void ieciidc_set_field_gv(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_ieciidc_pdu_set(&pdu, AVTP_IECIIDC_FIELD_GV, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00020000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void ieciidc_set_field_gateway_info(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_ieciidc_pdu_set(&pdu, AVTP_IECIIDC_FIELD_GATEWAY_INFO, 0x80C0FFEE); assert_int_equal(res, 0); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(ntohl(pdu.format_specific) == 0x80C0FFEE); assert_true(pdu.packet_info == 0); } static void ieciidc_set_field_tag(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_ieciidc_pdu_set(&pdu, AVTP_IECIIDC_FIELD_TAG, 2); assert_int_equal(res, 0); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(ntohl(pdu.packet_info) == 0x00008000); } static void ieciidc_set_field_channel(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_ieciidc_pdu_set(&pdu, AVTP_IECIIDC_FIELD_CHANNEL, 42); assert_int_equal(res, 0); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(ntohl(pdu.packet_info) == 0x00002A00); } static void ieciidc_set_field_tcode(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_ieciidc_pdu_set(&pdu, AVTP_IECIIDC_FIELD_TCODE, 10); assert_int_equal(res, 0); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(ntohl(pdu.packet_info) == 0x000000A0); } static void ieciidc_set_field_sy(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_ieciidc_pdu_set(&pdu, AVTP_IECIIDC_FIELD_SY, 10); assert_int_equal(res, 0); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(ntohl(pdu.packet_info) == 0x0000000A); } static void ieciidc_set_field_qi_1(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_QI_1, 2); assert_int_equal(res, 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(ntohl(pay->cip_1) == 0x80000000); assert_true(pay->cip_2 == 0); } static void ieciidc_set_field_qi_2(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_QI_2, 2); assert_int_equal(res, 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(pay->cip_1 == 0); assert_true(ntohl(pay->cip_2) == 0x80000000); } static void ieciidc_set_field_sid(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_SID, 42); assert_int_equal(res, 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(ntohl(pay->cip_1) == 0x2A000000); assert_true(pay->cip_2 == 0); } static void ieciidc_set_field_dbs(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_DBS, 0xAA); assert_int_equal(res, 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(ntohl(pay->cip_1) == 0x00AA0000); assert_true(pay->cip_2 == 0); } static void ieciidc_set_field_fn(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_FN, 2); assert_int_equal(res, 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(ntohl(pay->cip_1) == 0x00008000); assert_true(pay->cip_2 == 0); } static void ieciidc_set_field_qpc(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_QPC, 5); assert_int_equal(res, 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(ntohl(pay->cip_1) == 0x00002800); assert_true(pay->cip_2 == 0); } static void ieciidc_set_field_sph(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_SPH, 1); assert_int_equal(res, 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(ntohl(pay->cip_1) == 0x00000400); assert_true(pay->cip_2 == 0); } static void ieciidc_set_field_dbc(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_DBC, 0xAA); assert_int_equal(res, 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(ntohl(pay->cip_1) == 0x000000AA); assert_true(pay->cip_2 == 0); } static void ieciidc_set_field_fmt(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_FMT, 42); assert_int_equal(res, 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(pay->cip_1 == 0); assert_true(ntohl(pay->cip_2) == 0x2A000000); } static void ieciidc_set_field_syt(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_SYT, 0xAAAA); assert_int_equal(res, 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(pay->cip_1 == 0); assert_true(ntohl(pay->cip_2) == 0x0000AAAA); } static void ieciidc_set_field_tsf(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_TSF, 1); assert_int_equal(res, 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(pay->cip_1 == 0); assert_true(ntohl(pay->cip_2) == 0x00800000); } static void ieciidc_set_field_evt(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_EVT, 2); assert_int_equal(res, 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(pay->cip_1 == 0); assert_true(ntohl(pay->cip_2) == 0x00200000); } static void ieciidc_set_field_sfc(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_SFC, 5); assert_int_equal(res, 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(pay->cip_1 == 0); assert_true(ntohl(pay->cip_2) == 0x00050000); } static void ieciidc_set_field_n(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_N, 1); assert_int_equal(res, 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(pay->cip_1 == 0); assert_true(ntohl(pay->cip_2) == 0x00080000); } static void ieciidc_set_field_nd(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_ND, 1); assert_int_equal(res, 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(pay->cip_1 == 0); assert_true(ntohl(pay->cip_2) == 0x00800000); } static void ieciidc_set_field_no_data(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(IECIIDC_PDU_HEADER_SIZE); struct avtp_ieciidc_cip_payload *pay = (struct avtp_ieciidc_cip_payload *) &pdu->avtp_payload; memset(pdu, 0, IECIIDC_PDU_HEADER_SIZE); res = avtp_ieciidc_pdu_set(pdu, AVTP_IECIIDC_FIELD_CIP_NO_DATA, 0xFF); assert_int_equal(res, 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(pay->cip_1 == 0); assert_true(ntohl(pay->cip_2) == 0x00FF0000); } static void ieciidc_pdu_init_null_pdu(void **state) { int res; res = avtp_ieciidc_pdu_init(NULL, 0); assert_int_equal(res, -EINVAL); } static void ieciidc_pdu_init_invalid_tag(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_ieciidc_pdu_init(&pdu, 0x02); assert_int_equal(res, -EINVAL); } static void ieciidc_pdu_init(void **state) { int res; struct avtp_stream_pdu pdu; res = avtp_ieciidc_pdu_init(&pdu, 0x01); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00800000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(ntohl(pdu.packet_info) == 0x000040A0); } int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(ieciidc_get_field_null_pdu), cmocka_unit_test(ieciidc_get_field_null_val), cmocka_unit_test(ieciidc_get_field_invalid_field), cmocka_unit_test(ieciidc_get_field_sv), cmocka_unit_test(ieciidc_get_field_mr), cmocka_unit_test(ieciidc_get_field_tv), cmocka_unit_test(ieciidc_get_field_seq_num), cmocka_unit_test(ieciidc_get_field_tu), cmocka_unit_test(ieciidc_get_field_stream_id), cmocka_unit_test(ieciidc_get_field_timestamp), cmocka_unit_test(ieciidc_get_field_data_len), cmocka_unit_test(ieciidc_get_field_gv), cmocka_unit_test(ieciidc_get_field_gateway_info), cmocka_unit_test(ieciidc_get_field_tag), cmocka_unit_test(ieciidc_get_field_channel), cmocka_unit_test(ieciidc_get_field_tcode), cmocka_unit_test(ieciidc_get_field_sy), cmocka_unit_test(ieciidc_get_field_qi_1), cmocka_unit_test(ieciidc_get_field_qi_2), cmocka_unit_test(ieciidc_get_field_sid), cmocka_unit_test(ieciidc_get_field_dbs), cmocka_unit_test(ieciidc_get_field_fn), cmocka_unit_test(ieciidc_get_field_qpc), cmocka_unit_test(ieciidc_get_field_sph), cmocka_unit_test(ieciidc_get_field_dbc), cmocka_unit_test(ieciidc_get_field_fmt), cmocka_unit_test(ieciidc_get_field_syt), cmocka_unit_test(ieciidc_get_field_tsf), cmocka_unit_test(ieciidc_get_field_evt), cmocka_unit_test(ieciidc_get_field_sfc), cmocka_unit_test(ieciidc_get_field_n), cmocka_unit_test(ieciidc_get_field_nd), cmocka_unit_test(ieciidc_get_field_no_data), cmocka_unit_test(ieciidc_set_field_null_pdu), cmocka_unit_test(ieciidc_set_field_invalid_field), cmocka_unit_test(ieciidc_set_field_sv), cmocka_unit_test(ieciidc_set_field_mr), cmocka_unit_test(ieciidc_set_field_tv), cmocka_unit_test(ieciidc_set_field_seq_num), cmocka_unit_test(ieciidc_set_field_tu), cmocka_unit_test(ieciidc_set_field_stream_id), cmocka_unit_test(ieciidc_set_field_timestamp), cmocka_unit_test(ieciidc_set_field_data_len), cmocka_unit_test(ieciidc_set_field_gv), cmocka_unit_test(ieciidc_set_field_gateway_info), cmocka_unit_test(ieciidc_set_field_tag), cmocka_unit_test(ieciidc_set_field_channel), cmocka_unit_test(ieciidc_set_field_tcode), cmocka_unit_test(ieciidc_set_field_sy), cmocka_unit_test(ieciidc_set_field_qi_1), cmocka_unit_test(ieciidc_set_field_qi_2), cmocka_unit_test(ieciidc_set_field_sid), cmocka_unit_test(ieciidc_set_field_dbs), cmocka_unit_test(ieciidc_set_field_fn), cmocka_unit_test(ieciidc_set_field_qpc), cmocka_unit_test(ieciidc_set_field_sph), cmocka_unit_test(ieciidc_set_field_dbc), cmocka_unit_test(ieciidc_set_field_fmt), cmocka_unit_test(ieciidc_set_field_syt), cmocka_unit_test(ieciidc_set_field_tsf), cmocka_unit_test(ieciidc_set_field_evt), cmocka_unit_test(ieciidc_set_field_sfc), cmocka_unit_test(ieciidc_set_field_n), cmocka_unit_test(ieciidc_set_field_nd), cmocka_unit_test(ieciidc_set_field_no_data), cmocka_unit_test(ieciidc_pdu_init_null_pdu), cmocka_unit_test(ieciidc_pdu_init_invalid_tag), cmocka_unit_test(ieciidc_pdu_init), }; return cmocka_run_group_tests(tests, NULL, NULL); } libavtp-0.2.0/unit/test-rvf.c000066400000000000000000000604111420102630700160440ustar00rootroot00000000000000/* * Copyright (c) 2021, Fastree3D * Adrian Fiergolski * * 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 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 #include #include #include #include #include #include #include "avtp.h" #include "avtp_rvf.h" static void rvf_get_field_null_pdu(void **state) { int res; uint64_t val = 1; res = avtp_rvf_pdu_get(NULL, AVTP_RVF_FIELD_SV, &val); assert_int_equal(res, -EINVAL); } static void rvf_get_field_null_val(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_get(&pdu, AVTP_RVF_FIELD_SV, NULL); assert_int_equal(res, -EINVAL); } static void rvf_get_field_invalid_field(void **state) { int res; uint64_t val = 1; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_get(&pdu, AVTP_RVF_FIELD_MAX, &val); assert_int_equal(res, -EINVAL); } static void rvf_get_field_sv(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'sv' field to 1. */ pdu.subtype_data = htonl(0x00800000); res = avtp_rvf_pdu_get(&pdu, AVTP_RVF_FIELD_SV, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void rvf_get_field_mr(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'mr' field to 1. */ pdu.subtype_data = htonl(0x00080000); res = avtp_rvf_pdu_get(&pdu, AVTP_RVF_FIELD_MR, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void rvf_get_field_tv(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'tv' field to 1. */ pdu.subtype_data = htonl(0x00010000); res = avtp_rvf_pdu_get(&pdu, AVTP_RVF_FIELD_TV, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void rvf_get_field_seq_num(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'sequence_num' field to 0x55. */ pdu.subtype_data = htonl(0x00005500); res = avtp_rvf_pdu_get(&pdu, AVTP_RVF_FIELD_SEQ_NUM, &val); assert_int_equal(res, 0); assert_true(val == 0x55); } static void rvf_get_field_tu(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'tu' field to 1. */ pdu.subtype_data = htonl(0x00000001); res = avtp_rvf_pdu_get(&pdu, AVTP_RVF_FIELD_TU, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void rvf_get_field_stream_id(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'stream_id' field to 0xAABBCCDDEEFF0001. */ pdu.stream_id = htobe64(0xAABBCCDDEEFF0001); res = avtp_rvf_pdu_get(&pdu, AVTP_RVF_FIELD_STREAM_ID, &val); assert_int_equal(res, 0); assert_true(val == 0xAABBCCDDEEFF0001); } static void rvf_get_field_timestamp(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'avtp_timestamp' field to 0x80C0FFEE. */ pdu.avtp_time = htonl(0x80C0FFEE); res = avtp_rvf_pdu_get(&pdu, AVTP_RVF_FIELD_TIMESTAMP, &val); assert_int_equal(res, 0); assert_true(val == 0x80C0FFEE); } static void rvf_get_field_active_pixels(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'active_pixels' field to 0x20. */ pdu.format_specific = htonl(0x00200000); res = avtp_rvf_pdu_get(&pdu, AVTP_RVF_FIELD_ACTIVE_PIXELS, &val); assert_int_equal(res, 0); assert_true(val == 0x20); } static void rvf_get_field_format_total_lines(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'total_lines' field to 0x3C. */ pdu.format_specific = htonl(0x0000003C); res = avtp_rvf_pdu_get(&pdu, AVTP_RVF_FIELD_TOTAL_LINES, &val); assert_int_equal(res, 0); assert_true(val == 0x3C); } static void rvf_get_field_data_len(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'stream_data_length' field to 0xAAAA. */ pdu.packet_info = htonl(0xAAAA0000); res = avtp_rvf_pdu_get(&pdu, AVTP_RVF_FIELD_STREAM_DATA_LEN, &val); assert_int_equal(res, 0); assert_true(val == 0xAAAA); } static void rvf_get_field_ap(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'AP' field to 0x1. */ pdu.packet_info = htonl(0x00008000); res = avtp_rvf_pdu_get(&pdu, AVTP_RVF_FIELD_AP, &val); assert_int_equal(res, 0); assert_true(val == 0x1); } static void rvf_get_field_f(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'F' field to 0x1. */ pdu.packet_info = htonl(0x00002000); res = avtp_rvf_pdu_get(&pdu, AVTP_RVF_FIELD_F, &val); assert_int_equal(res, 0); assert_true(val == 0x1); } static void rvf_get_field_ef(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'EF' field to 0x1. */ pdu.packet_info = htonl(0x00001000); res = avtp_rvf_pdu_get(&pdu, AVTP_RVF_FIELD_EF, &val); assert_int_equal(res, 0); assert_true(val == 0x1); } static void rvf_get_field_evt(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'evt' field to 0xA. */ pdu.packet_info = htonl(0x00000A00); res = avtp_rvf_pdu_get(&pdu, AVTP_RVF_FIELD_EVT, &val); assert_int_equal(res, 0); assert_true(val == 0xA); } static void rvf_get_field_pd(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'PD' field to 0x1. */ pdu.packet_info = htonl(0x00000080); res = avtp_rvf_pdu_get(&pdu, AVTP_RVF_FIELD_PD, &val); assert_int_equal(res, 0); assert_true(val == 0x1); } static void rvf_get_field_i(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* Set 'I' field to 0x1. */ pdu.packet_info = htonl(0x00000040); res = avtp_rvf_pdu_get(&pdu, AVTP_RVF_FIELD_I, &val); assert_int_equal(res, 0); assert_true(val == 0x1); } static void rvf_set_field_null_pdu(void **state) { int res; res = avtp_rvf_pdu_set(NULL, AVTP_RVF_FIELD_SV, 1); assert_int_equal(res, -EINVAL); } static void rvf_set_field_invalid_field(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_set(&pdu, AVTP_RVF_FIELD_MAX, 1); assert_int_equal(res, -EINVAL); } static void rvf_set_field_sv(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_set(&pdu, AVTP_RVF_FIELD_SV, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00800000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void rvf_set_field_mr(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_set(&pdu, AVTP_RVF_FIELD_MR, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00080000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void rvf_set_field_tv(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_set(&pdu, AVTP_RVF_FIELD_TV, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00010000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void rvf_set_field_seq_num(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_set(&pdu, AVTP_RVF_FIELD_SEQ_NUM, 0x55); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00005500); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void rvf_set_field_tu(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_set(&pdu, AVTP_RVF_FIELD_TU, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00000001); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void rvf_set_field_stream_id(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_set(&pdu, AVTP_RVF_FIELD_STREAM_ID, 0xAABBCCDDEEFF0001); assert_int_equal(res, 0); assert_true(be64toh(pdu.stream_id) == 0xAABBCCDDEEFF0001); assert_true(pdu.subtype_data == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void rvf_set_field_timestamp(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_set(&pdu, AVTP_RVF_FIELD_TIMESTAMP, 0x80C0FFEE); assert_int_equal(res, 0); assert_true(ntohl(pdu.avtp_time) == 0x80C0FFEE); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void rvf_set_field_active_pixels(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_set(&pdu, AVTP_RVF_FIELD_ACTIVE_PIXELS, AVTP_RVF_PIXEL_DEPTH_16); assert_int_equal(res, 0); assert_true(ntohl(pdu.format_specific) == 0x00040000); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.packet_info == 0); } static void rvf_set_field_total_lines(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_set(&pdu, AVTP_RVF_FIELD_TOTAL_LINES, 0x3C); assert_int_equal(res, 0); assert_true(ntohl(pdu.format_specific) == 0x3C); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.packet_info == 0); } static void rvf_set_field_data_len(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_set(&pdu, AVTP_RVF_FIELD_STREAM_DATA_LEN, 0xAAAA); assert_int_equal(res, 0); assert_true(ntohl(pdu.packet_info) == 0xAAAA0000); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); } static void rvf_set_field_ap(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_set(&pdu, AVTP_RVF_FIELD_AP, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.packet_info) == 0x00008000); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); } static void rvf_set_field_f(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_set(&pdu, AVTP_RVF_FIELD_F, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.packet_info) == 0x00002000); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); } static void rvf_set_field_ef(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_set(&pdu, AVTP_RVF_FIELD_EF, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.packet_info) == 0x00001000); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); } static void rvf_set_field_evt(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_set(&pdu, AVTP_RVF_FIELD_EVT, 0xA); assert_int_equal(res, 0); assert_true(ntohl(pdu.packet_info) == 0x00000A00); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); } static void rvf_set_field_pd(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_set(&pdu, AVTP_RVF_FIELD_PD, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.packet_info) == 0x00000080); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); } static void rvf_set_field_i(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_rvf_pdu_set(&pdu, AVTP_RVF_FIELD_I, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.packet_info) == 0x00000040); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); } static void rvf_pdu_init_null_pdu(void **state) { int res; res = avtp_rvf_pdu_init(NULL); assert_int_equal(res, -EINVAL); } static void rvf_pdu_init(void **state) { int res; struct avtp_stream_pdu pdu; res = avtp_rvf_pdu_init(&pdu); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x07800000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(ntohl(pdu.format_specific) == 0x0000000); assert_true(pdu.packet_info == 0); } /**** Tests for RAW fields ****/ static void rvf_get_field_raw_pixel_depth(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); struct avtp_rvf_payload *pay = (struct avtp_rvf_payload *)pdu->avtp_payload; /* Set 'pixel_depth' field to AVTP_RVF_PIXEL_DEPTH_16 */ pay->raw_header = htobe64(0x0040000000000000); res = avtp_rvf_pdu_get(pdu, AVTP_RVF_FIELD_RAW_PIXEL_DEPTH, &val); assert_int_equal(res, 0); assert_true(val == AVTP_RVF_PIXEL_DEPTH_16); } static void rvf_get_field_raw_pixel_format(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); struct avtp_rvf_payload *pay = (struct avtp_rvf_payload *)pdu->avtp_payload; /* Set 'pixel_format' field to AVTP_RVF_PIXEL_DEPTH_16 */ pay->raw_header = htobe64(0x0003000000000000); res = avtp_rvf_pdu_get(pdu, AVTP_RVF_FIELD_RAW_PIXEL_FORMAT, &val); assert_int_equal(res, 0); assert_true(val == AVTP_RVF_PIXEL_FORMAT_422); } static void rvf_get_field_raw_frame_rate(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); struct avtp_rvf_payload *pay = (struct avtp_rvf_payload *)pdu->avtp_payload; /* Set 'frame rate' field to AVTP_RVF_FRAME_RATE_30 */ pay->raw_header = htobe64(0x0000150000000000); res = avtp_rvf_pdu_get(pdu, AVTP_RVF_FIELD_RAW_FRAME_RATE, &val); assert_int_equal(res, 0); assert_true(val == AVTP_RVF_FRAME_RATE_30); } static void rvf_get_field_raw_colorspace(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); struct avtp_rvf_payload *pay = (struct avtp_rvf_payload *)pdu->avtp_payload; /* Set 'colorspace' field to AVTP_RVF_COLORSPACE_GRAY */ pay->raw_header = htobe64(0x0000004000000000); res = avtp_rvf_pdu_get(pdu, AVTP_RVF_FIELD_RAW_COLORSPACE, &val); assert_int_equal(res, 0); assert_true(val == AVTP_RVF_COLORSPACE_GRAY); } static void rvf_get_field_raw_num_lines(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); struct avtp_rvf_payload *pay = (struct avtp_rvf_payload *)pdu->avtp_payload; /* Set 'num_lines' field to 0x05 */ pay->raw_header = htobe64(0x0000000500000000); res = avtp_rvf_pdu_get(pdu, AVTP_RVF_FIELD_RAW_NUM_LINES, &val); assert_int_equal(res, 0); assert_true(val == 0x5); } static void rvf_get_field_raw_i_seq_num(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); struct avtp_rvf_payload *pay = (struct avtp_rvf_payload *)pdu->avtp_payload; /* Set 'i_seq_num' field to 0x03 */ pay->raw_header = htobe64(0x0000000000030000); res = avtp_rvf_pdu_get(pdu, AVTP_RVF_FIELD_RAW_I_SEQ_NUM, &val); assert_int_equal(res, 0); assert_true(val == 0x3); } static void rvf_get_field_raw_line_number(void **state) { int res; uint64_t val; struct avtp_stream_pdu *pdu = alloca(sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); struct avtp_rvf_payload *pay = (struct avtp_rvf_payload *)pdu->avtp_payload; /* Set 'i_seq_num' field to 0x123 */ pay->raw_header = htobe64(0x0000000000000123); res = avtp_rvf_pdu_get(pdu, AVTP_RVF_FIELD_RAW_LINE_NUMBER, &val); assert_int_equal(res, 0); assert_true(val == 0x123); } static void rvf_set_field_raw_pixel_depth(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); struct avtp_rvf_payload *pay = (struct avtp_rvf_payload *)pdu->avtp_payload; memset(pdu, 0, sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); res = avtp_rvf_pdu_set(pdu, AVTP_RVF_FIELD_RAW_PIXEL_DEPTH, AVTP_RVF_PIXEL_DEPTH_16); assert_int_equal(res, 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(be64toh(pay->raw_header) == 0x0040000000000000); } static void rvf_set_field_raw_pixel_format(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); struct avtp_rvf_payload *pay = (struct avtp_rvf_payload *)pdu->avtp_payload; memset(pdu, 0, sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); res = avtp_rvf_pdu_set(pdu, AVTP_RVF_FIELD_RAW_PIXEL_FORMAT, AVTP_RVF_PIXEL_FORMAT_422); assert_int_equal(res, 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(be64toh(pay->raw_header) == 0x0003000000000000); } static void rvf_set_field_raw_frame_rate(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); struct avtp_rvf_payload *pay = (struct avtp_rvf_payload *)pdu->avtp_payload; memset(pdu, 0, sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); res = avtp_rvf_pdu_set(pdu, AVTP_RVF_FIELD_RAW_FRAME_RATE, AVTP_RVF_FRAME_RATE_30); assert_int_equal(res, 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(be64toh(pay->raw_header) == 0x0000150000000000); } static void rvf_set_field_raw_colorspace(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); struct avtp_rvf_payload *pay = (struct avtp_rvf_payload *)pdu->avtp_payload; memset(pdu, 0, sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); res = avtp_rvf_pdu_set(pdu, AVTP_RVF_FIELD_RAW_COLORSPACE, AVTP_RVF_COLORSPACE_GRAY); assert_int_equal(res, 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(be64toh(pay->raw_header) == 0x0000004000000000); } static void rvf_set_field_raw_num_lines(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); struct avtp_rvf_payload *pay = (struct avtp_rvf_payload *)pdu->avtp_payload; memset(pdu, 0, sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); res = avtp_rvf_pdu_set(pdu, AVTP_RVF_FIELD_RAW_NUM_LINES, 0x05); assert_int_equal(res, 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(be64toh(pay->raw_header) == 0x0000000500000000); } static void rvf_set_field_raw_i_seq_num(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); struct avtp_rvf_payload *pay = (struct avtp_rvf_payload *)pdu->avtp_payload; memset(pdu, 0, sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); res = avtp_rvf_pdu_set(pdu, AVTP_RVF_FIELD_RAW_I_SEQ_NUM, 0x03); assert_int_equal(res, 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(be64toh(pay->raw_header) == 0x0000000000030000); } static void rvf_set_field_raw_line_number(void **state) { int res; struct avtp_stream_pdu *pdu = alloca(sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); struct avtp_rvf_payload *pay = (struct avtp_rvf_payload *)pdu->avtp_payload; memset(pdu, 0, sizeof(struct avtp_stream_pdu) + sizeof(uint64_t)); res = avtp_rvf_pdu_set(pdu, AVTP_RVF_FIELD_RAW_LINE_NUMBER, 0x123); assert_int_equal(res, 0); assert_true(pdu->avtp_time == 0); assert_true(pdu->subtype_data == 0); assert_true(pdu->stream_id == 0); assert_true(pdu->format_specific == 0); assert_true(pdu->packet_info == 0); assert_true(be64toh(pay->raw_header) == 0x0000000000000123); } int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(rvf_get_field_null_pdu), cmocka_unit_test(rvf_get_field_null_val), cmocka_unit_test(rvf_get_field_invalid_field), cmocka_unit_test(rvf_get_field_sv), cmocka_unit_test(rvf_get_field_mr), cmocka_unit_test(rvf_get_field_tv), cmocka_unit_test(rvf_get_field_seq_num), cmocka_unit_test(rvf_get_field_tu), cmocka_unit_test(rvf_get_field_stream_id), cmocka_unit_test(rvf_get_field_timestamp), cmocka_unit_test(rvf_get_field_active_pixels), cmocka_unit_test(rvf_get_field_format_total_lines), cmocka_unit_test(rvf_get_field_data_len), cmocka_unit_test(rvf_get_field_ap), cmocka_unit_test(rvf_get_field_f), cmocka_unit_test(rvf_get_field_ef), cmocka_unit_test(rvf_get_field_evt), cmocka_unit_test(rvf_get_field_pd), cmocka_unit_test(rvf_get_field_i), cmocka_unit_test(rvf_get_field_raw_pixel_depth), cmocka_unit_test(rvf_get_field_raw_pixel_format), cmocka_unit_test(rvf_get_field_raw_frame_rate), cmocka_unit_test(rvf_get_field_raw_colorspace), cmocka_unit_test(rvf_get_field_raw_num_lines), cmocka_unit_test(rvf_get_field_raw_i_seq_num), cmocka_unit_test(rvf_get_field_raw_line_number), cmocka_unit_test(rvf_set_field_null_pdu), cmocka_unit_test(rvf_set_field_invalid_field), cmocka_unit_test(rvf_set_field_sv), cmocka_unit_test(rvf_set_field_mr), cmocka_unit_test(rvf_set_field_tv), cmocka_unit_test(rvf_set_field_seq_num), cmocka_unit_test(rvf_set_field_tu), cmocka_unit_test(rvf_set_field_stream_id), cmocka_unit_test(rvf_set_field_timestamp), cmocka_unit_test(rvf_set_field_active_pixels), cmocka_unit_test(rvf_set_field_total_lines), cmocka_unit_test(rvf_set_field_data_len), cmocka_unit_test(rvf_set_field_ap), cmocka_unit_test(rvf_set_field_f), cmocka_unit_test(rvf_set_field_ef), cmocka_unit_test(rvf_set_field_evt), cmocka_unit_test(rvf_set_field_pd), cmocka_unit_test(rvf_set_field_i), cmocka_unit_test(rvf_set_field_raw_pixel_depth), cmocka_unit_test(rvf_set_field_raw_pixel_format), cmocka_unit_test(rvf_set_field_raw_frame_rate), cmocka_unit_test(rvf_set_field_raw_colorspace), cmocka_unit_test(rvf_set_field_raw_num_lines), cmocka_unit_test(rvf_set_field_raw_i_seq_num), cmocka_unit_test(rvf_set_field_raw_line_number), cmocka_unit_test(rvf_pdu_init_null_pdu), cmocka_unit_test(rvf_pdu_init), }; return cmocka_run_group_tests(tests, NULL, NULL); } libavtp-0.2.0/unit/test-stream.c000066400000000000000000000225061420102630700165450ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation * * 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 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 #include #include #include #include #include "avtp.h" #include "avtp_stream.h" static void stream_get_field_null_pdu(void **state) { int res; uint64_t val; res = avtp_stream_pdu_get(NULL, AVTP_STREAM_FIELD_SV, &val); assert_int_equal(res, -EINVAL); } static void stream_get_field_null_val(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_stream_pdu_get(&pdu, AVTP_STREAM_FIELD_SV, NULL); assert_int_equal(res, -EINVAL); } static void stream_get_field_invalid_field(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; res = avtp_stream_pdu_get(&pdu, AVTP_STREAM_FIELD_MAX, &val); assert_int_equal(res, -EINVAL); } static void stream_get_field_sv(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* stream_set 'sv' field to 1. */ pdu.subtype_data = htonl(0x00800000); res = avtp_stream_pdu_get(&pdu, AVTP_STREAM_FIELD_SV, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void stream_get_field_mr(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* stream_set 'mr' field to 1. */ pdu.subtype_data = htonl(0x00080000); res = avtp_stream_pdu_get(&pdu, AVTP_STREAM_FIELD_MR, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void stream_get_field_tv(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* stream_set 'tv' field to 1. */ pdu.subtype_data = htonl(0x00010000); res = avtp_stream_pdu_get(&pdu, AVTP_STREAM_FIELD_TV, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void stream_get_field_seq_num(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* stream_set 'sequence_num' field to 0x55. */ pdu.subtype_data = htonl(0x00005500); res = avtp_stream_pdu_get(&pdu, AVTP_STREAM_FIELD_SEQ_NUM, &val); assert_int_equal(res, 0); assert_true(val == 0x55); } static void stream_get_field_tu(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* stream_set 'tu' field to 1. */ pdu.subtype_data = htonl(0x00000001); res = avtp_stream_pdu_get(&pdu, AVTP_STREAM_FIELD_TU, &val); assert_int_equal(res, 0); assert_true(val == 1); } static void stream_get_field_stream_id(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* stream_set 'stream_id' field to 0xAABBCCDDEEFF0001. */ pdu.stream_id = htobe64(0xAABBCCDDEEFF0001); res = avtp_stream_pdu_get(&pdu, AVTP_STREAM_FIELD_STREAM_ID, &val); assert_int_equal(res, 0); assert_true(val == 0xAABBCCDDEEFF0001); } static void stream_get_field_timestamp(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* stream_set 'avtp_timestamp' field to 0x80C0FFEE. */ pdu.avtp_time = htonl(0x80C0FFEE); res = avtp_stream_pdu_get(&pdu, AVTP_STREAM_FIELD_TIMESTAMP, &val); assert_int_equal(res, 0); assert_true(val == 0x80C0FFEE); } static void stream_get_field_data_len(void **state) { int res; uint64_t val; struct avtp_stream_pdu pdu = { 0 }; /* stream_set 'stream_data_length' field to 0xAAAA. */ pdu.packet_info = htonl(0xAAAA0000); res = avtp_stream_pdu_get(&pdu, AVTP_STREAM_FIELD_STREAM_DATA_LEN, &val); assert_int_equal(res, 0); assert_true(val == 0xAAAA); } static void stream_set_field_null_pdu(void **state) { int res; res = avtp_stream_pdu_set(NULL, AVTP_STREAM_FIELD_SV, 0); assert_int_equal(res, -EINVAL); } static void stream_set_field_invalid_field(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_stream_pdu_set(&pdu, AVTP_STREAM_FIELD_MAX, 1); assert_int_equal(res, -EINVAL); } static void stream_set_field_sv(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_stream_pdu_set(&pdu, AVTP_STREAM_FIELD_SV, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00800000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void stream_set_field_mr(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_stream_pdu_set(&pdu, AVTP_STREAM_FIELD_MR, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00080000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void stream_set_field_tv(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_stream_pdu_set(&pdu, AVTP_STREAM_FIELD_TV, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00010000); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void stream_set_field_seq_num(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_stream_pdu_set(&pdu, AVTP_STREAM_FIELD_SEQ_NUM, 0x55); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00005500); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void stream_set_field_tu(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_stream_pdu_set(&pdu, AVTP_STREAM_FIELD_TU, 1); assert_int_equal(res, 0); assert_true(ntohl(pdu.subtype_data) == 0x00000001); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void stream_set_field_stream_id(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_stream_pdu_set(&pdu, AVTP_STREAM_FIELD_STREAM_ID, 0xAABBCCDDEEFF0001); assert_int_equal(res, 0); assert_true(be64toh(pdu.stream_id) == 0xAABBCCDDEEFF0001); assert_true(pdu.subtype_data == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void stream_set_field_timestamp(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_stream_pdu_set(&pdu, AVTP_STREAM_FIELD_TIMESTAMP, 0x80C0FFEE); assert_int_equal(res, 0); assert_true(ntohl(pdu.avtp_time) == 0x80C0FFEE); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.format_specific == 0); assert_true(pdu.packet_info == 0); } static void stream_set_field_data_len(void **state) { int res; struct avtp_stream_pdu pdu = { 0 }; res = avtp_stream_pdu_set(&pdu, AVTP_STREAM_FIELD_STREAM_DATA_LEN, 0xAAAA); assert_int_equal(res, 0); assert_true(ntohl(pdu.packet_info) == 0xAAAA0000); assert_true(pdu.subtype_data == 0); assert_true(pdu.stream_id == 0); assert_true(pdu.avtp_time == 0); assert_true(pdu.format_specific == 0); } int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(stream_get_field_null_pdu), cmocka_unit_test(stream_get_field_null_val), cmocka_unit_test(stream_get_field_invalid_field), cmocka_unit_test(stream_get_field_sv), cmocka_unit_test(stream_get_field_mr), cmocka_unit_test(stream_get_field_tv), cmocka_unit_test(stream_get_field_seq_num), cmocka_unit_test(stream_get_field_tu), cmocka_unit_test(stream_get_field_stream_id), cmocka_unit_test(stream_get_field_timestamp), cmocka_unit_test(stream_get_field_data_len), cmocka_unit_test(stream_set_field_null_pdu), cmocka_unit_test(stream_set_field_invalid_field), cmocka_unit_test(stream_set_field_sv), cmocka_unit_test(stream_set_field_mr), cmocka_unit_test(stream_set_field_tv), cmocka_unit_test(stream_set_field_seq_num), cmocka_unit_test(stream_set_field_tu), cmocka_unit_test(stream_set_field_stream_id), cmocka_unit_test(stream_set_field_timestamp), cmocka_unit_test(stream_set_field_data_len), }; return cmocka_run_group_tests(tests, NULL, NULL); }