From dc44a61ef3af869a4481ef62f4e9aba56c6922de Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 16 Mar 2022 08:53:21 +0100 Subject: [PATCH] avbtp: add some more fields Add ADP entries timeout --- src/modules/module-avbtp/adp.c | 238 ++++++++++++++++++++-------- src/modules/module-avbtp/adp.h | 17 +- src/modules/module-avbtp/avdecc.c | 22 ++- src/modules/module-avbtp/internal.h | 2 +- 4 files changed, 202 insertions(+), 77 deletions(-) diff --git a/src/modules/module-avbtp/adp.c b/src/modules/module-avbtp/adp.c index 8f412b798..2be841e2f 100644 --- a/src/modules/module-avbtp/adp.c +++ b/src/modules/module-avbtp/adp.c @@ -33,6 +33,7 @@ struct entity { struct spa_list link; struct avbtp_packet_adp packet; uint64_t last_time; + unsigned advertise:1; }; struct adp { @@ -40,9 +41,10 @@ struct adp { struct spa_hook server_listener; struct spa_list entities; + uint64_t now; }; -struct entity *find_entity_by_id(struct adp *adp, uint64_t id) +static struct entity *find_entity_by_id(struct adp *adp, uint64_t id) { struct entity *e; spa_list_for_each(e, &adp->entities, link) @@ -50,62 +52,69 @@ struct entity *find_entity_by_id(struct adp *adp, uint64_t id) return e; return NULL; } +static void entity_free(struct entity *e) +{ + spa_list_remove(&e->link); + free(e); +} struct bit_info { uint32_t bits; const char *value; + const char *description; }; static const struct bit_info entity_capabilities_info[] = { - { AVBTP_ADP_ENTITY_CAPABILITY_EFU_MODE, "EFU Mode" }, - { AVBTP_ADP_ENTITY_CAPABILITY_ADDRESS_ACCESS_SUPPORTED, "Address Access Supported" }, - { AVBTP_ADP_ENTITY_CAPABILITY_GATEWAY_ENTITY, "Gateway Entity" }, - { AVBTP_ADP_ENTITY_CAPABILITY_AEM_SUPPORTED, "AEM Supported" }, - { AVBTP_ADP_ENTITY_CAPABILITY_LEGACY_AVC, "Legacy AVC" }, - { AVBTP_ADP_ENTITY_CAPABILITY_ASSOCIATION_ID_SUPPORTED, "Association Id Supported" }, - { AVBTP_ADP_ENTITY_CAPABILITY_ASSOCIATION_ID_VALID, "Association Id Valid" }, - { AVBTP_ADP_ENTITY_CAPABILITY_VENDOR_UNIQUE_SUPPORTED, "Vendor Unique Supported" }, - { AVBTP_ADP_ENTITY_CAPABILITY_CLASS_A_SUPPORTED, "Class A Supported" }, - { AVBTP_ADP_ENTITY_CAPABILITY_CLASS_B_SUPPORTED, "Class B Supported" }, - { AVBTP_ADP_ENTITY_CAPABILITY_GPTP_SUPPORTED, "gPTP Supported" }, - { AVBTP_ADP_ENTITY_CAPABILITY_AEM_AUTHENTICATION_SUPPORTED, "AEM Authentication Supported" }, - { AVBTP_ADP_ENTITY_CAPABILITY_AEM_AUTHENTICATION_REQUIRED, "AEM Authentication Required" }, - { AVBTP_ADP_ENTITY_CAPABILITY_AEM_PERSISTENT_ACQUIRE_SUPPORTED, "AEM Persisitent Acquire Supported" }, - { AVBTP_ADP_ENTITY_CAPABILITY_AEM_IDENTIFY_CONTROL_INDEX_VALID, "AEM Identify Control Index Valid" }, - { AVBTP_ADP_ENTITY_CAPABILITY_AEM_INTERFACE_INDEX_VALID, "AEM Interface Index Valid" }, - { AVBTP_ADP_ENTITY_CAPABILITY_GENERAL_CONTROLLER_IGNORE, "General Controller Ignore" }, + { AVBTP_ADP_ENTITY_CAPABILITY_EFU_MODE, "efu-mode", "EFU Mode" }, + { AVBTP_ADP_ENTITY_CAPABILITY_ADDRESS_ACCESS_SUPPORTED, "address-access-supported", "Address Access Supported" }, + { AVBTP_ADP_ENTITY_CAPABILITY_GATEWAY_ENTITY, "gateway-entity", "Gateway Entity" }, + { AVBTP_ADP_ENTITY_CAPABILITY_AEM_SUPPORTED, "aem-supported", "AEM Supported" }, + { AVBTP_ADP_ENTITY_CAPABILITY_LEGACY_AVC, "legacy-avc", "Legacy AVC" }, + { AVBTP_ADP_ENTITY_CAPABILITY_ASSOCIATION_ID_SUPPORTED, "association-id-supported", "Association Id Supported" }, + { AVBTP_ADP_ENTITY_CAPABILITY_ASSOCIATION_ID_VALID, "association-id-valid", "Association Id Valid" }, + { AVBTP_ADP_ENTITY_CAPABILITY_VENDOR_UNIQUE_SUPPORTED, "vandor-unique-suported", "Vendor Unique Supported" }, + { AVBTP_ADP_ENTITY_CAPABILITY_CLASS_A_SUPPORTED, "class-a-supported", "Class A Supported" }, + { AVBTP_ADP_ENTITY_CAPABILITY_CLASS_B_SUPPORTED, "class-b-supported", "Class B Supported" }, + { AVBTP_ADP_ENTITY_CAPABILITY_GPTP_SUPPORTED, "gptp-supported", "gPTP Supported" }, + { AVBTP_ADP_ENTITY_CAPABILITY_AEM_AUTHENTICATION_SUPPORTED, "aem-authentication-supported", "AEM Authentication Supported" }, + { AVBTP_ADP_ENTITY_CAPABILITY_AEM_AUTHENTICATION_REQUIRED, "aem-authentication-required", "AEM Authentication Required" }, + { AVBTP_ADP_ENTITY_CAPABILITY_AEM_PERSISTENT_ACQUIRE_SUPPORTED, "aem-persistent-acquire-supported", "AEM Persisitent Acquire Supported" }, + { AVBTP_ADP_ENTITY_CAPABILITY_AEM_IDENTIFY_CONTROL_INDEX_VALID, "aem-identify-control-index-valid", "AEM Identify Control Index Valid" }, + { AVBTP_ADP_ENTITY_CAPABILITY_AEM_INTERFACE_INDEX_VALID, "aem-interface-index-valid", "AEM Interface Index Valid" }, + { AVBTP_ADP_ENTITY_CAPABILITY_GENERAL_CONTROLLER_IGNORE, "general-controller-ignore", "General Controller Ignore" }, { AVBTP_ADP_ENTITY_CAPABILITY_ENTITY_NOT_READY, "Entity Not Ready" }, { 0, NULL }, }; static const struct bit_info talker_capabilities_info[] = { - { AVBTP_ADP_TALKER_CAPABILITY_IMPLEMENTED, "Implemented" }, - { AVBTP_ADP_TALKER_CAPABILITY_OTHER_SOURCE, "Other Source" }, - { AVBTP_ADP_TALKER_CAPABILITY_CONTROL_SOURCE, "Control Source" }, - { AVBTP_ADP_TALKER_CAPABILITY_MEDIA_CLOCK_SOURCE, "Media Clock Source" }, - { AVBTP_ADP_TALKER_CAPABILITY_SMPTE_SOURCE, "SMPTE Source" }, - { AVBTP_ADP_TALKER_CAPABILITY_MIDI_SOURCE, "MIDI Source" }, - { AVBTP_ADP_TALKER_CAPABILITY_AUDIO_SOURCE, "Audio Source" }, - { AVBTP_ADP_TALKER_CAPABILITY_VIDEO_SOURCE, "Video Source" }, + { AVBTP_ADP_TALKER_CAPABILITY_IMPLEMENTED, "implemented", "Implemented" }, + { AVBTP_ADP_TALKER_CAPABILITY_OTHER_SOURCE, "other-source", "Other Source" }, + { AVBTP_ADP_TALKER_CAPABILITY_CONTROL_SOURCE, "control-source", "Control Source" }, + { AVBTP_ADP_TALKER_CAPABILITY_MEDIA_CLOCK_SOURCE, "media-clock-source", "Media Clock Source" }, + { AVBTP_ADP_TALKER_CAPABILITY_SMPTE_SOURCE, "smpte-source", "SMPTE Source" }, + { AVBTP_ADP_TALKER_CAPABILITY_MIDI_SOURCE, "midi-source", "MIDI Source" }, + { AVBTP_ADP_TALKER_CAPABILITY_AUDIO_SOURCE, "audio-source", "Audio Source" }, + { AVBTP_ADP_TALKER_CAPABILITY_VIDEO_SOURCE, "video-source", "Video Source" }, { 0, NULL }, }; static const struct bit_info listener_capabilities_info[] = { - { AVBTP_ADP_LISTENER_CAPABILITY_IMPLEMENTED, "Implemented" }, - { AVBTP_ADP_LISTENER_CAPABILITY_OTHER_SINK, "Other Sink" }, - { AVBTP_ADP_LISTENER_CAPABILITY_CONTROL_SINK, "Control Sink" }, - { AVBTP_ADP_LISTENER_CAPABILITY_MEDIA_CLOCK_SINK, "Media Clock Sink" }, - { AVBTP_ADP_LISTENER_CAPABILITY_SMPTE_SINK, "SMPTE Sink" }, - { AVBTP_ADP_LISTENER_CAPABILITY_MIDI_SINK, "MIDI Sink" }, - { AVBTP_ADP_LISTENER_CAPABILITY_AUDIO_SINK, "Audio Sink" }, - { AVBTP_ADP_LISTENER_CAPABILITY_VIDEO_SINK, "Video Sink" }, + { AVBTP_ADP_LISTENER_CAPABILITY_IMPLEMENTED, "implemented", "Implemented" }, + { AVBTP_ADP_LISTENER_CAPABILITY_OTHER_SINK, "other-sink", "Other Sink" }, + { AVBTP_ADP_LISTENER_CAPABILITY_CONTROL_SINK, "control-sink", "Control Sink" }, + { AVBTP_ADP_LISTENER_CAPABILITY_MEDIA_CLOCK_SINK, "media-clock-sink", "Media Clock Sink" }, + { AVBTP_ADP_LISTENER_CAPABILITY_SMPTE_SINK, "smpte-sink", "SMPTE Sink" }, + { AVBTP_ADP_LISTENER_CAPABILITY_MIDI_SINK, "midi-sink", "MIDI Sink" }, + { AVBTP_ADP_LISTENER_CAPABILITY_AUDIO_SINK, "audio-sink", "Audio Sink" }, + { AVBTP_ADP_LISTENER_CAPABILITY_VIDEO_SINK, "video-sink", "Video Sink" }, { 0, NULL }, }; static const struct bit_info controller_capabilities_info[] = { - { AVBTP_ADP_CONTROLLER_CAPABILITY_IMPLEMENTED, "Implemented" }, - { AVBTP_ADP_CONTROLLER_CAPABILITY_LAYER3_PROXY, "Layer 3 Proxy" }, + { AVBTP_ADP_CONTROLLER_CAPABILITY_IMPLEMENTED, "implemented", "Implemented" }, + { AVBTP_ADP_CONTROLLER_CAPABILITY_LAYER3_PROXY, "layer-3-proxy", "Layer 3 Proxy" }, { 0, NULL }, }; + static void print_bit_info(int indent, uint32_t bits, const struct bit_info *info) { uint32_t i; @@ -139,6 +148,9 @@ static const char *message_type_as_string(uint8_t message_type) #define KEY_CONTROLLER_CAPABILITIES "controller-capabilities" #define KEY_AVAILABLE_INDEX "available-index" #define KEY_GPTP_GRANDMASTER_ID "gptp-grandmaster-id" +#define KEY_GPTP_DOMAIN_NUMBER "gptp-domain-number" +#define KEY_IDENTIFY_CONTROL_INDEX "indentify-control-index" +#define KEY_INTERFACE_INDEX "interface-index" #define KEY_ASSOCIATION_ID "association-id" static inline char *format_id(char *str, size_t size, const uint64_t id) @@ -162,8 +174,10 @@ static void adp_message_debug(struct adp *adp, const struct avbtp_packet_adp *p) pw_log_info("message-type: %d (%s)", v, message_type_as_string(v)); pw_log_info(" length: %d", AVBTP_PACKET_ADP_GET_LENGTH(p)); pw_log_info(" "KEY_VALID_TIME": %d", AVBTP_PACKET_ADP_GET_VALID_TIME(p)); - pw_log_info(" "KEY_ENTITY_ID": %s", format_id(buf, sizeof(buf), AVBTP_PACKET_ADP_GET_ENTITY_ID(p))); - pw_log_info(" "KEY_ENTITY_MODEL_ID": 0x%"PRIx64, AVBTP_PACKET_ADP_GET_ENTITY_MODEL_ID(p)); + pw_log_info(" "KEY_ENTITY_ID": %s", + format_id(buf, sizeof(buf), AVBTP_PACKET_ADP_GET_ENTITY_ID(p))); + pw_log_info(" "KEY_ENTITY_MODEL_ID": %s", + format_id(buf, sizeof(buf), AVBTP_PACKET_ADP_GET_ENTITY_MODEL_ID(p))); v = AVBTP_PACKET_ADP_GET_ENTITY_CAPABILITIES(p); pw_log_info(" "KEY_ENTITY_CAPABILITIES": 0x%08x", v); print_bit_info(4, v, entity_capabilities_info); @@ -179,8 +193,13 @@ static void adp_message_debug(struct adp *adp, const struct avbtp_packet_adp *p) pw_log_info(" "KEY_CONTROLLER_CAPABILITIES": %08x", v); print_bit_info(4, v, controller_capabilities_info); pw_log_info(" "KEY_AVAILABLE_INDEX": 0x%08x", AVBTP_PACKET_ADP_GET_AVAILABLE_INDEX(p)); - pw_log_info(" "KEY_GPTP_GRANDMASTER_ID": 0x%"PRIx64, AVBTP_PACKET_ADP_GET_GPTP_GRANDMASTER_ID(p)); - pw_log_info(" "KEY_ASSOCIATION_ID": 0x%08x", AVBTP_PACKET_ADP_GET_ASSOCIATION_ID(p)); + pw_log_info(" "KEY_GPTP_GRANDMASTER_ID": %s", + format_id(buf, sizeof(buf), AVBTP_PACKET_ADP_GET_GPTP_GRANDMASTER_ID(p))); + pw_log_info(" "KEY_GPTP_DOMAIN_NUMBER": %d", AVBTP_PACKET_ADP_GET_GPTP_DOMAIN_NUMBER(p)); + pw_log_info(" "KEY_IDENTIFY_CONTROL_INDEX": %d", AVBTP_PACKET_ADP_GET_IDENTIFY_CONTROL_INDEX(p)); + pw_log_info(" "KEY_INTERFACE_INDEX": %d", AVBTP_PACKET_ADP_GET_INTERFACE_INDEX(p)); + pw_log_info(" "KEY_ASSOCIATION_ID": %s", + format_id(buf, sizeof(buf), AVBTP_PACKET_ADP_GET_ASSOCIATION_ID(p))); } static int adp_message(void *data, uint64_t now, const void *message, int len) @@ -189,10 +208,10 @@ static int adp_message(void *data, uint64_t now, const void *message, int len) const struct avbtp_packet_adp *p = message; struct entity *e; - if (AVBTP_PACKET_GET_SUBTYPE(p) != AVBTP_SUBTYPE_ADP) + if (AVBTP_PACKET_GET_SUBTYPE(p) != AVBTP_SUBTYPE_ADP || + AVBTP_PACKET_ADP_GET_LENGTH(p) != AVBTP_ADP_DATA_LENGTH) return 0; - e = find_entity_by_id(adp, AVBTP_PACKET_ADP_GET_ENTITY_ID(p)); if (e == NULL) { e = calloc(1, sizeof(*e)); @@ -205,7 +224,7 @@ static int adp_message(void *data, uint64_t now, const void *message, int len) if (adp->server->debug_messages) adp_message_debug(adp, p); } - e->last_time = now; + e->last_time = adp->now = now; return 0; } @@ -217,9 +236,42 @@ static void adp_destroy(void *data) free(adp); } +static int send_advertise(struct adp *adp, uint64_t now, struct entity *e) +{ + e->last_time = now; + return 0; +} + +static void check_entries(struct adp *adp, uint64_t now) +{ + struct entity *e, *t; + char buf[128]; + + spa_list_for_each_safe(e, t, &adp->entities, link) { + int valid_time = AVBTP_PACKET_ADP_GET_VALID_TIME(&e->packet); + + if (e->advertise) { + if (e->last_time + (valid_time / 2) * SPA_NSEC_PER_SEC > now) + continue; + + pw_log_info("entity %s readvertise", + format_id(buf, sizeof(buf), AVBTP_PACKET_ADP_GET_ENTITY_ID(&e->packet))); + + send_advertise(adp, now, e); + } else { + if (e->last_time + (valid_time + 2) * SPA_NSEC_PER_SEC > now) + continue; + + pw_log_info("entity %s timeout", + format_id(buf, sizeof(buf), AVBTP_PACKET_ADP_GET_ENTITY_ID(&e->packet))); + entity_free(e); + } + } +} static void adp_periodic(void *data, uint64_t now) { struct adp *adp = data; + check_entries(adp, now); } static int parse_id(const char *value, int len, uint64_t *id) @@ -228,23 +280,47 @@ static int parse_id(const char *value, int len, uint64_t *id) uint8_t v[6]; uint16_t unique_id; if (spa_json_parse_stringn(value, len, str, sizeof(str)) <= 0) - return 0; + return -EINVAL; if (sscanf(str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hx", &v[0], &v[1], &v[2], &v[3], - &v[4], &v[5], &unique_id) != 7) + &v[4], &v[5], &unique_id) == 7) { + *id = (uint64_t) v[0] << 56 | + (uint64_t) v[1] << 48 | + (uint64_t) v[2] << 40 | + (uint64_t) v[3] << 32 | + (uint64_t) v[4] << 24 | + (uint64_t) v[5] << 16 | + unique_id; + } else if (!spa_atou64(str, id, 0)) return -EINVAL; - *id = (uint64_t) v[0] << 56 | - (uint64_t) v[1] << 48 | - (uint64_t) v[2] << 40 | - (uint64_t) v[3] << 32 | - (uint64_t) v[4] << 24 | - (uint64_t) v[5] << 16 | - unique_id; - return 0; + return 1; } -static int parse_bits(const char *value, int len, int *bits) +static int parse_bits(struct spa_json *it, const char *value, int len, const struct bit_info *info, int *bits) +{ + uint32_t i; + int b = 0; + struct spa_json sub; + char val[256]; + + if (spa_json_is_array(value, len)) { + spa_json_enter(it, &sub); + while (spa_json_get_string(&sub, val, sizeof(val)) > 0) { + for (i = 0; info[i].value; i++) { + if (spa_streq(val, info[i].value)) { + b |= info[i].bits; + break; + } + } + } + } else if (!spa_json_parse_int(value, len, &b)) { + return -EINVAL; + } + *bits = b; + return 1; +} + +static int do_help(struct adp *adp, const char *args) { - *bits = 0; return 0; } @@ -259,12 +335,16 @@ static int do_advertise(struct adp *adp, const char *args) if (e == NULL) return -errno; + e->advertise = true; + e->last_time = adp->now; + + p = &e->packet; + AVBTP_PACKET_ADP_SET_LENGTH(p, AVBTP_ADP_DATA_LENGTH); + spa_json_init(&it[0], args, strlen(args)); if (spa_json_enter_object(&it[0], &it[1]) <= 0) return -EINVAL; - p = &e->packet; - while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) { int len, int_val; const char *value; @@ -280,38 +360,47 @@ static int do_advertise(struct adp *adp, const char *args) if (spa_json_parse_int(value, len, &int_val)) AVBTP_PACKET_ADP_SET_VALID_TIME(p, int_val); } else if (spa_streq(key, KEY_ENTITY_ID)) { - if (parse_id(value, len, &id_val)) + if (parse_id(value, len, &id_val) > 0) AVBTP_PACKET_ADP_SET_ENTITY_ID(p, id_val); } else if (spa_streq(key, KEY_ENTITY_MODEL_ID)) { - if (parse_id(value, len, &id_val)) + if (parse_id(value, len, &id_val) > 0) AVBTP_PACKET_ADP_SET_ENTITY_MODEL_ID(p, id_val); } else if (spa_streq(key, KEY_ENTITY_CAPABILITIES)) { - if (parse_bits(value, len, &int_val)) + if (parse_bits(&it[1], value, len, entity_capabilities_info, &int_val)) AVBTP_PACKET_ADP_SET_ENTITY_CAPABILITIES(p, int_val); } else if (spa_streq(key, KEY_TALKER_STREAM_SOURCES)) { if (spa_json_parse_int(value, len, &int_val)) AVBTP_PACKET_ADP_SET_TALKER_STREAM_SOURCES(p, int_val); } else if (spa_streq(key, KEY_TALKER_CAPABILITIES)) { - if (parse_bits(value, len, &int_val)) + if (parse_bits(&it[1], value, len, talker_capabilities_info, &int_val)) AVBTP_PACKET_ADP_SET_TALKER_CAPABILITIES(p, int_val); } else if (spa_streq(key, KEY_LISTENER_STREAM_SINKS)) { if (spa_json_parse_int(value, len, &int_val)) AVBTP_PACKET_ADP_SET_LISTENER_STREAM_SINKS(p, int_val); } else if (spa_streq(key, KEY_LISTENER_CAPABILITIES)) { - if (parse_bits(value, len, &int_val)) + if (parse_bits(&it[1], value, len, listener_capabilities_info, &int_val)) AVBTP_PACKET_ADP_SET_LISTENER_CAPABILITIES(p, int_val); } else if (spa_streq(key, KEY_CONTROLLER_CAPABILITIES)) { - if (parse_bits(value, len, &int_val)) + if (parse_bits(&it[1], value, len, controller_capabilities_info, &int_val)) AVBTP_PACKET_ADP_SET_CONTROLLER_CAPABILITIES(p, int_val); } else if (spa_streq(key, KEY_AVAILABLE_INDEX)) { if (spa_json_parse_int(value, len, &int_val)) AVBTP_PACKET_ADP_SET_AVAILABLE_INDEX(p, int_val); } else if (spa_streq(key, KEY_GPTP_GRANDMASTER_ID)) { - if (parse_id(value, len, &id_val)) + if (parse_id(value, len, &id_val) > 0) AVBTP_PACKET_ADP_SET_GPTP_GRANDMASTER_ID(p, id_val); - } else if (spa_streq(key, KEY_ASSOCIATION_ID)) { + } else if (spa_streq(key, KEY_GPTP_DOMAIN_NUMBER)) { if (spa_json_parse_int(value, len, &int_val)) - AVBTP_PACKET_ADP_SET_ASSOCIATION_ID(p, int_val); + AVBTP_PACKET_ADP_SET_GPTP_DOMAIN_NUMBER(p, int_val); + } else if (spa_streq(key, KEY_IDENTIFY_CONTROL_INDEX)) { + if (spa_json_parse_int(value, len, &int_val)) + AVBTP_PACKET_ADP_SET_IDENTIFY_CONTROL_INDEX(p, int_val); + } else if (spa_streq(key, KEY_INTERFACE_INDEX)) { + if (spa_json_parse_int(value, len, &int_val)) + AVBTP_PACKET_ADP_SET_INTERFACE_INDEX(p, int_val); + } else if (spa_streq(key, KEY_ASSOCIATION_ID)) { + if (parse_id(value, len, &id_val)) + AVBTP_PACKET_ADP_SET_ASSOCIATION_ID(p, id_val); } } if (find_entity_by_id(adp, AVBTP_PACKET_ADP_GET_ENTITY_ID(p))) { @@ -336,19 +425,28 @@ static int do_discover(struct adp *adp, const char *args) return 0; } -static int adp_command(void *data, const char *command, const char *args) +static int adp_command(void *data, uint64_t now, const char *command, const char *args) { struct adp *adp = data; int res; - if (spa_streq(command, "/adp/advertise")) + if (!spa_strstartswith(command, "/adp/")) + return 0; + + command += strlen("/adp/"); + adp->now = now; + + if (spa_streq(command, "help")) + res = do_help(adp, args); + else if (spa_streq(command, "advertise")) res = do_advertise(adp, args); - else if (spa_streq(command, "/adp/depart")) + else if (spa_streq(command, "depart")) res = do_depart(adp, args); - else if (spa_streq(command, "/adp/discover")) + else if (spa_streq(command, "discover")) res = do_discover(adp, args); else res = -ENOTSUP; + return res; } diff --git a/src/modules/module-avbtp/adp.h b/src/modules/module-avbtp/adp.h index 02a08a1b3..1dce5eb88 100644 --- a/src/modules/module-avbtp/adp.h +++ b/src/modules/module-avbtp/adp.h @@ -72,6 +72,8 @@ #define AVBTP_ADP_CONTROLLER_CAPABILITY_IMPLEMENTED (1u<<0) #define AVBTP_ADP_CONTROLLER_CAPABILITY_LAYER3_PROXY (1u<<1) +#define AVBTP_ADP_DATA_LENGTH 56 + struct avbtp_packet_adp { uint8_t subtype; #if __BYTE_ORDER == __BIG_ENDIAN @@ -100,10 +102,11 @@ struct avbtp_packet_adp { uint32_t controller_capabilities; uint32_t available_index; uint64_t gptp_grandmaster_id; - uint32_t reserved0; + uint8_t gptp_domain_number; + uint8_t reserved0[3]; uint16_t identify_control_index; uint16_t interface_index; - uint32_t association_id; + uint64_t association_id; uint32_t reserved1; } __attribute__ ((__packed__)); @@ -123,7 +126,10 @@ struct avbtp_packet_adp { #define AVBTP_PACKET_ADP_SET_CONTROLLER_CAPABILITIES(p,v) ((p)->controller_capabilities = htonl(v)) #define AVBTP_PACKET_ADP_SET_AVAILABLE_INDEX(p,v) ((p)->available_index = htonl(v)) #define AVBTP_PACKET_ADP_SET_GPTP_GRANDMASTER_ID(p,v) ((p)->gptp_grandmaster_id = htobe64(v)) -#define AVBTP_PACKET_ADP_SET_ASSOCIATION_ID(p,v) ((p)->association_id = htonl(v)) +#define AVBTP_PACKET_ADP_SET_GPTP_DOMAIN_NUMBER(p,v) ((p)->gptp_domain_number = (v)) +#define AVBTP_PACKET_ADP_SET_IDENTIFY_CONTROL_INDEX(p,v) ((p)->identify_control_index = htons(v)) +#define AVBTP_PACKET_ADP_SET_INTERFACE_INDEX(p,v) ((p)->interface_index = htons(v)) +#define AVBTP_PACKET_ADP_SET_ASSOCIATION_ID(p,v) ((p)->association_id = htobe64(v)) #define AVBTP_PACKET_ADP_GET_SUBTYPE(p) ((p)->subtype) #define AVBTP_PACKET_ADP_GET_SV(p) ((p)->sv) @@ -141,7 +147,10 @@ struct avbtp_packet_adp { #define AVBTP_PACKET_ADP_GET_CONTROLLER_CAPABILITIES(p) ntohl((p)->controller_capabilities) #define AVBTP_PACKET_ADP_GET_AVAILABLE_INDEX(p) ntohl((p)->available_index) #define AVBTP_PACKET_ADP_GET_GPTP_GRANDMASTER_ID(p) be64toh((p)->gptp_grandmaster_id) -#define AVBTP_PACKET_ADP_GET_ASSOCIATION_ID(p) ntohl((p)->association_id) +#define AVBTP_PACKET_ADP_GET_GPTP_DOMAIN_NUMBER(p) ((p)->gptp_domain_number) +#define AVBTP_PACKET_ADP_GET_IDENTIFY_CONTROL_INDEX(p) ntohs((p)->identify_control_index) +#define AVBTP_PACKET_ADP_GET_INTERFACE_INDEX(p) ntohs((p)->interface_index) +#define AVBTP_PACKET_ADP_GET_ASSOCIATION_ID(p) be64toh((p)->association_id) struct avbtp_adp *avbtp_adp_register(struct server *server); diff --git a/src/modules/module-avbtp/avdecc.c b/src/modules/module-avbtp/avdecc.c index 4b1ad566a..c76e96c6e 100644 --- a/src/modules/module-avbtp/avdecc.c +++ b/src/modules/module-avbtp/avdecc.c @@ -48,13 +48,12 @@ #define server_emit_destroy(s) server_emit(s, destroy, 0) #define server_emit_message(s,n,m,l) server_emit(s, message, 0, n, m, l) #define server_emit_periodic(s,n) server_emit(s, periodic, 0, n) -#define server_emit_command(s,c,a) server_emit(s, command, 0, c, a) +#define server_emit_command(s,n,c,a) server_emit(s, command, 0, n, c, a) static void on_timer_event(void *data, uint64_t expirations) { struct server *server = data; struct timespec now; - clock_gettime(CLOCK_REALTIME, &now); server_emit_periodic(server, SPA_TIMESPEC_TO_NSEC(&now)); } @@ -165,6 +164,7 @@ struct server *avdecc_server_new(struct impl *impl, const char *ifname, struct s { struct server *server; int res = 0; + struct timespec now; server = calloc(1, sizeof(*server)); if (server == NULL) @@ -183,6 +183,24 @@ struct server *avdecc_server_new(struct impl *impl, const char *ifname, struct s avbtp_adp_register(server); avbtp_maap_register(server); + clock_gettime(CLOCK_REALTIME, &now); + server_emit_command(server, SPA_TIMESPEC_TO_NSEC(&now), + "/adp/advertise", + "{" + " valid-time = 10 " + " entity-id = \"00:01:02:03:04:05:0001\" " + " entity-model-id = \"00:01:02:03:04:05:0600\" " + " entity-capabilities = [ efu-mode aem-supported class-a-supported gptp-supported ] " + " talker-stream-sources = 5 " + " talker-capabilities = [ implemented audio-source ] " + " listener-stream-sinks = 4 " + " listener-capabilities = [ implemented audio-sink ] " + " controller-capabilities = [ ] " + " available-index = 10 " + " gptp-grandmaster-id = \"10:20:30:40:50:60:0001\" " + " gptp-domain-number = 6 " + " association-id = 0001 " + "}"); return server; error_free: diff --git a/src/modules/module-avbtp/internal.h b/src/modules/module-avbtp/internal.h index 5796a8562..f1a3a22d3 100644 --- a/src/modules/module-avbtp/internal.h +++ b/src/modules/module-avbtp/internal.h @@ -53,7 +53,7 @@ struct server_events { void (*periodic) (void *data, uint64_t now); - int (*command) (void *data, const char *command, const char *args); + int (*command) (void *data, uint64_t now, const char *command, const char *args); }; struct server {