mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-04-29 06:46:38 -04:00
module-avb: milan: introducing GET_DYNAMIC_INFO
This commit is contained in:
parent
42d51098ae
commit
d46523e6ad
5 changed files with 242 additions and 0 deletions
|
|
@ -806,6 +806,7 @@ if build_module_avb
|
|||
'module-avb/aecp-aem-cmds-resps/cmd-get-set-configuration.c',
|
||||
'module-avb/aecp-aem-cmds-resps/cmd-lock-entity.c',
|
||||
'module-avb/aecp-aem-cmds-resps/cmd-register-unsolicited-notifications.c',
|
||||
'module-avb/aecp-aem-cmds-resps/cmd-get-dynamic-info.c',
|
||||
'module-avb/aecp-aem-cmds-resps/reply-unsol-helpers.c',
|
||||
'module-avb/es-builder.c',
|
||||
'module-avb/avdecc.c',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,187 @@
|
|||
/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#include "../aecp.h"
|
||||
#include "../aecp-aem.h"
|
||||
#include "../aecp-aem-descriptors.h"
|
||||
#include "../aecp-aem-state.h"
|
||||
#include "../internal.h"
|
||||
|
||||
#include "cmd-get-dynamic-info.h"
|
||||
#include "cmd-resp-helpers.h"
|
||||
|
||||
/**
|
||||
* \see IEEE 1722.1-2021 Section 7.4.76 GET_DYNAMIC_INFO
|
||||
* \see Milan v1.2 Section 5.4.2.29
|
||||
*
|
||||
* Returns the current dynamic state for all descriptors in the requested
|
||||
* configuration. Each descriptor type contributes a fixed-size record;
|
||||
* descriptor types with no mutable runtime state are skipped.
|
||||
*/
|
||||
int handle_cmd_get_dynamic_info_milan_v12(struct aecp *aecp, int64_t now,
|
||||
const void *m, int len)
|
||||
{
|
||||
uint8_t buf[AVB_PACKET_MILAN_DEFAULT_MTU + sizeof(struct avb_ethernet_header)];
|
||||
struct server *server = aecp->server;
|
||||
const struct avb_ethernet_header *h_in = m;
|
||||
const struct avb_packet_aecp_aem *p_in = SPA_PTROFF(h_in, sizeof(*h_in), void);
|
||||
const struct avb_packet_aecp_aem_get_dynamic_info *cmd =
|
||||
(const struct avb_packet_aecp_aem_get_dynamic_info *)p_in->payload;
|
||||
struct avb_ethernet_header *h;
|
||||
struct avb_packet_aecp_aem *reply;
|
||||
struct avb_packet_aecp_aem_get_dynamic_info *resp_hdr;
|
||||
uint16_t config_idx;
|
||||
const struct descriptor *entity_desc;
|
||||
const struct avb_aem_desc_entity *entity;
|
||||
const struct descriptor *d;
|
||||
size_t psize, size;
|
||||
uint8_t *ptr;
|
||||
|
||||
/*
|
||||
* Milan v1.2 Section 5.4: AECP PDUs shall not exceed the interface MTU.
|
||||
* Reject anything that would overflow our response buffer before
|
||||
* touching it.
|
||||
*/
|
||||
if ((size_t)len > sizeof(buf)) {
|
||||
pw_log_warn("%s: command PDU exceeds MTU (%d bytes)", __func__, len);
|
||||
return reply_bad_arguments(aecp, m, len);
|
||||
}
|
||||
|
||||
config_idx = ntohs(cmd->configuration_index);
|
||||
|
||||
entity_desc = server_find_descriptor(server, AVB_AEM_DESC_ENTITY, 0);
|
||||
if (entity_desc == NULL)
|
||||
return reply_status(aecp, AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, m, len);
|
||||
|
||||
entity = (const struct avb_aem_desc_entity *)entity_desc->ptr;
|
||||
if (config_idx >= ntohs(entity->configurations_count))
|
||||
return reply_status(aecp, AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, m, len);
|
||||
|
||||
memcpy(buf, m, len);
|
||||
h = (struct avb_ethernet_header *)buf;
|
||||
reply = SPA_PTROFF(h, sizeof(*h), void);
|
||||
|
||||
AVB_PACKET_AECP_SET_MESSAGE_TYPE(&reply->aecp, AVB_AECP_MESSAGE_TYPE_AEM_RESPONSE);
|
||||
AVB_PACKET_AECP_SET_STATUS(&reply->aecp, AVB_AECP_AEM_STATUS_SUCCESS);
|
||||
|
||||
resp_hdr = (struct avb_packet_aecp_aem_get_dynamic_info *)reply->payload;
|
||||
resp_hdr->configuration_index = htons(config_idx);
|
||||
resp_hdr->reserved = 0;
|
||||
|
||||
psize = sizeof(*resp_hdr);
|
||||
size = sizeof(*h) + sizeof(*reply) + psize;
|
||||
ptr = buf + size;
|
||||
|
||||
spa_list_for_each(d, &server->descriptors, link) {
|
||||
switch (d->type) {
|
||||
case AVB_AEM_DESC_ENTITY: {
|
||||
const struct avb_aem_desc_entity *e =
|
||||
(const struct avb_aem_desc_entity *)d->ptr;
|
||||
struct avb_aem_dynamic_info_entity rec;
|
||||
|
||||
if (size + sizeof(rec) > sizeof(buf)) {
|
||||
pw_log_warn("%s: buffer full, truncating response", __func__);
|
||||
goto done;
|
||||
}
|
||||
rec.hdr.descriptor_type = htons(d->type);
|
||||
rec.hdr.descriptor_index = htons(d->index);
|
||||
rec.current_configuration = e->current_configuration;
|
||||
rec.reserved = 0;
|
||||
memcpy(ptr, &rec, sizeof(rec));
|
||||
ptr += sizeof(rec);
|
||||
psize += sizeof(rec);
|
||||
size += sizeof(rec);
|
||||
break;
|
||||
}
|
||||
case AVB_AEM_DESC_AUDIO_UNIT: {
|
||||
const struct avb_aem_desc_audio_unit *au =
|
||||
(const struct avb_aem_desc_audio_unit *)d->ptr;
|
||||
struct avb_aem_dynamic_info_audio_unit rec;
|
||||
|
||||
if (size + sizeof(rec) > sizeof(buf)) {
|
||||
pw_log_warn("%s: buffer full, truncating response", __func__);
|
||||
goto done;
|
||||
}
|
||||
rec.hdr.descriptor_type = htons(d->type);
|
||||
rec.hdr.descriptor_index = htons(d->index);
|
||||
rec.current_sampling_rate = au->current_sampling_rate.pull_frequency;
|
||||
memcpy(ptr, &rec, sizeof(rec));
|
||||
ptr += sizeof(rec);
|
||||
psize += sizeof(rec);
|
||||
size += sizeof(rec);
|
||||
break;
|
||||
}
|
||||
case AVB_AEM_DESC_STREAM_INPUT: {
|
||||
const struct aecp_aem_stream_input_state *state =
|
||||
(const struct aecp_aem_stream_input_state *)d->ptr;
|
||||
struct avb_aem_dynamic_info_stream rec;
|
||||
|
||||
if (size + sizeof(rec) > sizeof(buf)) {
|
||||
pw_log_warn("%s: buffer full, truncating response", __func__);
|
||||
goto done;
|
||||
}
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
rec.hdr.descriptor_type = htons(d->type);
|
||||
rec.hdr.descriptor_index = htons(d->index);
|
||||
rec.stream_id = 0;
|
||||
rec.stream_format = state->desc.current_format;
|
||||
if (state->desc.current_format != 0)
|
||||
rec.stream_info_flags =
|
||||
htonl(AVB_AEM_STREAM_INFO_FLAG_STREAM_FORMAT_VALID);
|
||||
memcpy(ptr, &rec, sizeof(rec));
|
||||
ptr += sizeof(rec);
|
||||
psize += sizeof(rec);
|
||||
size += sizeof(rec);
|
||||
break;
|
||||
}
|
||||
case AVB_AEM_DESC_STREAM_OUTPUT: {
|
||||
const struct aecp_aem_stream_output_state *state =
|
||||
(const struct aecp_aem_stream_output_state *)d->ptr;
|
||||
struct avb_aem_dynamic_info_stream rec;
|
||||
|
||||
if (size + sizeof(rec) > sizeof(buf)) {
|
||||
pw_log_warn("%s: buffer full, truncating response", __func__);
|
||||
goto done;
|
||||
}
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
rec.hdr.descriptor_type = htons(d->type);
|
||||
rec.hdr.descriptor_index = htons(d->index);
|
||||
rec.stream_id = 0;
|
||||
rec.stream_format = state->desc.current_format;
|
||||
if (state->desc.current_format != 0)
|
||||
rec.stream_info_flags =
|
||||
htonl(AVB_AEM_STREAM_INFO_FLAG_STREAM_FORMAT_VALID);
|
||||
memcpy(ptr, &rec, sizeof(rec));
|
||||
ptr += sizeof(rec);
|
||||
psize += sizeof(rec);
|
||||
size += sizeof(rec);
|
||||
break;
|
||||
}
|
||||
case AVB_AEM_DESC_CLOCK_DOMAIN: {
|
||||
const struct avb_aem_desc_clock_domain *cd =
|
||||
(const struct avb_aem_desc_clock_domain *)d->ptr;
|
||||
struct avb_aem_dynamic_info_clock_domain rec;
|
||||
|
||||
if (size + sizeof(rec) > sizeof(buf)) {
|
||||
pw_log_warn("%s: buffer full, truncating response", __func__);
|
||||
goto done;
|
||||
}
|
||||
rec.hdr.descriptor_type = htons(d->type);
|
||||
rec.hdr.descriptor_index = htons(d->index);
|
||||
rec.clock_source_index = cd->clock_source_index;
|
||||
rec.reserved = 0;
|
||||
memcpy(ptr, &rec, sizeof(rec));
|
||||
ptr += sizeof(rec);
|
||||
psize += sizeof(rec);
|
||||
size += sizeof(rec);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
AVB_PACKET_SET_LENGTH(&reply->aecp.hdr, psize + AVB_PACKET_CONTROL_DATA_OFFSET);
|
||||
return avb_server_send_packet(server, h->src, AVB_TSN_ETH, buf, size);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef __AVB_AECP_AEM_CMD_GET_DYNAMIC_INFO_H__
|
||||
#define __AVB_AECP_AEM_CMD_GET_DYNAMIC_INFO_H__
|
||||
|
||||
#include "../aecp-aem.h"
|
||||
|
||||
int handle_cmd_get_dynamic_info_milan_v12(struct aecp *aecp, int64_t now,
|
||||
const void *m, int len);
|
||||
|
||||
#endif /* __AVB_AECP_AEM_CMD_GET_DYNAMIC_INFO_H__ */
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
#include "aecp-aem-cmds-resps/cmd-get-set-stream-format.h"
|
||||
#include "aecp-aem-cmds-resps/cmd-get-set-clock-source.h"
|
||||
#include "aecp-aem-cmds-resps/cmd-lock-entity.h"
|
||||
#include "aecp-aem-cmds-resps/cmd-get-dynamic-info.h"
|
||||
|
||||
|
||||
/* ACQUIRE_ENTITY */
|
||||
|
|
@ -364,6 +365,9 @@ static const struct cmd_info cmd_info_milan_v12[] = {
|
|||
|
||||
AECP_AEM_HANDLE_CMD(AVB_AECP_AEM_CMD_GET_SAMPLING_RATE, true,
|
||||
handle_cmd_get_sampling_rate_common),
|
||||
|
||||
AECP_AEM_HANDLE_CMD(AVB_AECP_AEM_CMD_GET_DYNAMIC_INFO, true,
|
||||
handle_cmd_get_dynamic_info_milan_v12),
|
||||
};
|
||||
|
||||
static const struct {
|
||||
|
|
|
|||
|
|
@ -226,6 +226,44 @@ struct avb_packet_aecp_aem_operation_status {
|
|||
uint16_t percent_complete;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
/* GET_DYNAMIC_INFO (IEEE 1722.1-2021 Section 7.4.76, Milan v1.2 Section 5.4.2.29) */
|
||||
struct avb_packet_aecp_aem_get_dynamic_info {
|
||||
uint16_t configuration_index;
|
||||
uint16_t reserved;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct avb_aem_dynamic_info_hdr {
|
||||
uint16_t descriptor_type;
|
||||
uint16_t descriptor_index;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct avb_aem_dynamic_info_entity {
|
||||
struct avb_aem_dynamic_info_hdr hdr;
|
||||
uint16_t current_configuration;
|
||||
uint16_t reserved;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct avb_aem_dynamic_info_audio_unit {
|
||||
struct avb_aem_dynamic_info_hdr hdr;
|
||||
uint32_t current_sampling_rate;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct avb_aem_dynamic_info_stream {
|
||||
struct avb_aem_dynamic_info_hdr hdr;
|
||||
uint64_t stream_id;
|
||||
uint64_t stream_format;
|
||||
uint32_t stream_info_flags;
|
||||
uint16_t acmp_connection_count;
|
||||
uint8_t flags_ex;
|
||||
uint8_t pbsta;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct avb_aem_dynamic_info_clock_domain {
|
||||
struct avb_aem_dynamic_info_hdr hdr;
|
||||
uint16_t clock_source_index;
|
||||
uint16_t reserved;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct avb_packet_aecp_aem {
|
||||
struct avb_packet_aecp_header aecp;
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue