From bb1ef8ea5e4af4bd91c6c417cfb144e28d642e43 Mon Sep 17 00:00:00 2001 From: hackerman-kl Date: Sat, 6 Dec 2025 17:25:44 +0100 Subject: [PATCH] module-avb: milan: introducing full entity model for mlian v1.2 --- src/modules/meson.build | 1 + src/modules/module-avb/descriptors.c | 824 ++++++++++++++++++ src/modules/module-avb/descriptors.h | 253 +----- .../module-avb/entity-model-milan-v12.h | 477 ++++++++++ 4 files changed, 1303 insertions(+), 252 deletions(-) create mode 100644 src/modules/module-avb/descriptors.c create mode 100644 src/modules/module-avb/entity-model-milan-v12.h diff --git a/src/modules/meson.build b/src/modules/meson.build index 260ecfa5c..4d9732cb9 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -749,6 +749,7 @@ if build_module_avb 'module-avb/aecp-aem-cmds-resps/reply-unsol-helpers.c', 'module-avb/es-builder.c', 'module-avb/avdecc.c', + 'module-avb/descriptors.c', 'module-avb/maap.c', 'module-avb/mmrp.c', 'module-avb/mrp.c', diff --git a/src/modules/module-avb/descriptors.c b/src/modules/module-avb/descriptors.c new file mode 100644 index 000000000..57d9315b8 --- /dev/null +++ b/src/modules/module-avb/descriptors.c @@ -0,0 +1,824 @@ +/* PipeWire */ +/* SPDX-FileCopyrightText: Copyright © 2022 Wim Taymans */ +/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki (alexandre.malki@kebag-logic.com) */ +/* SPDX-FileCopyrightText: Copyright © 2025 Simon Gapp */ +/* SPDX-License-Identifier: MIT */ + +#include "adp.h" +#include "aecp-aem.h" +#include "aecp-aem-types.h" +#include "aecp-aem-descriptors.h" +#include "aecp-aem-controls.h" +#include "es-builder.h" + +#include "entity-model-milan-v12.h" + +static void init_descriptor_legacy_avb(struct server *server) +{ + es_builder_add_descriptor(server, AVB_AEM_DESC_STRINGS, 0, + sizeof(struct avb_aem_desc_strings), + &(struct avb_aem_desc_strings) + { + .string_0 = "PipeWire", + .string_1 = "Configuration 1", + .string_2 = "Wim Taymans", + }); + + es_builder_add_descriptor(server, AVB_AEM_DESC_LOCALE, 0, + sizeof(struct avb_aem_desc_locale), + &(struct avb_aem_desc_locale) + { + .locale_identifier = "en-EN", + .number_of_strings = htons(1), + .base_strings = htons(0) + }); + + es_builder_add_descriptor(server, AVB_AEM_DESC_ENTITY, 0, + sizeof(struct avb_aem_desc_entity), + &(struct avb_aem_desc_entity) + { + .entity_id = htobe64(server->entity_id), + .entity_model_id = htobe64(0), + .entity_capabilities = htonl( + AVB_ADP_ENTITY_CAPABILITY_AEM_SUPPORTED | + AVB_ADP_ENTITY_CAPABILITY_CLASS_A_SUPPORTED | + AVB_ADP_ENTITY_CAPABILITY_GPTP_SUPPORTED | + AVB_ADP_ENTITY_CAPABILITY_AEM_IDENTIFY_CONTROL_INDEX_VALID | + AVB_ADP_ENTITY_CAPABILITY_AEM_INTERFACE_INDEX_VALID), + + .talker_stream_sources = htons(8), + .talker_capabilities = htons( + AVB_ADP_TALKER_CAPABILITY_IMPLEMENTED | + AVB_ADP_TALKER_CAPABILITY_AUDIO_SOURCE), + .listener_stream_sinks = htons(8), + .listener_capabilities = htons( + AVB_ADP_LISTENER_CAPABILITY_IMPLEMENTED | + AVB_ADP_LISTENER_CAPABILITY_AUDIO_SINK), + .controller_capabilities = htons(0), + .available_index = htonl(0), + .association_id = htobe64(0), + .entity_name = "PipeWire", + .vendor_name_string = htons(2), + .model_name_string = htons(0), + .firmware_version = "0.3.48", + .group_name = "", + .serial_number = "", + .configurations_count = htons(1), + .current_configuration = htons(0) + }); + struct { + struct avb_aem_desc_configuration desc; + struct avb_aem_desc_descriptor_count descriptor_counts[8]; + } __attribute__ ((__packed__)) config = + { + { + .object_name = "Configuration 1", + .localized_description = htons(1), + .descriptor_counts_count = htons(8), + .descriptor_counts_offset = htons( + 4 + sizeof(struct avb_aem_desc_configuration)), + }, + .descriptor_counts = { + { htons(AVB_AEM_DESC_AUDIO_UNIT), htons(1) }, + { htons(AVB_AEM_DESC_STREAM_INPUT), htons(1) }, + { htons(AVB_AEM_DESC_STREAM_OUTPUT), htons(1) }, + { htons(AVB_AEM_DESC_AVB_INTERFACE), htons(1) }, + { htons(AVB_AEM_DESC_CLOCK_SOURCE), htons(1) }, + { htons(AVB_AEM_DESC_CONTROL), htons(2) }, + { htons(AVB_AEM_DESC_LOCALE), htons(1) }, + { htons(AVB_AEM_DESC_CLOCK_DOMAIN), htons(1) } + } + }; + es_builder_add_descriptor(server, AVB_AEM_DESC_CONFIGURATION, 0, + sizeof(config), &config); + + struct { + struct avb_aem_desc_audio_unit desc; + struct avb_aem_desc_sampling_rate sampling_rates[6]; + } __attribute__ ((__packed__)) audio_unit = + { + { + .object_name = "PipeWire", + .localized_description = htons(0), + .clock_domain_index = htons(0), + .number_of_stream_input_ports = htons(1), + .base_stream_input_port = htons(0), + .number_of_stream_output_ports = htons(1), + .base_stream_output_port = htons(0), + .number_of_external_input_ports = htons(8), + .base_external_input_port = htons(0), + .number_of_external_output_ports = htons(8), + .base_external_output_port = htons(0), + .number_of_internal_input_ports = htons(0), + .base_internal_input_port = htons(0), + .number_of_internal_output_ports = htons(0), + .base_internal_output_port = htons(0), + .number_of_controls = htons(0), + .base_control = htons(0), + .number_of_signal_selectors = htons(0), + .base_signal_selector = htons(0), + .number_of_mixers = htons(0), + .base_mixer = htons(0), + .number_of_matrices = htons(0), + .base_matrix = htons(0), + .number_of_splitters = htons(0), + .base_splitter = htons(0), + .number_of_combiners = htons(0), + .base_combiner = htons(0), + .number_of_demultiplexers = htons(0), + .base_demultiplexer = htons(0), + .number_of_multiplexers = htons(0), + .base_multiplexer = htons(0), + .number_of_transcoders = htons(0), + .base_transcoder = htons(0), + .number_of_control_blocks = htons(0), + .base_control_block = htons(0), + .current_sampling_rate = htonl(48000), + .sampling_rates_offset = htons( + 4 + sizeof(struct avb_aem_desc_audio_unit)), + .sampling_rates_count = htons(6), + }, + .sampling_rates = { + { .pull_frequency = htonl(44100) }, + { .pull_frequency = htonl(48000) }, + { .pull_frequency = htonl(88200) }, + { .pull_frequency = htonl(96000) }, + { .pull_frequency = htonl(176400) }, + { .pull_frequency = htonl(192000) }, + } + }; + es_builder_add_descriptor(server, AVB_AEM_DESC_AUDIO_UNIT, 0, + sizeof(audio_unit), &audio_unit); + + struct { + struct avb_aem_desc_stream desc; + uint64_t stream_formats[6]; + } __attribute__ ((__packed__)) stream_input_0 = + { + { + .object_name = "Stream Input 1", + .localized_description = htons(0xffff), + .clock_domain_index = htons(0), + .stream_flags = htons( + AVB_AEM_DESC_STREAM_FLAG_SYNC_SOURCE | + AVB_AEM_DESC_STREAM_FLAG_CLASS_A), + .current_format = htobe64(0x00a0020840000800ULL), + .formats_offset = htons( + 4 + sizeof(struct avb_aem_desc_stream)), + .number_of_formats = htons(6), + .backup_talker_entity_id_0 = htobe64(0), + .backup_talker_unique_id_0 = htons(0), + .backup_talker_entity_id_1 = htobe64(0), + .backup_talker_unique_id_1 = htons(0), + .backup_talker_entity_id_2 = htobe64(0), + .backup_talker_unique_id_2 = htons(0), + .backedup_talker_entity_id = htobe64(0), + .backedup_talker_unique = htons(0), + .avb_interface_index = htons(0), + .buffer_length = htons(8) + }, + .stream_formats = { + htobe64(0x00a0010860000800ULL), + htobe64(0x00a0020860000800ULL), + htobe64(0x00a0030860000800ULL), + htobe64(0x00a0040860000800ULL), + htobe64(0x00a0050860000800ULL), + htobe64(0x00a0060860000800ULL), + }, + }; + es_builder_add_descriptor(server, AVB_AEM_DESC_STREAM_INPUT, 0, + sizeof(stream_input_0), &stream_input_0); + + struct { + struct avb_aem_desc_stream desc; + uint64_t stream_formats[6]; + } __attribute__ ((__packed__)) stream_output_0 = + { + { + .object_name = "Stream Output 1", + .localized_description = htons(0xffff), + .clock_domain_index = htons(0), + .stream_flags = htons( + AVB_AEM_DESC_STREAM_FLAG_CLASS_A), + .current_format = htobe64(0x00a0020840000800ULL), + .formats_offset = htons( + 4 + sizeof(struct avb_aem_desc_stream)), + .number_of_formats = htons(6), + .backup_talker_entity_id_0 = htobe64(0), + .backup_talker_unique_id_0 = htons(0), + .backup_talker_entity_id_1 = htobe64(0), + .backup_talker_unique_id_1 = htons(0), + .backup_talker_entity_id_2 = htobe64(0), + .backup_talker_unique_id_2 = htons(0), + .backedup_talker_entity_id = htobe64(0), + .backedup_talker_unique = htons(0), + .avb_interface_index = htons(0), + .buffer_length = htons(8) + }, + .stream_formats = { + htobe64(0x00a0010860000800ULL), + htobe64(0x00a0020860000800ULL), + htobe64(0x00a0030860000800ULL), + htobe64(0x00a0040860000800ULL), + htobe64(0x00a0050860000800ULL), + htobe64(0x00a0060860000800ULL), + }, + }; + es_builder_add_descriptor(server, AVB_AEM_DESC_STREAM_OUTPUT, 0, + sizeof(stream_output_0), &stream_output_0); + + struct avb_aem_desc_avb_interface avb_interface = { + .localized_description = htons(0xffff), + .interface_flags = htons( + AVB_AEM_DESC_AVB_INTERFACE_FLAG_GPTP_GRANDMASTER_SUPPORTED), + .clock_identity = htobe64(0), + .priority1 = 0, + .clock_class = 0, + .offset_scaled_log_variance = htons(0), + .clock_accuracy = 0, + .priority2 = 0, + .domain_number = 0, + .log_sync_interval = 0, + .log_announce_interval = 0, + .log_pdelay_interval = 0, + .port_number = 0, + }; + strncpy(avb_interface.object_name, server->ifname, 63); + memcpy(avb_interface.mac_address, server->mac_addr, 6); + es_builder_add_descriptor(server, AVB_AEM_DESC_AVB_INTERFACE, 0, + sizeof(avb_interface), &avb_interface); + + struct avb_aem_desc_clock_source clock_source = { + .object_name = "Stream Clock", + .localized_description = htons(0xffff), + .clock_source_flags = htons(0), + .clock_source_type = htons( + AVB_AEM_DESC_CLOCK_SOURCE_TYPE_INPUT_STREAM), + .clock_source_identifier = htobe64(0), + .clock_source_location_type = htons(AVB_AEM_DESC_STREAM_INPUT), + .clock_source_location_index = htons(0), + }; + es_builder_add_descriptor(server, AVB_AEM_DESC_CLOCK_SOURCE, 0, + sizeof(clock_source), &clock_source); + +} + +static void init_descriptor_milan_v12(struct server *server) +{ + // TODO PERSISTENCE: retrieve the saved buffers. + /**************************************************************************************/ + /* IEEE 1722.1-2021, Sec. 7.2.12 - STRINGS Descriptor + * Up to 7 localized strings + */ + es_builder_add_descriptor(server, AVB_AEM_DESC_STRINGS, 0, + sizeof(struct avb_aem_desc_strings), + &(struct avb_aem_desc_strings) + { + .string_0 = DSC_STRINGS_0_DEVICE_NAME, + .string_1 = DSC_STRINGS_1_CONFIGURATION_NAME, + .string_2 = DSC_STRINGS_2_MANUFACTURER_NAME, + .string_3 = DSC_STRINGS_3_GROUP_NAME, + .string_4 = DSC_STRINGS_4_MAINTAINER_0, + .string_5 = DSC_STRINGS_4_MAINTAINER_1, + } + ); + + /**************************************************************************************/ + /* IEEE 1722.1-2021, Sec. 7.2.11 - LOCALE Descriptor */ + es_builder_add_descriptor(server, AVB_AEM_DESC_LOCALE, 0, + sizeof(struct avb_aem_desc_locale), + &(struct avb_aem_desc_locale) + { + .locale_identifier = DSC_LOCALE_LANGUAGE_CODE, + .number_of_strings = htons(DSC_LOCALE_NO_OF_STRINGS), + .base_strings = htons(DSC_LOCALE_BASE_STRINGS) + }); + + /**************************************************************************************/ + /* IEEE 1722.1-2021, Sec. 7.2.1 - ENTITY Descriptor */ + /* Milan v1.2, Sec. 5.3.3.1 */ + + es_builder_add_descriptor(server, AVB_AEM_DESC_ENTITY, 0, + sizeof(struct avb_aem_desc_entity), + &(struct avb_aem_desc_entity) + { + .entity_id = htobe64(DSC_ENTITY_MODEL_ENTITY_ID), + .entity_model_id = htobe64(DSC_ENTITY_MODEL_ID), + .entity_capabilities = htonl(DSC_ENTITY_MODEL_ENTITY_CAPABILITIES), + + .talker_stream_sources = htons(DSC_ENTITY_MODEL_TALKER_STREAM_SOURCES), + .talker_capabilities = htons(DSC_ENTITY_MODEL_TALKER_CAPABILITIES), + + .listener_stream_sinks = htons(DSC_ENTITY_MODEL_LISTENER_STREAM_SINKS), + .listener_capabilities = htons(DSC_ENTITY_MODEL_LISTENER_CAPABILITIES), + + .controller_capabilities = htons(DSC_ENTITY_MODEL_CONTROLLER_CAPABILITIES), + + .available_index = htonl(DSC_ENTITY_MODEL_AVAILABLE_INDEX), + .association_id = htobe64(DSC_ENTITY_MODEL_ASSOCIATION_ID), + + .entity_name = DSC_ENTITY_MODEL_ENTITY_NAME, + .vendor_name_string = htons(DSC_ENTITY_MODEL_VENDOR_NAME_STRING), + .model_name_string = htons(DSC_ENTITY_MODEL_MODEL_NAME_STRING), + .firmware_version = DSC_ENTITY_MODEL_FIRMWARE_VERSION, + .group_name = DSC_ENTITY_MODEL_GROUP_NAME, + .serial_number = DSC_ENTITY_MODEL_SERIAL_NUMBER, + .configurations_count = htons(DSC_ENTITY_MODEL_CONFIGURATIONS_COUNT), + .current_configuration = htons(DSC_ENTITY_MODEL_CURRENT_CONFIGURATION) + }); + + /**************************************************************************************/ + /* IEEE 1722.1-2021, Sec. 7.2.2 - CONFIGURATION Descriptor*/ + /* Milan v1.2, Sec. 5.3.3.2 */ + + struct { + struct avb_aem_desc_configuration desc; + struct avb_aem_desc_descriptor_count descriptor_counts[DSC_CONFIGURATION_DESCRIPTOR_COUNTS_COUNT]; + } __attribute__ ((__packed__)) config = + { + { + .object_name = DSC_CONFIGURATION_OBJECT_NAME, + .localized_description = htons(DSC_CONFIGURATION_LOCALIZED_DESCRIPTION), + .descriptor_counts_count = htons(DSC_CONFIGURATION_DESCRIPTOR_COUNTS_COUNT), + // TODO: Does it work? Was the commented out lines, now replaced with hard coded value from IEEE. + // .descriptor_counts_offset = htons( + // 4 + sizeof(struct avb_aem_desc_configuration)), + // }, + .descriptor_counts_offset = htons(DSC_CONFIGURATION_DESCRIPTOR_COUNTS_OFFSET), + }, + .descriptor_counts = { + { htons(AVB_AEM_DESC_AUDIO_UNIT), htons(DSC_CONFIGURATION_NO_OF_AUDIO_UNITS) }, + { htons(AVB_AEM_DESC_STREAM_INPUT), htons(DSC_CONFIGURATION_NO_OF_STREAM_INPUTS) }, + { htons(AVB_AEM_DESC_STREAM_OUTPUT), htons(DSC_CONFIGURATION_NO_OF_STREAM_OUTPUTS) }, + { htons(AVB_AEM_DESC_AVB_INTERFACE), htons(DSC_CONFIGURATION_NO_OF_AVB_INTERFACES) }, + { htons(AVB_AEM_DESC_CLOCK_DOMAIN), htons(DSC_CONFIGURATION_NO_OF_CLOCK_DOMAINS) }, + { htons(AVB_AEM_DESC_CLOCK_SOURCE), htons(DSC_CONFIGURATION_NO_OF_CLOCK_SOURCES) }, + { htons(AVB_AEM_DESC_CONTROL), htons(DSC_CONFIGURATION_NO_OF_CONTROLS) }, + { htons(AVB_AEM_DESC_LOCALE), htons(DSC_CONFIGURATION_NO_OF_LOCALES) }, + } + }; + es_builder_add_descriptor(server, AVB_AEM_DESC_CONFIGURATION, 0, + sizeof(config), &config); + + /* Second configuration for tests*/ + struct { + struct avb_aem_desc_configuration desc; + struct avb_aem_desc_descriptor_count descriptor_counts[8]; + } __attribute__ ((__packed__)) config1 = + { + { + .object_name = "Non - redundant - 96kHz", + .localized_description = htons(1), + .descriptor_counts_count = htons(8), + .descriptor_counts_offset = htons( + 4 + sizeof(struct avb_aem_desc_configuration)), + }, + .descriptor_counts = { + { htons(AVB_AEM_DESC_AUDIO_UNIT), htons(1) }, + { htons(AVB_AEM_DESC_STREAM_INPUT), htons(2) }, + { htons(AVB_AEM_DESC_STREAM_OUTPUT), htons(1) }, + { htons(AVB_AEM_DESC_AVB_INTERFACE), htons(1) }, + { htons(AVB_AEM_DESC_CLOCK_DOMAIN), htons(1) }, + { htons(AVB_AEM_DESC_CLOCK_SOURCE), htons(3) }, + { htons(AVB_AEM_DESC_CONTROL), htons(1) }, + { htons(AVB_AEM_DESC_LOCALE), htons(1) }, + } + }; + es_builder_add_descriptor(server, AVB_AEM_DESC_CONFIGURATION, 1, + sizeof(config), &config1); + + /**************************************************************************************/ + /* IEEE 1722.1-2021, Sec. 7.2.22 CONTROL Descriptor*/ + /* Milan v1.2, Sec. 5.3.3.10 */ + + struct { + struct avb_aem_desc_control desc; + struct avb_aem_desc_value_format value_inf; + } __attribute__ ((__packed__)) ctrl = + { + { + .object_name = DSC_CONTROL_OBJECT_NAME, + .localized_description = htons(DSC_CONTROL_LOCALIZED_DESCRIPTION), + + .block_latency = htons(DSC_CONTROL_BLOCK_LATENCY), + .control_latency = htons(DSC_CONTROL_CONTROL_LATENCY), + .control_domain = htons(DSC_CONTROL_CONTROL_DOMAIN), + .control_value_type = htons(DSC_CONTROL_CONTROL_VALUE_TYPE), + .control_type = htobe64(DSC_CONTROL_CONTROL_TYPE), + .reset_time = htonl(DSC_CONTROL_RESET_TIME), + // TODO: This is not specified in Table 7-38 + .descriptor_counts_offset = htons( + 4 + sizeof(struct avb_aem_desc_control)), + .number_of_values = htons(1), + .signal_type = htons(0xffff), + .signal_index = htons(0), + .signal_output = htons(0), + }, + { + .minimum = DSC_CONTROL_IDENTIFY_MIN, + .maximum = DSC_CONTROL_IDENTIFY_MAX, + .step = DSC_CONTROL_IDENTIFY_STEP, + .default_value = DSC_CONTROL_IDENTIFY_DEFAULT_VALUE, + .current_value = DSC_CONTROL_IDENTIFY_CURRENT_VALUE, + .localized_description = htons(DSC_CONTROL_LOCALIZED_DESCRIPTION), + } + }; + es_builder_add_descriptor(server, AVB_AEM_DESC_CONTROL, 0, + sizeof(ctrl), &ctrl); + + /**************************************************************************************/ + /* IEEE 1722.1-2021, Sec. 7.2.19 AUDIO_MAP Descriptor */ + /* Milan v1.2, Sec. 5.3.3.9 */ + + struct { + struct avb_aem_desc_audio_map desc; + struct avb_aem_audio_mapping_format maps[DSC_AUDIO_MAPS_NO_OF_MAPPINGS]; + } __attribute__((__packed__)) maps_input = { + .desc = { + .mapping_offset = htons(AVB_AEM_AUDIO_MAPPING_FORMAT_OFFSET), + .number_of_mappings = htons(DSC_AUDIO_MAPS_NO_OF_MAPPINGS), + }, + }; + + for (uint32_t map_idx = 0; map_idx < DSC_AUDIO_MAPS_NO_OF_MAPPINGS; map_idx++) { + maps_input.maps[map_idx].mapping_stream_index = htons(DSC_AUDIO_MAPS_MAPPING_STREAM_INDEX); + maps_input.maps[map_idx].mapping_cluster_channel = htons(DSC_AUDIO_MAPS_MAPPING_CLUSTER_CHANNEL); + maps_input.maps[map_idx].mapping_cluster_offset = htons(map_idx); + maps_input.maps[map_idx].mapping_stream_channel = htons(map_idx); + } + es_builder_add_descriptor(server, AVB_AEM_DESC_AUDIO_MAP, 0, + sizeof(maps_input), &maps_input); + + struct { + struct avb_aem_desc_audio_map desc; + struct avb_aem_audio_mapping_format maps[DSC_AUDIO_MAPS_NO_OF_MAPPINGS]; + } __attribute__((__packed__)) maps_output= { + .desc = { + .mapping_offset = htons(AVB_AEM_AUDIO_MAPPING_FORMAT_OFFSET), + .number_of_mappings = htons(DSC_AUDIO_MAPS_NO_OF_MAPPINGS), + }, + }; + + for (uint32_t map_idx = 0; map_idx < DSC_AUDIO_MAPS_NO_OF_MAPPINGS; map_idx++) { + maps_output.maps[map_idx].mapping_stream_index = htons(DSC_AUDIO_MAPS_MAPPING_STREAM_INDEX); + maps_output.maps[map_idx].mapping_cluster_channel = htons(DSC_AUDIO_MAPS_MAPPING_CLUSTER_CHANNEL); + maps_output.maps[map_idx].mapping_cluster_offset = htons(DSC_AUDIO_MAPS_NO_OF_MAPPINGS+map_idx); + maps_output.maps[map_idx].mapping_stream_channel = htons(DSC_AUDIO_MAPS_NO_OF_MAPPINGS+map_idx); + } + + es_builder_add_descriptor(server, AVB_AEM_DESC_AUDIO_MAP, 1, + sizeof(maps_output), &maps_output); + + /**************************************************************************************/ + /* IEEE 1722.1-2021, Sec. 7.2.16 AUDIO_CLUSTER Descriptor */ + /* Milan v1.2, Sec. 5.3.3.8 */ + + struct avb_aem_desc_audio_cluster clusters[DSC_AUDIO_CLUSTER_NO_OF_CLUSTERS]; + + for (uint32_t cluster_idx = 0; cluster_idx < DSC_AUDIO_CLUSTER_NO_OF_CLUSTERS; cluster_idx++) { + memset(clusters[cluster_idx].object_name, 0, + sizeof(clusters[cluster_idx].object_name)); + // TODO: Make this scale automatically + if (cluster_idx < 8) { + snprintf(clusters[cluster_idx].object_name, DSC_AUDIO_CLUSTER_OBJECT_NAME_LEN_IN_OCTET-1, + "Input %2u", cluster_idx); + } else { + snprintf(clusters[cluster_idx].object_name, DSC_AUDIO_CLUSTER_OBJECT_NAME_LEN_IN_OCTET-1, + "Output %2u", cluster_idx); + } + + clusters[cluster_idx].localized_description = htons(DSC_AUDIO_CLUSTER_LOCALIZED_DESCRIPTION); + clusters[cluster_idx].signal_type = htons(DSC_AUDIO_CLUSTER_SIGNAL_TYPE); + clusters[cluster_idx].signal_index = htons(DSC_AUDIO_CLUSTER_SIGNAL_INDEX); + clusters[cluster_idx].signal_output = htons(DSC_AUDIO_CLUSTER_SIGNAL_OUTPUT); + clusters[cluster_idx].path_latency = htonl(DSC_AUDIO_CLUSTER_PATH_LATENCY_IN_NS); + clusters[cluster_idx].block_latency = htonl(DSC_AUDIO_CLUSTER_BLOCK_LATENCY_IN_NS); + clusters[cluster_idx].channel_count = htons(DSC_AUDIO_CLUSTER_CHANNEL_COUNT); + clusters[cluster_idx].format = DSC_AUDIO_CLUSTER_FORMAT; + clusters[cluster_idx].aes3_data_type_ref = DSC_AUDIO_CLUSTER_AES3_DATA_TYPE_REF; + clusters[cluster_idx].aes3_data_type = htons(DSC_AUDIO_CLUSTER_AES3_DATA_TYPE); + + es_builder_add_descriptor(server, AVB_AEM_DESC_AUDIO_CLUSTER, cluster_idx, + sizeof(clusters[0]), &clusters[cluster_idx]); + } + + /**************************************************************************************/ + /* IEEE 1722.1-2021, Sec. 7.2.13 STREAM_PORT_INPUT Descriptor */ + /* Milan v1.2, Sec. 5.3.3.7 */ + + struct avb_aem_desc_stream_port stream_port_input0 = { + .clock_domain_index = htons(DSC_STREAM_PORT_INPUT_CLOCK_DOMAIN_INDEX), + .port_flags = htons(DSC_STREAM_PORT_INPUT_PORT_FLAGS), + .number_of_controls = htons(DSC_STREAM_PORT_INPUT_NUMBER_OF_CONTROLS), + .base_control = htons(DSC_STREAM_PORT_INPUT_BASE_CONTROL), + .number_of_clusters = htons(DSC_STREAM_PORT_INPUT_NUMBER_OF_CLUSTERS), + .base_cluster = htons(DSC_STREAM_PORT_INPUT_BASE_CLUSTER), + .number_of_maps = htons(DSC_STREAM_PORT_INPUT_NUMBER_OF_MAPS), + .base_map = htons(DSC_STREAM_PORT_INPUT_BASE_MAP), + }; + es_builder_add_descriptor(server, AVB_AEM_DESC_STREAM_PORT_INPUT, 0, + sizeof(stream_port_input0), &stream_port_input0); + + /**************************************************************************************/ + /* IEEE 1722.1-2021, Sec. 7.2.13 STREAM_PORT_OUTPUT Descriptor */ + /* Milan v1.2, Sec. 5.3.3.7 */ + struct avb_aem_desc_stream_port stream_port_output0 = { + .clock_domain_index = htons(DSC_STREAM_PORT_OUTPUT_CLOCK_DOMAIN_INDEX), + .port_flags = htons(DSC_STREAM_PORT_OUTPUT_PORT_FLAGS), + .number_of_controls = htons(DSC_STREAM_PORT_OUTPUT_NUMBER_OF_CONTROLS), + .base_control = htons(DSC_STREAM_PORT_OUTPUT_BASE_CONTROL), + .number_of_clusters = htons(DSC_STREAM_PORT_OUTPUT_NUMBER_OF_CLUSTERS), + .base_cluster = htons(DSC_STREAM_PORT_OUTPUT_BASE_CLUSTER), + .number_of_maps = htons(DSC_STREAM_PORT_OUTPUT_NUMBER_OF_MAPS), + .base_map = htons(DSC_STREAM_PORT_OUTPUT_BASE_MAP), + }; + es_builder_add_descriptor(server, AVB_AEM_DESC_STREAM_PORT_OUTPUT, 0, + sizeof(stream_port_output0), &stream_port_output0); + + /**************************************************************************************/ + /* IEEE 1722.1-2021, Sec. 7.2.3 AUDIO_UNIT Descriptor */ + /* Milan v1.2, Sec. 5.3.3.3 */ + + struct { + struct avb_aem_desc_audio_unit desc; + struct avb_aem_desc_sampling_rate sampling_rates[DSC_AUDIO_UNIT_SUPPORTED_SAMPLING_RATE_COUNT]; + } __attribute__ ((__packed__)) audio_unit = + { + { + .object_name = DSC_AUDIO_UNIT_OBJECT_NAME, + .localized_description = htons(DSC_AUDIO_UNIT_LOCALIZED_DESCRIPTION), + .clock_domain_index = htons(DSC_AUDIO_UNIT_CLOCK_DOMAIN_INDEX), + .number_of_stream_input_ports = htons(DSC_AUDIO_UNIT_NUMBER_OF_STREAM_INPUT_PORTS), + .base_stream_input_port = htons(DSC_AUDIO_UNIT_BASE_STREAM_INPUT_PORT), + .number_of_stream_output_ports = htons(DSC_AUDIO_UNIT_NUMBER_OF_STREAM_OUTPUT_PORTS), + .base_stream_output_port = htons(DSC_AUDIO_UNIT_BASE_STREAM_OUTPUT_PORT), + .number_of_external_input_ports = htons(DSC_AUDIO_UNIT_NUMBER_OF_EXTERNAL_INPUT_PORTS), + .base_external_input_port = htons(DSC_AUDIO_UNIT_BASE_EXTERNAL_INPUT_PORT), + .number_of_external_output_ports = htons(DSC_AUDIO_UNIT_NUMBER_OF_EXTERNAL_OUTPUT_PORTS), + .base_external_output_port = htons(DSC_AUDIO_UNIT_BASE_EXTERNAL_OUTPUT_PORT), + .number_of_internal_input_ports = htons(DSC_AUDIO_UNIT_NUMBER_OF_INTERNAL_INPUT_PORTS), + .base_internal_input_port = htons(DSC_AUDIO_UNIT_BASE_INTERNAL_INPUT_PORT), + .number_of_internal_output_ports = htons(DSC_AUDIO_UNIT_NUMBER_OF_INTERNAL_OUTPUT_PORTS), + .base_internal_output_port = htons(DSC_AUDIO_UNIT_BASE_INTERNAL_OUTPUT_PORT), + .number_of_controls = htons(DSC_AUDIO_UNIT_NUMBER_OF_CONTROLS), + .base_control = htons(DSC_AUDIO_UNIT_BASE_CONTROL), + .number_of_signal_selectors = htons(DSC_AUDIO_UNIT_NUMBER_OF_SIGNAL_SELECTORS), + .base_signal_selector = htons(DSC_AUDIO_UNIT_BASE_SIGNAL_SELECTOR), + .number_of_mixers = htons(DSC_AUDIO_UNIT_NUMBER_OF_MIXERS), + .base_mixer = htons(DSC_AUDIO_UNIT_BASE_MIXER), + .number_of_matrices = htons(DSC_AUDIO_UNIT_NUMBER_OF_MATRICES), + .base_matrix = htons(DSC_AUDIO_UNIT_BASE_MATRIX), + .number_of_splitters = htons(DSC_AUDIO_UNIT_NUMBER_OF_SPLITTERS), + .base_splitter = htons(DSC_AUDIO_UNIT_BASE_SPLITTER), + .number_of_combiners = htons(DSC_AUDIO_UNIT_NUMBER_OF_COMBINERS), + .base_combiner = htons(DSC_AUDIO_UNIT_BASE_COMBINER), + .number_of_demultiplexers = htons(DSC_AUDIO_UNIT_NUMBER_OF_DEMULTIPLEXERS), + .base_demultiplexer = htons(DSC_AUDIO_UNIT_BASE_DEMULTIPLEXER), + .number_of_multiplexers = htons(DSC_AUDIO_UNIT_NUMBER_OF_MULTIPLEXERS), + .base_multiplexer = htons(DSC_AUDIO_UNIT_BASE_MULTIPLEXER), + .number_of_transcoders = htons(DSC_AUDIO_UNIT_NUMBER_OF_TRANSCODERS), + .base_transcoder = htons(DSC_AUDIO_UNIT_BASE_TRANSCODER), + .number_of_control_blocks = htons(DSC_AUDIO_UNIT_NUMBER_OF_CONTROL_BLOCKS), + .base_control_block = htons(DSC_AUDIO_UNIT_BASE_CONTROL_BLOCK), + .current_sampling_rate = htonl(DSC_AUDIO_UNIT_CURRENT_SAMPLING_RATE_IN_HZ), + .sampling_rates_offset = htons(DSC_AUDIO_UNIT_SAMPLING_RATES_OFFSET), + .sampling_rates_count = htons(DSC_AUDIO_UNIT_SUPPORTED_SAMPLING_RATE_COUNT), + }, + .sampling_rates = { + // Set the list of supported audio unit sample rate + { .pull_frequency = htonl(DSC_AUDIO_UNIT_SUPPORTED_SAMPLING_RATE_IN_HZ_0) }, + } + }; + es_builder_add_descriptor(server, AVB_AEM_DESC_AUDIO_UNIT, 0, + sizeof(audio_unit), &audio_unit); + + /**************************************************************************************/ + /* IEEE 1722.1-2021, Sec. 7.2.6 STREAM_INPUT Descriptor */ + /* Milan v1.2, Sec. 5.3.3.4 */ + + // TODO: 1722.1 lists redundant parameters that are not mentioned here. + + struct { + struct avb_aem_desc_stream desc; + uint64_t stream_formats[DSC_STREAM_INPUT_NUMBER_OF_FORMATS]; + } __attribute__ ((__packed__)) stream_input_0 = + { + { + .object_name = DSC_STREAM_INPUT_OBJECT_NAME, + .localized_description = htons(DSC_STREAM_INPUT_LOCALIZED_DESCRIPTION), + .clock_domain_index = htons(DSC_STREAM_INPUT_CLOCK_DOMAIN_INDEX), + .stream_flags = htons(DSC_STREAM_INPUT_STREAM_FLAGS), + .current_format = htobe64(DSC_STREAM_INPUT_CURRENT_FORMAT), + .formats_offset = htons(DSC_STREAM_INPUT_FORMATS_OFFSET), + .number_of_formats = htons(DSC_STREAM_INPUT_NUMBER_OF_FORMATS), + .backup_talker_entity_id_0 = htobe64(DSC_STREAM_INPUT_BACKUP_TALKER_ENTITY_ID_0), + .backup_talker_unique_id_0 = htons(DSC_STREAM_INPUT_BACKUP_TALKER_UNIQUE_ID_0), + .backup_talker_entity_id_1 = htobe64(DSC_STREAM_INPUT_BACKUP_TALKER_ENTITY_ID_1), + .backup_talker_unique_id_1 = htons(DSC_STREAM_INPUT_BACKUP_TALKER_UNIQUE_ID_1), + .backup_talker_entity_id_2 = htobe64(DSC_STREAM_INPUT_BACKUP_TALKER_ENTITY_ID_2), + .backup_talker_unique_id_2 = htons(DSC_STREAM_INPUT_BACKUP_TALKER_UNIQUE_ID_2), + .backedup_talker_entity_id = htobe64(DSC_STREAM_INPUT_BACKEDUP_TALKER_ENTITY_ID), + .backedup_talker_unique = htons(DSC_STREAM_INPUT_BACKEDUP_TALKER_UNIQUE_ID), + .avb_interface_index = htons(DSC_STREAM_INPUT_AVB_INTERFACE_INDEX), + .buffer_length = htonl(DSC_STREAM_INPUT_BUFFER_LENGTH_IN_NS) + }, + .stream_formats = { + htobe64(DSC_STREAM_INPUT_FORMATS_0), + htobe64(DSC_STREAM_INPUT_FORMATS_1), + htobe64(DSC_STREAM_INPUT_FORMATS_2), + htobe64(DSC_STREAM_INPUT_FORMATS_3), + htobe64(DSC_STREAM_INPUT_FORMATS_4), + }, + }; + es_builder_add_descriptor(server, AVB_AEM_DESC_STREAM_INPUT, 0, + sizeof(stream_input_0), &stream_input_0); + + /**************************************************************************************/ + /* IEEE 1722.1-2021, Sec. 7.2.6 STREAM_INPUT Descriptor */ + /* Milan v1.2, Sec. 5.3.3.4 */ + + struct { + struct avb_aem_desc_stream desc; + uint64_t stream_formats[DSC_STREAM_INPUT_CRF_NUMBER_OF_FORMATS]; + } __attribute__ ((__packed__)) stream_input_crf_0 = + { + { + .object_name = DSC_STREAM_INPUT_CRF_OBJECT_NAME, + .localized_description = htons(DSC_STREAM_INPUT_CRF_LOCALIZED_DESCRIPTION), + .clock_domain_index = htons(DSC_STREAM_INPUT_CRF_CLOCK_DOMAIN_INDEX), + .stream_flags = htons(DSC_STREAM_INPUT_CRF_STREAM_FLAGS), + .current_format = htobe64(DSC_STREAM_INPUT_CRF_CURRENT_FORMAT), + .formats_offset = htons(DSC_STREAM_INPUT_CRF_FORMATS_OFFSET), + .number_of_formats = htons(DSC_STREAM_INPUT_CRF_NUMBER_OF_FORMATS), + .backup_talker_entity_id_0 = htobe64(DSC_STREAM_INPUT_CRF_BACKUP_TALKER_ENTITY_ID_0), + .backup_talker_unique_id_0 = htons(DSC_STREAM_INPUT_CRF_BACKUP_TALKER_UNIQUE_ID_0), + .backup_talker_entity_id_1 = htobe64(DSC_STREAM_INPUT_CRF_BACKUP_TALKER_ENTITY_ID_1), + .backup_talker_unique_id_1 = htons(DSC_STREAM_INPUT_CRF_BACKUP_TALKER_UNIQUE_ID_1), + .backup_talker_entity_id_2 = htobe64(DSC_STREAM_INPUT_CRF_BACKUP_TALKER_ENTITY_ID_2), + .backup_talker_unique_id_2 = htons(DSC_STREAM_INPUT_CRF_BACKUP_TALKER_UNIQUE_ID_2), + .backedup_talker_entity_id = htobe64(DSC_STREAM_INPUT_CRF_BACKEDUP_TALKER_ENTITY_ID), + .backedup_talker_unique = htons(DSC_STREAM_INPUT_CRF_BACKEDUP_TALKER_UNIQUE_ID), + .avb_interface_index = htons(DSC_STREAM_INPUT_CRF_AVB_INTERFACE_INDEX), + .buffer_length = htonl(DSC_STREAM_INPUT_CRF_BUFFER_LENGTH_IN_NS) + }, + .stream_formats = { + htobe64(DSC_STREAM_INPUT_CRF_FORMATS_0), + }, + }; + es_builder_add_descriptor(server, AVB_AEM_DESC_STREAM_INPUT, 1, + sizeof(stream_input_crf_0), &stream_input_crf_0); + + + /**************************************************************************************/ + /* IEEE 1722.1-2021, Sec. 7.2.6 STREAM_OUTPUT Descriptor */ + /* Milan v1.2, Sec. 5.3.3.4 */ + struct { + struct avb_aem_desc_stream desc; + uint64_t stream_formats[DSC_STREAM_OUTPUT_NUMBER_OF_FORMATS]; + } __attribute__ ((__packed__)) stream_output_0 = + { + { + .object_name = DSC_STREAM_OUTPUT_OBJECT_NAME, + .localized_description = htons(DSC_STREAM_OUTPUT_LOCALIZED_DESCRIPTION), + .clock_domain_index = htons(DSC_STREAM_OUTPUT_CLOCK_DOMAIN_INDEX), + .stream_flags = htons(DSC_STREAM_OUTPUT_STREAM_FLAGS), + .current_format = htobe64(DSC_STREAM_OUTPUT_CURRENT_FORMAT), + .formats_offset = htons(DSC_STREAM_OUTPUT_FORMATS_OFFSET), + .number_of_formats = htons(DSC_STREAM_OUTPUT_NUMBER_OF_FORMATS), + .backup_talker_entity_id_0 = htobe64(DSC_STREAM_OUTPUT_BACKUP_TALKER_ENTITY_ID_0), + .backup_talker_unique_id_0 = htons(DSC_STREAM_OUTPUT_BACKUP_TALKER_UNIQUE_ID_0), + .backup_talker_entity_id_1 = htobe64(DSC_STREAM_OUTPUT_BACKUP_TALKER_ENTITY_ID_1), + .backup_talker_unique_id_1 = htons(DSC_STREAM_OUTPUT_BACKUP_TALKER_UNIQUE_ID_1), + .backup_talker_entity_id_2 = htobe64(DSC_STREAM_OUTPUT_BACKUP_TALKER_ENTITY_ID_2), + .backup_talker_unique_id_2 = htons(DSC_STREAM_OUTPUT_BACKUP_TALKER_UNIQUE_ID_2), + .backedup_talker_entity_id = htobe64(DSC_STREAM_OUTPUT_BACKEDUP_TALKER_ENTITY_ID), + .backedup_talker_unique = htons(DSC_STREAM_OUTPUT_BACKEDUP_TALKER_UNIQUE_ID), + .avb_interface_index = htons(DSC_STREAM_OUTPUT_AVB_INTERFACE_INDEX), + .buffer_length = htons(DSC_STREAM_OUTPUT_BUFFER_LENGTH_IN_NS) + }, + .stream_formats = { + htobe64(DSC_STREAM_OUTPUT_FORMATS_0), + htobe64(DSC_STREAM_OUTPUT_FORMATS_1), + htobe64(DSC_STREAM_OUTPUT_FORMATS_2), + htobe64(DSC_STREAM_OUTPUT_FORMATS_3), + htobe64(DSC_STREAM_OUTPUT_FORMATS_4), + }, + }; + es_builder_add_descriptor(server, AVB_AEM_DESC_STREAM_OUTPUT, 0, + sizeof(stream_output_0), &stream_output_0); + + /**************************************************************************************/ + /* IEEE 1722.1-2021, Sec. 7.2.8 AVB Interface Descriptor */ + /* Milan v1.2, Sec. 5.3.3.5 */ + + struct avb_aem_desc_avb_interface avb_interface = { + .localized_description = htons(DSC_AVB_INTERFACE_LOCALIZED_DESCRIPTION), + .interface_flags = htons(DSC_AVB_INTERFACE_INTERFACE_FLAGS), + .clock_identity = htobe64(DSC_AVB_INTERFACE_CLOCK_IDENTITY), + .priority1 = DSC_AVB_INTERFACE_PRIORITY1, + .clock_class = DSC_AVB_INTERFACE_CLOCK_CLASS, + .offset_scaled_log_variance = htons(DSC_AVB_INTERFACE_OFFSET_SCALED_LOG_VARIANCE), + .clock_accuracy = DSC_AVB_INTERFACE_CLOCK_ACCURACY, + .priority2 = DSC_AVB_INTERFACE_PRIORITY2, + .domain_number = DSC_AVB_INTERFACE_DOMAIN_NUMBER, + .log_sync_interval = DSC_AVB_INTERFACE_LOG_SYNC_INTERVAL, + .log_announce_interval = DSC_AVB_INTERFACE_LOG_ANNOUNCE_INTERVAL, + .log_pdelay_interval = DSC_AVB_INTERFACE_PDELAY_INTERVAL, + .port_number = DSC_AVB_INTERFACE_PORT_NUMBER, + }; + + memset(avb_interface.object_name, 0, sizeof(avb_interface.object_name)); + strncpy(avb_interface.object_name, "", 63); + memcpy(avb_interface.mac_address, server->mac_addr, 6); + es_builder_add_descriptor(server, AVB_AEM_DESC_AVB_INTERFACE, 0, + sizeof(avb_interface), &avb_interface); + + /**************************************************************************************/ + /* IEEE 1722.1-2021, Sec. 7.2.9 CLOCK_SOURCE Descriptor */ + /* Milan v1.2, Sec. 5.3.3.6 */ + + // Internal Clock Descriptor + struct avb_aem_desc_clock_source clock_source_internal = { + .object_name = DSC_CLOCK_SOURCE_INTERNAL_OBJECT_NAME, + .localized_description = htons(DSC_CLOCK_SOURCE_INTERNAL_LOCALIZED_DESCRIPTION), + .clock_source_flags = htons(DSC_CLOCK_SOURCE_INTERNAL_FLAGS), + .clock_source_type = htons(DSC_CLOCK_SOURCE_INTERNAL_TYPE), + .clock_source_identifier = htobe64(DSC_CLOCK_SOURCE_INTERNAL_IDENTIFIER), + .clock_source_location_type = htons(DSC_CLOCK_SOURCE_INTERNAL_LOCATION_TYPE), + .clock_source_location_index = htons(DSC_CLOCK_SOURCE_INTERNAL_LOCATION_INDEX), + }; + es_builder_add_descriptor(server, AVB_AEM_DESC_CLOCK_SOURCE, 0, + sizeof(clock_source_internal), &clock_source_internal); + + // AAF Clock Descriptor + struct avb_aem_desc_clock_source clock_source_aaf = { + .object_name = DSC_CLOCK_SOURCE_AAF_OBJECT_NAME, + .localized_description = htons(DSC_CLOCK_SOURCE_AAF_LOCALIZED_DESCRIPTION), + .clock_source_flags = htons(DSC_CLOCK_SOURCE_AAF_FLAGS), + .clock_source_type = htons(DSC_CLOCK_SOURCE_AAF_TYPE), + .clock_source_identifier = htobe64(DSC_CLOCK_SOURCE_AAF_IDENTIFIER), + .clock_source_location_type = htons(DSC_CLOCK_SOURCE_AAF_LOCATION_TYPE), + .clock_source_location_index = htons(DSC_CLOCK_SOURCE_AAF_LOCATION_INDEX), + }; + es_builder_add_descriptor(server, AVB_AEM_DESC_CLOCK_SOURCE, 1, + sizeof(clock_source_aaf), &clock_source_aaf); + + // CRF Clock Descriptor + struct avb_aem_desc_clock_source clock_source_crf = { + .object_name = DSC_CLOCK_SOURCE_CRF_OBJECT_NAME, + .localized_description = htons(DSC_CLOCK_SOURCE_CRF_LOCALIZED_DESCRIPTION), + .clock_source_flags = htons(DSC_CLOCK_SOURCE_CRF_FLAGS), + .clock_source_type = htons(DSC_CLOCK_SOURCE_CRF_TYPE), + .clock_source_identifier = htobe64(DSC_CLOCK_SOURCE_CRF_IDENTIFIER), + .clock_source_location_type = htons(DSC_CLOCK_SOURCE_CRF_LOCATION_TYPE), + .clock_source_location_index = htons(DSC_CLOCK_SOURCE_CRF_LOCATION_INDEX), + }; + es_builder_add_descriptor(server, AVB_AEM_DESC_CLOCK_SOURCE, 2, + sizeof(clock_source_crf), &clock_source_crf); + + /**************************************************************************************/ + /* IEEE 1722.1-2021, Sec. 7.2.32 CLOCK_DOMAIN Descriptor */ + /* Milan v1.2, Sec. 5.3.3.11 */ + + struct { + struct avb_aem_desc_clock_domain desc; + uint16_t clock_sources_idx[DSC_CLOCK_DOMAIN_CLOCK_SOURCES_COUNT]; + } __attribute__ ((__packed__)) clock_domain = { + .desc = { + .object_name = DSC_CLOCK_DOMAIN_OBJECT_NAME, + .localized_description = htons(DSC_CLOCK_DOMAIN_LOCALIZED_DESCRIPTION), + .clock_source_index = htons(DSC_CLOCK_DOMAIN_CLOCK_SOURCE_INDEX), + .descriptor_counts_offset = htons(DSC_CLOCK_DOMAIN_DESCRIPTOR_COUNTS_OFFSET), + .clock_sources_count = htons(DSC_CLOCK_DOMAIN_CLOCK_SOURCES_COUNT), + }, + .clock_sources_idx = { + htons(DSC_CLOCK_DOMAIN_SOURCES_0), + htons(DSC_CLOCK_DOMAIN_SOURCES_1), + htons(DSC_CLOCK_DOMAIN_SOURCES_2), + }, + }; + + es_builder_add_descriptor(server, AVB_AEM_DESC_CLOCK_DOMAIN, 0, + sizeof(clock_domain), &clock_domain); + +} + +void init_descriptors(struct server *server) +{ + if (!server) { + pw_log_error("No server"); + spa_assert(0); + } + + switch (server->avb_mode) { + case AVB_MODE_LEGACY: + init_descriptor_legacy_avb(server); + break; + case AVB_MODE_MILAN_V12: + init_descriptor_milan_v12(server); + break; + default: + pw_log_error("Unknown AVB mode"); + break; + } +} diff --git a/src/modules/module-avb/descriptors.h b/src/modules/module-avb/descriptors.h index 241242406..f69a83f57 100644 --- a/src/modules/module-avb/descriptors.h +++ b/src/modules/module-avb/descriptors.h @@ -3,12 +3,6 @@ /* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki (alexandre.malki@kebag-logic.com) */ /* SPDX-License-Identifier: MIT */ -#include "adp.h" -#include "aecp-aem.h" -#include "aecp-aem-descriptors.h" -#include "es-builder.h" -#include "internal.h" - /** * \todo This whole code needs to be re-factore, * configuring the entity using such a "HARDCODED" @@ -25,249 +19,4 @@ * Having the YANG would allow directly to know the * capabilites/limits of the protocol */ -static inline void init_descriptors(struct server *server) -{ - es_builder_add_descriptor(server, AVB_AEM_DESC_STRINGS, 0, - sizeof(struct avb_aem_desc_strings), - &(struct avb_aem_desc_strings) - { - .string_0 = "PipeWire", - .string_1 = "Configuration 1", - .string_2 = "Wim Taymans", - }); - es_builder_add_descriptor(server, AVB_AEM_DESC_LOCALE, 0, - sizeof(struct avb_aem_desc_locale), - &(struct avb_aem_desc_locale) - { - .locale_identifier = "en-EN", - .number_of_strings = htons(1), - .base_strings = htons(0) - }); - es_builder_add_descriptor(server, AVB_AEM_DESC_ENTITY, 0, - sizeof(struct avb_aem_desc_entity), - &(struct avb_aem_desc_entity) - { - .entity_id = htobe64(server->entity_id), - .entity_model_id = htobe64(0), - .entity_capabilities = htonl( - AVB_ADP_ENTITY_CAPABILITY_AEM_SUPPORTED | - AVB_ADP_ENTITY_CAPABILITY_CLASS_A_SUPPORTED | - AVB_ADP_ENTITY_CAPABILITY_GPTP_SUPPORTED | - AVB_ADP_ENTITY_CAPABILITY_AEM_IDENTIFY_CONTROL_INDEX_VALID | - AVB_ADP_ENTITY_CAPABILITY_AEM_INTERFACE_INDEX_VALID), - - .talker_stream_sources = htons(8), - .talker_capabilities = htons( - AVB_ADP_TALKER_CAPABILITY_IMPLEMENTED | - AVB_ADP_TALKER_CAPABILITY_AUDIO_SOURCE), - .listener_stream_sinks = htons(8), - .listener_capabilities = htons( - AVB_ADP_LISTENER_CAPABILITY_IMPLEMENTED | - AVB_ADP_LISTENER_CAPABILITY_AUDIO_SINK), - .controller_capabilities = htons(0), - .available_index = htonl(0), - .association_id = htobe64(0), - .entity_name = "PipeWire", - .vendor_name_string = htons(2), - .model_name_string = htons(0), - .firmware_version = "0.3.48", - .group_name = "", - .serial_number = "", - .configurations_count = htons(1), - .current_configuration = htons(0) - }); - struct { - struct avb_aem_desc_configuration desc; - struct avb_aem_desc_descriptor_count descriptor_counts[8]; - } __attribute__ ((__packed__)) config = - { - { - .object_name = "Configuration 1", - .localized_description = htons(1), - .descriptor_counts_count = htons(8), - .descriptor_counts_offset = htons( - 4 + sizeof(struct avb_aem_desc_configuration)), - }, - .descriptor_counts = { - { htons(AVB_AEM_DESC_AUDIO_UNIT), htons(1) }, - { htons(AVB_AEM_DESC_STREAM_INPUT), htons(1) }, - { htons(AVB_AEM_DESC_STREAM_OUTPUT), htons(1) }, - { htons(AVB_AEM_DESC_AVB_INTERFACE), htons(1) }, - { htons(AVB_AEM_DESC_CLOCK_SOURCE), htons(1) }, - { htons(AVB_AEM_DESC_CONTROL), htons(2) }, - { htons(AVB_AEM_DESC_LOCALE), htons(1) }, - { htons(AVB_AEM_DESC_CLOCK_DOMAIN), htons(1) } - } - }; - es_builder_add_descriptor(server, AVB_AEM_DESC_CONFIGURATION, 0, - sizeof(config), &config); - - struct { - struct avb_aem_desc_audio_unit desc; - struct avb_aem_desc_sampling_rate sampling_rates[6]; - } __attribute__ ((__packed__)) audio_unit = - { - { - .object_name = "PipeWire", - .localized_description = htons(0), - .clock_domain_index = htons(0), - .number_of_stream_input_ports = htons(1), - .base_stream_input_port = htons(0), - .number_of_stream_output_ports = htons(1), - .base_stream_output_port = htons(0), - .number_of_external_input_ports = htons(8), - .base_external_input_port = htons(0), - .number_of_external_output_ports = htons(8), - .base_external_output_port = htons(0), - .number_of_internal_input_ports = htons(0), - .base_internal_input_port = htons(0), - .number_of_internal_output_ports = htons(0), - .base_internal_output_port = htons(0), - .number_of_controls = htons(0), - .base_control = htons(0), - .number_of_signal_selectors = htons(0), - .base_signal_selector = htons(0), - .number_of_mixers = htons(0), - .base_mixer = htons(0), - .number_of_matrices = htons(0), - .base_matrix = htons(0), - .number_of_splitters = htons(0), - .base_splitter = htons(0), - .number_of_combiners = htons(0), - .base_combiner = htons(0), - .number_of_demultiplexers = htons(0), - .base_demultiplexer = htons(0), - .number_of_multiplexers = htons(0), - .base_multiplexer = htons(0), - .number_of_transcoders = htons(0), - .base_transcoder = htons(0), - .number_of_control_blocks = htons(0), - .base_control_block = htons(0), - .current_sampling_rate = htonl(48000), - .sampling_rates_offset = htons( - 4 + sizeof(struct avb_aem_desc_audio_unit)), - .sampling_rates_count = htons(6), - }, - .sampling_rates = { - { .pull_frequency = htonl(44100) }, - { .pull_frequency = htonl(48000) }, - { .pull_frequency = htonl(88200) }, - { .pull_frequency = htonl(96000) }, - { .pull_frequency = htonl(176400) }, - { .pull_frequency = htonl(192000) }, - } - }; - es_builder_add_descriptor(server, AVB_AEM_DESC_AUDIO_UNIT, 0, - sizeof(audio_unit), &audio_unit); - - struct { - struct avb_aem_desc_stream desc; - uint64_t stream_formats[6]; - } __attribute__ ((__packed__)) stream_input_0 = - { - { - .object_name = "Stream Input 1", - .localized_description = htons(0xffff), - .clock_domain_index = htons(0), - .stream_flags = htons( - AVB_AEM_DESC_STREAM_FLAG_SYNC_SOURCE | - AVB_AEM_DESC_STREAM_FLAG_CLASS_A), - .current_format = htobe64(0x00a0020840000800ULL), - .formats_offset = htons( - 4 + sizeof(struct avb_aem_desc_stream)), - .number_of_formats = htons(6), - .backup_talker_entity_id_0 = htobe64(0), - .backup_talker_unique_id_0 = htons(0), - .backup_talker_entity_id_1 = htobe64(0), - .backup_talker_unique_id_1 = htons(0), - .backup_talker_entity_id_2 = htobe64(0), - .backup_talker_unique_id_2 = htons(0), - .backedup_talker_entity_id = htobe64(0), - .backedup_talker_unique = htons(0), - .avb_interface_index = htons(0), - .buffer_length = htons(8) - }, - .stream_formats = { - htobe64(0x00a0010860000800ULL), - htobe64(0x00a0020860000800ULL), - htobe64(0x00a0030860000800ULL), - htobe64(0x00a0040860000800ULL), - htobe64(0x00a0050860000800ULL), - htobe64(0x00a0060860000800ULL), - }, - }; - es_builder_add_descriptor(server, AVB_AEM_DESC_STREAM_INPUT, 0, - sizeof(stream_input_0), &stream_input_0); - - struct { - struct avb_aem_desc_stream desc; - uint64_t stream_formats[6]; - } __attribute__ ((__packed__)) stream_output_0 = - { - { - .object_name = "Stream Output 1", - .localized_description = htons(0xffff), - .clock_domain_index = htons(0), - .stream_flags = htons( - AVB_AEM_DESC_STREAM_FLAG_CLASS_A), - .current_format = htobe64(0x00a0020840000800ULL), - .formats_offset = htons( - 4 + sizeof(struct avb_aem_desc_stream)), - .number_of_formats = htons(6), - .backup_talker_entity_id_0 = htobe64(0), - .backup_talker_unique_id_0 = htons(0), - .backup_talker_entity_id_1 = htobe64(0), - .backup_talker_unique_id_1 = htons(0), - .backup_talker_entity_id_2 = htobe64(0), - .backup_talker_unique_id_2 = htons(0), - .backedup_talker_entity_id = htobe64(0), - .backedup_talker_unique = htons(0), - .avb_interface_index = htons(0), - .buffer_length = htons(8) - }, - .stream_formats = { - htobe64(0x00a0010860000800ULL), - htobe64(0x00a0020860000800ULL), - htobe64(0x00a0030860000800ULL), - htobe64(0x00a0040860000800ULL), - htobe64(0x00a0050860000800ULL), - htobe64(0x00a0060860000800ULL), - }, - }; - es_builder_add_descriptor(server, AVB_AEM_DESC_STREAM_OUTPUT, 0, - sizeof(stream_output_0), &stream_output_0); - - struct avb_aem_desc_avb_interface avb_interface = { - .localized_description = htons(0xffff), - .interface_flags = htons( - AVB_AEM_DESC_AVB_INTERFACE_FLAG_GPTP_GRANDMASTER_SUPPORTED), - .clock_identity = htobe64(0), - .priority1 = 0, - .clock_class = 0, - .offset_scaled_log_variance = htons(0), - .clock_accuracy = 0, - .priority2 = 0, - .domain_number = 0, - .log_sync_interval = 0, - .log_announce_interval = 0, - .log_pdelay_interval = 0, - .port_number = 0, - }; - strncpy(avb_interface.object_name, server->ifname, 63); - memcpy(avb_interface.mac_address, server->mac_addr, 6); - es_builder_add_descriptor(server, AVB_AEM_DESC_AVB_INTERFACE, 0, - sizeof(avb_interface), &avb_interface); - - struct avb_aem_desc_clock_source clock_source = { - .object_name = "Stream Clock", - .localized_description = htons(0xffff), - .clock_source_flags = htons(0), - .clock_source_type = htons( - AVB_AEM_DESC_CLOCK_SOURCE_TYPE_INPUT_STREAM), - .clock_source_identifier = htobe64(0), - .clock_source_location_type = htons(AVB_AEM_DESC_STREAM_INPUT), - .clock_source_location_index = htons(0), - }; - es_builder_add_descriptor(server, AVB_AEM_DESC_CLOCK_SOURCE, 0, - sizeof(clock_source), &clock_source); -} +void init_descriptors(struct server *server); diff --git a/src/modules/module-avb/entity-model-milan-v12.h b/src/modules/module-avb/entity-model-milan-v12.h new file mode 100644 index 000000000..f729326db --- /dev/null +++ b/src/modules/module-avb/entity-model-milan-v12.h @@ -0,0 +1,477 @@ +/* PipeWire */ +/* SPDX-FileCopyrightText: Copyright © 2025 Kebag-Logic */ +/* SPDX-FileCopyrightText: Copyright © 2025 Simon Gapp */ +/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki */ +/* SPDX-License-Identifier: MIT */ + +#ifndef __DESCRIPTOR_ENTITY_MODEL_MILAN_H__ +#define __DESCRIPTOR_ENTITY_MODEL_MILAN_H__ + +#define TALKER_ENABLE 1 + +// TODO: Make defines as long as specified length +/**************************************************************************************/ +/* IEEE 1722.1-2021, Sec. 7.2.12 - STRINGS Descriptor +* Up to 7 localized strings +*/ +#define DSC_STRINGS_0_DEVICE_NAME "PipeWire" +#define DSC_STRINGS_1_CONFIGURATION_NAME "NON - redundant - 48kHz" +#define DSC_STRINGS_2_MANUFACTURER_NAME "Kebag Logic" +#define DSC_STRINGS_3_GROUP_NAME "Kebag Logic" +#define DSC_STRINGS_4_MAINTAINER_0 "Alexandre Malki" +#define DSC_STRINGS_4_MAINTAINER_1 "Simon Gapp" + +/**************************************************************************************/ +/* IEEE 1722.1-2021, Sec. 7.2.11 - LOCALE Descriptor */ +#define DSC_LOCALE_LANGUAGE_CODE "en-EN" +#define DSC_LOCALE_NO_OF_STRINGS 1 +#define DSC_LOCALE_BASE_STRINGS 0 + +/**************************************************************************************/ +/* IEEE 1722.1-2021, Sec. 7.2.1 - ENTITY Descriptor */ +/* Milan v1.2, Sec. 5.3.3.1 */ + +#define DSC_ENTITY_MODEL_ENTITY_ID 0xDEAD00BEEF00FEED +#define DSC_ENTITY_MODEL_ID 0 +#define DSC_ENTITY_MODEL_ENTITY_CAPABILITIES (AVB_ADP_ENTITY_CAPABILITY_AEM_SUPPORTED | \ + AVB_ADP_ENTITY_CAPABILITY_CLASS_A_SUPPORTED | \ + AVB_ADP_ENTITY_CAPABILITY_GPTP_SUPPORTED | \ + AVB_ADP_ENTITY_CAPABILITY_AEM_IDENTIFY_CONTROL_INDEX_VALID | \ + AVB_ADP_ENTITY_CAPABILITY_AEM_INTERFACE_INDEX_VALID) +/* IEEE 1722.1-2021, Table 7-2 - ENTITY Descriptor +* This is the maximum number of STREAM_OUTPUT +* descriptors the ATDECC Entity has for +* Output Streams in any of its Configurations */ + +#if TALKER_ENABLE + #define DSC_ENTITY_MODEL_TALKER_STREAM_SOURCES 8 + #define DSC_ENTITY_MODEL_TALKER_CAPABILITIES (AVB_ADP_TALKER_CAPABILITY_IMPLEMENTED | \ + AVB_ADP_TALKER_CAPABILITY_AUDIO_SOURCE) +#else + #define DSC_ENTITY_MODEL_TALKER_STREAM_SOURCES 0 + #define DSC_ENTITY_MODEL_TALKER_CAPABILITIES 0 +#endif + + +#define DSC_ENTITY_MODEL_LISTENER_STREAM_SINKS 8 +#define DSC_ENTITY_MODEL_LISTENER_CAPABILITIES (AVB_ADP_LISTENER_CAPABILITY_IMPLEMENTED | \ + AVB_ADP_LISTENER_CAPABILITY_AUDIO_SINK) +#define DSC_ENTITY_MODEL_CONTROLLER_CAPABILITIES 0 +/* IEEE 1722.1-2021, Table 7-2 ENTITY Descriptor +* The available index of the ATDECC Entity. +* This is the same as the available_index field +* in ATDECC Discovery Protocol.*/ +#define DSC_ENTITY_MODEL_AVAILABLE_INDEX 0 +/* IEEE 1722.1-2021, Table 7-2 ENTITY Descriptor + * The association ID for the ATDECC Entity. + * This is the same as association_id field + * in ATDECC Discovery Protocol*/ +#define DSC_ENTITY_MODEL_ASSOCIATION_ID 0 +#define DSC_ENTITY_MODEL_ENTITY_NAME DSC_STRINGS_0_DEVICE_NAME +/* IEEE 1722.1-2021, Table 7-2 - ENTITY Descriptor + * The localized string reference pointing to the + * localized vendor name. See 7.3.7. */ +#define DSC_ENTITY_MODEL_VENDOR_NAME_STRING 2 +/* IEEE 1722.1-2021, Table 7-2 - ENTITY Descriptor + * The localized string reference pointing to the + * localized model name. See 7.3.7. */ +#define DSC_ENTITY_MODEL_MODEL_NAME_STRING 0 +#define DSC_ENTITY_MODEL_FIRMWARE_VERSION "0.3.48" +#define DSC_ENTITY_MODEL_GROUP_NAME DSC_STRINGS_3_GROUP_NAME +#define DSC_ENTITY_MODEL_SERIAL_NUMBER "0xBEBEDEAD" +#define DSC_ENTITY_MODEL_CONFIGURATIONS_COUNT 2 +#define DSC_ENTITY_MODEL_CURRENT_CONFIGURATION 0 + +/**************************************************************************************/ +/* IEEE 1722.1-2021, Sec. 7.2.2 - CONFIGURATION Descriptor*/ +/* Milan v1.2, Sec. 5.3.3.2 */ +#define DSC_CONFIGURATION_DESCRIPTOR_COUNTS_COUNT 8 +#define DSC_CONFIGURATION_OBJECT_NAME DSC_STRINGS_1_CONFIGURATION_NAME +/* IEEE 1722.1-2021, Table 7-3 CONFIGURATION Descriptor + * The localized string reference pointing to the + * localized Configuration name. */ +#define DSC_CONFIGURATION_LOCALIZED_DESCRIPTION 1 +/* IEEE 1722.1-2021, Table 7-3 CONFIGURATION Descriptor + * The offset to the descriptor_counts field from the + * start of the descriptor. This field is set to 74 for + * this version of AEM. */ +#define DSC_CONFIGURATION_DESCRIPTOR_COUNTS_OFFSET 74 + +#define DSC_CONFIGURATION_NO_OF_AUDIO_UNITS 1 +#define DSC_CONFIGURATION_NO_OF_STREAM_INPUTS 2 + +#define DSC_CONFIGURATION_NO_OF_STREAM_OUTPUTS 1 + +#define DSC_CONFIGURATION_NO_OF_AVB_INTERFACES 1 +#define DSC_CONFIGURATION_NO_OF_CLOCK_DOMAINS 1 +#define DSC_CONFIGURATION_NO_OF_CLOCK_SOURCES 3 +#define DSC_CONFIGURATION_NO_OF_CONTROLS 1 +#define DSC_CONFIGURATION_NO_OF_LOCALES 1 + +/**************************************************************************************/ +/* IEEE 1722.1-2021, Sec. 7.2.22 CONTROL Descriptor*/ +/* Milan v1.2, Sec. 5.3.3.10 */ + +#define DSC_CONTROL_OBJECT_NAME "Identify" +#define DSC_CONTROL_LOCALIZED_DESCRIPTION AVB_AEM_DESC_INVALID +#define DSC_CONTROL_BLOCK_LATENCY 500 +#define DSC_CONTROL_CONTROL_LATENCY 500 +#define DSC_CONTROL_CONTROL_DOMAIN 0 +#define DSC_CONTROL_CONTROL_VALUE_TYPE AECP_AEM_CTRL_LINEAR_UINT8 +#define DSC_CONTROL_CONTROL_TYPE AEM_CTRL_TYPE_IDENTIFY +/* IEEE 1722.1-2021, Table 7-39 - CONTROL Descriptor + * The time period in microseconds from when a control + * is set with the SET_CONTROL command till it automatically + * resets to its default values. + * When this is set to zero (0) automatic resets do not happen. */ +// TODO: Milan v1.2: The PAAD remains in identification mode until the value of the “IDENTIFY” CONTROL descriptor is set back to 0. +#define DSC_CONTROL_RESET_TIME 3 +#define DSC_CONTROL_NUMBER_OF_VALUES 1 +#define DSC_CONTROL_SIGNAL_TYPE AVB_AEM_DESC_INVALID +#define DSC_CONTROL_SIGNAL_INDEX 0 +#define DSC_CONTROL_SIGNAL_OUTPUT 0 + +#define DSC_CONTROL_IDENTIFY_MIN 0 +#define DSC_CONTROL_IDENTIFY_MAX 255 +#define DSC_CONTROL_IDENTIFY_STEP 255 +#define DSC_CONTROL_IDENTIFY_DEFAULT_VALUE 0 +#define DSC_CONTROL_IDENTIFY_CURRENT_VALUE 0 +#define DSC_CONTROL_LOCALIZED_DESCRIPTION AVB_AEM_DESC_INVALID + +/**************************************************************************************/ +/* IEEE 1722.1-2021, Sec. 7.2.19 AUDIO_MAP Descriptor */ +/* Milan v1.2, Sec. 5.3.3.9 */ + +// TODO: Prepared for for loop over total number of audio maps +#define DSC_AUDIO_MAPS_TOTAL_NO_OF_MAPS 2 + +#define DSC_AUDIO_MAPS_NO_OF_MAPPINGS 8 +#define DSC_AUDIO_MAPS_MAPPING_STREAM_INDEX 0 +#define DSC_AUDIO_MAPS_MAPPING_CLUSTER_CHANNEL 0 + +/**************************************************************************************/ +/* IEEE 1722.1-2021, Sec. 7.2.16 AUDIO_CLUSTER Descriptor */ +/* Milan v1.2, Sec. 5.3.3.8 */ +#define DSC_AUDIO_CLUSTER_NO_OF_CLUSTERS 16 +#define DSC_AUDIO_CLUSTER_OBJECT_NAME_LEN_IN_OCTET 64 +#define DSC_AUDIO_CLUSTER_OBJECT_NAME_INPUT "Input" +#define DSC_AUDIO_CLUSTER_OBJECT_NAME_OUTPUT "Output" + +#define DSC_AUDIO_CLUSTER_LOCALIZED_DESCRIPTION AVB_AEM_DESC_INVALID + +/* The signal_type and signal_index fields indicate the + * object providing the signal destined for the channels + * of the streams mapped to the port. For a signal which + * is sourced internally from the Unit, the signal_type + * is set to AUDIO_UNIT and signal_index is set to the + * index of the Unit. For a Cluster attached to a + * STREAM_PORT_INPUT the signal_type and signal_index + * fields is set to INVALID and zero (0) respectively. */ +#define DSC_AUDIO_CLUSTER_SIGNAL_TYPE 0 +#define DSC_AUDIO_CLUSTER_SIGNAL_INDEX 0 +/* The index of the output of the signal source of the + * cluster. For a signal_type of SIGNAL_SPLITTER or + * SIGNAL_DEMULTIPLEXER this is which output of the + * object it is being sourced from, for a signal_type + * of MATRIX this is the column the signal is from + * and for any other signal_type this is zero (0). */ +#define DSC_AUDIO_CLUSTER_SIGNAL_OUTPUT 0 +#define DSC_AUDIO_CLUSTER_PATH_LATENCY_IN_NS 500 +#define DSC_AUDIO_CLUSTER_BLOCK_LATENCY_IN_NS 500 +#define DSC_AUDIO_CLUSTER_CHANNEL_COUNT 1 +#define DSC_AUDIO_CLUSTER_FORMAT AVB_AEM_AUDIO_CLUSTER_TYPE_MBLA +#define DSC_AUDIO_CLUSTER_AES3_DATA_TYPE_REF 0 +#define DSC_AUDIO_CLUSTER_AES3_DATA_TYPE 0 + +/**************************************************************************************/ +/* IEEE 1722.1-2021, Sec. 7.2.13 STREAM_PORT_INPUT Descriptor */ +/* Milan v1.2, Sec. 5.3.3.7 */ + +#define DSC_STREAM_PORT_INPUT_CLOCK_DOMAIN_INDEX 0x0000 +#define DSC_STREAM_PORT_INPUT_PORT_FLAGS AVB_AEM_PORT_FLAG_CLOCK_SYNC_SOURCE +/* The number of clusters within the Port. This corresponds to the number of + * AUDIO_CLUSTER, VIDEO_CLUSTER or SENSOR_CLUSTER descriptors which represent + * these clusters. */ +// TODO: Validate value +#define DSC_STREAM_PORT_INPUT_NUMBER_OF_CONTROLS 0 +#define DSC_STREAM_PORT_INPUT_BASE_CONTROL 0 +// TODO: Validate value +#define DSC_STREAM_PORT_INPUT_NUMBER_OF_CLUSTERS 8 +#define DSC_STREAM_PORT_INPUT_BASE_CLUSTER 0 +#define DSC_STREAM_PORT_INPUT_NUMBER_OF_MAPS 1 +#define DSC_STREAM_PORT_INPUT_BASE_MAP 0 + + /**************************************************************************************/ +/* IEEE 1722.1-2021, Sec. 7.2.13 STREAM_PORT_OUTPUT Descriptor */ +/* Milan v1.2, Sec. 5.3.3.7 */ + +#define DSC_STREAM_PORT_OUTPUT_CLOCK_DOMAIN_INDEX 0 +#define DSC_STREAM_PORT_OUTPUT_PORT_FLAGS AVB_AEM_PORT_FLAG_NO_FLAG +#define DSC_STREAM_PORT_OUTPUT_NUMBER_OF_CONTROLS 0 +#define DSC_STREAM_PORT_OUTPUT_BASE_CONTROL 0 +// TODO: Verify +#define DSC_STREAM_PORT_OUTPUT_NUMBER_OF_CLUSTERS 8 +#define DSC_STREAM_PORT_OUTPUT_BASE_CLUSTER 8 +#define DSC_STREAM_PORT_OUTPUT_NUMBER_OF_MAPS 1 +#define DSC_STREAM_PORT_OUTPUT_BASE_MAP 1 + +/**************************************************************************************/ +/* IEEE 1722.1-2021, Sec. 7.2.3 AUDIO_UNIT Descriptor */ +/* Milan v1.2, Sec. 5.3.3.3 */ + +/* IEEE 1722.1-2021, Sec. 7.3.1 + * A sampling rate consists of a 3 bit pull field + * representing a multiplier and a 29 bit + * base_frequency in hertz, as detailed in Figure 7-2. + * The pull field specifies the multiplier modifier + * of the base_frequency field which is required to + * calculate the appropriate nominal sampling rate. + * The pull field may have one of the values defined + * in Table 7-70: + * The base_frequency field defines the nominal base + * sampling rate in Hz, from 1 Hz to 536 870 911 Hz. + * The value of this field is augmented by the + * pull field value.*/ +#define BUILD_SAMPLING_RATE(pull, base_freq_hz) \ +(((uint32_t)(pull) << 29) | ((uint32_t)(base_freq_hz) & 0x1FFFFFFF)) + + +#define DSC_AUDIO_UNIT_OBJECT_NAME "" +#define DSC_AUDIO_UNIT_LOCALIZED_DESCRIPTION 0xFFFF +#define DSC_AUDIO_UNIT_CLOCK_DOMAIN_INDEX 0x0000 + +#define DSC_AUDIO_UNIT_NUMBER_OF_STREAM_INPUT_PORTS 0x0001 +#define DSC_AUDIO_UNIT_BASE_STREAM_INPUT_PORT 0x0000 + +#if TALKER_ENABLE + #define DSC_AUDIO_UNIT_NUMBER_OF_STREAM_OUTPUT_PORTS 0x0001 +#else + #define DSC_AUDIO_UNIT_NUMBER_OF_STREAM_OUTPUT_PORTS 0x0000 +#endif + +#define DSC_AUDIO_UNIT_BASE_STREAM_OUTPUT_PORT 0x0000 + +#define DSC_AUDIO_UNIT_NUMBER_OF_EXTERNAL_INPUT_PORTS 0x0008 +#define DSC_AUDIO_UNIT_BASE_EXTERNAL_INPUT_PORT 0x0000 + +#define DSC_AUDIO_UNIT_NUMBER_OF_EXTERNAL_OUTPUT_PORTS 0x0008 +#define DSC_AUDIO_UNIT_BASE_EXTERNAL_OUTPUT_PORT 0x0000 + +#define DSC_AUDIO_UNIT_NUMBER_OF_INTERNAL_INPUT_PORTS 0x0000 +#define DSC_AUDIO_UNIT_BASE_INTERNAL_INPUT_PORT 0x0000 + +#define DSC_AUDIO_UNIT_NUMBER_OF_INTERNAL_OUTPUT_PORTS 0x0000 +#define DSC_AUDIO_UNIT_BASE_INTERNAL_OUTPUT_PORT 0x0000 + +#define DSC_AUDIO_UNIT_NUMBER_OF_CONTROLS 0x0000 +#define DSC_AUDIO_UNIT_BASE_CONTROL 0x0000 + +#define DSC_AUDIO_UNIT_NUMBER_OF_SIGNAL_SELECTORS 0x0000 +#define DSC_AUDIO_UNIT_BASE_SIGNAL_SELECTOR 0x0000 + +#define DSC_AUDIO_UNIT_NUMBER_OF_MIXERS 0x0000 +#define DSC_AUDIO_UNIT_BASE_MIXER 0x0000 + +#define DSC_AUDIO_UNIT_NUMBER_OF_MATRICES 0x0000 +#define DSC_AUDIO_UNIT_BASE_MATRIX 0x0000 + +#define DSC_AUDIO_UNIT_NUMBER_OF_SPLITTERS 0x0000 +#define DSC_AUDIO_UNIT_BASE_SPLITTER 0x0000 + +#define DSC_AUDIO_UNIT_NUMBER_OF_COMBINERS 0x0000 +#define DSC_AUDIO_UNIT_BASE_COMBINER 0x0000 + +#define DSC_AUDIO_UNIT_NUMBER_OF_DEMULTIPLEXERS 0x0000 +#define DSC_AUDIO_UNIT_BASE_DEMULTIPLEXER 0x0000 + +#define DSC_AUDIO_UNIT_NUMBER_OF_MULTIPLEXERS 0x0000 +#define DSC_AUDIO_UNIT_BASE_MULTIPLEXER 0x0000 + +#define DSC_AUDIO_UNIT_NUMBER_OF_TRANSCODERS 0x0000 +#define DSC_AUDIO_UNIT_BASE_TRANSCODER 0x0000 + +#define DSC_AUDIO_UNIT_NUMBER_OF_CONTROL_BLOCKS 0x0000 +#define DSC_AUDIO_UNIT_BASE_CONTROL_BLOCK 0x0000 + +#define DSC_AUDIO_UNIT_SAMPLING_RATE_PULL 0 +#define DSC_AUDIO_UNIT_SAMPLING_RATE_BASE_FREQ_IN_HZ 48000 +#define DSC_AUDIO_UNIT_CURRENT_SAMPLING_RATE_IN_HZ \ +BUILD_SAMPLING_RATE(DSC_AUDIO_UNIT_SAMPLING_RATE_PULL, DSC_AUDIO_UNIT_SAMPLING_RATE_BASE_FREQ_IN_HZ) +/* The offset to the sample_rates field from the start of the descriptor. + * This field is 144 for this version of AEM.*/ +#define DSC_AUDIO_UNIT_SAMPLING_RATES_OFFSET 144 +#define DSC_AUDIO_UNIT_SUPPORTED_SAMPLING_RATE_COUNT 0x0001 +#define DSC_AUDIO_UNIT_SUPPORTED_SAMPLING_RATE_IN_HZ_0 \ +BUILD_SAMPLING_RATE(DSC_AUDIO_UNIT_SAMPLING_RATE_PULL, DSC_AUDIO_UNIT_SAMPLING_RATE_BASE_FREQ_IN_HZ) + +/**************************************************************************************/ +/* IEEE 1722.1-2021, Sec. 7.2.6 STREAM_INPUT Descriptor */ +/* Milan v1.2, Sec. 5.3.3.4 */ + +// TODO: 1722.1 lists redundant parameters that are not mentioned here. + +#define DSC_STREAM_INPUT_OBJECT_NAME "Stream 1" +#define DSC_STREAM_INPUT_LOCALIZED_DESCRIPTION AVB_AEM_DESC_INVALID +#define DSC_STREAM_INPUT_CLOCK_DOMAIN_INDEX 0 +#define DSC_STREAM_INPUT_STREAM_FLAGS (AVB_AEM_DESC_STREAM_FLAG_SYNC_SOURCE | AVB_AEM_DESC_STREAM_FLAG_CLASS_A) +// To match my talker +// TODO: Define based on AUDIO_UNIT etc. +#define DSC_STREAM_INPUT_CURRENT_FORMAT 0x0205022001006000ULL + +// TODO: Is 132 here, should be 138 according to spec +#define DSC_STREAM_INPUT_FORMATS_OFFSET (4 + sizeof(struct avb_aem_desc_stream)) +#define DSC_STREAM_INPUT_NUMBER_OF_FORMATS 5 + +#define DSC_STREAM_INPUT_BACKUP_TALKER_ENTITY_ID_0 0 +#define DSC_STREAM_INPUT_BACKUP_TALKER_UNIQUE_ID_0 0 + +#define DSC_STREAM_INPUT_BACKUP_TALKER_ENTITY_ID_1 0 +#define DSC_STREAM_INPUT_BACKUP_TALKER_UNIQUE_ID_1 0 + +#define DSC_STREAM_INPUT_BACKUP_TALKER_ENTITY_ID_2 0 +#define DSC_STREAM_INPUT_BACKUP_TALKER_UNIQUE_ID_2 0 + +#define DSC_STREAM_INPUT_BACKEDUP_TALKER_ENTITY_ID 0 +#define DSC_STREAM_INPUT_BACKEDUP_TALKER_UNIQUE_ID 0 + +#define DSC_STREAM_INPUT_AVB_INTERFACE_INDEX 0 +#define DSC_STREAM_INPUT_BUFFER_LENGTH_IN_NS 2126000 + +#define DSC_STREAM_INPUT_FORMATS_0 DSC_STREAM_INPUT_CURRENT_FORMAT +#define DSC_STREAM_INPUT_FORMATS_1 0x0205022000406000ULL +#define DSC_STREAM_INPUT_FORMATS_2 0x0205022000806000ULL +#define DSC_STREAM_INPUT_FORMATS_3 0x0205022001806000ULL +#define DSC_STREAM_INPUT_FORMATS_4 0x0205022002006000ULL + +/**************************************************************************************/ +/* IEEE 1722.1-2021, Sec. 7.2.6 STREAM_INPUT Descriptor */ +/* Milan v1.2, Sec. 5.3.3.4 */ + +#define DSC_STREAM_INPUT_CRF_OBJECT_NAME "CRF" +#define DSC_STREAM_INPUT_CRF_LOCALIZED_DESCRIPTION AVB_AEM_DESC_INVALID +#define DSC_STREAM_INPUT_CRF_CLOCK_DOMAIN_INDEX 0 +#define DSC_STREAM_INPUT_CRF_STREAM_FLAGS (AVB_AEM_DESC_STREAM_FLAG_SYNC_SOURCE | AVB_AEM_DESC_STREAM_FLAG_CLASS_A) +#define DSC_STREAM_INPUT_CRF_CURRENT_FORMAT 0x041060010000BB80ULL + +#define DSC_STREAM_INPUT_CRF_FORMATS_OFFSET (4 + sizeof(struct avb_aem_desc_stream)) +#define DSC_STREAM_INPUT_CRF_NUMBER_OF_FORMATS 1 + +#define DSC_STREAM_INPUT_CRF_BACKUP_TALKER_ENTITY_ID_0 0 +#define DSC_STREAM_INPUT_CRF_BACKUP_TALKER_UNIQUE_ID_0 0 + +#define DSC_STREAM_INPUT_CRF_BACKUP_TALKER_ENTITY_ID_1 0 +#define DSC_STREAM_INPUT_CRF_BACKUP_TALKER_UNIQUE_ID_1 0 + +#define DSC_STREAM_INPUT_CRF_BACKUP_TALKER_ENTITY_ID_2 0 +#define DSC_STREAM_INPUT_CRF_BACKUP_TALKER_UNIQUE_ID_2 0 + +#define DSC_STREAM_INPUT_CRF_BACKEDUP_TALKER_ENTITY_ID 0 +#define DSC_STREAM_INPUT_CRF_BACKEDUP_TALKER_UNIQUE_ID 0 + +#define DSC_STREAM_INPUT_CRF_AVB_INTERFACE_INDEX 0 +#define DSC_STREAM_INPUT_CRF_BUFFER_LENGTH_IN_NS 2126000 + +#define DSC_STREAM_INPUT_CRF_FORMATS_0 DSC_STREAM_INPUT_CRF_CURRENT_FORMAT + +/**************************************************************************************/ +/* IEEE 1722.1-2021, Sec. 7.2.6 STREAM_OUTPUT Descriptor */ +/* Milan v1.2, Sec. 5.3.3.4 */ + +#define DSC_STREAM_OUTPUT_OBJECT_NAME "Stream output 1" +#define DSC_STREAM_OUTPUT_LOCALIZED_DESCRIPTION AVB_AEM_DESC_INVALID +#define DSC_STREAM_OUTPUT_CLOCK_DOMAIN_INDEX 0 +#define DSC_STREAM_OUTPUT_STREAM_FLAGS (AVB_AEM_DESC_STREAM_FLAG_CLASS_A) +#define DSC_STREAM_OUTPUT_CURRENT_FORMAT 0x0205022002006000ULL + +#define DSC_STREAM_OUTPUT_FORMATS_OFFSET (4 + sizeof(struct avb_aem_desc_stream)) +#define DSC_STREAM_OUTPUT_NUMBER_OF_FORMATS 5 + +#define DSC_STREAM_OUTPUT_BACKUP_TALKER_ENTITY_ID_0 0 +#define DSC_STREAM_OUTPUT_BACKUP_TALKER_UNIQUE_ID_0 0 + +#define DSC_STREAM_OUTPUT_BACKUP_TALKER_ENTITY_ID_1 0 +#define DSC_STREAM_OUTPUT_BACKUP_TALKER_UNIQUE_ID_1 0 + +#define DSC_STREAM_OUTPUT_BACKUP_TALKER_ENTITY_ID_2 0 +#define DSC_STREAM_OUTPUT_BACKUP_TALKER_UNIQUE_ID_2 0 + +#define DSC_STREAM_OUTPUT_BACKEDUP_TALKER_ENTITY_ID 0 +#define DSC_STREAM_OUTPUT_BACKEDUP_TALKER_UNIQUE_ID 0 + +#define DSC_STREAM_OUTPUT_AVB_INTERFACE_INDEX 0 +#define DSC_STREAM_OUTPUT_BUFFER_LENGTH_IN_NS 8 + +// TODO: No hardcoded values! +#define DSC_STREAM_OUTPUT_FORMATS_0 0x0205022000406000ULL +#define DSC_STREAM_OUTPUT_FORMATS_1 0x0205022000806000ULL +#define DSC_STREAM_OUTPUT_FORMATS_2 0x0205022001006000ULL +#define DSC_STREAM_OUTPUT_FORMATS_3 0x0205022001806000ULL +#define DSC_STREAM_OUTPUT_FORMATS_4 DSC_STREAM_OUTPUT_CURRENT_FORMAT + +/**************************************************************************************/ +/* IEEE 1722.1-2021, Sec. 7.2.8 AVB Interface Descriptor */ +/* Milan v1.2, Sec. 5.3.3.5 */ + +#define DSC_AVB_INTERFACE_LOCALIZED_DESCRIPTION AVB_AEM_DESC_INVALID +#define DSC_AVB_INTERFACE_INTERFACE_FLAGS (AVB_AEM_DESC_AVB_INTERFACE_FLAG_GPTP_GRANDMASTER_SUPPORTED | \ + AVB_AEM_DESC_AVB_INTERFACE_FLAG_GPTP_SUPPORTED | \ + AVB_AEM_DESC_AVB_INTERFACE_FLAG_SRP_SUPPORTED) +// TODO: This is a dynamic parameter +#define DSC_AVB_INTERFACE_CLOCK_IDENTITY 0x3cc0c6FFFE0002CB +#define DSC_AVB_INTERFACE_PRIORITY1 0xF8 +#define DSC_AVB_INTERFACE_CLOCK_CLASS 0xF8 +#define DSC_AVB_INTERFACE_OFFSET_SCALED_LOG_VARIANCE 0x436A +#define DSC_AVB_INTERFACE_CLOCK_ACCURACY 0x21 +#define DSC_AVB_INTERFACE_PRIORITY2 0xF8 +#define DSC_AVB_INTERFACE_DOMAIN_NUMBER 0 +#define DSC_AVB_INTERFACE_LOG_SYNC_INTERVAL 0 +#define DSC_AVB_INTERFACE_LOG_ANNOUNCE_INTERVAL 0 +#define DSC_AVB_INTERFACE_PDELAY_INTERVAL 0 +#define DSC_AVB_INTERFACE_PORT_NUMBER 0 + +/**************************************************************************************/ +/* IEEE 1722.1-2021, Sec. 7.2.9 CLOCK_SOURCE Descriptor */ +/* Milan v1.2, Sec. 5.3.3.6 */ + +// Internal Clock Source +#define DSC_CLOCK_SOURCE_INTERNAL_OBJECT_NAME "Internal" +#define DSC_CLOCK_SOURCE_INTERNAL_LOCALIZED_DESCRIPTION AVB_AEM_DESC_INVALID +#define DSC_CLOCK_SOURCE_INTERNAL_FLAGS 0x0002 +#define DSC_CLOCK_SOURCE_INTERNAL_TYPE AVB_AEM_DESC_CLOCK_SOURCE_TYPE_INTERNAL +#define DSC_CLOCK_SOURCE_INTERNAL_IDENTIFIER 0 +#define DSC_CLOCK_SOURCE_INTERNAL_LOCATION_TYPE AVB_AEM_DESC_CLOCK_SOURCE +#define DSC_CLOCK_SOURCE_INTERNAL_LOCATION_INDEX 0 + +// AAF Stream Clock Source +#define DSC_CLOCK_SOURCE_AAF_OBJECT_NAME "Stream Clock" +#define DSC_CLOCK_SOURCE_AAF_LOCALIZED_DESCRIPTION AVB_AEM_DESC_INVALID +#define DSC_CLOCK_SOURCE_AAF_FLAGS 0x0002 +#define DSC_CLOCK_SOURCE_AAF_TYPE AVB_AEM_DESC_CLOCK_SOURCE_TYPE_INPUT_STREAM +#define DSC_CLOCK_SOURCE_AAF_IDENTIFIER 0 +#define DSC_CLOCK_SOURCE_AAF_LOCATION_TYPE AVB_AEM_DESC_STREAM_INPUT +#define DSC_CLOCK_SOURCE_AAF_LOCATION_INDEX 0 + +// CRF Clock Source +#define DSC_CLOCK_SOURCE_CRF_OBJECT_NAME "CRF Clock" +#define DSC_CLOCK_SOURCE_CRF_LOCALIZED_DESCRIPTION AVB_AEM_DESC_INVALID +#define DSC_CLOCK_SOURCE_CRF_FLAGS 0x0002 +#define DSC_CLOCK_SOURCE_CRF_TYPE AVB_AEM_DESC_CLOCK_SOURCE_TYPE_INPUT_STREAM +#define DSC_CLOCK_SOURCE_CRF_IDENTIFIER 0 +#define DSC_CLOCK_SOURCE_CRF_LOCATION_TYPE AVB_AEM_DESC_STREAM_INPUT +#define DSC_CLOCK_SOURCE_CRF_LOCATION_INDEX 1 + +/**************************************************************************************/ +/* IEEE 1722.1-2021, Sec. 7.2.32 CLOCK_DOMAIN Descriptor */ +/* Milan v1.2, Sec. 5.3.3.11 */ + +#define DSC_CLOCK_DOMAIN_OBJECT_NAME "Clock Reference Format" +#define DSC_CLOCK_DOMAIN_LOCALIZED_DESCRIPTION AVB_AEM_DESC_INVALID +#define DSC_CLOCK_DOMAIN_CLOCK_SOURCE_INDEX 0 +#define DSC_CLOCK_DOMAIN_DESCRIPTOR_COUNTS_OFFSET (4 + sizeof(struct avb_aem_desc_clock_domain)) +#define DSC_CLOCK_DOMAIN_CLOCK_SOURCES_COUNT 3 + +#define DSC_CLOCK_DOMAIN_SOURCES_0 0 // Internal +#define DSC_CLOCK_DOMAIN_SOURCES_1 1 // AAF +#define DSC_CLOCK_DOMAIN_SOURCES_2 2 // CRF + +#endif // __DESCRIPTOR_ENTITY_MODEL_MILAN_H__