From c2ada3175e03ea728f630078a57a671a45ed505d Mon Sep 17 00:00:00 2001 From: hackerman-kl Date: Sun, 7 Dec 2025 13:27:00 +0100 Subject: [PATCH] module-avb: aecp-aem: SET/GET STREAM_FORMAT answer implemented. In the current state the GET/SET stream format can handle the commands response however, yet, it does not take care of checking that: * A bound input stream cannot have it set, should reply accordingly * A STREAMING_STREAM output stream cannot have it set, should reply accordingly. --- src/modules/meson.build | 4 +- .../cmd-get-set-stream-format.c | 152 ++++++++++++++++++ .../cmd-get-set-stream-format.h | 16 ++ src/modules/module-avb/aecp-aem.c | 9 +- 4 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-stream-format.c create mode 100644 src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-stream-format.h diff --git a/src/modules/meson.build b/src/modules/meson.build index 6da14d849..9915d3735 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -736,11 +736,13 @@ if build_module_avb 'module-avb/acmp.c', 'module-avb/aecp.c', 'module-avb/aecp-aem.c', - 'module-avb/aecp-aem-cmds-resps/cmd-lock-entity.c', 'module-avb/aecp-aem-cmds-resps/cmd-available.c', 'module-avb/aecp-aem-cmds-resps/cmd-get-set-name.c', 'module-avb/aecp-aem-cmds-resps/cmd-register-unsolicited-notifications.c', 'module-avb/aecp-aem-cmds-resps/cmd-deregister-unsolicited-notifications.c', + 'module-avb/aecp-aem-cmds-resps/cmd-register-unsolicited-notifications.c', + 'module-avb/aecp-aem-cmds-resps/cmd-get-set-stream-format.c', + 'module-avb/aecp-aem-cmds-resps/cmd-lock-entity.c', 'module-avb/aecp-aem-cmds-resps/reply-unsol-helpers.c', 'module-avb/es-builder.c', 'module-avb/avdecc.c', diff --git a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-stream-format.c b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-stream-format.c new file mode 100644 index 000000000..a3bb925b5 --- /dev/null +++ b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-stream-format.c @@ -0,0 +1,152 @@ +/* AVB support */ +/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki */ +/* SPDX-License-Identifier: MIT */ + +#include +#include +#include + +#include "../aecp.h" +#include "../aecp-aem.h" +#include "../aecp-aem-state.h" +#include "../aecp-aem-descriptors.h" +#include "../aecp-aem-types.h" + +#include "cmd-get-set-stream-format.h" +#include "cmd-resp-helpers.h" +#include "reply-unsol-helpers.h" + +static int send_unsol_stream_format(struct aecp *aecp, void *msg, int len) +{ + struct avb_ethernet_header *h_unsol = (void*)msg; + struct avb_packet_aecp_aem *p_unsol = SPA_PTROFF(h_unsol, sizeof(*h_unsol), void); + struct aecp_aem_base_info info = { 0 }; + + /* Set the originator controller ID to avoid echo */ + info.controller_entity_id = htobe64(p_unsol->aecp.controller_guid); + info.expire_timeout = INT64_MAX; + + return reply_unsolicited_notifications(aecp, &info, msg, len, false); +} + +/** + * \see IEEE 1722.1-2021 7.4.10 + * \see Milan V1.2 5.4.2.8 GET_STREAM_FORMAT + */ +int handle_cmd_get_stream_format_milan_v12(struct aecp *aecp, int64_t now, + const void *m, int len) +{ + uint8_t buf[2048]; + struct server *server = aecp->server; + const struct avb_ethernet_header *h = m; + const struct avb_packet_aecp_aem *p = SPA_PTROFF(h, sizeof(*h), void); + const struct avb_packet_aecp_aem_setget_stream_format *get_cmd; + struct avb_ethernet_header *h_reply; + struct avb_packet_aecp_aem *p_reply; + struct avb_packet_aecp_aem_setget_stream_format *get_reply; + struct descriptor *desc; + struct avb_aem_desc_stream *stream_desc; + uint16_t desc_type, desc_id; + + get_cmd = (const struct avb_packet_aecp_aem_setget_stream_format *)p->payload; + desc_type = ntohs(get_cmd->descriptor_type); + desc_id = ntohs(get_cmd->descriptor_id); + + desc = server_find_descriptor(server, desc_type, desc_id); + if (desc == NULL) + return reply_status(aecp, + AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, m, len); + + if (desc_type != AVB_AEM_DESC_STREAM_INPUT && + desc_type != AVB_AEM_DESC_STREAM_OUTPUT) + return reply_status(aecp, + AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, m, len); + + stream_desc = (struct avb_aem_desc_stream *)desc->ptr; + + memcpy(buf, m, len); + h_reply = (struct avb_ethernet_header *)buf; + p_reply = SPA_PTROFF(h_reply, sizeof(*h_reply), void); + get_reply = (struct avb_packet_aecp_aem_setget_stream_format *)p_reply->payload; + + get_reply->stream_format = stream_desc->current_format; + + return reply_success(aecp, buf, len); +} + +/** + * \see IEEE 1722.1-2021 7.4.9 + * \see Milan V1.2 5.4.2.7 SET_STREAM_FORMAT + */ +int handle_cmd_set_stream_format_milan_v12(struct aecp *aecp, int64_t now, + const void *m, int len) +{ + uint8_t buf[2048]; + struct server *server = aecp->server; + const struct avb_ethernet_header *h = m; + const struct avb_packet_aecp_aem *p = SPA_PTROFF(h, sizeof(*h), void); + const struct avb_packet_aecp_aem_setget_stream_format *set_cmd; + struct avb_ethernet_header *h_reply; + struct avb_packet_aecp_aem *p_reply; + struct avb_packet_aecp_aem_setget_stream_format *set_reply; + struct descriptor *desc; + struct avb_aem_desc_stream *stream_desc; + uint16_t desc_type, desc_id; + uint64_t new_format; + int i; + int rc; + bool found = false; + + set_cmd = (const struct avb_packet_aecp_aem_setget_stream_format *)p->payload; + desc_type = ntohs(set_cmd->descriptor_type); + desc_id = ntohs(set_cmd->descriptor_id); + new_format = set_cmd->stream_format; + + desc = server_find_descriptor(server, desc_type, desc_id); + if (desc == NULL) + return reply_status(aecp, + AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, m, len); + + if (desc_type == AVB_AEM_DESC_STREAM_INPUT) { + struct aecp_aem_stream_input_state *state = + (struct aecp_aem_stream_input_state *)desc->ptr; + stream = &state->stream; + // TODO check if the stream is bound + } else if (desc_type == AVB_AEM_DESC_STREAM_OUTPUT) { + struct aecp_aem_stream_output_state *state = + (struct aecp_aem_stream_output_state *)desc->ptr; + stream = &state->stream; + // TODO check if the stream is STREAM_RUNNING + } else { + return reply_status(aecp, + AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, m, len); + } + + stream_desc = (struct avb_aem_desc_stream *)desc->ptr; + for (i = 0; i < ntohs(stream_desc->number_of_formats); i++) { + if (stream_desc->stream_formats[i] == new_format) { + found = true; + break; + } + } + + + memcpy(buf, m, len); + h_reply = (struct avb_ethernet_header *)buf; + p_reply = SPA_PTROFF(h_reply, sizeof(*h_reply), void); + set_reply = (struct avb_packet_aecp_aem_setget_stream_format*)p_reply->payload; + + /** If this not found, return the current format */ + if (!found) { + set_reply->stream_format = stream_desc->current_format; + return reply_status(aecp, + AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, m, len); + } + + stream_desc->current_format = new_format; + rc = reply_success(aecp, buf, len); + if (rc < 0) + return rc; + + return send_unsol_stream_format(aecp, buf, len); +} diff --git a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-stream-format.h b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-stream-format.h new file mode 100644 index 000000000..3441d9bec --- /dev/null +++ b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-stream-format.h @@ -0,0 +1,16 @@ +/* AVB support */ +/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki */ +/* SPDX-License-Identifier: MIT */ + +#ifndef __AVB_AECP_AEM_CMD_GET_SET_STREAM_FORMAT_H__ +#define __AVB_AECP_AEM_CMD_GET_SET_STREAM_FORMAT_H__ + +#include "../aecp-aem.h" + +int handle_cmd_set_stream_format_milan_v12(struct aecp *aecp, int64_t now, + const void *m, int len); + +int handle_cmd_get_stream_format_milan_v12(struct aecp *aecp, int64_t now, + const void *m, int len); + +#endif //__AVB_AECP_AEM_CMD_GET_SET_STREAM_FORMAT_H__ diff --git a/src/modules/module-avb/aecp-aem.c b/src/modules/module-avb/aecp-aem.c index 9a4b8948d..74d807381 100644 --- a/src/modules/module-avb/aecp-aem.c +++ b/src/modules/module-avb/aecp-aem.c @@ -10,10 +10,11 @@ /* The headers including the command and response of the system */ #include "aecp-aem-cmds-resps/cmd-available.h" -#include "aecp-aem-cmds-resps/cmd-lock-entity.h" #include "aecp-aem-cmds-resps/cmd-register-unsolicited-notifications.h" #include "aecp-aem-cmds-resps/cmd-deregister-unsolicited-notifications.h" #include "aecp-aem-cmds-resps/cmd-get-set-name.h" +#include "aecp-aem-cmds-resps/cmd-get-set-stream-format.h" +#include "aecp-aem-cmds-resps/cmd-lock-entity.h" /* ACQUIRE_ENTITY */ @@ -293,6 +294,12 @@ static const struct cmd_info cmd_info_milan_v12[] = { AECP_AEM_HANDLE_CMD(AVB_AECP_AEM_CMD_ENTITY_AVAILABLE, true, handle_cmd_entity_available_milan_v12), + AECP_AEM_HANDLE_CMD(AVB_AECP_AEM_CMD_SET_STREAM_FORMAT, false, + handle_cmd_set_stream_format_milan_v12), + + AECP_AEM_HANDLE_CMD(AVB_AECP_AEM_CMD_GET_STREAM_FORMAT, true, + handle_cmd_get_stream_format_milan_v12), + AECP_AEM_HANDLE_CMD(AVB_AECP_AEM_CMD_READ_DESCRIPTOR, true, handle_read_descriptor_common),