mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-04-30 06:46:49 -04:00
first draft for ACMP/ timeout handling, and communication between SRP/ADP and the ACMP state machine
This commit is contained in:
parent
ad543e37f5
commit
4856f85de2
18 changed files with 2970 additions and 285 deletions
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue