avb: implement some descriptors

Work on raw ethernet frames.
This commit is contained in:
Wim Taymans 2022-03-17 19:13:43 +01:00
parent da14e9f59d
commit 4613c7822f
14 changed files with 1052 additions and 452 deletions

View file

@ -525,6 +525,7 @@ pipewire_module_avbtp = shared_library('pipewire-module-avbtp',
'module-avbtp/avb.c', 'module-avbtp/avb.c',
'module-avbtp/adp.c', 'module-avbtp/adp.c',
'module-avbtp/aecp.c', 'module-avbtp/aecp.c',
'module-avbtp/aecp-aem.c',
'module-avbtp/avdecc.c', 'module-avbtp/avdecc.c',
'module-avbtp/maap.c' ], 'module-avbtp/maap.c' ],
include_directories : [configinc], include_directories : [configinc],

View file

@ -26,6 +26,7 @@
#define AVBTP_AAF_H #define AVBTP_AAF_H
struct avbtp_packet_aaf { struct avbtp_packet_aaf {
struct avbtp_ethernet_header hdr;
uint8_t subtype; uint8_t subtype;
#if __BYTE_ORDER == __BIG_ENDIAN #if __BYTE_ORDER == __BIG_ENDIAN
unsigned sv:1; unsigned sv:1;

View file

@ -224,7 +224,7 @@ static int send_discover(struct adp *adp, uint64_t entity_id)
return 0; return 0;
} }
static int adp_message(void *data, uint64_t now, const uint8_t mac[6], const void *message, int len) static int adp_message(void *data, uint64_t now, const void *message, int len)
{ {
struct adp *adp = data; struct adp *adp = data;
const struct avbtp_packet_adp *p = message; const struct avbtp_packet_adp *p = message;

View file

@ -0,0 +1,191 @@
/* AVB support
*
* Copyright © 2022 Wim Taymans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef AVBTP_AECP_AEM_DESCRIPTORS_H
#define AVBTP_AECP_AEM_DESCRIPTORS_H
#include "internal.h"
#define AVBTP_AEM_DESC_ENTITY 0x0000
#define AVBTP_AEM_DESC_CONFIGURATION 0x0001
#define AVBTP_AEM_DESC_AUDIO_UNIT 0x0002
#define AVBTP_AEM_DESC_VIDEO_UNIT 0x0003
#define AVBTP_AEM_DESC_SENSOR_UNIT 0x0004
#define AVBTP_AEM_DESC_STREAM_INPUT 0x0005
#define AVBTP_AEM_DESC_STREAM_OUTPUT 0x0006
#define AVBTP_AEM_DESC_JACK_INPUT 0x0007
#define AVBTP_AEM_DESC_JACK_OUTPUT 0x0008
#define AVBTP_AEM_DESC_AVB_INTERFACE 0x0009
#define AVBTP_AEM_DESC_CLOCK_SOURCE 0x000a
#define AVBTP_AEM_DESC_MEMORY_OBJECT 0x000b
#define AVBTP_AEM_DESC_LOCALE 0x000c
#define AVBTP_AEM_DESC_STRINGS 0x000d
#define AVBTP_AEM_DESC_STREAM_PORT_INPUT 0x000e
#define AVBTP_AEM_DESC_STREAM_PORT_OUTPUT 0x000f
#define AVBTP_AEM_DESC_EXTERNAL_PORT_INPUT 0x0010
#define AVBTP_AEM_DESC_EXTERNAL_PORT_OUTPUT 0x0011
#define AVBTP_AEM_DESC_INTERNAL_PORT_INPUT 0x0012
#define AVBTP_AEM_DESC_INTERNAL_PORT_OUTPUT 0x0013
#define AVBTP_AEM_DESC_AUDIO_CLUSTER 0x0014
#define AVBTP_AEM_DESC_VIDEO_CLUSTER 0x0015
#define AVBTP_AEM_DESC_SENSOR_CLUSTER 0x0016
#define AVBTP_AEM_DESC_AUDIO_MAP 0x0017
#define AVBTP_AEM_DESC_VIDEO_MAP 0x0018
#define AVBTP_AEM_DESC_SENSOR_MAP 0x0019
#define AVBTP_AEM_DESC_CONTROL 0x001a
#define AVBTP_AEM_DESC_SIGNAL_SELECTOR 0x001b
#define AVBTP_AEM_DESC_MIXER 0x001c
#define AVBTP_AEM_DESC_MATRIX 0x001d
#define AVBTP_AEM_DESC_MATRIX_SIGNAL 0x001e
#define AVBTP_AEM_DESC_SIGNAL_SPLITTER 0x001f
#define AVBTP_AEM_DESC_SIGNAL_COMBINER 0x0020
#define AVBTP_AEM_DESC_SIGNAL_DEMULTIPLEXER 0x0021
#define AVBTP_AEM_DESC_SIGNAL_MULTIPLEXER 0x0022
#define AVBTP_AEM_DESC_SIGNAL_TRANSCODER 0x0023
#define AVBTP_AEM_DESC_CLOCK_DOMAIN 0x0024
#define AVBTP_AEM_DESC_CONTROL_BLOCK 0x0025
#define AVBTP_AEM_DESC_INVALID 0xffff
struct avbtp_aem_desc_entity {
uint64_t entity_id;
uint64_t entity_model_id;
uint32_t entity_capabilities;
uint16_t talker_stream_sources;
uint16_t talker_capabilities;
uint16_t listener_stream_sinks;
uint16_t listener_capabilities;
uint32_t controller_capabilities;
uint32_t available_index;
uint64_t association_id;
char entity_name[64];
uint16_t vendor_name_string;
uint16_t model_name_string;
char firmware_version[64];
char group_name[64];
char serial_number[64];
uint16_t configurations_count;
uint16_t current_configuration;
} __attribute__ ((__packed__));
struct avbtp_aem_desc_descriptor_count {
uint16_t descriptor_type;
uint16_t descriptor_count;
} __attribute__ ((__packed__));
struct avbtp_aem_desc_configuration {
char object_name[64];
uint16_t localized_description;
uint16_t descriptor_counts_count;
uint16_t descriptor_counts_offset;
struct avbtp_aem_desc_descriptor_count descriptor_counts[0];
} __attribute__ ((__packed__));
struct avbtp_aem_desc_sampling_rate {
uint32_t pull_frequency;
} __attribute__ ((__packed__));
struct avbtp_aem_desc_audio_unit {
char object_name[64];
uint16_t localized_description;
uint16_t clock_domain_index;
uint16_t number_of_stream_input_ports;
uint16_t base_stream_input_port;
uint16_t number_of_stream_output_ports;
uint16_t base_stream_output_port;
uint16_t number_of_external_input_ports;
uint16_t base_external_input_port;
uint16_t number_of_external_output_ports;
uint16_t base_external_output_port;
uint16_t number_of_internal_input_ports;
uint16_t base_internal_input_port;
uint16_t number_of_internal_output_ports;
uint16_t base_internal_output_port;
uint16_t number_of_controls;
uint16_t base_control;
uint16_t number_of_signal_selectors;
uint16_t base_signal_selector;
uint16_t number_of_mixers;
uint16_t base_mixer;
uint16_t number_of_matrices;
uint16_t base_matrix;
uint16_t number_of_splitters;
uint16_t base_splitter;
uint16_t number_of_combiners;
uint16_t base_combiner;
uint16_t number_of_demultiplexers;
uint16_t base_demultiplexer;
uint16_t number_of_multiplexers;
uint16_t base_multiplexer;
uint16_t number_of_transcoders;
uint16_t base_transcoder;
uint16_t number_of_control_blocks;
uint16_t base_control_block;
uint32_t current_sampling_rate;
uint16_t sampling_rates_offset;
uint16_t sampling_rates_count;
struct avbtp_aem_desc_sampling_rate sampling_rates[0];
} __attribute__ ((__packed__));
#define AVBTP_AEM_DESC_STREAM_FLAG_SYNC_SOURCE (1<<0)
#define AVBTP_AEM_DESC_STREAM_FLAG_CLASS_A (1<<1)
#define AVBTP_AEM_DESC_STREAM_FLAG_CLASS_B (1<<2)
struct avbtp_aem_desc_stream {
char object_name[64];
uint16_t localized_description;
uint16_t clock_domain_index;
uint16_t stream_flags;
uint64_t current_format;
uint16_t formats_offset;
uint16_t number_of_formats;
uint64_t backup_talker_entity_id_0;
uint16_t backup_talker_unique_id_0;
uint64_t backup_talker_entity_id_1;
uint16_t backup_talker_unique_id_1;
uint64_t backup_talker_entity_id_2;
uint16_t backup_talker_unique_id_2;
uint64_t backedup_talker_entity_id;
uint16_t backedup_talker_unique;
uint16_t avb_interface_index;
uint32_t buffer_length;
uint64_t stream_formats[0];
} __attribute__ ((__packed__));
struct avbtp_aem_desc_locale {
char locale_identifier[64];
uint16_t number_of_strings;
uint16_t base_strings;
} __attribute__ ((__packed__));
struct avbtp_aem_desc_strings {
char string_0[64];
char string_1[64];
char string_2[64];
char string_3[64];
char string_4[64];
char string_5[64];
char string_6[64];
} __attribute__ ((__packed__));
#endif /* AVBTP_AECP_AEM_DESCRIPTORS_H */

View file

@ -0,0 +1,230 @@
/* AVB support
*
* Copyright © 2022 Wim Taymans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "aecp-aem.h"
#include "aecp-aem-descriptors.h"
static int reply_status(struct aecp *aecp, int status, const void *m, int len)
{
struct server *server = aecp->server;
uint8_t buf[len];
struct avbtp_packet_aecp_header *reply = (struct avbtp_packet_aecp_header*)buf;
memcpy(reply, m, len);
AVBTP_PACKET_AECP_SET_MESSAGE_TYPE(reply, AVBTP_AECP_MESSAGE_TYPE_AEM_RESPONSE);
AVBTP_PACKET_AECP_SET_STATUS(reply, status);
return avbtp_server_send_packet(server, reply->hdr.eth.src, reply, len);
}
static int reply_not_implemented(struct aecp *aecp, const void *m, int len)
{
return reply_status(aecp, AVBTP_AECP_AEM_STATUS_NOT_IMPLEMENTED, m, len);
}
static int reply_success(struct aecp *aecp, const void *m, int len)
{
return reply_status(aecp, AVBTP_AECP_AEM_STATUS_SUCCESS, m, len);
}
/* ACQUIRE_ENTITY */
static int handle_acquire_entity(struct aecp *aecp, const void *m, int len)
{
struct server *server = aecp->server;
const struct avbtp_packet_aecp_aem *p = m;
const struct avbtp_packet_aecp_aem_acquire *ae;
const struct descriptor *desc;
uint16_t desc_type, desc_id;
ae = (const struct avbtp_packet_aecp_aem_acquire*)p->payload;
desc_type = ntohs(ae->descriptor_type);
desc_id = ntohs(ae->descriptor_id);
desc = find_descriptor(server, desc_type, desc_id);
if (desc == NULL)
return reply_status(aecp, AVBTP_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, p, len);
if (desc_type != AVBTP_AEM_DESC_ENTITY || desc_id != 0)
return reply_not_implemented(aecp, m, len);
return reply_success(aecp, m, len);
}
/* LOCK_ENTITY */
static int handle_lock_entity(struct aecp *aecp, const void *m, int len)
{
struct server *server = aecp->server;
const struct avbtp_packet_aecp_aem *p = m;
const struct avbtp_packet_aecp_aem_acquire *ae;
const struct descriptor *desc;
uint16_t desc_type, desc_id;
ae = (const struct avbtp_packet_aecp_aem_acquire*)p->payload;
desc_type = ntohs(ae->descriptor_type);
desc_id = ntohs(ae->descriptor_id);
desc = find_descriptor(server, desc_type, desc_id);
if (desc == NULL)
return reply_status(aecp, AVBTP_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, p, len);
if (desc_type != AVBTP_AEM_DESC_ENTITY || desc_id != 0)
return reply_not_implemented(aecp, m, len);
return reply_success(aecp, m, len);
}
/* READ_DESCRIPTOR */
static int handle_read_descriptor(struct aecp *aecp, const void *h, int len)
{
struct server *server = aecp->server;
const struct avbtp_packet_aecp_aem *p = h;
struct avbtp_packet_aecp_header *reply;
uint16_t desc_type, desc_id;
const struct descriptor *desc;
const struct avbtp_packet_aecp_aem_read_descriptor *rd;
uint8_t buf[2048];
size_t size;
rd = (struct avbtp_packet_aecp_aem_read_descriptor*)p->payload;
desc_type = ntohs(rd->descriptor_type);
desc_id = ntohs(rd->descriptor_id);
pw_log_info("descriptor type:%04x index:%d", desc_type, desc_id);
desc = find_descriptor(server, desc_type, desc_id);
if (desc == NULL)
return reply_status(aecp, AVBTP_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, p, len);
size = sizeof(struct avbtp_packet_aecp_aem) + sizeof(*rd);
memcpy(buf, p, size);
memcpy(buf + size, desc->ptr, desc->size);
size += desc->size;
reply = (struct avbtp_packet_aecp_header *)buf;
AVBTP_PACKET_SET_LENGTH(&reply->hdr, size - 26 );
AVBTP_PACKET_AECP_SET_MESSAGE_TYPE(reply, AVBTP_AECP_MESSAGE_TYPE_AEM_RESPONSE);
AVBTP_PACKET_AECP_SET_STATUS(reply, AVBTP_AECP_AEM_STATUS_SUCCESS);
return avbtp_server_send_packet(server, reply->hdr.eth.src, reply, size);
}
/* AEM_COMMAND */
struct cmd_info {
uint16_t type;
const char *name;
int (*handle) (struct aecp *aecp, const void *p, int len);
};
static const struct cmd_info cmd_info[] = {
{ AVBTP_AECP_AEM_CMD_ACQUIRE_ENTITY, "acquire-entity", handle_acquire_entity, },
{ AVBTP_AECP_AEM_CMD_LOCK_ENTITY, "lock-entity", handle_lock_entity, },
{ AVBTP_AECP_AEM_CMD_ENTITY_AVAILABLE, "entity-available", NULL, },
{ AVBTP_AECP_AEM_CMD_CONTROLLER_AVAILABLE, "controller-available", NULL, },
{ AVBTP_AECP_AEM_CMD_READ_DESCRIPTOR, "read-descriptor", handle_read_descriptor, },
{ AVBTP_AECP_AEM_CMD_WRITE_DESCRIPTOR, "write-descriptor", NULL, },
{ AVBTP_AECP_AEM_CMD_SET_CONFIGURATION, "set-configuration", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_CONFIGURATION, "get-configuration", NULL, },
{ AVBTP_AECP_AEM_CMD_SET_STREAM_FORMAT, "set-stream-format", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_STREAM_FORMAT, "get-stream-format", NULL, },
{ AVBTP_AECP_AEM_CMD_SET_VIDEO_FORMAT, "set-video-format", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_VIDEO_FORMAT, "get-video-format", NULL, },
{ AVBTP_AECP_AEM_CMD_SET_SENSOR_FORMAT, "set-sensor-format", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_SENSOR_FORMAT, "get-sensor-format", NULL, },
{ AVBTP_AECP_AEM_CMD_SET_STREAM_INFO, "set-stream-info", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_STREAM_INFO, "get-stream-info", NULL, },
{ AVBTP_AECP_AEM_CMD_SET_NAME, "set-name", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_NAME, "get-name", NULL, },
{ AVBTP_AECP_AEM_CMD_SET_ASSOCIATION_ID, "set-association-id", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_ASSOCIATION_ID, "get-association-id", NULL, },
{ AVBTP_AECP_AEM_CMD_SET_SAMPLING_RATE, "set-sampling-rate", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_SAMPLING_RATE, "get-sampling-rate", NULL, },
{ AVBTP_AECP_AEM_CMD_SET_CLOCK_SOURCE, "set-clock-source", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_CLOCK_SOURCE, "get-clock-source", NULL, },
{ AVBTP_AECP_AEM_CMD_SET_CONTROL, "set-control", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_CONTROL, "get-control", NULL, },
{ AVBTP_AECP_AEM_CMD_INCREMENT_CONTROL, "increment-control", NULL, },
{ AVBTP_AECP_AEM_CMD_DECREMENT_CONTROL, "decrement-control", NULL, },
{ AVBTP_AECP_AEM_CMD_SET_SIGNAL_SELECTOR, "set-signal-selector", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_SIGNAL_SELECTOR, "get-signal-selector", NULL, },
{ AVBTP_AECP_AEM_CMD_SET_MIXER, "set-mixer", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_MIXER, "get-mixer", NULL, },
{ AVBTP_AECP_AEM_CMD_SET_MATRIX, "set-matrix", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_MATRIX, "get-matrix", NULL, },
{ AVBTP_AECP_AEM_CMD_START_STREAMING, "start-streaming", NULL, },
{ AVBTP_AECP_AEM_CMD_STOP_STREAMING, "stop-streaming", NULL, },
{ AVBTP_AECP_AEM_CMD_REGISTER_UNSOLICITED_NOTIFICATION, "register-unsolicited-notification", NULL, },
{ AVBTP_AECP_AEM_CMD_DEREGISTER_UNSOLICITED_NOTIFICATION, "deregister-unsolicited-notification", NULL, },
{ AVBTP_AECP_AEM_CMD_IDENTIFY_NOTIFICATION, "identify-notification", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_AVB_INFO, "get-avb-info", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_AS_PATH, "get-as-path", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_COUNTERS, "get-counters", NULL, },
{ AVBTP_AECP_AEM_CMD_REBOOT, "reboot", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_AUDIO_MAP, "get-audio-map", NULL, },
{ AVBTP_AECP_AEM_CMD_ADD_AUDIO_MAPPINGS, "add-audio-mappings", NULL, },
{ AVBTP_AECP_AEM_CMD_REMOVE_AUDIO_MAPPINGS, "remove-audio-mappings", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_VIDEO_MAP, "get-video-map", NULL, },
{ AVBTP_AECP_AEM_CMD_ADD_VIDEO_MAPPINGS, "add-video-mappings", NULL, },
{ AVBTP_AECP_AEM_CMD_REMOVE_VIDEO_MAPPINGS, "remove-video-mappings", NULL, },
{ AVBTP_AECP_AEM_CMD_GET_SENSOR_MAP, "get-sensor-map", NULL, }
};
static inline const struct cmd_info *find_cmd_info(uint16_t type, const char *name)
{
uint32_t i;
for (i = 0; i < SPA_N_ELEMENTS(cmd_info); i++) {
if ((name == NULL && type == cmd_info[i].type) ||
(name != NULL && spa_streq(name, cmd_info[i].name)))
return &cmd_info[i];
}
return NULL;
}
int avbtp_aecp_aem_handle_command(struct aecp *aecp, const void *m, int len)
{
const struct avbtp_packet_aecp_aem *p = m;
uint16_t cmd_type;
const struct cmd_info *info;
cmd_type = AVBTP_PACKET_AEM_GET_COMMAND_TYPE(p);
info = find_cmd_info(cmd_type, NULL);
if (info == NULL)
return reply_not_implemented(aecp, m, len);
pw_log_info("aem command %s", info->name);
if (info->handle == NULL)
return reply_not_implemented(aecp, m, len);
return info->handle(aecp, m, len);
}
int avbtp_aecp_aem_handle_response(struct aecp *aecp, const void *m, int len)
{
return 0;
}

View file

@ -25,46 +25,311 @@
#ifndef AVBTP_AEM_H #ifndef AVBTP_AEM_H
#define AVBTP_AEM_H #define AVBTP_AEM_H
#include "packets.h" #include "aecp.h"
#define AVBTP_AEM_DESC_ENTITY 0x0000 #define AVBTP_AECP_AEM_STATUS_SUCCESS 0
#define AVBTP_AEM_DESC_CONFIGURATION 0x0001 #define AVBTP_AECP_AEM_STATUS_NOT_IMPLEMENTED 1
#define AVBTP_AEM_DESC_AUDIO_UNIT 0x0002 #define AVBTP_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR 2
#define AVBTP_AEM_DESC_VIDEO_UNIT 0x0003 #define AVBTP_AECP_AEM_STATUS_ENTITY_LOCKED 3
#define AVBTP_AEM_DESC_SENSOR_UNIT 0x0004 #define AVBTP_AECP_AEM_STATUS_ENTITY_ACQUIRED 4
#define AVBTP_AEM_DESC_STREAM_INPUT 0x0005 #define AVBTP_AECP_AEM_STATUS_NOT_AUTHENTICATED 5
#define AVBTP_AEM_DESC_STREAM_OUTPUT 0x0006 #define AVBTP_AECP_AEM_STATUS_AUTHENTICATION_DISABLED 6
#define AVBTP_AEM_DESC_JACK_INPUT 0x0007 #define AVBTP_AECP_AEM_STATUS_BAD_ARGUMENTS 7
#define AVBTP_AEM_DESC_JACK_OUTPUT 0x0008 #define AVBTP_AECP_AEM_STATUS_NO_RESOURCES 8
#define AVBTP_AEM_DESC_AVB_INTERFACE 0x0009 #define AVBTP_AECP_AEM_STATUS_IN_PROGRESS 9
#define AVBTP_AEM_DESC_CLOCK_SOURCE 0x000a #define AVBTP_AECP_AEM_STATUS_ENTITY_MISBEHAVING 10
#define AVBTP_AEM_DESC_MEMORY_OBJECT 0x000b #define AVBTP_AECP_AEM_STATUS_NOT_SUPPORTED 11
#define AVBTP_AEM_DESC_LOCALE 0x000c #define AVBTP_AECP_AEM_STATUS_STREAM_IS_RUNNING 12
#define AVBTP_AEM_DESC_STRINGS 0x000d
#define AVBTP_AEM_DESC_STREAM_PORT_INPUT 0x000e #define AVBTP_AECP_AEM_CMD_ACQUIRE_ENTITY 0x0000
#define AVBTP_AEM_DESC_STREAM_PORT_OUTPUT 0x000f #define AVBTP_AECP_AEM_CMD_LOCK_ENTITY 0x0001
#define AVBTP_AEM_DESC_EXTERNAL_PORT_INPUT 0x0010 #define AVBTP_AECP_AEM_CMD_ENTITY_AVAILABLE 0x0002
#define AVBTP_AEM_DESC_EXTERNAL_PORT_OUTPUT 0x0011 #define AVBTP_AECP_AEM_CMD_CONTROLLER_AVAILABLE 0x0003
#define AVBTP_AEM_DESC_INTERNAL_PORT_INPUT 0x0012 #define AVBTP_AECP_AEM_CMD_READ_DESCRIPTOR 0x0004
#define AVBTP_AEM_DESC_INTERNAL_PORT_OUTPUT 0x0013 #define AVBTP_AECP_AEM_CMD_WRITE_DESCRIPTOR 0x0005
#define AVBTP_AEM_DESC_AUDIO_CLUSTER 0x0014 #define AVBTP_AECP_AEM_CMD_SET_CONFIGURATION 0x0006
#define AVBTP_AEM_DESC_VIDEO_CLUSTER 0x0015 #define AVBTP_AECP_AEM_CMD_GET_CONFIGURATION 0x0007
#define AVBTP_AEM_DESC_SENSOR_CLUSTER 0x0016 #define AVBTP_AECP_AEM_CMD_SET_STREAM_FORMAT 0x0008
#define AVBTP_AEM_DESC_AUDIO_MAP 0x0017 #define AVBTP_AECP_AEM_CMD_GET_STREAM_FORMAT 0x0009
#define AVBTP_AEM_DESC_VIDEO_MAP 0x0018 #define AVBTP_AECP_AEM_CMD_SET_VIDEO_FORMAT 0x000a
#define AVBTP_AEM_DESC_SENSOR_MAP 0x0019 #define AVBTP_AECP_AEM_CMD_GET_VIDEO_FORMAT 0x000b
#define AVBTP_AEM_DESC_CONTROL 0x001a #define AVBTP_AECP_AEM_CMD_SET_SENSOR_FORMAT 0x000c
#define AVBTP_AEM_DESC_SIGNAL_SELECTOR 0x001b #define AVBTP_AECP_AEM_CMD_GET_SENSOR_FORMAT 0x000d
#define AVBTP_AEM_DESC_MIXER 0x001c #define AVBTP_AECP_AEM_CMD_SET_STREAM_INFO 0x000e
#define AVBTP_AEM_DESC_MATRIX 0x001d #define AVBTP_AECP_AEM_CMD_GET_STREAM_INFO 0x000f
#define AVBTP_AEM_DESC_MATRIX_SIGNAL 0x001e #define AVBTP_AECP_AEM_CMD_SET_NAME 0x0010
#define AVBTP_AEM_SIGNAL_SPLITTER 0x001f #define AVBTP_AECP_AEM_CMD_GET_NAME 0x0011
#define AVBTP_AEM_SIGNAL_COMBINER 0x0020 #define AVBTP_AECP_AEM_CMD_SET_ASSOCIATION_ID 0x0012
#define AVBTP_AEM_SIGNAL_DEMULTIPLEXER 0x0021 #define AVBTP_AECP_AEM_CMD_GET_ASSOCIATION_ID 0x0013
#define AVBTP_AEM_SIGNAL_MULTIPLEXER 0x0022 #define AVBTP_AECP_AEM_CMD_SET_SAMPLING_RATE 0x0014
#define AVBTP_AEM_SIGNAL_TRANSCODER 0x0023 #define AVBTP_AECP_AEM_CMD_GET_SAMPLING_RATE 0x0015
#define AVBTP_AEM_CLOCK_DOMAIN 0x0024 #define AVBTP_AECP_AEM_CMD_SET_CLOCK_SOURCE 0x0016
#define AVBTP_AEM_CONTROL_BLOCK 0x0025 #define AVBTP_AECP_AEM_CMD_GET_CLOCK_SOURCE 0x0017
#define AVBTP_AEM_INVALID 0xffff #define AVBTP_AECP_AEM_CMD_SET_CONTROL 0x0018
#define AVBTP_AECP_AEM_CMD_GET_CONTROL 0x0019
#define AVBTP_AECP_AEM_CMD_INCREMENT_CONTROL 0x001a
#define AVBTP_AECP_AEM_CMD_DECREMENT_CONTROL 0x001b
#define AVBTP_AECP_AEM_CMD_SET_SIGNAL_SELECTOR 0x001c
#define AVBTP_AECP_AEM_CMD_GET_SIGNAL_SELECTOR 0x001d
#define AVBTP_AECP_AEM_CMD_SET_MIXER 0x001e
#define AVBTP_AECP_AEM_CMD_GET_MIXER 0x001f
#define AVBTP_AECP_AEM_CMD_SET_MATRIX 0x0020
#define AVBTP_AECP_AEM_CMD_GET_MATRIX 0x0021
#define AVBTP_AECP_AEM_CMD_START_STREAMING 0x0022
#define AVBTP_AECP_AEM_CMD_STOP_STREAMING 0x0023
#define AVBTP_AECP_AEM_CMD_REGISTER_UNSOLICITED_NOTIFICATION 0x0024
#define AVBTP_AECP_AEM_CMD_DEREGISTER_UNSOLICITED_NOTIFICATION 0x0025
#define AVBTP_AECP_AEM_CMD_IDENTIFY_NOTIFICATION 0x0026
#define AVBTP_AECP_AEM_CMD_GET_AVB_INFO 0x0027
#define AVBTP_AECP_AEM_CMD_GET_AS_PATH 0x0028
#define AVBTP_AECP_AEM_CMD_GET_COUNTERS 0x0029
#define AVBTP_AECP_AEM_CMD_REBOOT 0x002a
#define AVBTP_AECP_AEM_CMD_GET_AUDIO_MAP 0x002b
#define AVBTP_AECP_AEM_CMD_ADD_AUDIO_MAPPINGS 0x002c
#define AVBTP_AECP_AEM_CMD_REMOVE_AUDIO_MAPPINGS 0x002d
#define AVBTP_AECP_AEM_CMD_GET_VIDEO_MAP 0x002e
#define AVBTP_AECP_AEM_CMD_ADD_VIDEO_MAPPINGS 0x002f
#define AVBTP_AECP_AEM_CMD_REMOVE_VIDEO_MAPPINGS 0x0030
#define AVBTP_AECP_AEM_CMD_GET_SENSOR_MAP 0x0031
#define AVBTP_AECP_AEM_CMD_ADD_SENSOR_MAPPINGS 0x0032
#define AVBTP_AECP_AEM_CMD_REMOVE_SENSOR_MAPPINGS 0x0033
#define AVBTP_AECP_AEM_CMD_START_OPERATION 0x0034
#define AVBTP_AECP_AEM_CMD_ABORT_OPERATION 0x0035
#define AVBTP_AECP_AEM_CMD_OPERATION_STATUS 0x0036
#define AVBTP_AECP_AEM_CMD_AUTH_ADD_KEY 0x0037
#define AVBTP_AECP_AEM_CMD_AUTH_DELETE_KEY 0x0038
#define AVBTP_AECP_AEM_CMD_AUTH_GET_KEY_LIST 0x0039
#define AVBTP_AECP_AEM_CMD_AUTH_GET_KEY 0x003a
#define AVBTP_AECP_AEM_CMD_AUTH_ADD_KEY_TO_CHAIN 0x003b
#define AVBTP_AECP_AEM_CMD_AUTH_DELETE_KEY_FROM_CHAIN 0x003c
#define AVBTP_AECP_AEM_CMD_AUTH_GET_KEYCHAIN_LIST 0x003d
#define AVBTP_AECP_AEM_CMD_AUTH_GET_IDENTITY 0x003e
#define AVBTP_AECP_AEM_CMD_AUTH_ADD_TOKEN 0x003f
#define AVBTP_AECP_AEM_CMD_AUTH_DELETE_TOKEN 0x0040
#define AVBTP_AECP_AEM_CMD_AUTHENTICATE 0x0041
#define AVBTP_AECP_AEM_CMD_DEAUTHENTICATE 0x0042
#define AVBTP_AECP_AEM_CMD_ENABLE_TRANSPORT_SECURITY 0x0043
#define AVBTP_AECP_AEM_CMD_DISABLE_TRANSPORT_SECURITY 0x0044
#define AVBTP_AECP_AEM_CMD_ENABLE_STREAM_ENCRYPTION 0x0045
#define AVBTP_AECP_AEM_CMD_DISABLE_STREAM_ENCRYPTION 0x0046
#define AVBTP_AECP_AEM_CMD_SET_MEMORY_OBJECT_LENGTH 0x0047
#define AVBTP_AECP_AEM_CMD_GET_MEMORY_OBJECT_LENGTH 0x0048
#define AVBTP_AECP_AEM_CMD_SET_STREAM_BACKUP 0x0049
#define AVBTP_AECP_AEM_CMD_GET_STREAM_BACKUP 0x004a
#define AVBTP_AECP_AEM_CMD_EXPANSION 0x7fff
#define AVBTP_AEM_ACQUIRE_ENTITY_PERSISTENT_FLAG (1<<0)
struct avbtp_packet_aecp_aem_acquire {
uint32_t flags;
uint64_t owner_guid;
uint16_t descriptor_type;
uint16_t descriptor_id;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_lock {
uint32_t flags;
uint64_t locked_guid;
uint16_t descriptor_type;
uint16_t descriptor_id;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_read_descriptor {
uint16_t configuration;
uint8_t reserved[2];
uint16_t descriptor_type;
uint16_t descriptor_id;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_setget_configuration {
uint16_t reserved;
uint16_t configuration_index;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_setget_stream_format {
uint16_t descriptor_type;
uint16_t descriptor_id;
uint64_t stream_format;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_setget_video_format {
uint16_t descriptor_type;
uint16_t descriptor_id;
uint32_t format_specific;
uint16_t aspect_ratio;
uint16_t color_space;
uint32_t frame_size;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_setget_sensor_format {
uint16_t descriptor_type;
uint16_t descriptor_id;
uint64_t sensor_format;
} __attribute__ ((__packed__));
#define AVBTP_AEM_STREAM_INFO_FLAG_CLASS_B (1u<<0)
#define AVBTP_AEM_STREAM_INFO_FLAG_FAST_CONNECT (1u<<1)
#define AVBTP_AEM_STREAM_INFO_FLAG_SAVED_STATE (1u<<2)
#define AVBTP_AEM_STREAM_INFO_FLAG_STREAMING_WAIT (1u<<3)
#define AVBTP_AEM_STREAM_INFO_FLAG_ENCRYPTED_PDU (1u<<4)
#define AVBTP_AEM_STREAM_INFO_FLAG_STREAM_VLAN_ID_VALID (1u<<25)
#define AVBTP_AEM_STREAM_INFO_FLAG_CONNECTED (1u<<26)
#define AVBTP_AEM_STREAM_INFO_FLAG_MSRP_FAILURE_VALID (1u<<27)
#define AVBTP_AEM_STREAM_INFO_FLAG_STREAM_DEST_MAC_VALID (1u<<28)
#define AVBTP_AEM_STREAM_INFO_FLAG_MSRP_ACC_LAT_VALID (1u<<29)
#define AVBTP_AEM_STREAM_INFO_FLAG_STREAM_ID_VALID (1u<<30)
#define AVBTP_AEM_STREAM_INFO_FLAG_STREAM_FORMAT_VALID (1u<<31)
struct avbtp_packet_aecp_aem_setget_stream_info {
uint16_t descriptor_type;
uint16_t descriptor_index;
uint32_t aem_stream_info_flags;
uint64_t stream_format;
uint64_t stream_id;
uint32_t msrp_accumulated_latency;
uint8_t stream_dest_mac[6];
uint8_t msrp_failure_code;
uint8_t reserved;
uint64_t msrp_failure_bridge_id;
uint16_t stream_vlan_id;
uint16_t reserved2;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_setget_name {
uint16_t descriptor_type;
uint16_t descriptor_index;
uint16_t name_index;
uint16_t configuration_index;
char name[64];
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_setget_association_id {
uint16_t descriptor_type;
uint16_t descriptor_index;
uint64_t association_id;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_setget_sampling_rate {
uint16_t descriptor_type;
uint16_t descriptor_id;
uint32_t sampling_rate;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_setget_clock_source {
uint16_t descriptor_type;
uint16_t descriptor_id;
uint16_t clock_source_index;
uint16_t reserved;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_setget_control {
uint16_t descriptor_type;
uint16_t descriptor_id;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_incdec_control {
uint16_t descriptor_type;
uint16_t descriptor_id;
uint16_t index_count;
uint16_t reserved;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_setget_signal_selector {
uint16_t descriptor_type;
uint16_t descriptor_id;
uint16_t signal_type;
uint16_t signal_index;
uint16_t signal_output;
uint16_t reserved;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_setget_mixer {
uint16_t descriptor_type;
uint16_t descriptor_id;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_setget_matrix {
uint16_t descriptor_type;
uint16_t descriptor_index;
uint16_t matrix_column;
uint16_t matrix_row;
uint16_t region_width;
uint16_t region_height;
uint16_t rep_direction_value_count;
uint16_t item_offset;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_startstop_streaming {
uint16_t descriptor_type;
uint16_t descriptor_id;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_identify_notification {
uint16_t descriptor_type;
uint16_t descriptor_id;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_get_avb_info {
uint16_t descriptor_type;
uint16_t descriptor_id;
uint64_t gptp_grandmaster_id;
uint32_t propagation_delay;
uint8_t gptp_domain_number;
uint8_t flags;
uint16_t msrp_mappings_count;
uint32_t msrp_mappings;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_get_as_path {
uint16_t descriptor_index;
uint16_t reserved;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_get_counters {
uint16_t descriptor_type;
uint16_t descriptor_id;
uint32_t counters_valid;
uint8_t counters_block[0];
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_reboot {
uint16_t descriptor_type;
uint16_t descriptor_id;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_start_operation {
uint16_t descriptor_type;
uint16_t descriptor_id;
uint16_t operation_id;
uint16_t operation_type;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_operation_status {
uint16_t descriptor_type;
uint16_t descriptor_id;
uint16_t operation_id;
uint16_t percent_complete;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem {
struct avbtp_packet_aecp_header aecp;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned u:1;
unsigned cmd1:7;
#elif __BYTE_ORDER == __LITTLE_ENDIAN
unsigned cmd1:7;
unsigned u:1;
#endif
uint8_t cmd2;
uint8_t payload[0];
} __attribute__ ((__packed__));
#define AVBTP_PACKET_AEM_SET_COMMAND_TYPE(p,v) ((p)->cmd1 = ((v) >> 8),(p)->cmd2 = (v))
#define AVBTP_PACKET_AEM_GET_COMMAND_TYPE(p) ((p)->cmd1 << 8 | (p)->cmd2)
int avbtp_aecp_aem_handle_command(struct aecp *aecp, const void *m, int len);
int avbtp_aecp_aem_handle_response(struct aecp *aecp, const void *m, int len);
#endif /* AVBTP_AEM_H */ #endif /* AVBTP_AEM_H */

View file

@ -31,183 +31,71 @@
#include "aecp-aem.h" #include "aecp-aem.h"
#include "internal.h" #include "internal.h"
struct aecp { struct msg_info {
struct server *server; uint16_t type;
struct spa_hook server_listener; const char *name;
const char *description;
uint64_t now; int (*handle) (struct aecp *aecp, const void *p, int len);
}; };
static void aecp_message_debug(struct aecp *aecp, const struct avbtp_packet_aecp_header *p) static int reply_not_implemented(struct aecp *aecp, const void *p, int len)
{
}
static int reply_status(struct aecp *aecp, const uint8_t dest[6], int status,
const void *p, int len)
{ {
struct server *server = aecp->server; struct server *server = aecp->server;
uint8_t buf[len]; uint8_t buf[len];
struct avbtp_packet_aecp_header *reply = (struct avbtp_packet_aecp_header*)buf; struct avbtp_packet_aecp_header *reply = (struct avbtp_packet_aecp_header*)buf;
memcpy(reply, p, len); memcpy(reply, p, len);
AVBTP_PACKET_AECP_SET_MESSAGE_TYPE(reply, AVBTP_AECP_MESSAGE_TYPE_AEM_RESPONSE); AVBTP_PACKET_AECP_SET_STATUS(reply, AVBTP_AECP_STATUS_NOT_IMPLEMENTED);
AVBTP_PACKET_AECP_SET_STATUS(reply, status);
return avbtp_server_send_packet(server, dest, reply, len); return avbtp_server_send_packet(server, reply->hdr.eth.src, reply, len);
} }
static int reply_not_implemented(struct aecp *aecp, const uint8_t dest[6], static const struct msg_info msg_info[] = {
const void *p, int len) { AVBTP_AECP_MESSAGE_TYPE_AEM_COMMAND, "aem-command", "AEM Command", avbtp_aecp_aem_handle_command, },
{ { AVBTP_AECP_MESSAGE_TYPE_AEM_RESPONSE, "aem-response", "AEM Response", avbtp_aecp_aem_handle_response, },
return reply_status(aecp, dest, AVBTP_AECP_AEM_STATUS_NOT_IMPLEMENTED, p, len); { AVBTP_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_COMMAND, "address-access-command", "Address Access Command", NULL, },
} { AVBTP_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_RESPONSE, "address-access-response", "Address Access Response", NULL, },
{ AVBTP_AECP_MESSAGE_TYPE_AVC_COMMAND, "avc-command", "AVC Command", NULL, },
static int reply_success(struct aecp *aecp, const uint8_t dest[6], { AVBTP_AECP_MESSAGE_TYPE_AVC_RESPONSE, "avc-response", "AVC Response", NULL, },
const void *p, int len) { AVBTP_AECP_MESSAGE_TYPE_VENDOR_UNIQUE_COMMAND, "vendor-unique-command", "Vendor Unique Command", NULL, },
{ { AVBTP_AECP_MESSAGE_TYPE_VENDOR_UNIQUE_RESPONSE, "vendor-unique-response", "Vendor Unique Response", NULL, },
return reply_status(aecp, dest, AVBTP_AECP_AEM_STATUS_SUCCESS, p, len); { AVBTP_AECP_MESSAGE_TYPE_EXTENDED_COMMAND, "extended-command", "Extended Command", NULL, },
} { AVBTP_AECP_MESSAGE_TYPE_EXTENDED_RESPONSE, "extended-response", "Extended Response", NULL, },
struct desc_info {
uint16_t type;
const char *name;
const char *description;
int (*handle) (struct aecp *aecp, const uint8_t src[6], uint16_t id, const void *p, int len);
}; };
const struct desc_info desc_info[] = { static inline const struct msg_info *find_msg_info(uint16_t type, const char *name)
{ AVBTP_AEM_DESC_ENTITY, "entity", "Entitiy", NULL, },
{ AVBTP_AEM_DESC_CONFIGURATION, "configuration", "Configuration", NULL, },
{ AVBTP_AEM_DESC_AUDIO_UNIT, "audio-unit", "Audio Unit", NULL, },
{ AVBTP_AEM_DESC_VIDEO_UNIT, "video-unit", "Video Unit", NULL, },
{ AVBTP_AEM_DESC_SENSOR_UNIT, "sensor-unit", "Sensor Unit", NULL, },
{ AVBTP_AEM_DESC_STREAM_INPUT, "stream-input", "Stream Input", NULL, },
{ AVBTP_AEM_DESC_STREAM_OUTPUT, "stream-output", "Stream Output", NULL, },
{ AVBTP_AEM_DESC_JACK_INPUT, "jack-input", "Jack Input", NULL, },
{ AVBTP_AEM_DESC_JACK_OUTPUT, "jack-output", "Jack Output", NULL, },
{ AVBTP_AEM_DESC_AVB_INTERFACE, "avb-interface", "AVB Interface", NULL, },
{ AVBTP_AEM_DESC_CLOCK_SOURCE, "clock-source", "Clock Source", NULL, },
{ AVBTP_AEM_DESC_MEMORY_OBJECT, "memory-object", "Memory Object", NULL, },
{ AVBTP_AEM_DESC_LOCALE, "locale", "Locale", NULL, },
{ AVBTP_AEM_DESC_STRINGS, "string", "Strings", NULL, },
{ AVBTP_AEM_DESC_STREAM_PORT_INPUT, "stream-port-input", "Stream Port Input", NULL, },
{ AVBTP_AEM_DESC_STREAM_PORT_OUTPUT, "stream-port-output", "Stream Port output", NULL, },
{ AVBTP_AEM_DESC_EXTERNAL_PORT_INPUT, "external-port-input", "External Port Input", NULL, },
{ AVBTP_AEM_DESC_EXTERNAL_PORT_OUTPUT, "external-port-output", "External Port Output", NULL, },
{ AVBTP_AEM_DESC_INTERNAL_PORT_INPUT, "internal-port-inut", "Internal Port Input", NULL, },
{ AVBTP_AEM_DESC_INTERNAL_PORT_OUTPUT, "internal-port-inut", "Internal Port Output", NULL, },
{ AVBTP_AEM_DESC_AUDIO_CLUSTER, "audio-cluster", "Audio Cluster", NULL, },
{ AVBTP_AEM_DESC_VIDEO_CLUSTER, "video-cluster", "Video Cluster", NULL, },
{ AVBTP_AEM_DESC_SENSOR_CLUSTER, "sensor-cluster", "Sensor Cluster", NULL, },
{ AVBTP_AEM_DESC_AUDIO_MAP, "audio-map", "Audio Map", NULL, },
{ AVBTP_AEM_DESC_VIDEO_MAP, "video-map", "Video Map", NULL, },
{ AVBTP_AEM_DESC_SENSOR_MAP, "sensor-map", "Sensor Map", NULL, },
{ AVBTP_AEM_DESC_CONTROL, "control", "Control", NULL, },
{ AVBTP_AEM_DESC_SIGNAL_SELECTOR, "signal-selector", "Signal Selector", NULL, },
{ AVBTP_AEM_DESC_MIXER, "mixer", "Mixer", NULL, },
{ AVBTP_AEM_DESC_MATRIX, "matrix", "Matrix", NULL, },
{ AVBTP_AEM_DESC_MATRIX_SIGNAL, "matrix-signal", "Matrix Signal", NULL, },
};
static inline const struct desc_info *find_desc_info(uint16_t type, const char *name)
{ {
uint32_t i; uint32_t i;
for (i = 0; i < SPA_N_ELEMENTS(desc_info); i++) { for (i = 0; i < SPA_N_ELEMENTS(msg_info); i++) {
if ((name == NULL && type == desc_info[i].type) || if ((name == NULL && type == msg_info[i].type) ||
(name != NULL && spa_streq(name, desc_info[i].name))) (name != NULL && spa_streq(name, msg_info[i].name)))
return &desc_info[i]; return &msg_info[i];
} }
return NULL; return NULL;
} }
static int handle_aem_command_read_descriptor(struct aecp *aecp, const uint8_t src[6], static int aecp_message(void *data, uint64_t now, const void *message, int len)
const struct avbtp_packet_aecp_aem *p, int len)
{
uint16_t desc_type, desc_id;
const struct desc_info *info;
desc_type = ntohs(p->read_descriptor_cmd.descriptor_type);
desc_id = ntohs(p->read_descriptor_cmd.descriptor_id);
info = find_desc_info(desc_type, NULL);
if (info == NULL)
return reply_status(aecp, src, AVBTP_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, p, len);
pw_log_info("read-desc %s", info->name);
if (info->handle == NULL)
return reply_not_implemented(aecp, src, p, len);
return info->handle(aecp, src, desc_id, p, len);
}
static int handle_aem_command(struct aecp *aecp, const uint8_t src[6],
const struct avbtp_packet_aecp_header *h, int len)
{
struct avbtp_packet_aecp_aem *p = (struct avbtp_packet_aecp_aem *)h;
int res = -ENOTSUP;
uint16_t cmd_type;
cmd_type = AVBTP_PACKET_AEM_GET_COMMAND_TYPE(p);
pw_log_info("aem command %d", cmd_type);
switch (cmd_type) {
case AVBTP_AECP_AEM_CMD_ACQUIRE_ENTITY:
break;
case AVBTP_AECP_AEM_CMD_LOCK_ENTITY:
break;
case AVBTP_AECP_AEM_CMD_READ_DESCRIPTOR:
res = handle_aem_command_read_descriptor(aecp, src, p, len);
break;
case AVBTP_AECP_AEM_CMD_REGISTER_UNSOLICITED_NOTIFICATION:
res = reply_success(aecp, src, h, len);
break;
default:
break;
}
if (res == -ENOTSUP)
reply_not_implemented(aecp, src, h, len);
return res;
}
static int aecp_message(void *data, uint64_t now, const uint8_t src[6], const void *message, int len)
{ {
struct aecp *aecp = data; struct aecp *aecp = data;
const struct avbtp_packet_aecp_header *p = message; const struct avbtp_packet_aecp_header *p = message;
const struct msg_info *info;
int message_type; int message_type;
if (AVBTP_PACKET_GET_SUBTYPE(&p->hdr) != AVBTP_SUBTYPE_AECP) if (AVBTP_PACKET_GET_SUBTYPE(&p->hdr) != AVBTP_SUBTYPE_AECP)
return 0; return 0;
message_type = AVBTP_PACKET_AECP_GET_MESSAGE_TYPE(p); message_type = AVBTP_PACKET_AECP_GET_MESSAGE_TYPE(p);
pw_log_info("got AECP message %02x from %02x:%02x:%02x:%02x:%02x:%02x",
message_type, src[0], src[1], src[2], src[3], src[4], src[5]);
switch (message_type) { info = find_msg_info(message_type, NULL);
case AVBTP_AECP_MESSAGE_TYPE_AEM_COMMAND: if (info == NULL)
handle_aem_command(aecp, src, p, len); return reply_not_implemented(aecp, p, len);
break;
case AVBTP_AECP_MESSAGE_TYPE_AEM_RESPONSE: pw_log_info("got AECP message %s", info->name);
break;
case AVBTP_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_COMMAND: if (info->handle == NULL)
break; return reply_not_implemented(aecp, p, len);
case AVBTP_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_RESPONSE:
break; return info->handle(aecp, p, len);
case AVBTP_AECP_MESSAGE_TYPE_AVC_COMMAND:
break;
case AVBTP_AECP_MESSAGE_TYPE_AVC_RESPONSE:
break;
case AVBTP_AECP_MESSAGE_TYPE_VENDOR_UNIQUE_COMMAND:
break;
case AVBTP_AECP_MESSAGE_TYPE_VENDOR_UNIQUE_RESPONSE:
break;
case AVBTP_AECP_MESSAGE_TYPE_EXTENDED_COMMAND:
break;
case AVBTP_AECP_MESSAGE_TYPE_EXTENDED_RESPONSE:
break;
}
return 0;
} }
static void aecp_destroy(void *data) static void aecp_destroy(void *data)

View file

@ -28,7 +28,6 @@
#include "packets.h" #include "packets.h"
#include "internal.h" #include "internal.h"
#define AVBTP_AECP_MESSAGE_TYPE_AEM_COMMAND 0 #define AVBTP_AECP_MESSAGE_TYPE_AEM_COMMAND 0
#define AVBTP_AECP_MESSAGE_TYPE_AEM_RESPONSE 1 #define AVBTP_AECP_MESSAGE_TYPE_AEM_RESPONSE 1
#define AVBTP_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_COMMAND 2 #define AVBTP_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_COMMAND 2
@ -40,19 +39,8 @@
#define AVBTP_AECP_MESSAGE_TYPE_EXTENDED_COMMAND 14 #define AVBTP_AECP_MESSAGE_TYPE_EXTENDED_COMMAND 14
#define AVBTP_AECP_MESSAGE_TYPE_EXTENDED_RESPONSE 15 #define AVBTP_AECP_MESSAGE_TYPE_EXTENDED_RESPONSE 15
#define AVBTP_AECP_AEM_STATUS_SUCCESS 0 #define AVBTP_AECP_STATUS_SUCCESS 0
#define AVBTP_AECP_AEM_STATUS_NOT_IMPLEMENTED 1 #define AVBTP_AECP_STATUS_NOT_IMPLEMENTED 1
#define AVBTP_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR 2
#define AVBTP_AECP_AEM_STATUS_ENTITY_LOCKED 3
#define AVBTP_AECP_AEM_STATUS_ENTITY_ACQUIRED 4
#define AVBTP_AECP_AEM_STATUS_NOT_AUTHENTICATED 5
#define AVBTP_AECP_AEM_STATUS_AUTHENTICATION_DISABLED 6
#define AVBTP_AECP_AEM_STATUS_BAD_ARGUMENTS 7
#define AVBTP_AECP_AEM_STATUS_NO_RESOURCES 8
#define AVBTP_AECP_AEM_STATUS_IN_PROGRESS 9
#define AVBTP_AECP_AEM_STATUS_ENTITY_MISBEHAVING 10
#define AVBTP_AECP_AEM_STATUS_NOT_SUPPORTED 11
#define AVBTP_AECP_AEM_STATUS_STREAM_IS_RUNNING 12
struct avbtp_packet_aecp_header { struct avbtp_packet_aecp_header {
struct avbtp_packet_header hdr; struct avbtp_packet_header hdr;
@ -73,196 +61,6 @@ struct avbtp_packet_aecp_header {
#define AVBTP_PACKET_AECP_GET_CONTROLLER_GUID(p,v) be64toh((p)->controller_guid) #define AVBTP_PACKET_AECP_GET_CONTROLLER_GUID(p,v) be64toh((p)->controller_guid)
#define AVBTP_PACKET_AECP_GET_SEQUENCE_ID(p,v) ntohs((p)->sequence_id) #define AVBTP_PACKET_AECP_GET_SEQUENCE_ID(p,v) ntohs((p)->sequence_id)
#define AVBTP_AECP_AEM_CMD_ACQUIRE_ENTITY 0
#define AVBTP_AECP_AEM_CMD_LOCK_ENTITY 1
#define AVBTP_AECP_AEM_CMD_ENTITY_AVAILABLE 2
#define AVBTP_AECP_AEM_CMD_CONTROLLER_AVAILABLE 3
#define AVBTP_AECP_AEM_CMD_READ_DESCRIPTOR 4
#define AVBTP_AECP_AEM_CMD_WRITE_DESCRIPTOR 5
#define AVBTP_AECP_AEM_CMD_SET_CONFIGURATION 6
#define AVBTP_AECP_AEM_CMD_GET_CONFIGURATION 7
#define AVBTP_AECP_AEM_CMD_SET_STREAM_FORMAT 8
#define AVBTP_AECP_AEM_CMD_GET_STREAM_FORMAT 9
#define AVBTP_AECP_AEM_CMD_SET_VIDEO_FORMAT 10
#define AVBTP_AECP_AEM_CMD_GET_VIDEO_FORMAT 11
#define AVBTP_AECP_AEM_CMD_SET_SENSOR_FORMAT 12
#define AVBTP_AECP_AEM_CMD_GET_SENSOR_FORMAT 13
#define AVBTP_AECP_AEM_CMD_SET_STREAM_INFO 14
#define AVBTP_AECP_AEM_CMD_GET_STREAM_INFO 15
#define AVBTP_AECP_AEM_CMD_SET_NAME 16
#define AVBTP_AECP_AEM_CMD_GET_NAME 17
#define AVBTP_AECP_AEM_CMD_SET_ASSOCIATION_ID 18
#define AVBTP_AECP_AEM_CMD_GET_ASSOCIATION_ID 19
#define AVBTP_AECP_AEM_CMD_SET_SAMPLING_RATE 20
#define AVBTP_AECP_AEM_CMD_GET_SAMPLING_RATE 21
#define AVBTP_AECP_AEM_CMD_SET_CLOCK_SOURCE 22
#define AVBTP_AECP_AEM_CMD_GET_CLOCK_SOURCE 23
#define AVBTP_AECP_AEM_CMD_SET_CONTROL 24
#define AVBTP_AECP_AEM_CMD_GET_CONTROL 25
#define AVBTP_AECP_AEM_CMD_INCREMENT_CONTROL 26
#define AVBTP_AECP_AEM_CMD_DECREMENT_CONTROL 27
#define AVBTP_AECP_AEM_CMD_SET_SIGNAL_SELECTOR 28
#define AVBTP_AECP_AEM_CMD_GET_SIGNAL_SELECTOR 29
#define AVBTP_AECP_AEM_CMD_SET_MIXER 30
#define AVBTP_AECP_AEM_CMD_GET_MIXER 31
#define AVBTP_AECP_AEM_CMD_SET_MATRIX 32
#define AVBTP_AECP_AEM_CMD_GET_MATRIX 33
#define AVBTP_AECP_AEM_CMD_START_STREAMING 34
#define AVBTP_AECP_AEM_CMD_STOP_STREAMING 35
#define AVBTP_AECP_AEM_CMD_REGISTER_UNSOLICITED_NOTIFICATION 36
#define AVBTP_AECP_AEM_CMD_DEREGISTER_UNSOLICITED_NOTIFICATION 37
#define AVBTP_AECP_AEM_CMD_IDENTIFY_NOTIFICATION 38
#define AVBTP_AECP_AEM_CMD_GET_AVB_INFO 39
#define AVBTP_AECP_AEM_CMD_GET_AS_PATH 40
#define AVBTP_AECP_AEM_CMD_GET_COUNTERS 41
#define AVBTP_AECP_AEM_CMD_REBOOT 42
#define AVBTP_AECP_AEM_CMD_GET_AUDIO_MAP 43
#define AVBTP_AECP_AEM_CMD_ADD_AUDIO_MAPPINGS 44
#define AVBTP_AECP_AEM_CMD_REMOVE_AUDIO_MAPPINGS 45
#define AVBTP_AECP_AEM_CMD_GET_VIDEO_MAP 46
#define AVBTP_AECP_AEM_CMD_ADD_VIDEO_MAPPINGS 47
#define AVBTP_AECP_AEM_CMD_REMOVE_VIDEO_MAPPINGS 48
#define AVBTP_AECP_AEM_CMD_GET_SENSOR_MAP 49
#define AVBTP_AECP_AEM_CMD_ADD_SENSOR_MAPPINGS 50
#define AVBTP_AECP_AEM_CMD_REMOVE_SENSOR_MAPPINGS 51
#define AVBTP_AECP_AEM_CMD_START_OPERATION 52
#define AVBTP_AECP_AEM_CMD_ABORT_OPERATION 53
#define AVBTP_AECP_AEM_CMD_OPERATION_STATUS 54
#define AVBTP_AECP_AEM_CMD_AUTH_ADD_KEY 55
#define AVBTP_AECP_AEM_CMD_AUTH_DELETE_KEY 56
#define AVBTP_AECP_AEM_CMD_AUTH_GET_KEY_COUNT 57
#define AVBTP_AECP_AEM_CMD_AUTH_GET_KEY 58
#define AVBTP_AECP_AEM_CMD_AUTHENTICATE 59
#define AVBTP_AECP_AEM_CMD_DEAUTHENTICATE 60
struct avbtp_packet_aecp_aem_acquire {
uint32_t flags;
uint64_t owner_guid;
uint16_t descriptor_type;
uint16_t descriptor_id;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_lock {
uint32_t flags;
uint64_t locked_guid;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_read_descriptor_c {
uint16_t configuration;
uint8_t reserved[2];
uint16_t descriptor_type;
uint16_t descriptor_id;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_read_descriptor_r {
uint16_t configuration;
uint8_t reserved[2];
uint8_t descriptor[512];
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_setget_stream_format {
uint16_t descriptor_type;
uint16_t descriptor_id;
uint64_t stream_format;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_setget_sampling_rate {
uint16_t descriptor_type;
uint16_t descriptor_id;
uint32_t sampling_rate;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_setget_clock_source {
uint16_t descriptor_type;
uint16_t descriptor_id;
uint16_t clock_source_index;
uint16_t reserved;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_setget_control {
uint16_t descriptor_type;
uint16_t descriptor_id;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_startstop_streaming {
uint16_t descriptor_type;
uint16_t descriptor_id;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_identify_notification {
uint16_t descriptor_type;
uint16_t descriptor_id;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_get_avb_info_c {
uint16_t descriptor_type;
uint16_t descriptor_id;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_get_avb_info_r {
uint16_t descriptor_type;
uint16_t descriptor_id;
uint64_t as_grandmaster_id;
uint32_t propagation_delay;
uint16_t reserved;
uint16_t msrp_mappings_count;
uint32_t msrp_mappings;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_get_counters {
uint16_t descriptor_type;
uint16_t descriptor_id;
uint32_t counters_valid;
uint8_t counters_block[128];
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_start_operation {
uint16_t descriptor_type;
uint16_t descriptor_id;
uint16_t operation_id;
uint16_t operation_type;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem_operation_status {
uint16_t descriptor_type;
uint16_t descriptor_id;
uint16_t operation_id;
uint16_t percent_complete;
} __attribute__ ((__packed__));
struct avbtp_packet_aecp_aem {
struct avbtp_packet_aecp_header aecp;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned u:1;
unsigned cmd1:7;
#elif __BYTE_ORDER == __LITTLE_ENDIAN
unsigned cmd1:7;
unsigned u:1;
#endif
uint8_t cmd2;
union {
struct avbtp_packet_aecp_aem_acquire acquire_entity;
struct avbtp_packet_aecp_aem_lock lock_entity;
struct avbtp_packet_aecp_aem_read_descriptor_c read_descriptor_cmd;
struct avbtp_packet_aecp_aem_read_descriptor_r read_descriptor_rsp;
struct avbtp_packet_aecp_aem_setget_stream_format stream_format;
struct avbtp_packet_aecp_aem_setget_sampling_rate sampling_rate;
struct avbtp_packet_aecp_aem_setget_clock_source clock_source;
struct avbtp_packet_aecp_aem_setget_control control;
struct avbtp_packet_aecp_aem_startstop_streaming streaming;
struct avbtp_packet_aecp_aem_get_avb_info_c avb_info_cmd;
struct avbtp_packet_aecp_aem_get_avb_info_r avb_info_rsp;
struct avbtp_packet_aecp_aem_get_counters counters;
struct avbtp_packet_aecp_aem_start_operation start_operation;
struct avbtp_packet_aecp_aem_operation_status operation_status;
};
} __attribute__ ((__packed__));
#define AVBTP_PACKET_AEM_SET_COMMAND_TYPE(p,v) ((p)->cmd1 = ((v) >> 8),(p)->cmd2 = (v))
#define AVBTP_PACKET_AEM_GET_COMMAND_TYPE(p) ((p)->cmd1 << 8 | (p)->cmd2)
struct avbtp_aecp *avbtp_aecp_register(struct server *server); struct avbtp_aecp *avbtp_aecp_register(struct server *server);
#endif /* AVBTP_AECP_H */ #endif /* AVBTP_AECP_H */

View file

@ -42,12 +42,15 @@
#include "adp.h" #include "adp.h"
#include "aecp.h" #include "aecp.h"
#include "maap.h" #include "maap.h"
#include "descriptors.h"
#define DEFAULT_INTERVAL 1 #define DEFAULT_INTERVAL 1
static const uint8_t AVB_MAC_BROADCAST[6] = { 0x91, 0xe0, 0xf0, 0x01, 0x00, 0x00 };
#define server_emit(s,m,v,...) spa_hook_list_call(&s->listener_list, struct server_events, m, v, ##__VA_ARGS__) #define server_emit(s,m,v,...) spa_hook_list_call(&s->listener_list, struct server_events, m, v, ##__VA_ARGS__)
#define server_emit_destroy(s) server_emit(s, destroy, 0) #define server_emit_destroy(s) server_emit(s, destroy, 0)
#define server_emit_message(s,n,mc,m,l) server_emit(s, message, 0, n, mc, m, l) #define server_emit_message(s,n,m,l) server_emit(s, message, 0, n, m, l)
#define server_emit_periodic(s,n) server_emit(s, periodic, 0, n) #define server_emit_periodic(s,n) server_emit(s, periodic, 0, n)
#define server_emit_command(s,n,c,a) server_emit(s, command, 0, n, c, a) #define server_emit_command(s,n,c,a) server_emit(s, command, 0, n, c, a)
@ -65,17 +68,10 @@ static void on_socket_data(void *data, int fd, uint32_t mask)
struct timespec now; struct timespec now;
if (mask & SPA_IO_IN) { if (mask & SPA_IO_IN) {
int len, count; int len;
struct sockaddr_ll sll;
uint8_t buffer[2048]; uint8_t buffer[2048];
socklen_t sl;
sl = sizeof(sll); len = recv(fd, buffer, sizeof(buffer), 0);
len = recvfrom(fd, buffer, sizeof(buffer), 0,
(struct sockaddr *)&sll, &sl);
if (sll.sll_protocol != htons(ETH_P_TSN))
return;
if (len < 0) { if (len < 0) {
pw_log_warn("got recv error: %m"); pw_log_warn("got recv error: %m");
@ -84,27 +80,30 @@ static void on_socket_data(void *data, int fd, uint32_t mask)
pw_log_warn("short packet received (%d < %d)", len, pw_log_warn("short packet received (%d < %d)", len,
(int)sizeof(struct avbtp_packet_header)); (int)sizeof(struct avbtp_packet_header));
} else { } else {
struct avbtp_ethernet_header *hdr = (struct avbtp_ethernet_header*)buffer;
if (htons(hdr->type) != ETH_P_TSN)
return;
if (memcmp(hdr->dest, AVB_MAC_BROADCAST, ETH_ALEN) != 0 &&
memcmp(hdr->dest, server->mac_addr, ETH_ALEN) != 0)
return;
clock_gettime(CLOCK_REALTIME, &now); clock_gettime(CLOCK_REALTIME, &now);
server_emit_message(server, SPA_TIMESPEC_TO_NSEC(&now), server_emit_message(server, SPA_TIMESPEC_TO_NSEC(&now), buffer, len);
sll.sll_addr, buffer, len);
} }
} }
} }
int avbtp_server_send_packet(struct server *server, const uint8_t dest[6], void *data, size_t size) int avbtp_server_send_packet(struct server *server, const uint8_t dest[6], void *data, size_t size)
{ {
struct sockaddr_ll sll; struct avbtp_ethernet_header *hdr = (struct avbtp_ethernet_header*)data;
int res = 0; int res = 0;
spa_zero(sll); memcpy(hdr->dest, dest, ETH_ALEN);
sll.sll_family = AF_PACKET; memcpy(hdr->src, server->mac_addr, ETH_ALEN);
sll.sll_protocol = htons(ETH_P_TSN); hdr->type = htons(ETH_P_TSN);
sll.sll_ifindex = server->ifindex;
sll.sll_halen = ETH_ALEN;
memcpy(sll.sll_addr, dest, ETH_ALEN);
if ((res = sendto(server->source->fd, data, size, 0, if (send(server->source->fd, data, size, 0) < 0) {
(struct sockaddr *)&sll, sizeof(sll))) < 0) {
res = -errno; res = -errno;
pw_log_warn("got send error: %m"); pw_log_warn("got send error: %m");
} }
@ -113,8 +112,7 @@ int avbtp_server_send_packet(struct server *server, const uint8_t dest[6], void
int avbtp_server_broadcast_packet(struct server *server, void *data, size_t size) int avbtp_server_broadcast_packet(struct server *server, void *data, size_t size)
{ {
static const uint8_t dest[6] = { 0x91, 0xe0, 0xf0, 0x01, 0x00, 0x00 }; return avbtp_server_send_packet(server, AVB_MAC_BROADCAST, data, size);
return avbtp_server_send_packet(server, dest, data, size);
} }
static int setup_socket(struct server *server) static int setup_socket(struct server *server)
@ -126,7 +124,7 @@ static int setup_socket(struct server *server)
struct sockaddr_ll sll; struct sockaddr_ll sll;
struct timespec value, interval; struct timespec value, interval;
fd = socket(AF_PACKET, SOCK_DGRAM|SOCK_NONBLOCK, htons(ETH_P_ALL)); fd = socket(AF_PACKET, SOCK_RAW|SOCK_NONBLOCK, htons(ETH_P_ALL));
if (fd < 0) { if (fd < 0) {
pw_log_error("socket() failed: %m"); pw_log_error("socket() failed: %m");
return -errno; return -errno;
@ -226,10 +224,13 @@ struct server *avdecc_server_new(struct impl *impl, const char *ifname, struct s
if ((res = setup_socket(server)) < 0) if ((res = setup_socket(server)) < 0)
goto error_free; goto error_free;
init_descriptors(server);
avbtp_adp_register(server); avbtp_adp_register(server);
avbtp_aecp_register(server); avbtp_aecp_register(server);
avbtp_maap_register(server); avbtp_maap_register(server);
clock_gettime(CLOCK_REALTIME, &now); clock_gettime(CLOCK_REALTIME, &now);
server_emit_command(server, SPA_TIMESPEC_TO_NSEC(&now), server_emit_command(server, SPA_TIMESPEC_TO_NSEC(&now),
"/adp/advertise", "/adp/advertise",

View file

@ -0,0 +1,220 @@
/* PipeWire
*
* Copyright © 2022 Wim Taymans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "aecp-aem.h"
#include "aecp-aem-descriptors.h"
#include "internal.h"
static void add_descriptor(struct server *server, uint16_t type, uint16_t index, size_t size, void *ptr)
{
struct descriptor *d;
if ((d = calloc(1, sizeof(struct descriptor) + size)) == NULL)
return;
d->type = type;
d->index = index;
d->size = size;
d->ptr = SPA_PTROFF(d, sizeof(struct descriptor), void);
memcpy(d->ptr, ptr, size);
server->descriptors[server->n_descriptors++] = d;
}
void init_descriptors(struct server *server)
{
add_descriptor(server, AVBTP_AEM_DESC_STRINGS, 0,
sizeof(struct avbtp_aem_desc_strings),
&(struct avbtp_aem_desc_strings)
{
.string_0 = "PipeWire",
.string_1 = "Configuration 1",
.string_2 = "Wim Taymans",
});
add_descriptor(server, AVBTP_AEM_DESC_LOCALE, 0,
sizeof(struct avbtp_aem_desc_locale),
&(struct avbtp_aem_desc_locale)
{
.locale_identifier = "en-EN",
.number_of_strings = htons(1),
.base_strings = htons(0)
});
add_descriptor(server, AVBTP_AEM_DESC_ENTITY, 0,
sizeof(struct avbtp_aem_desc_entity),
&(struct avbtp_aem_desc_entity)
{
.entity_id = htobe64(server->entity_id),
.entity_model_id = htobe64(0),
.entity_capabilities = htonl(
AVBTP_ADP_ENTITY_CAPABILITY_AEM_SUPPORTED |
AVBTP_ADP_ENTITY_CAPABILITY_CLASS_A_SUPPORTED |
AVBTP_ADP_ENTITY_CAPABILITY_GPTP_SUPPORTED |
AVBTP_ADP_ENTITY_CAPABILITY_AEM_IDENTIFY_CONTROL_INDEX_VALID |
AVBTP_ADP_ENTITY_CAPABILITY_AEM_INTERFACE_INDEX_VALID),
.talker_stream_sources = htons(8),
.talker_capabilities = htons(
AVBTP_ADP_TALKER_CAPABILITY_IMPLEMENTED |
AVBTP_ADP_TALKER_CAPABILITY_AUDIO_SOURCE),
.listener_stream_sinks = htons(8),
.listener_capabilities = htons(
AVBTP_ADP_LISTENER_CAPABILITY_IMPLEMENTED |
AVBTP_ADP_LISTENER_CAPABILITY_AUDIO_SINK),
.controller_capabilities = htons(0),
.available_index = htonl(0),
.association_id = htobe64(0),
.entity_name = "PipeWire",
.vendor_name_string = htons(2),
.model_name_string = htons(0),
.firmware_version = "0.3.48",
.group_name = "",
.serial_number = "",
.configurations_count = htons(1),
.current_configuration = htons(0)
});
struct {
struct avbtp_aem_desc_configuration desc;
struct avbtp_aem_desc_descriptor_count descriptor_counts[8];
} __attribute__ ((__packed__)) config =
{
{
.object_name = "Configuration 1",
.localized_description = htons(1),
.descriptor_counts_count = htons(8),
.descriptor_counts_offset = htons(
sizeof(struct avbtp_packet_aecp_aem) +
sizeof(struct avbtp_packet_aecp_aem_read_descriptor) +
sizeof(struct avbtp_aem_desc_configuration)),
},
.descriptor_counts = {
{ htons(AVBTP_AEM_DESC_AUDIO_UNIT), htons(1) },
{ htons(AVBTP_AEM_DESC_STREAM_INPUT), htons(1) },
{ htons(AVBTP_AEM_DESC_STREAM_OUTPUT), htons(1) },
{ htons(AVBTP_AEM_DESC_AVB_INTERFACE), htons(1) },
{ htons(AVBTP_AEM_DESC_CLOCK_SOURCE), htons(13) },
{ htons(AVBTP_AEM_DESC_CONTROL), htons(2) },
{ htons(AVBTP_AEM_DESC_LOCALE), htons(1) },
{ htons(AVBTP_AEM_DESC_CLOCK_DOMAIN), htons(1) }
}
};
add_descriptor(server, AVBTP_AEM_DESC_CONFIGURATION, 0,
sizeof(config), &config);
struct {
struct avbtp_aem_desc_audio_unit desc;
struct avbtp_aem_desc_sampling_rate sampling_rates[6];
} __attribute__ ((__packed__)) audio_unit =
{
{
.object_name = "PipeWire",
.localized_description = htons(0),
.clock_domain_index = htons(0),
.number_of_stream_input_ports = htons(1),
.base_stream_input_port = htons(0),
.number_of_stream_output_ports = htons(1),
.base_stream_output_port = htons(0),
.number_of_external_input_ports = htons(8),
.base_external_input_port = htons(0),
.number_of_external_output_ports = htons(8),
.base_external_output_port = htons(0),
.number_of_internal_input_ports = htons(0),
.base_internal_input_port = htons(0),
.number_of_internal_output_ports = htons(0),
.base_internal_output_port = htons(0),
.number_of_controls = htons(0),
.base_control = htons(0),
.number_of_signal_selectors = htons(0),
.base_signal_selector = htons(0),
.number_of_mixers = htons(0),
.base_mixer = htons(0),
.number_of_matrices = htons(0),
.base_matrix = htons(0),
.number_of_splitters = htons(0),
.base_splitter = htons(0),
.number_of_combiners = htons(0),
.base_combiner = htons(0),
.number_of_demultiplexers = htons(0),
.base_demultiplexer = htons(0),
.number_of_multiplexers = htons(0),
.base_multiplexer = htons(0),
.number_of_transcoders = htons(0),
.base_transcoder = htons(0),
.number_of_control_blocks = htons(0),
.base_control_block = htons(0),
.current_sampling_rate = htonl(48000),
.sampling_rates_offset = htons(
4 + sizeof(struct avbtp_aem_desc_audio_unit)),
.sampling_rates_count = htons(6),
},
.sampling_rates = {
{ .pull_frequency = htonl(44100) },
{ .pull_frequency = htonl(48000) },
{ .pull_frequency = htonl(88200) },
{ .pull_frequency = htonl(96000) },
{ .pull_frequency = htonl(176400) },
{ .pull_frequency = htonl(192000) },
}
};
add_descriptor(server, AVBTP_AEM_DESC_AUDIO_UNIT, 0,
sizeof(audio_unit), &audio_unit);
struct {
struct avbtp_aem_desc_stream desc;
uint64_t stream_formats[6];
} __attribute__ ((__packed__)) stream_input_0 =
{
{
.object_name = "Stream Input 1",
.localized_description = htons(0xffff),
.clock_domain_index = htons(0),
.stream_flags = htons(
AVBTP_AEM_DESC_STREAM_FLAG_SYNC_SOURCE |
AVBTP_AEM_DESC_STREAM_FLAG_CLASS_A),
.current_format = htobe64(0x00a0020840000800ULL),
.formats_offset = htons(
4 + sizeof(struct avbtp_aem_desc_stream)),
.number_of_formats = htons(6),
.backup_talker_entity_id_0 = htobe64(0),
.backup_talker_unique_id_0 = htons(0),
.backup_talker_entity_id_1 = htobe64(0),
.backup_talker_unique_id_1 = htons(0),
.backup_talker_entity_id_2 = htobe64(0),
.backup_talker_unique_id_2 = htons(0),
.backedup_talker_entity_id = htobe64(0),
.backedup_talker_unique = htons(0),
.avb_interface_index = htons(0),
.buffer_length = htons(8)
},
.stream_formats = {
htobe64(0x00a0010860000800ULL),
htobe64(0x00a0020860000800ULL),
htobe64(0x00a0030860000800ULL),
htobe64(0x00a0040860000800ULL),
htobe64(0x00a0050860000800ULL),
htobe64(0x00a0060860000800ULL),
},
};
add_descriptor(server, AVBTP_AEM_DESC_STREAM_INPUT, 0,
sizeof(stream_input_0), &stream_input_0);
}

View file

@ -49,13 +49,20 @@ struct server_events {
/** the server is destroyed */ /** the server is destroyed */
void (*destroy) (void *data); void (*destroy) (void *data);
int (*message) (void *data, uint64_t now, const uint8_t src[6], const void *message, int len); int (*message) (void *data, uint64_t now, const void *message, int len);
void (*periodic) (void *data, uint64_t now); void (*periodic) (void *data, uint64_t now);
int (*command) (void *data, uint64_t now, const char *command, const char *args); int (*command) (void *data, uint64_t now, const char *command, const char *args);
}; };
struct descriptor {
uint16_t type;
uint16_t index;
uint32_t size;
void *ptr;
};
struct server { struct server {
struct spa_list link; struct spa_list link;
struct impl *impl; struct impl *impl;
@ -70,9 +77,23 @@ struct server {
struct spa_hook_list listener_list; struct spa_hook_list listener_list;
const struct descriptor *descriptors[512];
uint32_t n_descriptors;
unsigned debug_messages:1; unsigned debug_messages:1;
}; };
static inline const struct descriptor *find_descriptor(struct server *server, uint16_t type, uint16_t index)
{
uint32_t i;
for (i = 0; i < server->n_descriptors; i++) {
if (server->descriptors[i]->type == type &&
server->descriptors[i]->index == index)
return server->descriptors[i];
}
return NULL;
}
struct server *avdecc_server_new(struct impl *impl, const char *ifname, struct spa_dict *props); struct server *avdecc_server_new(struct impl *impl, const char *ifname, struct spa_dict *props);
void avdecc_server_free(struct server *server); void avdecc_server_free(struct server *server);
@ -82,6 +103,14 @@ void avdecc_server_add_listener(struct server *server, struct spa_hook *listener
int avbtp_server_broadcast_packet(struct server *server, void *data, size_t size); int avbtp_server_broadcast_packet(struct server *server, void *data, size_t size);
int avbtp_server_send_packet(struct server *server, const uint8_t dest[6], void *data, size_t size); int avbtp_server_send_packet(struct server *server, const uint8_t dest[6], void *data, size_t size);
struct aecp {
struct server *server;
struct spa_hook server_listener;
uint64_t now;
};
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif #endif

View file

@ -52,7 +52,7 @@ static void maap_message_debug(struct maap *maap, const struct avbtp_packet_maap
v = AVBTP_PACKET_MAAP_GET_MESSAGE_TYPE(p); v = AVBTP_PACKET_MAAP_GET_MESSAGE_TYPE(p);
pw_log_info("message-type: %d (%s)", v, message_type_as_string(v)); pw_log_info("message-type: %d (%s)", v, message_type_as_string(v));
pw_log_info(" maap-version: %d", AVBTP_PACKET_MAAP_GET_MAAP_VERSION(p)); pw_log_info(" maap-version: %d", AVBTP_PACKET_MAAP_GET_MAAP_VERSION(p));
pw_log_info(" length: %d", AVBTP_PACKET_MAAP_GET_LENGTH(p)); pw_log_info(" length: %d", AVBTP_PACKET_GET_LENGTH(&p->hdr));
pw_log_info(" stream-id: 0x%"PRIx64, AVBTP_PACKET_MAAP_GET_STREAM_ID(p)); pw_log_info(" stream-id: 0x%"PRIx64, AVBTP_PACKET_MAAP_GET_STREAM_ID(p));
addr = AVBTP_PACKET_MAAP_GET_REQUEST_START(p); addr = AVBTP_PACKET_MAAP_GET_REQUEST_START(p);
@ -65,12 +65,12 @@ static void maap_message_debug(struct maap *maap, const struct avbtp_packet_maap
pw_log_info(" conflict-count: %d", AVBTP_PACKET_MAAP_GET_CONFLICT_COUNT(p)); pw_log_info(" conflict-count: %d", AVBTP_PACKET_MAAP_GET_CONFLICT_COUNT(p));
} }
static int maap_message(void *data, uint64_t now, const uint8_t src[6], const void *message, int len) static int maap_message(void *data, uint64_t now, const void *message, int len)
{ {
struct maap *maap = data; struct maap *maap = data;
const struct avbtp_packet_maap *p = message; const struct avbtp_packet_maap *p = message;
if (AVBTP_PACKET_GET_SUBTYPE(p) != AVBTP_SUBTYPE_MAAP) if (AVBTP_PACKET_GET_SUBTYPE(&p->hdr) != AVBTP_SUBTYPE_MAAP)
return 0; return 0;
if (maap->server->debug_messages) if (maap->server->debug_messages)

View file

@ -33,23 +33,7 @@
#define AVBTP_MAAP_MESSAGE_TYPE_ANNOUNCE 3 #define AVBTP_MAAP_MESSAGE_TYPE_ANNOUNCE 3
struct avbtp_packet_maap { struct avbtp_packet_maap {
uint8_t subtype; struct avbtp_packet_header hdr;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned sv:1;
unsigned version:3;
unsigned message_type:4;
unsigned maap_version:5;
unsigned len1:3;
#elif __BYTE_ORDER == __LITTLE_ENDIAN
unsigned message_type:4;
unsigned version:3;
unsigned sv:1;
unsigned len1:3;
unsigned maap_version:5;
#endif
uint8_t len2:8;
uint64_t stream_id; uint64_t stream_id;
uint8_t request_start[6]; uint8_t request_start[6];
uint16_t request_count; uint16_t request_count;
@ -57,24 +41,15 @@ struct avbtp_packet_maap {
uint16_t conflict_count; uint16_t conflict_count;
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
#define AVBTP_PACKET_MAAP_SET_SUBTYPE(p,v) ((p)->subtype = (v)) #define AVBTP_PACKET_MAAP_SET_MESSAGE_TYPE(p,v) AVBTP_PACKET_SET_SUB1(&(p)->hdr, v)
#define AVBTP_PACKET_MAAP_SET_SV(p,v) ((p)->sv = (v)) #define AVBTP_PACKET_MAAP_SET_MAAP_VERSION(p,v) AVBTP_PACKET_SET_SUB2(&(p)->hdr, v)
#define AVBTP_PACKET_MAAP_SET_VERSION(p,v) ((p)->version = (v))
#define AVBTP_PACKET_MAAP_SET_MESSAGE_TYPE(p,v) ((p)->message_type = (v))
#define AVBTP_PACKET_MAAP_SET_MAAP_VERSION(p,v) ((p)->maap_version = (v))
#define AVBTP_PACKET_MAAP_SET_LENGTH(p,v) ((p)->len1 = ((v) >> 8),(p)->len2 = (v))
#define AVBTP_PACKET_MAAP_SET_STREAM_ID(p,v) ((p)->stream_id = htobe64(v)) #define AVBTP_PACKET_MAAP_SET_STREAM_ID(p,v) ((p)->stream_id = htobe64(v))
#define AVBTP_PACKET_MAAP_SET_REQUEST_START(p,v) memcpy((p)->request_start, (v), 6) #define AVBTP_PACKET_MAAP_SET_REQUEST_START(p,v) memcpy((p)->request_start, (v), 6)
#define AVBTP_PACKET_MAAP_SET_REQUEST_COUNT(p,v) ((p)->request_count = htons(v)) #define AVBTP_PACKET_MAAP_SET_REQUEST_COUNT(p,v) ((p)->request_count = htons(v))
#define AVBTP_PACKET_MAAP_SET_CONFLICT_START(p,v) memcpy((p)->conflict_start, (v), 6) #define AVBTP_PACKET_MAAP_SET_CONFLICT_START(p,v) memcpy((p)->conflict_start, (v), 6)
#define AVBTP_PACKET_MAAP_SET_CONFLICT_COUNT(p,v) ((p)->conflict_count = htons(v)) #define AVBTP_PACKET_MAAP_SET_CONFLICT_COUNT(p,v) ((p)->conflict_count = htons(v))
#define AVBTP_PACKET_MAAP_GET_MESSAGE_TYPE(p) AVBTP_PACKET_GET_SUB1(&(p)->hdr)
#define AVBTP_PACKET_MAAP_GET_SUBTYPE(p) ((p)->subtype) #define AVBTP_PACKET_MAAP_GET_MAAP_VERSION(p) AVBTP_PACKET_GET_SUB2(&(p)->hdr)
#define AVBTP_PACKET_MAAP_GET_SV(p) ((p)->sv)
#define AVBTP_PACKET_MAAP_GET_VERSION(p) ((p)->version)
#define AVBTP_PACKET_MAAP_GET_MESSAGE_TYPE(p) ((p)->message_type)
#define AVBTP_PACKET_MAAP_GET_MAAP_VERSION(p) ((p)->maap_version)
#define AVBTP_PACKET_MAAP_GET_LENGTH(p) (((p)->len1 << 8) | (p)->len2)
#define AVBTP_PACKET_MAAP_GET_STREAM_ID(p) be64toh((p)->stream_id) #define AVBTP_PACKET_MAAP_GET_STREAM_ID(p) be64toh((p)->stream_id)
#define AVBTP_PACKET_MAAP_GET_REQUEST_START(p) ((p)->request_start) #define AVBTP_PACKET_MAAP_GET_REQUEST_START(p) ((p)->request_start)
#define AVBTP_PACKET_MAAP_GET_REQUEST_COUNT(p) ntohs((p)->request_count) #define AVBTP_PACKET_MAAP_GET_REQUEST_COUNT(p) ntohs((p)->request_count)

View file

@ -48,13 +48,14 @@
#define AVBTP_SUBTYPE_MAAP 0xFE #define AVBTP_SUBTYPE_MAAP 0xFE
#define AVBTP_SUBTYPE_EF_CONTROL 0xFF #define AVBTP_SUBTYPE_EF_CONTROL 0xFF
struct avbtp_ehternet_header { struct avbtp_ethernet_header {
uint8_t dest[6]; uint8_t dest[6];
uint8_t src[6]; uint8_t src[6];
uint16_t type; uint16_t type;
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
struct avbtp_packet_header { struct avbtp_packet_header {
struct avbtp_ethernet_header eth;
uint8_t subtype; uint8_t subtype;
#if __BYTE_ORDER == __BIG_ENDIAN #if __BYTE_ORDER == __BIG_ENDIAN
unsigned sv:1; /* stream_id valid */ unsigned sv:1; /* stream_id valid */