Merge branch '5294-a-configurable-aem-entity-model' into 'master'

Resolve "milan-avb: A configurable AEM Entity model"

See merge request pipewire/pipewire!2845
This commit is contained in:
sirmb 2026-06-01 00:52:48 +00:00
commit 2d05f5e1e6
3 changed files with 130 additions and 15 deletions

View file

@ -72,6 +72,18 @@ avb.properties = {
ifname = "enp3s0"
milan = false
ptp.management-socket = "/var/run/ptp4lro"
entity = {
#entity_name = ""
#group_name = ""
#serial_number = ""
#firmware_version = ""
#vendor_name = ""
#model_name = ""
#talker_capabilities = ""
#listener_capabilities = ""
#entity_capabilities = ""
#controller_capabilities = ""
}
}
avb.properties.rules = [

View file

@ -12,6 +12,7 @@
#include "es-builder.h"
#include "entity-model-milan-v12.h"
#include "entity-parser.h"
static void init_descriptor_legacy_avb(struct server *server)
{
@ -331,35 +332,39 @@ static void init_descriptor_milan_v12(struct server *server)
/**************************************************************************************/
/* IEEE 1722.1-2021, Sec. 7.2.1 - ENTITY Descriptor */
/* Milan v1.2, Sec. 5.3.3.1 */
struct avb_entity_config entity_conf = conf_load_entity(server->impl->props);
es_builder_add_descriptor(server, AVB_AEM_DESC_ENTITY, 0,
sizeof(struct avb_aem_desc_entity),
&(struct avb_aem_desc_entity)
struct avb_aem_desc_entity entity_desc =
{
.entity_id = htobe64(server->entity_id),
.entity_model_id = htobe64(DSC_ENTITY_MODEL_ID),
.entity_capabilities = htonl(DSC_ENTITY_MODEL_ENTITY_CAPABILITIES),
.entity_capabilities = htonl(entity_conf.entity_capabilities),
.talker_stream_sources = htons(DSC_ENTITY_MODEL_TALKER_STREAM_SOURCES),
.talker_capabilities = htons(DSC_ENTITY_MODEL_TALKER_CAPABILITIES),
.talker_capabilities = htons(entity_conf.talker_capabilities),
.listener_stream_sinks = htons(DSC_ENTITY_MODEL_LISTENER_STREAM_SINKS),
.listener_capabilities = htons(DSC_ENTITY_MODEL_LISTENER_CAPABILITIES),
.listener_capabilities = htons(entity_conf.listener_capabilities),
.controller_capabilities = htons(DSC_ENTITY_MODEL_CONTROLLER_CAPABILITIES),
.controller_capabilities = htons(entity_conf.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,
.vendor_name_string = htons(entity_conf.vendor_name),
.model_name_string = htons(entity_conf.model_name),
.configurations_count = htons(DSC_ENTITY_MODEL_CONFIGURATIONS_COUNT),
.current_configuration = htons(DSC_ENTITY_MODEL_CURRENT_CONFIGURATION)
});
};
memcpy(entity_desc.entity_name, entity_conf.entity_name, sizeof(entity_desc.entity_name));
memcpy(entity_desc.firmware_version, entity_conf.firmware_version, sizeof(entity_desc.firmware_version));
memcpy(entity_desc.group_name, entity_conf.group_name, sizeof(entity_desc.group_name));
memcpy(entity_desc.serial_number, entity_conf.serial_number, sizeof(entity_desc.serial_number));
es_builder_add_descriptor(server, AVB_AEM_DESC_ENTITY, 0,
sizeof(struct avb_aem_desc_entity),
&entity_desc);
/**************************************************************************************/
/* IEEE 1722.1-2021, Sec. 7.2.2 - CONFIGURATION Descriptor*/
@ -854,5 +859,5 @@ void init_descriptors(struct server *server)
default:
pw_log_error("Unknown AVB mode");
break;
}
}
}

View file

