first draft for ACMP/ timeout handling, and communication between SRP/ADP and the ACMP state machine

This commit is contained in:
hackerman-kl 2026-01-19 09:39:49 +01:00 committed by Wim Taymans
parent ad543e37f5
commit 4856f85de2
18 changed files with 2970 additions and 285 deletions

View file

@ -6,60 +6,6 @@
#include "../aecp-aem-state.h" #include "../aecp-aem-state.h"
#include "../stream.h" #include "../stream.h"
struct pending *pending_find(struct acmp *acmp, uint32_t type, uint16_t sequence_id)
{
struct pending *p;
spa_list_for_each(p, &acmp->pending[type], link)
if (p->sequence_id == sequence_id)
return p;
return NULL;
}
void pending_free(struct acmp *acmp, struct pending *p)
{
spa_list_remove(&p->link);
free(p);
}
void pending_destroy(struct acmp *acmp)
{
struct pending *p, *t;
for (uint32_t list_id = 0; list_id < PENDING_CONTROLLER; list_id++) {
spa_list_for_each_safe(p, t, &acmp->pending[list_id], link) {
pending_free(acmp, p);
}
}
}
void *pending_new(struct acmp *acmp, uint32_t type, uint64_t now, uint32_t timeout_ms,
const void *m, size_t size)
{
struct pending *p;
struct avb_ethernet_header *h;
struct avb_packet_acmp *pm;
p = calloc(1, sizeof(*p) + size);
if (p == NULL)
return NULL;
p->last_time = now;
p->timeout = timeout_ms * SPA_NSEC_PER_MSEC;
p->sequence_id = acmp->sequence_id[type]++;
p->size = size;
p->ptr = SPA_PTROFF(p, sizeof(*p), void);
memcpy(p->ptr, m, size);
h = p->ptr;
pm = SPA_PTROFF(h, sizeof(*h), void);
p->old_sequence_id = ntohs(pm->sequence_id);
pm->sequence_id = htons(p->sequence_id);
spa_list_append(&acmp->pending[type], &p->link);
return p->ptr;
}
struct stream *find_stream(struct server *server, enum spa_direction direction, struct stream *find_stream(struct server *server, enum spa_direction direction,
uint16_t index) uint16_t index)
{ {
@ -75,13 +21,13 @@ struct stream *find_stream(struct server *server, enum spa_direction direction,
type = AVB_AEM_DESC_STREAM_OUTPUT; type = AVB_AEM_DESC_STREAM_OUTPUT;
break; break;
default: default:
pw_log_error("Unkown direction\n"); pw_log_error("Unkown direction");
return NULL; return NULL;
} }
desc = server_find_descriptor(server, type, index); desc = server_find_descriptor(server, type, index);
if (!desc) { if (!desc) {
pw_log_error("Could not find stream type %u index %u\n", pw_log_error("Could not find stream type %u index %u",
type, index); type, index);
return NULL; return NULL;
} }
@ -90,19 +36,19 @@ struct stream *find_stream(struct server *server, enum spa_direction direction,
case SPA_DIRECTION_INPUT: case SPA_DIRECTION_INPUT:
struct aecp_aem_stream_input_state *stream_in; struct aecp_aem_stream_input_state *stream_in;
stream_in = desc->ptr; stream_in = desc->ptr;
stream = &stream_in->stream; stream = &stream_in->common.stream;
break; break;
case SPA_DIRECTION_OUTPUT: case SPA_DIRECTION_OUTPUT:
struct aecp_aem_stream_output_state *stream_out; struct aecp_aem_stream_output_state *stream_out;
stream_out = desc->ptr; stream_out = desc->ptr;
stream = &stream_out->stream; stream = &stream_out->common.stream;
break; break;
} }
return stream; return stream;
} }
int reply_not_supported(struct acmp *acmp, uint8_t type, const void *m, int len) int acmp_reply_not_supported(struct acmp *acmp, uint8_t type, const void *m, int len)
{ {
struct server *server = acmp->server; struct server *server = acmp->server;
uint8_t buf[len]; uint8_t buf[len];
@ -115,12 +61,3 @@ int reply_not_supported(struct acmp *acmp, uint8_t type, const void *m, int len)
return avb_server_send_packet(server, h->src, AVB_TSN_ETH, buf, len); return avb_server_send_packet(server, h->src, AVB_TSN_ETH, buf, len);
} }
int retry_pending(struct acmp *acmp, uint64_t now, struct pending *p)
{
struct server *server = acmp->server;
struct avb_ethernet_header *h = p->ptr;
p->retry++;
p->last_time = now;
return avb_server_send_packet(server, h->dest, AVB_TSN_ETH, p->ptr, p->size);
}

View file

@ -9,20 +9,14 @@
#include <pipewire/pipewire.h> #include <pipewire/pipewire.h>
#include "../acmp.h" #include "../acmp.h"
struct pending {
struct spa_list link;
uint64_t last_time;
uint64_t timeout;
uint16_t old_sequence_id;
uint16_t sequence_id;
uint16_t retry;
size_t size;
void *ptr;
};
struct acmp { struct acmp {
struct server *server; struct server *server;
struct spa_hook server_listener; struct spa_hook server_listener;
};
struct acmp_legacy_avb {
struct acmp acmp;
#define PENDING_TALKER 0 #define PENDING_TALKER 0
#define PENDING_LISTENER 1 #define PENDING_LISTENER 1
@ -31,20 +25,18 @@ struct acmp {
uint16_t sequence_id[3]; uint16_t sequence_id[3];
}; };
struct pending *pending_find(struct acmp *acmp, uint32_t type, uint16_t sequence_id); struct acmp_milan_v12 {
struct acmp acmp;
void pending_free(struct acmp *acmp, struct pending *p); struct spa_list timers_lt;
struct spa_list pending_tk;
uint16_t sequence_id[2];
};
void pending_destroy(struct acmp *acmp);
void *pending_new(struct acmp *acmp, uint32_t type, uint64_t now,
uint32_t timeout_ms, const void *m, size_t size);
int retry_pending(struct acmp *acmp, uint64_t now, struct pending *p);
struct stream *find_stream(struct server *server, enum spa_direction direction, struct stream *find_stream(struct server *server, enum spa_direction direction,
uint16_t index); uint16_t index);
int reply_not_supported(struct acmp *acmp, uint8_t type, const void *m, int len); int acmp_reply_not_supported(struct acmp *acmp, uint8_t type, const void *m, int len);
#endif //AVB_ACMP_COMMON_H #endif //AVB_ACMP_COMMON_H

View file

@ -5,6 +5,78 @@
#include "acmp-common.h" #include "acmp-common.h"
#include "acmp-legacy-avb.h" #include "acmp-legacy-avb.h"
struct pending {
struct spa_list link;
uint64_t last_time;
uint64_t timeout;
uint16_t old_sequence_id;
uint16_t sequence_id;
uint16_t retry;
size_t size;
void *ptr;
};
static struct pending *pending_find(struct acmp_legacy_avb *acmp_legacy, uint32_t type, uint16_t sequence_id)
{
struct pending *p;
spa_list_for_each(p, &acmp_legacy->pending[type], link)
if (p->sequence_id == sequence_id)
return p;
return NULL;
}
static void pending_free(struct acmp_legacy_avb *acmp_legacy, struct pending *p)
{
spa_list_remove(&p->link);
free(p);
}
static void pending_destroy(struct acmp_legacy_avb *acmp_legacy)
{
struct pending *p, *t;
for (uint32_t list_id = 0; list_id < PENDING_CONTROLLER; list_id++) {
spa_list_for_each_safe(p, t, &acmp_legacy->pending[list_id], link) {
pending_free(acmp_legacy, p);
}
}
}
static void *pending_new(struct acmp_legacy_avb *acmp_legacy, uint32_t type, uint64_t now, uint32_t timeout_ms,
const void *m, size_t size)
{
struct pending *p;
struct avb_ethernet_header *h;
struct avb_packet_acmp *pm;
p = calloc(1, sizeof(*p) + size);
if (p == NULL)
return NULL;
p->last_time = now;
p->timeout = timeout_ms * SPA_NSEC_PER_MSEC;
p->sequence_id = acmp_legacy->sequence_id[type]++;
p->size = size;
p->ptr = SPA_PTROFF(p, sizeof(*p), void);
memcpy(p->ptr, m, size);
h = p->ptr;
pm = SPA_PTROFF(h, sizeof(*h), void);
p->old_sequence_id = ntohs(pm->sequence_id);
pm->sequence_id = htons(p->sequence_id);
spa_list_append(&acmp_legacy->pending[type], &p->link);
return p->ptr;
}
int retry_pending(struct acmp_legacy_avb *acmp_legacy, uint64_t now, struct pending *p)
{
struct acmp *acmp = (struct acmp*)acmp_legacy;
struct server *server = acmp->server;
struct avb_ethernet_header *h = p->ptr;
p->retry++;
p->last_time = now;
return avb_server_send_packet(server, h->dest, AVB_TSN_ETH, p->ptr, p->size);
}
int handle_connect_tx_command_legacy_avb(struct acmp *acmp, uint64_t now, int handle_connect_tx_command_legacy_avb(struct acmp *acmp, uint64_t now,
const void *m, int len) const void *m, int len)
{ {
@ -43,6 +115,7 @@ done:
int handle_connect_tx_response_legacy_avb(struct acmp *acmp, uint64_t now, int handle_connect_tx_response_legacy_avb(struct acmp *acmp, uint64_t now,
const void *m, int len) const void *m, int len)
{ {
struct acmp_legacy_avb *acmp_legacy = (struct acmp_legacy_avb *) acmp;
struct server *server = acmp->server; struct server *server = acmp->server;
struct avb_ethernet_header *h; struct avb_ethernet_header *h;
const struct avb_packet_acmp *resp = SPA_PTROFF(m, sizeof(*h), void); const struct avb_packet_acmp *resp = SPA_PTROFF(m, sizeof(*h), void);
@ -57,7 +130,7 @@ int handle_connect_tx_response_legacy_avb(struct acmp *acmp, uint64_t now,
sequence_id = ntohs(resp->sequence_id); sequence_id = ntohs(resp->sequence_id);
pending = pending_find(acmp, PENDING_TALKER, sequence_id); pending = pending_find(acmp_legacy, PENDING_TALKER, sequence_id);
if (pending == NULL) if (pending == NULL)
return 0; return 0;
@ -79,7 +152,7 @@ int handle_connect_tx_response_legacy_avb(struct acmp *acmp, uint64_t now,
res = avb_server_send_packet(server, h->dest, AVB_TSN_ETH, h, pending->size); res = avb_server_send_packet(server, h->dest, AVB_TSN_ETH, h, pending->size);
pending_free(acmp, pending); pending_free(acmp_legacy, pending);
return res; return res;
} }
@ -117,6 +190,7 @@ done:
int handle_disconnect_tx_response_legacy_avb(struct acmp *acmp, uint64_t now, int handle_disconnect_tx_response_legacy_avb(struct acmp *acmp, uint64_t now,
const void *m, int len) const void *m, int len)
{ {
struct acmp_legacy_avb *acmp_legacy = (struct acmp_legacy_avb *) acmp;
struct server *server = acmp->server; struct server *server = acmp->server;
struct avb_ethernet_header *h; struct avb_ethernet_header *h;
struct avb_packet_acmp *reply; struct avb_packet_acmp *reply;
@ -131,7 +205,7 @@ int handle_disconnect_tx_response_legacy_avb(struct acmp *acmp, uint64_t now,
sequence_id = ntohs(resp->sequence_id); sequence_id = ntohs(resp->sequence_id);
pending = pending_find(acmp, PENDING_TALKER, sequence_id); pending = pending_find(acmp_legacy, PENDING_TALKER, sequence_id);
if (pending == NULL) if (pending == NULL)
return 0; return 0;
@ -151,7 +225,7 @@ int handle_disconnect_tx_response_legacy_avb(struct acmp *acmp, uint64_t now,
res = avb_server_send_packet(server, h->dest, AVB_TSN_ETH, h, pending->size); res = avb_server_send_packet(server, h->dest, AVB_TSN_ETH, h, pending->size);
pending_free(acmp, pending); pending_free(acmp_legacy, pending);
return res; return res;
} }
@ -159,6 +233,7 @@ int handle_disconnect_tx_response_legacy_avb(struct acmp *acmp, uint64_t now,
int handle_connect_rx_command_legacy_avb(struct acmp *acmp, uint64_t now, int handle_connect_rx_command_legacy_avb(struct acmp *acmp, uint64_t now,
const void *m, int len) const void *m, int len)
{ {
struct acmp_legacy_avb *acmp_legacy = (struct acmp_legacy_avb *) acmp;
struct server *server = acmp->server; struct server *server = acmp->server;
struct avb_ethernet_header *h; struct avb_ethernet_header *h;
const struct avb_packet_acmp *p = SPA_PTROFF(m, sizeof(*h), void); const struct avb_packet_acmp *p = SPA_PTROFF(m, sizeof(*h), void);
@ -167,7 +242,7 @@ int handle_connect_rx_command_legacy_avb(struct acmp *acmp, uint64_t now,
if (be64toh(p->listener_guid) != server->entity_id) if (be64toh(p->listener_guid) != server->entity_id)
return 0; return 0;
h = pending_new(acmp, PENDING_TALKER, now, h = pending_new(acmp_legacy, PENDING_TALKER, now,
AVB_ACMP_TIMEOUT_CONNECT_TX_COMMAND_MS, m, len); AVB_ACMP_TIMEOUT_CONNECT_TX_COMMAND_MS, m, len);
if (h == NULL) if (h == NULL)
return -errno; return -errno;
@ -182,6 +257,7 @@ int handle_connect_rx_command_legacy_avb(struct acmp *acmp, uint64_t now,
int handle_disconnect_rx_command_legacy_avb(struct acmp *acmp, uint64_t now, int handle_disconnect_rx_command_legacy_avb(struct acmp *acmp, uint64_t now,
const void *m, int len) const void *m, int len)
{ {
struct acmp_legacy_avb *acmp_legacy = (struct acmp_legacy_avb *) acmp;
struct server *server = acmp->server; struct server *server = acmp->server;
struct avb_ethernet_header *h; struct avb_ethernet_header *h;
const struct avb_packet_acmp *p = SPA_PTROFF(m, sizeof(*h), void); const struct avb_packet_acmp *p = SPA_PTROFF(m, sizeof(*h), void);
@ -190,7 +266,7 @@ int handle_disconnect_rx_command_legacy_avb(struct acmp *acmp, uint64_t now,
if (be64toh(p->listener_guid) != server->entity_id) if (be64toh(p->listener_guid) != server->entity_id)
return 0; return 0;
h = pending_new(acmp, PENDING_TALKER, now, h = pending_new(acmp_legacy, PENDING_TALKER, now,
AVB_ACMP_TIMEOUT_DISCONNECT_TX_COMMAND_MS, m, len); AVB_ACMP_TIMEOUT_DISCONNECT_TX_COMMAND_MS, m, len);
if (h == NULL) if (h == NULL)
return -errno; return -errno;
@ -201,3 +277,54 @@ int handle_disconnect_rx_command_legacy_avb(struct acmp *acmp, uint64_t now,
return avb_server_send_packet(server, h->dest, AVB_TSN_ETH, h, len); return avb_server_send_packet(server, h->dest, AVB_TSN_ETH, h, len);
} }
static void check_timeout(struct acmp *acmp, uint64_t now, uint16_t type)
{
struct acmp_legacy_avb *acmp_avb = (struct acmp_legacy_avb *)acmp;
struct pending *p, *t;
spa_list_for_each_safe(p, t, &acmp_avb->pending[type], link) {
if (p->last_time + p->timeout > now)
continue;
if (p->retry == 0) {
pw_log_info("%p: pending timeout, retry", p);
retry_pending(acmp_avb, now, p);
} else {
pw_log_info("%p: pending timeout, fail", p);
pending_free(acmp_avb, p);
}
}
}
void acmp_periodic_avb_legacy(void *data, uint64_t now)
{
struct acmp *acmp = data;
check_timeout(acmp, now, PENDING_TALKER);
check_timeout(acmp, now, PENDING_LISTENER);
check_timeout(acmp, now, PENDING_CONTROLLER);
}
struct acmp* acmp_server_init_legacy_avb(void)
{
struct acmp_legacy_avb *acmp_avb;
acmp_avb = calloc(1, sizeof(*acmp_avb));
if (acmp_avb == NULL)
return NULL;
spa_list_init(&acmp_avb->pending[PENDING_TALKER]);
spa_list_init(&acmp_avb->pending[PENDING_LISTENER]);
spa_list_init(&acmp_avb->pending[PENDING_CONTROLLER]);
return (struct acmp *)acmp_avb;
}
void acmp_server_destroy_legacy_avb(struct acmp *acmp)
{
struct acmp_legacy_avb *acmp_legacy = (struct acmp_legacy_avb *)acmp;
pending_destroy(acmp_legacy);
free(acmp_legacy);
}

View file

@ -7,6 +7,13 @@
#include <stdint.h> #include <stdint.h>
#include "../acmp.h" #include "../acmp.h"
struct acmp* acmp_server_init_legacy_avb(void);
void acmp_periodic_avb_legacy(void *data, uint64_t now);
void acmp_server_destroy_legacy_avb(struct acmp *acmp);
int handle_connect_tx_command_legacy_avb(struct acmp *acmp, uint64_t now, int handle_connect_tx_command_legacy_avb(struct acmp *acmp, uint64_t now,
const void *m, int len); const void *m, int len);

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,67 @@
/* SPDX-FileCopyrightText: Copyright © 2027 Alexandre Malki <alexandre.malki@kebag-logic.com> */ /* SPDX-FileCopyrightText: Copyright © 2026 Alexandre Malki <alexandre.malki@kebag-logic.com> */
/* SPDX-License-Identifier: MIT */ /* SPDX-License-Identifier: MIT */
#ifndef AVB_ACMP_MILAN_V12_H #ifndef AVB_ACMP_MILAN_V12_H
#define AVB_ACMP_MILAN_V12_H #define AVB_ACMP_MILAN_V12_H
#include <stdint.h> #include <stdint.h>
#include "acmp-common.h"
/** Milan v1.2 ACMP */
enum fsm_acmp_state_milan_v12 {
FSM_ACMP_STATE_MILAN_V12_UNBOUND,
FSM_ACMP_STATE_MILAN_V12_PRB_W_AVAIL,
FSM_ACMP_STATE_MILAN_V12_PRB_W_DELAY,
FSM_ACMP_STATE_MILAN_V12_PRB_W_RESP,
FSM_ACMP_STATE_MILAN_V12_PRB_W_RESP2,
FSM_ACMP_STATE_MILAN_V12_PRB_W_RETRY,
FSM_ACMP_STATE_MILAN_V12_SETTLED_NO_RSV,
FSM_ACMP_STATE_MILAN_V12_SETTLED_RSV_OK,
FSM_ACMP_STATE_MILAN_V12_MAX,
};
struct acmp* acmp_server_init_milan_v12(void);
void acmp_destroy_milan_v12(struct acmp *acmp);
void acmp_periodic_milan_v12(struct acmp *acmp, uint64_t now);
int handle_probe_tx_command_milan_v12(struct acmp *acmp, uint64_t now,
const void *m, int len);
int handle_disconnect_tx_command_milan_v12(struct acmp *acmp, uint64_t now,
const void *m, int len);
int handle_get_tx_state_command_milan_v12(struct acmp *acmp, uint64_t now,
const void *m, int len);
int handle_get_tx_connection_command_milan_v12(struct acmp *acmp, uint64_t now,
const void *m, int len);
int handle_unbind_rx_command_milan_v12(struct acmp *acmp, uint64_t now,
const void *m, int len);
int handle_bind_rx_command_milan_v12(struct acmp *acmp, uint64_t now,
const void *m, int len);
int handle_probe_tx_response_milan_v12(struct acmp *acmp, uint64_t now,
const void *m, int len);
int handle_get_rx_state_command_milan_v12(struct acmp *acmp, uint64_t now,
const void *m, int len);
int handle_evt_tk_discovered_milan_v12(struct acmp *acmp, uint64_t entity);
int handle_evt_tk_departed_milan_v12(struct acmp *acmp, uint64_t entity);
int handle_evt_tk_registered_milan_v12(struct acmp *acmp, uint64_t talker_guid);
int handle_evt_tk_unregistered_milan_v12(struct acmp *acmp, uint64_t talker_guid);
int acmp_tmr_no_resp_milan_v12(struct acmp *acmp, uint64_t now);
int acmp_tmr_retry_milan_v12(struct acmp *acmp, uint64_t now);
int acmp_tmr_delay_milan_v12(struct acmp *acmp, uint64_t now);
int acmp_tmr_no_tk_milan_v12(struct acmp *acmp, uint64_t now);
int handle_acmp_cli_cmd_milan_v12(struct acmp *acmp, const char *args, FILE *out);
#endif //AVB_ACMP_MILAN_V12_H #endif //AVB_ACMP_MILAN_V12_H

View file

@ -13,7 +13,6 @@
#include "internal.h" #include "internal.h"
#include "stream.h" #include "stream.h"
#include "aecp-aem-descriptors.h" #include "aecp-aem-descriptors.h"
#include "aecp-aem-state.h"
#include "acmp-cmds-resps/acmp-common.h" #include "acmp-cmds-resps/acmp-common.h"
#include "acmp-cmds-resps/acmp-legacy-avb.h" #include "acmp-cmds-resps/acmp-legacy-avb.h"
@ -27,16 +26,35 @@ static int handle_ignore(struct acmp *acmp, uint64_t now, const void *m, int len
} }
static const char * const acmp_cmd_names[] = { static const char * const acmp_cmd_names[] = {
[AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND] = "connect-tx-command", /** Milan V1.2 Section 5.5.2.2 (PDU) */
[AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE] = "connect-tx-response", [AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND] =
"connect-tx-command/probe-tx-command",
/** Milan V1.2 Section 5.5.2.2 (PDU) */
[AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE] =
"connect-tx-response/probe-tx-response",
[AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND] = "disconnect-tx-command", [AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND] = "disconnect-tx-command",
[AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE] = "disconnect-tx-response", [AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE] = "disconnect-tx-response",
[AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_COMMAND] = "get-tx-state-command", [AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_COMMAND] = "get-tx-state-command",
[AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE] = "get-tx-state-response", [AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE] = "get-tx-state-response",
[AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND] = "connect-rx-command",
[AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE] = "connect-rx-response", /** Milan V1.2 Section 5.5.2.2 (PDU) */
[AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_COMMAND] = "disconnect-rx-command", [AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND] =
[AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE] = "disconnect-rx-response", "connect-rx-command/bind-rx-command",
/** Milan V1.2 Section 5.5.2.2 (PDU) */
[AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE] =
"connect-rx-response/bind-rx-response",
/** Milan V1.2 Section 5.5.2.2 (PDU) */
[AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_COMMAND] =
"disconnect-rx-command/unbind-rx-command",
/** Milan V1.2 Section 5.5.2.2 (PDU) */
[AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE] =
"disconnect-rx-response/unbind-rx-response",
[AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_COMMAND] = "get-rx-state-command", [AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_COMMAND] = "get-rx-state-command",
[AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE] = "get-rx-state-response", [AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE] = "get-rx-state-response",
[AVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_COMMAND] = "get-tx-connection-command", [AVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_COMMAND] = "get-tx-connection-command",
@ -51,15 +69,32 @@ struct acmp_cmds {
[mtype] = { .handle = handler } [mtype] = { .handle = handler }
static const struct acmp_cmds acmp_cmds_legacy_avb[] = { static const struct acmp_cmds acmp_cmds_legacy_avb[] = {
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND, handle_connect_tx_command_legacy_avb), AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND,
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE, handle_connect_tx_response_legacy_avb), handle_connect_tx_command_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND, handle_disconnect_tx_command_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE, handle_disconnect_tx_response_legacy_avb), AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE,
handle_connect_tx_response_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND,
handle_disconnect_tx_command_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE,
handle_disconnect_tx_response_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_COMMAND, NULL), AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_COMMAND, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE, handle_ignore),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND, handle_connect_rx_command_legacy_avb), AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE,
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE, handle_ignore), handle_ignore),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_COMMAND, handle_disconnect_rx_command_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND,
handle_connect_rx_command_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE,
handle_ignore),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_COMMAND,
handle_disconnect_rx_command_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE, NULL), AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_COMMAND, handle_ignore), AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_COMMAND, handle_ignore),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE, handle_ignore), AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE, handle_ignore),
@ -68,19 +103,37 @@ static const struct acmp_cmds acmp_cmds_legacy_avb[] = {
}; };
static const struct acmp_cmds acmp_cmds_milan_v12[] = { static const struct acmp_cmds acmp_cmds_milan_v12[] = {
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE, NULL), AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND,
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND, NULL), handle_probe_tx_command_milan_v12),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_COMMAND, NULL), AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE,
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE, NULL), handle_probe_tx_response_milan_v12),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND,
handle_bind_rx_command_milan_v12),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_COMMAND,
handle_unbind_rx_command_milan_v12),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND,
handle_unbind_rx_command_milan_v12),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE,
handle_ignore),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_COMMAND,
handle_get_rx_state_command_milan_v12),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE, NULL), AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_COMMAND, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE, NULL), AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_COMMAND, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_COMMAND, NULL), AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_COMMAND, NULL),
/** Milan V1.2 Section 5.5.2.2 (PDU) , Milan does not requires them */
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_COMMAND, handle_ignore),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE, handle_ignore),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_RESPONSE, NULL), AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_RESPONSE, NULL),
}; };
@ -115,7 +168,7 @@ static int acmp_message(void *data, uint64_t now, const void *message, int len)
return 0; return 0;
if (memcmp(h->dest, mac, 6) != 0 && if (memcmp(h->dest, mac, 6) != 0 &&
memcmp(h->dest, server->mac_addr, 6) != 0) memcmp(h->dest, server->mac_addr, 6) != 0)
return 0; return 0;
if (AVB_PACKET_GET_SUBTYPE(&p->hdr) != AVB_SUBTYPE_ACMP) if (AVB_PACKET_GET_SUBTYPE(&p->hdr) != AVB_SUBTYPE_ACMP)
@ -126,11 +179,11 @@ static int acmp_message(void *data, uint64_t now, const void *message, int len)
pw_log_info("got ACMP message %s", acmp_cmd_names[mtype]); pw_log_info("got ACMP message %s", acmp_cmd_names[mtype]);
if (mtype < 0 || (size_t)mtype >= acmp_cmds_modes[server->avb_mode].count) { if (mtype < 0 || (size_t)mtype >= acmp_cmds_modes[server->avb_mode].count) {
return reply_not_supported(acmp, mtype | 1, message, len); return acmp_reply_not_supported(acmp, mtype | 1, message, len);
} }
if (acmp_cmds_modes[server->avb_mode].cmds[mtype].handle == NULL) if (acmp_cmds_modes[server->avb_mode].cmds[mtype].handle == NULL)
return reply_not_supported(acmp, mtype | 1, message, len); return acmp_reply_not_supported(acmp, mtype | 1, message, len);
return acmp_cmds_modes[server->avb_mode].cmds[mtype].handle(acmp, now, message, len); return acmp_cmds_modes[server->avb_mode].cmds[mtype].handle(acmp, now, message, len);
} }
@ -138,41 +191,27 @@ static int acmp_message(void *data, uint64_t now, const void *message, int len)
static void acmp_destroy(void *data) static void acmp_destroy(void *data)
{ {
struct acmp *acmp = data; struct acmp *acmp = data;
spa_hook_remove(&acmp->server_listener); switch (acmp->server->avb_mode) {
pending_destroy(acmp); case AVB_MODE_MILAN_V12:
free(acmp); acmp_destroy_milan_v12(acmp);
} break;
case AVB_MODE_LEGACY:
static void check_timeout(struct acmp *acmp, uint64_t now, uint16_t type) acmp_server_destroy_legacy_avb(acmp);
{ break;
struct pending *p, *t; default:
pw_log_warn("Unknown avb_mode");
spa_list_for_each_safe(p, t, &acmp->pending[type], link) { break;
if (p->last_time + p->timeout > now)
continue;
if (p->retry == 0) {
pw_log_info("%p: pending timeout, retry", p);
retry_pending(acmp, now, p);
} else {
pw_log_info("%p: pending timeout, fail", p);
pending_free(acmp, p);
}
} }
spa_hook_remove(&acmp->server_listener);
} }
static void acmp_periodic(void *data, uint64_t now)
{
struct acmp *acmp = data;
check_timeout(acmp, now, PENDING_TALKER);
check_timeout(acmp, now, PENDING_LISTENER);
check_timeout(acmp, now, PENDING_CONTROLLER);
}
static int do_help(struct acmp *acmp, const char *args, FILE *out) static int do_help(struct acmp *acmp, const char *args, FILE *out)
{ {
fprintf(out, "{ \"type\": \"help\"," fprintf(out, "{ \"type\": \"help\","
"\"text\": \"" "\"text\": \""
"/adp/help: this help \\n" " /acmp/help: this help \\n"
"\" }"); "\" }");
return 0; return 0;
} }
@ -189,12 +228,108 @@ static int acmp_command(void *data, uint64_t now, const char *command, const cha
if (spa_streq(command, "help")) if (spa_streq(command, "help"))
res = do_help(acmp, args, out); res = do_help(acmp, args, out);
else if (spa_streq(command, "milan_v12"))
res = handle_acmp_cli_cmd_milan_v12(acmp, args, out);
else else
res = -ENOTSUP; res = -ENOTSUP;
return res; return res;
} }
static void acmp_periodic(void *data, uint64_t now)
{
struct acmp *acmp = (struct acmp*)data;
switch (acmp->server->avb_mode) {
case AVB_MODE_MILAN_V12:
acmp_periodic_milan_v12(acmp, now);
break;
case AVB_MODE_LEGACY:
acmp_periodic_avb_legacy(acmp, now);
break;
default:
pw_log_warn("Unknown avb_mode");
break;
}
}
int handle_evt_tk_discovered(struct avb_acmp *avb_acmp, uint64_t entity)
{
struct acmp *acmp = (struct acmp*)avb_acmp;
switch (acmp->server->avb_mode) {
case AVB_MODE_MILAN_V12:
return handle_evt_tk_discovered_milan_v12(acmp, entity);
break;
case AVB_MODE_LEGACY:
pw_log_warn("not implemented for legacy avb");
break;
default:
pw_log_warn("Unknown avb_mode");
break;
}
return -1;
}
int handle_evt_tk_departed(struct avb_acmp *avb_acmp, uint64_t entity)
{
struct acmp *acmp = (struct acmp*)avb_acmp;
switch (acmp->server->avb_mode) {
case AVB_MODE_MILAN_V12:
return handle_evt_tk_departed_milan_v12(acmp, entity);
break;
case AVB_MODE_LEGACY:
pw_log_warn("not implemented for legacy avb");
break;
default:
pw_log_warn("Unknown avb_mode");
break;
}
return 0;
}
int handle_evt_tk_registered(struct avb_acmp *avb_acmp, uint64_t entity)
{
struct acmp *acmp = (struct acmp*)avb_acmp;
switch (acmp->server->avb_mode) {
case AVB_MODE_MILAN_V12:
return handle_evt_tk_registered_milan_v12(acmp, entity);
break;
case AVB_MODE_LEGACY:
pw_log_warn("not implemented for legacy avb");
break;
default:
pw_log_warn("Unknown avb_mode");
break;
}
return -1;
}
int handle_evt_tk_unregistered(struct avb_acmp *avb_acmp, uint64_t entity)
{
struct acmp *acmp = (struct acmp*)avb_acmp;
switch (acmp->server->avb_mode) {
case AVB_MODE_MILAN_V12:
return handle_evt_tk_unregistered_milan_v12(acmp, entity);
break;
case AVB_MODE_LEGACY:
pw_log_warn("not implemented for legacy avb");
break;
default:
pw_log_warn("Unknown avb_mode");
break;
}
return -1;
}
static const struct server_events server_events = { static const struct server_events server_events = {
AVB_VERSION_SERVER_EVENTS, AVB_VERSION_SERVER_EVENTS,
.destroy = acmp_destroy, .destroy = acmp_destroy,
@ -203,19 +338,81 @@ static const struct server_events server_events = {
.command = acmp_command .command = acmp_command
}; };
int acmp_init_listener_stream_output(struct avb_acmp *avb_acmp,
struct aecp_aem_stream_output_state *stream_st)
{
int rc = 0;
pw_log_warn("Not implemented");
#if 0
switch (acmp->server->avb_mode) {
case AVB_MODE_MILAN_V12:
rc = acmp_init_talker_stream_milan_v12(acmp, stream_st);
break;
case AVB_MODE_LEGACY:
default:
break;
}
#endif
return rc;
}
int acmp_init_listener_stream_input(struct avb_acmp *avb_acmp,
struct aecp_aem_stream_input_state *stream_st)
{
int rc = 0;
pw_log_warn("Not implemented");
#if 0
switch (acmp->server->avb_mode) {
case AVB_MODE_MILAN_V12:
break;
case AVB_MODE_LEGACY:
default:
break;
}
#endif
return rc;
}
int acmp_fini_stream(struct acmp *acmp, struct stream *stream)
{
int rc = 0;
#if 0
switch (acmp->server->avb_mode) {
case AVB_MODE_MILAN_V12:
rc = acmp_fini_stream_milan_v12(acmp, stream);
break;
case AVB_MODE_LEGACY:
default:
break;
}
#endif
return rc;
}
struct avb_acmp *avb_acmp_register(struct server *server) struct avb_acmp *avb_acmp_register(struct server *server)
{ {
struct acmp *acmp; struct acmp *acmp;
acmp = calloc(1, sizeof(*acmp)); switch (server->avb_mode) {
case AVB_MODE_MILAN_V12:
acmp = acmp_server_init_milan_v12();
break;
case AVB_MODE_LEGACY:
acmp = acmp_server_init_legacy_avb();
break;
default:
acmp = NULL;
break;
}
if (acmp == NULL) if (acmp == NULL)
return NULL; return NULL;
acmp->server = server; acmp->server = server;
spa_list_init(&acmp->pending[PENDING_TALKER]);
spa_list_init(&acmp->pending[PENDING_LISTENER]);
spa_list_init(&acmp->pending[PENDING_CONTROLLER]);
avdecc_server_add_listener(server, &acmp->server_listener, &server_events, acmp); avdecc_server_add_listener(server, &acmp->server_listener, &server_events, acmp);
return (struct avb_acmp*)acmp; return (struct avb_acmp*)acmp;

View file

@ -8,6 +8,22 @@
#include "packets.h" #include "packets.h"
#include "internal.h" #include "internal.h"
#include "acmp-cmds-resps/acmp-common.h"
#include "aecp-aem-state.h"
/** 1722.1 defines this for the ACMP and the AEM FSMs */
#define AVB_ACMP_FLAG_CLASS_B (1<<0)
#define AVB_ACMP_FLAG_FAST_CONNECT (1<<1)
#define AVB_ACMP_FLAG_SAVED_STATES (1<<2)
#define AVB_ACMP_FLAG_STREAMING_WAIT (1<<3)
#define AVB_ACMP_FLAG_SUPPORTS_ENCRYPTED (1<<4)
#define AVB_ACMP_FLAG_ENCRYPTED_PDU (1<<5)
#define AVB_ACMP_FLAG_SRP_REGISTRATION_FAILED (1<<6)
#define AVB_ACMP_FLAG_CL_ENTRIES_VALID (1<<7)
#define AVB_ACMP_FLAG_NO_SRP (1<<8)
#define AVB_ACMP_FLAG_UDP (1<<9)
#define AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND 0 #define AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND 0
#define AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE 1 #define AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE 1
#define AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND 2 #define AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND 2
@ -52,6 +68,9 @@
#define AVB_ACMP_TIMEOUT_GET_RX_STATE_COMMAND_MS 200 #define AVB_ACMP_TIMEOUT_GET_RX_STATE_COMMAND_MS 200
#define AVB_ACMP_TIMEOUT_GET_TX_CONNECTION_COMMAND 200 #define AVB_ACMP_TIMEOUT_GET_TX_CONNECTION_COMMAND 200
struct avb_acmp;
struct avb_packet_acmp { struct avb_packet_acmp {
struct avb_packet_header hdr; struct avb_packet_header hdr;
uint64_t stream_id; uint64_t stream_id;
@ -74,7 +93,22 @@ struct avb_packet_acmp {
#define AVB_PACKET_ACMP_GET_MESSAGE_TYPE(p) AVB_PACKET_GET_SUB1(&(p)->hdr) #define AVB_PACKET_ACMP_GET_MESSAGE_TYPE(p) AVB_PACKET_GET_SUB1(&(p)->hdr)
#define AVB_PACKET_ACMP_GET_STATUS(p) AVB_PACKET_GET_SUB2(&(p)->hdr) #define AVB_PACKET_ACMP_GET_STATUS(p) AVB_PACKET_GET_SUB2(&(p)->hdr)
int acmp_init_listener_stream_output(struct avb_acmp *avb_acmp,
struct aecp_aem_stream_output_state *stream_st);
int acmp_init_listener_stream_input(struct avb_acmp *avb_acmp,
struct aecp_aem_stream_input_state *stream_st);
int acmp_fini_listener_stream(struct avb_acmp *avb_acmp,
struct aecp_aem_stream_input_state *stream_st);
struct avb_acmp *avb_acmp_register(struct server *server); struct avb_acmp *avb_acmp_register(struct server *server);
void avb_acmp_unregister(struct avb_acmp *acmp); void avb_acmp_unregister(struct avb_acmp *acmp);
int handle_evt_tk_discovered(struct avb_acmp *avb_acmp, uint64_t entity);
int handle_evt_tk_departed(struct avb_acmp *avb_acmp, uint64_t entity);
int handle_evt_tk_registered(struct avb_acmp *avb_acmp, uint64_t entity);
int handle_evt_tk_unregistered(struct avb_acmp *avb_acmp, uint64_t entity);
#endif /* AVB_ACMP_H */ #endif /* AVB_ACMP_H */

View file

@ -7,6 +7,7 @@
#include <pipewire/pipewire.h> #include <pipewire/pipewire.h>
#include "adp.h" #include "adp.h"
#include "acmp.h"
#include "aecp-aem-descriptors.h" #include "aecp-aem-descriptors.h"
#include "internal.h" #include "internal.h"
#include "utils.h" #include "utils.h"
@ -80,7 +81,7 @@ static int send_discover(struct adp *adp, uint64_t entity_id)
AVB_PACKET_SET_SUBTYPE(&p->hdr, AVB_SUBTYPE_ADP); AVB_PACKET_SET_SUBTYPE(&p->hdr, AVB_SUBTYPE_ADP);
AVB_PACKET_SET_LENGTH(&p->hdr, AVB_ADP_CONTROL_DATA_LENGTH); AVB_PACKET_SET_LENGTH(&p->hdr, AVB_ADP_CONTROL_DATA_LENGTH);
AVB_PACKET_ADP_SET_MESSAGE_TYPE(p, AVB_ADP_MESSAGE_TYPE_ENTITY_DISCOVER); AVB_PACKET_ADP_SET_MESSAGE_TYPE(p, AVB_ADP_MESSAGE_TYPE_ENTITY_DISCOVER);
p->entity_id = htonl(entity_id); p->entity_id = htobe64(entity_id);
avb_server_send_packet(adp->server, mac, AVB_TSN_ETH, buf, len); avb_server_send_packet(adp->server, mac, AVB_TSN_ETH, buf, len);
return 0; return 0;
} }
@ -128,15 +129,63 @@ static int adp_message(void *data, uint64_t now, const void *message, int len)
spa_list_append(&adp->entities, &e->link); spa_list_append(&adp->entities, &e->link);
pw_log_info("entity %s available", pw_log_info("entity %s available",
avb_utils_format_id(buf, sizeof(buf), entity_id)); avb_utils_format_id(buf, sizeof(buf), entity_id));
if (server->avb_mode == AVB_MODE_MILAN_V12) {
//Milan V1.2 Section 5.6.4.5.1
if (handle_evt_tk_discovered(server->acmp, entity_id)) {
pw_log_info("handling available event");
return -1;
}
}
} else {
if (server->avb_mode == AVB_MODE_MILAN_V12) {
//Milan V1.2
//Milan V1.2 Section 5.6.4.5.2
struct avb_ethernet_header *h_saved = (struct avb_ethernet_header *) e->buf;
struct avb_packet_adp *p_saved =
SPA_PTROFF(h_saved, sizeof(*h_saved), void);
if (p_saved->available_index != p->available_index) {
if (handle_evt_tk_departed(server->acmp, entity_id)) {
pw_log_info("handling departing event");
return -1;
}
bool has_gptp_domain_changed =
(p_saved->gptp_domain_number != p->gptp_domain_number) ||
(p_saved->gptp_grandmaster_id != p->gptp_grandmaster_id);
if (has_gptp_domain_changed) {
e->last_time = INT64_MAX;
spa_list_remove(&e->link);
pw_log_info("Removing from the adp list \n");
return 0;
}
if (handle_evt_tk_discovered(server->acmp, entity_id)) {
pw_log_warn("handling available event");
return -1;
}
}
memcpy(e->buf, message, len);
}
} }
e->last_time = now; e->last_time = now;
break; break;
case AVB_ADP_MESSAGE_TYPE_ENTITY_DEPARTING: case AVB_ADP_MESSAGE_TYPE_ENTITY_DEPARTING:
if (e != NULL) { if (e != NULL) {
if (server->avb_mode == AVB_MODE_MILAN_V12) {
// Milan v1.2 Section 5.6.4.5.3
handle_evt_tk_departed(server->acmp, entity_id);
}
pw_log_info("entity %s departing", pw_log_info("entity %s departing",
avb_utils_format_id(buf, sizeof(buf), entity_id)); avb_utils_format_id(buf, sizeof(buf), entity_id));
entity_free(e); entity_free(e);
} }
break; break;
case AVB_ADP_MESSAGE_TYPE_ENTITY_DISCOVER: case AVB_ADP_MESSAGE_TYPE_ENTITY_DISCOVER:
pw_log_info("entity %s advertise", pw_log_info("entity %s advertise",
@ -174,6 +223,7 @@ static void check_timeout(struct adp *adp, uint64_t now)
{ {
struct entity *e, *t; struct entity *e, *t;
char buf[128]; char buf[128];
struct avb_acmp *avb_acmp = adp->server->acmp;
spa_list_for_each_safe(e, t, &adp->entities, link) { spa_list_for_each_safe(e, t, &adp->entities, link) {
if (e->last_time + (e->valid_time + 2) * SPA_NSEC_PER_SEC > now) if (e->last_time + (e->valid_time + 2) * SPA_NSEC_PER_SEC > now)
@ -182,6 +232,8 @@ static void check_timeout(struct adp *adp, uint64_t now)
pw_log_info("entity %s timeout", pw_log_info("entity %s timeout",
avb_utils_format_id(buf, sizeof(buf), e->entity_id)); avb_utils_format_id(buf, sizeof(buf), e->entity_id));
handle_evt_tk_departed(avb_acmp, e->entity_id);
if (e->advertise) if (e->advertise)
send_departing(adp, now, e); send_departing(adp, now, e);
@ -218,7 +270,7 @@ static int check_advertise(struct adp *adp, uint64_t now)
d = server_find_descriptor(server, AVB_AEM_DESC_ENTITY, 0); d = server_find_descriptor(server, AVB_AEM_DESC_ENTITY, 0);
if (d == NULL) if (d == NULL)
return 0; return -1;
entity = d->ptr; entity = d->ptr;
entity_id = be64toh(entity->entity_id); entity_id = be64toh(entity->entity_id);
@ -345,6 +397,40 @@ static const struct server_events server_events = {
.command = adp_command .command = adp_command
}; };
bool adp_is_discovered_entity(struct server *server, uint64_t entity_id)
{
struct adp *adp = (struct adp*)server->adp;
struct entity *entity = find_entity_by_id(adp, entity_id);
if (entity == NULL) {
return false;
}
return true;
}
int adp_start_discovery_entity(struct server *server, uint64_t entity_id)
{
pw_log_info("ADP: start discovery of entity 0x%"PRIx64, entity_id);
return send_discover((struct adp*) server->adp, entity_id);
}
void adp_stop_discovery_entity(struct server *server, uint64_t entity_id)
{
struct entity *e, *t;
struct adp *adp = (struct adp*)server->adp;
pw_log_info("ADP: stop discovery of entity 0x%" PRIx64, entity_id);
spa_list_for_each_safe(e, t, &adp->entities, link) {
if (e->entity_id == entity_id) {
entity_free(e);
return;
}
}
pw_log_warn("Could not find entity 0x%"PRIx64, entity_id);
}
struct avb_adp *avb_adp_register(struct server *server) struct avb_adp *avb_adp_register(struct server *server)
{ {
struct adp *adp; struct adp *adp;

View file

@ -54,6 +54,8 @@
#define AVB_ADP_CONTROL_DATA_LENGTH 56 #define AVB_ADP_CONTROL_DATA_LENGTH 56
struct avb_adp;
struct avb_packet_adp { struct avb_packet_adp {
struct avb_packet_header hdr; struct avb_packet_header hdr;
uint64_t entity_id; uint64_t entity_id;
@ -80,6 +82,9 @@ struct avb_packet_adp {
#define AVB_PACKET_ADP_GET_MESSAGE_TYPE(p) AVB_PACKET_GET_SUB1(&(p)->hdr) #define AVB_PACKET_ADP_GET_MESSAGE_TYPE(p) AVB_PACKET_GET_SUB1(&(p)->hdr)
#define AVB_PACKET_ADP_GET_VALID_TIME(p) AVB_PACKET_GET_SUB2(&(p)->hdr) #define AVB_PACKET_ADP_GET_VALID_TIME(p) AVB_PACKET_GET_SUB2(&(p)->hdr)
bool adp_is_discovered_entity(struct server *server, uint64_t entity_id);
int adp_start_discovery_entity(struct server *server, uint64_t entity_id);
void adp_stop_discovery_entity(struct server *server, uint64_t entity_id);
struct avb_adp *avb_adp_register(struct server *server); struct avb_adp *avb_adp_register(struct server *server);
void avb_adp_unregister(struct avb_adp *adp); void avb_adp_unregister(struct avb_adp *adp);

View file

@ -100,7 +100,6 @@ int handle_cmd_set_stream_format_milan_v12(struct aecp *aecp, int64_t now,
int i; int i;
int rc; int rc;
bool found = false; bool found = false;
void *stream;
set_cmd = (const struct avb_packet_aecp_aem_setget_stream_format *)p->payload; set_cmd = (const struct avb_packet_aecp_aem_setget_stream_format *)p->payload;
desc_type = ntohs(set_cmd->descriptor_type); desc_type = ntohs(set_cmd->descriptor_type);
@ -113,21 +112,14 @@ int handle_cmd_set_stream_format_milan_v12(struct aecp *aecp, int64_t now,
AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, m, len); AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, m, len);
if (desc_type == AVB_AEM_DESC_STREAM_INPUT) { 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 // TODO check if the stream is bound
} else if (desc_type == AVB_AEM_DESC_STREAM_OUTPUT) { } 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 // TODO check if the stream is STREAM_RUNNING
} else { } else {
return reply_status(aecp, return reply_status(aecp,
AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, m, len); AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, m, len);
} }
(void)stream;
stream_desc = (struct avb_aem_desc_stream *)desc->ptr; stream_desc = (struct avb_aem_desc_stream *)desc->ptr;
for (i = 0; i < ntohs(stream_desc->number_of_formats); i++) { for (i = 0; i < ntohs(stream_desc->number_of_formats); i++) {
if (stream_desc->stream_formats[i] == new_format) { if (stream_desc->stream_formats[i] == new_format) {

View file

@ -33,68 +33,37 @@
* notificaction. * notificaction.
*/ */
struct aecp_aem_state_base { struct aecp_aem_state_base {
/** uint64_t controller_entity_id;
* Originator of the control
* This is needed so the unsoolictied notification does not send back SUCCESS
* to the originator of of the unsolicited notification
*/
uint64_t controller_entity_id;
/** int64_t last_update;
* To avoid sending on every change for unsol notifications, only once a
* second
*/
int64_t last_update;
/** timeout absolute time*/ /** timeout absolute time*/
int64_t expire_timeout; int64_t expire_timeout;
}; };
/** /**
* \brief the structure keeps track of the registered controller entities * \brief the structure keeps track of the registered controller entities
*/ */
struct aecp_aem_unsol_notification_state { struct aecp_aem_unsol_notification_state {
/** uint64_t ctrler_entity_id;
* The controller is that is locking this system
*/
uint64_t ctrler_entity_id;
/** uint8_t ctrler_mac_addr[6];
* mac Address of the controller
*/
uint8_t ctrler_mac_addr[6];
/** uint8_t port_id;
* Port where the registeration originated from
*/
uint8_t port_id;
/***
* The sequence ID of the next unsolicited notification
*/
uint16_t next_seq_id; uint16_t next_seq_id;
/** bool is_registered;
* Actual value of the lock, get removed when unregistere or expired.
*/
bool is_registered;
}; };
struct aecp_aem_base_info { struct aecp_aem_base_info {
/** Originator of the control uint64_t controller_entity_id;
* This is needed so the unsoolictied notification does not send back SUCCESS
* to the originator of of the unsolicited notification */
uint64_t controller_entity_id;
/** int64_t last_update;
* To avoid sending on every change for unsol notifications, only once a
* a second
* */
int64_t last_update;
/** timeout absolute time*/ /** timeout absolute time*/
int64_t expire_timeout; int64_t expire_timeout;
}; };
struct aecp_aem_lock_state { struct aecp_aem_lock_state {
@ -138,43 +107,79 @@ struct aecp_aem_entity_legacy_avb_state {
* Table 7-156 * Table 7-156
*/ */
struct aecp_aem_stream_input_counters { struct aecp_aem_stream_input_counters {
struct aecp_aem_state_base base_state; struct aecp_aem_state_base base_state;
uint32_t media_locked; uint32_t media_locked;
uint32_t media_unlocked; uint32_t media_unlocked;
uint32_t stream_interrupted; uint32_t stream_interrupted;
uint32_t seq_mistmatch; uint32_t seq_mistmatch;
uint32_t media_reset; uint32_t media_reset;
/** Timestamp Uncertain */ /** Timestamp Uncertain */
uint32_t tu; uint32_t tu;
uint32_t unsupported_format; uint32_t unsupported_format;
uint32_t late_timestamp; uint32_t late_timestamp;
uint32_t early_timestamp; uint32_t early_timestamp;
uint32_t frame_rx; uint32_t frame_rx;
};
struct stream_common {
struct stream stream;
struct avb_msrp_attribute *msrp_attr;
}; };
struct aecp_aem_stream_input_state { struct aecp_aem_stream_input_state {
struct avb_aem_desc_stream desc; struct avb_aem_desc_stream desc;
struct aecp_aem_stream_input_counters counters; struct aecp_aem_stream_input_counters counters;
struct stream stream; struct stream_common common;
};
struct stream_input_saved_binding_param {
uint64_t controller_guid;
uint64_t talker_guid;
uint64_t listener_guid;
uint16_t talker_unique_id;
uint16_t listener_unique_id;
/** 1722.1-2021 Table 7.145 use the same as in the aecp packet*/
uint32_t aem_flags;
};
struct acmp_stream_status_common {
struct stream_input_saved_binding_param saved_bindings;
uint8_t probing_status;
uint8_t acmp_status;
uint8_t stream_dest_mac[6];
uint16_t stream_vlanid;
};
struct acmp_stream_status_milan_v12 {
struct acmp_stream_status_common common;
uint32_t fsm_acmp_state;
};
/**
* \brief The Milan v1.2 stream structure needs more information
* about the different protocol*/
struct aecp_aem_stream_input_state_milan_v12 {
struct aecp_aem_stream_input_state stream_in_sta;
struct acmp_stream_status_milan_v12 acmp_status;
}; };
struct aecp_aem_stream_output_counters { struct aecp_aem_stream_output_counters {
struct aecp_aem_state_base base_state; struct aecp_aem_state_base base_state;
uint32_t stream_start; uint32_t stream_start;
uint32_t stream_stop; uint32_t stream_stop;
uint32_t media_reset; uint32_t media_reset;
uint32_t tu; uint32_t tu;
uint32_t frame_tx; uint32_t frame_tx;
}; };
struct aecp_aem_stream_output_state { struct aecp_aem_stream_output_state {
struct avb_aem_desc_stream desc; struct avb_aem_desc_stream desc;
struct aecp_aem_stream_output_counters counters; struct aecp_aem_stream_output_counters counters;
struct stream stream; struct stream_common common;
}; };
#endif // AVB_AECP_AEM_STATE_H #endif // AVB_AECP_AEM_STATE_H

View file

@ -63,11 +63,17 @@ struct avb_packet_aecp_aem_setget_sensor_format {
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
#define AVB_AEM_STREAM_INFO_FLAG_CLASS_B (1u<<0)
#define AVB_AEM_STREAM_INFO_FLAG_FAST_CONNECT (1u<<1) #define AVB_AEM_STREAM_INFO_FLAG_CLASS_B (1u<<0)
#define AVB_AEM_STREAM_INFO_FLAG_SAVED_STATE (1u<<2) #define AVB_AEM_STREAM_INFO_FLAG_FAST_CONNECT (1u<<1)
#define AVB_AEM_STREAM_INFO_FLAG_STREAMING_WAIT (1u<<3) #define AVB_AEM_STREAM_INFO_FLAG_SAVED_STATE (1u<<2)
#define AVB_AEM_STREAM_INFO_FLAG_ENCRYPTED_PDU (1u<<4) #define AVB_AEM_STREAM_INFO_FLAG_STREAMING_WAIT (1u<<3)
#define AVB_AEM_STREAM_INFO_FLAG_SUPPORTS_ENCRYPTED (1u<<4)
#define AVB_AEM_STREAM_INFO_FLAG_ENCRYPTED_PDU (1u<<5)
#define AVB_AEM_STREAM_INFO_FLAG_SRP_REGISTERING_FAILED (1u<<6)
#define AVB_AEM_STREAM_INFO_FLAG_CL_ENTRIES_VALID (1u<<7)
#define AVB_AEM_STREAM_INFO_FLAG_NO_SRP (1u<<8)
#define AVB_AEM_STREAM_INFO_FLAG_UDP (1u<<9)
#define AVB_AEM_STREAM_INFO_FLAG_STREAM_VLAN_ID_VALID (1u<<25) #define AVB_AEM_STREAM_INFO_FLAG_STREAM_VLAN_ID_VALID (1u<<25)
#define AVB_AEM_STREAM_INFO_FLAG_CONNECTED (1u<<26) #define AVB_AEM_STREAM_INFO_FLAG_CONNECTED (1u<<26)
#define AVB_AEM_STREAM_INFO_FLAG_MSRP_FAILURE_VALID (1u<<27) #define AVB_AEM_STREAM_INFO_FLAG_MSRP_FAILURE_VALID (1u<<27)
@ -76,10 +82,59 @@ struct avb_packet_aecp_aem_setget_sensor_format {
#define AVB_AEM_STREAM_INFO_FLAG_STREAM_ID_VALID (1u<<30) #define AVB_AEM_STREAM_INFO_FLAG_STREAM_ID_VALID (1u<<30)
#define AVB_AEM_STREAM_INFO_FLAG_STREAM_FORMAT_VALID (1u<<31) #define AVB_AEM_STREAM_INFO_FLAG_STREAM_FORMAT_VALID (1u<<31)
union aem_stream_info_flags {
struct {
uint32_t class_b:1;
uint32_t fast_connect:1;
uint32_t saved_state:1;
uint32_t streaming_wait:1;
uint32_t supports_encrypted:1;
uint32_t encrypted_pdu:1;
union {
uint32_t talker_failed:1;
// Milan V1.2
uint32_t registering_failed:1;
};
uint32_t rsvd_0:1;
uint32_t no_srp:1;
uint32_t rsvd_1:10;
uint32_t ip_flags_valid:1;
uint32_t ip_src_port_valid:1;
uint32_t ip_dst_port_valid:1;
uint32_t ip_src_addr_valid:1;
uint32_t ip_dst_addr_valid:1;
uint32_t not_registering_srp:1;
uint32_t stream_vlan_id_valid:1;
uint32_t connected:1;
uint32_t msrp_failure_valid:1;
uint32_t stream_dst_valid:1;
uint32_t msrp_acc_lat_valid:1;
uint32_t stream_id_valid:1;
uint32_t stream_format_valid:1;
} ;
uint32_t flags;
} __attribute__ ((__packed__));
union aem_stream_info_flag_extended {
struct {
uint16_t ip_flags;
uint16_t source_port;
uint16_t destination_port;
} legacy_avb;
struct {
uint16_t rsvd_0;
uint32_t flags_ex_registering:1;
uint32_t rsvd_1:31;
uint32_t pbsta:3;
uint32_t acmpsta:5;
uint32_t rsvd_2:24;
} milan_v12;
} __attribute__ ((__packed__));
struct avb_packet_aecp_aem_setget_stream_info { struct avb_packet_aecp_aem_setget_stream_info {
uint16_t descriptor_type; uint16_t descriptor_type;
uint16_t descriptor_index; uint16_t descriptor_index;
uint32_t aem_stream_info_flags; union aem_stream_info_flags flags;
uint64_t stream_format; uint64_t stream_format;
uint64_t stream_id; uint64_t stream_id;
uint32_t msrp_accumulated_latency; uint32_t msrp_accumulated_latency;
@ -88,7 +143,7 @@ struct avb_packet_aecp_aem_setget_stream_info {
uint8_t reserved; uint8_t reserved;
uint64_t msrp_failure_bridge_id; uint64_t msrp_failure_bridge_id;
uint16_t stream_vlan_id; uint16_t stream_vlan_id;
uint16_t reserved2; union aem_stream_info_flag_extended flags_ex;
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
struct avb_packet_aecp_aem_setget_name { struct avb_packet_aecp_aem_setget_name {

View file

@ -412,8 +412,8 @@ struct server *avdecc_server_new(struct impl *impl, struct spa_dict *props)
server->mmrp = avb_mmrp_register(server); server->mmrp = avb_mmrp_register(server);
server->msrp = avb_msrp_register(server); server->msrp = avb_msrp_register(server);
server->mvrp = avb_mvrp_register(server); server->mvrp = avb_mvrp_register(server);
avb_adp_register(server); server->adp = avb_adp_register(server);
avb_acmp_register(server); server->acmp = avb_acmp_register(server);
server->domain_attr = avb_msrp_attribute_new(server->msrp, server->domain_attr = avb_msrp_attribute_new(server->msrp,
AVB_MSRP_ATTRIBUTE_TYPE_DOMAIN); AVB_MSRP_ATTRIBUTE_TYPE_DOMAIN);

View file

@ -80,7 +80,7 @@ static struct descriptor *es_buidler_desc_stream_general_prepare(struct server *
} }
pstream_input = desc->ptr; pstream_input = desc->ptr;
stream = &pstream_input->stream; stream = &pstream_input->common.stream;
direction = SPA_DIRECTION_INPUT; direction = SPA_DIRECTION_INPUT;
break; break;
case AVB_AEM_DESC_STREAM_OUTPUT: case AVB_AEM_DESC_STREAM_OUTPUT:
@ -96,7 +96,7 @@ static struct descriptor *es_buidler_desc_stream_general_prepare(struct server *
} }
pstream_output = desc->ptr; pstream_output = desc->ptr;
stream = &pstream_output->stream; stream = &pstream_output->common.stream;
direction = SPA_DIRECTION_OUTPUT; direction = SPA_DIRECTION_OUTPUT;
break; break;

View file

@ -113,6 +113,8 @@ struct server {
struct avb_mvrp *mvrp; struct avb_mvrp *mvrp;
struct avb_msrp *msrp; struct avb_msrp *msrp;
struct avb_maap *maap; struct avb_maap *maap;
struct avb_adp *adp;
struct avb_acmp *acmp;
struct avb_msrp_attribute *domain_attr; struct avb_msrp_attribute *domain_attr;
}; };

View file

@ -16,6 +16,7 @@
#include "iec61883.h" #include "iec61883.h"
#include "stream.h" #include "stream.h"
#include "aecp-aem-state.h" #include "aecp-aem-state.h"
#include "acmp-cmds-resps/acmp-common.h"
#include "utils.h" #include "utils.h"
static void on_stream_destroy(void *d) static void on_stream_destroy(void *d)
@ -245,6 +246,12 @@ struct stream *server_create_stream(struct server *server, struct stream *stream
struct spa_pod_builder b; struct spa_pod_builder b;
int res; int res;
struct stream_common *common;
struct avb_msrp_attribute *msrp_attr;
common = SPA_CONTAINER_OF(stream, struct stream_common, stream);
stream->server = server; stream->server = server;
stream->direction = direction; stream->direction = direction;
stream->prio = AVB_MSRP_PRIORITY_DEFAULT; stream->prio = AVB_MSRP_PRIORITY_DEFAULT;
@ -258,10 +265,6 @@ struct stream *server_create_stream(struct server *server, struct stream *stream
(uint64_t)server->mac_addr[5] << 16 | (uint64_t)server->mac_addr[5] << 16 |
htons(index); htons(index);
stream->vlan_attr = avb_mvrp_attribute_new(server->mvrp,
AVB_MVRP_ATTRIBUTE_TYPE_VID);
stream->vlan_attr->attr.vid.vlan = htons(stream->vlan_id);
stream->buffer_data = calloc(1, BUFFER_SIZE); stream->buffer_data = calloc(1, BUFFER_SIZE);
stream->buffer_size = BUFFER_SIZE; stream->buffer_size = BUFFER_SIZE;
spa_ringbuffer_init(&stream->ring); spa_ringbuffer_init(&stream->ring);
@ -283,14 +286,20 @@ struct stream *server_create_stream(struct server *server, struct stream *stream
PW_KEY_NODE_WANT_DRIVER, "true", PW_KEY_NODE_WANT_DRIVER, "true",
NULL)); NULL));
} }
#if 0
mvrp_attr = &stream_in_state->mvrp_attr
*mvrp_attr = avb_mvrp_attribute_new(mvrp_attr, AVB_MVRP_ATTRIBUTE_TYPE_VID);
(*mvrp_attr)->attr.vid.vlan = htons(stream->vlan_id);
#endif
if (stream->stream == NULL) if (stream->stream == NULL)
goto error_free; goto error_free;
pw_stream_add_listener(stream->stream, pw_stream_add_listener(stream->stream,
&stream->stream_listener, &stream->stream_listener,
direction == SPA_DIRECTION_INPUT ? direction == SPA_DIRECTION_INPUT ?
&source_stream_events : &source_stream_events :
&sink_stream_events, &sink_stream_events,
stream); stream);
stream->info.info.raw.format = SPA_AUDIO_FORMAT_S24_32_BE; stream->info.info.raw.format = SPA_AUDIO_FORMAT_S24_32_BE;
@ -320,22 +329,33 @@ struct stream *server_create_stream(struct server *server, struct stream *stream
setup_pdu(stream); setup_pdu(stream);
setup_msg(stream); setup_msg(stream);
stream->listener_attr = avb_msrp_attribute_new(server->msrp, if (stream->direction == SPA_DIRECTION_OUTPUT) {
AVB_MSRP_ATTRIBUTE_TYPE_LISTENER); msrp_attr = avb_msrp_attribute_new(server->msrp,
stream->talker_attr = avb_msrp_attribute_new(server->msrp, AVB_MSRP_ATTRIBUTE_TYPE_LISTENER);
AVB_MSRP_ATTRIBUTE_TYPE_TALKER_ADVERTISE); } else {
stream->talker_attr->attr.talker.vlan_id = htons(stream->vlan_id);
stream->talker_attr->attr.talker.tspec_max_frame_size = htons(32 + stream->frames_per_pdu * stream->stride); msrp_attr = avb_msrp_attribute_new(server->msrp,
stream->talker_attr->attr.talker.tspec_max_interval_frames = AVB_MSRP_ATTRIBUTE_TYPE_TALKER_ADVERTISE);
htons(AVB_MSRP_TSPEC_MAX_INTERVAL_FRAMES_DEFAULT);
stream->talker_attr->attr.talker.priority = stream->prio; msrp_attr->attr.talker.vlan_id = htons(stream->vlan_id);
stream->talker_attr->attr.talker.rank = AVB_MSRP_RANK_DEFAULT;
stream->talker_attr->attr.talker.accumulated_latency = htonl(95); msrp_attr->attr.talker.tspec_max_frame_size =
htons(32 + stream->frames_per_pdu * stream->stride);
msrp_attr->attr.talker.tspec_max_interval_frames =
htons(AVB_MSRP_TSPEC_MAX_INTERVAL_FRAMES_DEFAULT);
msrp_attr->attr.talker.priority = stream->prio;
msrp_attr->attr.talker.rank = AVB_MSRP_RANK_DEFAULT;
msrp_attr->attr.talker.accumulated_latency = htonl(95);
}
common->msrp_attr = msrp_attr;
spa_list_append(&server->streams, &stream->link); spa_list_append(&server->streams, &stream->link);
return stream; return stream;
error_free_stream: error_free_stream:
pw_stream_destroy(stream->stream); pw_stream_destroy(stream->stream);
errno = -res; errno = -res;
@ -346,7 +366,10 @@ error_free:
void stream_destroy(struct stream *stream) void stream_destroy(struct stream *stream)
{ {
avb_mrp_attribute_destroy(stream->listener_attr->mrp); struct stream_common *common;
common = SPA_CONTAINER_OF(stream, struct stream_common, stream);
avb_mrp_attribute_destroy(common->msrp_attr->mrp);
} }
static int setup_socket(struct stream *stream) static int setup_socket(struct stream *stream)
@ -418,6 +441,8 @@ int stream_activate(struct stream *stream, uint16_t index, uint64_t now)
struct server *server = stream->server; struct server *server = stream->server;
struct avb_frame_header *h = (void*)stream->pdu; struct avb_frame_header *h = (void*)stream->pdu;
int fd, res; int fd, res;
struct stream_common *common;
common = SPA_CONTAINER_OF(stream, struct stream_common, stream);
if (stream->source == NULL) { if (stream->source == NULL) {
if ((fd = setup_socket(stream)) < 0) if ((fd = setup_socket(stream)) < 0)
@ -433,55 +458,63 @@ int stream_activate(struct stream *stream, uint16_t index, uint64_t now)
} }
} }
#if 0
FIXME!!! This should be used only one and activated once and for all..
avb_mrp_attribute_begin(stream->vlan_attr->mrp, now); avb_mrp_attribute_begin(stream->vlan_attr->mrp, now);
avb_mrp_attribute_join(stream->vlan_attr->mrp, now, true); avb_mrp_attribute_join(stream->vlan_attr->mrp, now, true);
#endif
if (stream->direction == SPA_DIRECTION_INPUT) { if (stream->direction == SPA_DIRECTION_INPUT) {
stream->listener_attr->attr.listener.stream_id = htobe64(stream->peer_id); common->msrp_attr->attr.listener.stream_id = htobe64(stream->peer_id);
stream->listener_attr->param = AVB_MSRP_LISTENER_PARAM_READY; common->msrp_attr->param = AVB_MSRP_LISTENER_PARAM_READY;
avb_mrp_attribute_begin(stream->listener_attr->mrp, now); avb_mrp_attribute_begin(common->msrp_attr->mrp, now);
avb_mrp_attribute_join(stream->listener_attr->mrp, now, true); avb_mrp_attribute_join(common->msrp_attr->mrp, now, true);
#if 0
stream->talker_attr->attr.talker.stream_id = htobe64(stream->peer_id); stream->talker_attr->attr.talker.stream_id = htobe64(stream->peer_id);
avb_mrp_attribute_begin(stream->talker_attr->mrp, now); avb_mrp_attribute_begin(stream->talker_attr->mrp, now);
#endif
} else { } else {
if ((res = avb_maap_get_address(server->maap, stream->addr, index)) < 0) if ((res = avb_maap_get_address(server->maap, stream->addr, index)) < 0)
return res; return res;
#if 0
stream->listener_attr->attr.listener.stream_id = htobe64(stream->id); stream->listener_attr->attr.listener.stream_id = htobe64(stream->id);
stream->listener_attr->param = AVB_MSRP_LISTENER_PARAM_IGNORE; stream->listener_attr->param = AVB_MSRP_LISTENER_PARAM_IGNORE;
avb_mrp_attribute_begin(stream->listener_attr->mrp, now); avb_mrp_attribute_begin(stream->listener_attr->mrp, now);
#endif
stream->talker_attr->attr.talker.stream_id = htobe64(stream->id); common->msrp_attr->attr.talker.stream_id = htobe64(stream->id);
memcpy(stream->talker_attr->attr.talker.dest_addr, stream->addr, 6); memcpy(common->msrp_attr->attr.talker.dest_addr, stream->addr, 6);
stream->sock_addr.sll_halen = ETH_ALEN; stream->sock_addr.sll_halen = ETH_ALEN;
memcpy(&stream->sock_addr.sll_addr, stream->addr, ETH_ALEN); memcpy(&stream->sock_addr.sll_addr, stream->addr, ETH_ALEN);
memcpy(h->dest, stream->addr, 6); memcpy(h->dest, stream->addr, 6);
memcpy(h->src, server->mac_addr, 6); memcpy(h->src, server->mac_addr, 6);
avb_mrp_attribute_begin(stream->talker_attr->mrp, now); avb_mrp_attribute_begin(common->msrp_attr->mrp, now);
avb_mrp_attribute_join(stream->talker_attr->mrp, now, true); avb_mrp_attribute_join(common->msrp_attr->mrp, now, true);
} }
pw_stream_set_active(stream->stream, true); pw_stream_set_active(stream->stream, true);
return 0; return 0;
} }
int stream_deactivate(struct stream *stream, uint64_t now) int stream_deactivate(struct stream *stream, uint64_t now)
{ {
struct stream_common *common;
common = SPA_CONTAINER_OF(stream, struct stream_common, stream);
pw_stream_set_active(stream->stream, false); pw_stream_set_active(stream->stream, false);
if (stream->source != NULL) { if (stream->source != NULL) {
pw_loop_destroy_source(stream->server->impl->loop, stream->source); pw_loop_destroy_source(stream->server->impl->loop, stream->source);
stream->source = NULL; stream->source = NULL;
} }
#if 0
avb_mrp_attribute_leave(stream->vlan_attr->mrp, now); avb_mrp_attribute_leave(stream->vlan_attr->mrp, now);
#endif //
avb_mrp_attribute_leave(common->msrp_attr->mrp, now);
if (stream->direction == SPA_DIRECTION_INPUT) {
avb_mrp_attribute_leave(stream->listener_attr->mrp, now);
} else {
avb_mrp_attribute_leave(stream->talker_attr->mrp, now);
}
return 0; return 0;
} }

View file

@ -61,10 +61,6 @@ struct stream {
uint64_t format; uint64_t format;
uint32_t stride; uint32_t stride;
struct spa_audio_info info; struct spa_audio_info info;
struct avb_msrp_attribute *talker_attr;
struct avb_msrp_attribute *listener_attr;
struct avb_mvrp_attribute *vlan_attr;
}; };
#include "msrp.h" #include "msrp.h"