@ -0,0 +1,98 @@
#ifndef ENTITY_PARSER_H
#define ENTITY_PARSER_H
#include "aecp-aem-descriptors.h"
#include "avb.h"
#include "entity-model-milan-v12.h"
#include "internal.h"
#include "descriptors.h"
#include "strings.h"
#include <cstddef>
struct avb_entity_config {
char entity_name[64];
char group_name[64];
char serial_number[64];
char firmware_version[64];
uint16_t vendor_name;
uint16_t model_name;
uint16_t talker_capabilities;
uint16_t listener_capabilities;
uint32_t entity_capabilities;
uint32_t controller_capabilities;
};
static inline struct avb_entity_config conf_load_entity (struct pw_properties *props) {
// Grab entity field and turn into pw_properties struct
struct avb_entity_config entity_conf;
char *str;
pw_log_info("Acquiring entity properties from entity dict in avb.properties");
str = pw_properties_get(props, "entity");
struct pw_properties *entity_props;
entity_props = pw_properties_new(NULL,NULL);
pw_properties_update_string(entity_props, str, strlen(str));
// Assign properties to aem_entity_config struct
// First handle strings
//TODO: with strings, check utf8 format and set as a filled 64 byte char array
// check zero padding and utf8 format
pw_log_info("Assigning entity properties");
char *name = pw_properties_get(entity_props, "entity_name");
char *entity_name;
int use_default = name ? 1 : 0;
size_t len;
if (name){
len = strnlen(name, 64);
if (validate_utf8(name, len)) entity_name = name;
else use_default = 1;
if (use_default){
len = strnlen(name, 64);
entity_name = (char *)DSC_ENTITY_MODEL_ENTITY_NAME;
}
memcpy(entity_conf.entity_name, entity_name, 64);
memset(entity_conf.entity_name + len, 0, 64 - len);
char *serial = pw_properties_get(entity_props, "serial_number");
char *serial_number = serial ? serial : DSC_ENTITY_MODEL_SERIAL_NUMBER;
strncpy(entity_conf.serial_number, serial_number, sizeof(entity_conf.serial_number));
char *firmware = pw_properties_get(entity_props, "firmware_version");
char *firmware_version = firmware ? firmware : DSC_ENTITY_MODEL_FIRMWARE_VERSION;
strncpy(entity_conf.firmware_version, firmware_version, sizeof(entity_conf.firmware_version));
char *group = pw_properties_get(entity_props, "group_name");
char *group_name = group ? group: DSC_ENTITY_MODEL_GROUP_NAME;
strncpy(entity_conf.group_name, group_name, sizeof(entity_conf.group_name));
// Handle integers
uint32_t vendor_name;
int vn_found = pw_properties_fetch_uint32(entity_props, "vendor_name", &vendor_name);
entity_conf.vendor_name = !vn_found ? (uint16_t)vendor_name : DSC_ENTITY_MODEL_VENDOR_NAME_STRING;
uint32_t model_name;
int mn_found = pw_properties_fetch_uint32(entity_props, "model_name", &model_name);
entity_conf.model_name = !mn_found ? (uint16_t)model_name : DSC_ENTITY_MODEL_MODEL_NAME_STRING;
uint32_t talker_capabilities;
int tc_found = pw_properties_fetch_uint32(entity_props, "talker_capabilities", &talker_capabilities);
entity_conf.talker_capabilities = !tc_found ? (uint16_t)talker_capabilities : DSC_ENTITY_MODEL_TALKER_CAPABILITIES;
uint32_t listener_capabilities;
int lc_found = pw_properties_fetch_uint32(entity_props, "listener_capabilities", &listener_capabilities);
entity_conf.listener_capabilities = !lc_found ? (uint16_t)listener_capabilities : DSC_ENTITY_MODEL_LISTENER_CAPABILITIES;
uint32_t entity_capabilities;
int ec_found = pw_properties_fetch_uint32(entity_props, "entity_capabilities", &entity_capabilities);
entity_conf.entity_capabilities = !ec_found ? entity_capabilities : DSC_ENTITY_MODEL_ENTITY_CAPABILITIES;
uint32_t controller_capabilities;
int cc_found = pw_properties_fetch_uint32(entity_props, "controller_capabilities", &controller_capabilities);
entity_conf.controller_capabilities = !cc_found ? controller_capabilities : DSC_ENTITY_MODEL_CONTROLLER_CAPABILITIES;
return entity_conf;
}
#endif /* ENTITY_PARSER_H */