From 4613c7822fb24be479ea950ec9d476957e6f227b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 17 Mar 2022 19:13:43 +0100 Subject: [PATCH] avb: implement some descriptors Work on raw ethernet frames. --- src/modules/meson.build | 1 + src/modules/module-avbtp/aaf.h | 1 + src/modules/module-avbtp/adp.c | 2 +- .../module-avbtp/aecp-aem-descriptors.h | 191 ++++++++++ src/modules/module-avbtp/aecp-aem.c | 230 ++++++++++++ src/modules/module-avbtp/aecp-aem.h | 345 ++++++++++++++++-- src/modules/module-avbtp/aecp.c | 184 ++-------- src/modules/module-avbtp/aecp.h | 206 +---------- src/modules/module-avbtp/avdecc.c | 49 +-- src/modules/module-avbtp/descriptors.h | 220 +++++++++++ src/modules/module-avbtp/internal.h | 31 +- src/modules/module-avbtp/maap.c | 6 +- src/modules/module-avbtp/maap.h | 35 +- src/modules/module-avbtp/packets.h | 3 +- 14 files changed, 1052 insertions(+), 452 deletions(-) create mode 100644 src/modules/module-avbtp/aecp-aem-descriptors.h create mode 100644 src/modules/module-avbtp/aecp-aem.c create mode 100644 src/modules/module-avbtp/descriptors.h diff --git a/src/modules/meson.build b/src/modules/meson.build index b92c27679..1f15511b1 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -525,6 +525,7 @@ pipewire_module_avbtp = shared_library('pipewire-module-avbtp', 'module-avbtp/avb.c', 'module-avbtp/adp.c', 'module-avbtp/aecp.c', + 'module-avbtp/aecp-aem.c', 'module-avbtp/avdecc.c', 'module-avbtp/maap.c' ], include_directories : [configinc], diff --git a/src/modules/module-avbtp/aaf.h b/src/modules/module-avbtp/aaf.h index 45cb509df..bb4487028 100644 --- a/src/modules/module-avbtp/aaf.h +++ b/src/modules/module-avbtp/aaf.h @@ -26,6 +26,7 @@ #define AVBTP_AAF_H struct avbtp_packet_aaf { + struct avbtp_ethernet_header hdr; uint8_t subtype; #if __BYTE_ORDER == __BIG_ENDIAN unsigned sv:1; diff --git a/src/modules/module-avbtp/adp.c b/src/modules/module-avbtp/adp.c index f3dbb5c88..b99267cc5 100644 --- a/src/modules/module-avbtp/adp.c +++ b/src/modules/module-avbtp/adp.c @@ -224,7 +224,7 @@ static int send_discover(struct adp *adp, uint64_t entity_id) 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; const struct avbtp_packet_adp *p = message; diff --git a/src/modules/module-avbtp/aecp-aem-descriptors.h b/src/modules/module-avbtp/aecp-aem-descriptors.h new file mode 100644 index 000000000..ad167e211 --- /dev/null +++ b/src/modules/module-avbtp/aecp-aem-descriptors.h @@ -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 */ diff --git a/src/modules/module-avbtp/aecp-aem.c b/src/modules/module-avbtp/aecp-aem.c new file mode 100644 index 000000000..94aee223c --- /dev/null +++ b/src/modules/module-avbtp/aecp-aem.c @@ -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; +} diff --git a/src/modules/module-avbtp/aecp-aem.h b/src/modules/module-avbtp/aecp-aem.h index 455f31590..6b10f4a13 100644 --- a/src/modules/module-avbtp/aecp-aem.h +++ b/src/modules/module-avbtp/aecp-aem.h @@ -25,46 +25,311 @@ #ifndef AVBTP_AEM_H #define AVBTP_AEM_H -#include "packets.h" +#include "aecp.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_SIGNAL_SPLITTER 0x001f -#define AVBTP_AEM_SIGNAL_COMBINER 0x0020 -#define AVBTP_AEM_SIGNAL_DEMULTIPLEXER 0x0021 -#define AVBTP_AEM_SIGNAL_MULTIPLEXER 0x0022 -#define AVBTP_AEM_SIGNAL_TRANSCODER 0x0023 -#define AVBTP_AEM_CLOCK_DOMAIN 0x0024 -#define AVBTP_AEM_CONTROL_BLOCK 0x0025 -#define AVBTP_AEM_INVALID 0xffff +#define AVBTP_AECP_AEM_STATUS_SUCCESS 0 +#define AVBTP_AECP_AEM_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 + +#define AVBTP_AECP_AEM_CMD_ACQUIRE_ENTITY 0x0000 +#define AVBTP_AECP_AEM_CMD_LOCK_ENTITY 0x0001 +#define AVBTP_AECP_AEM_CMD_ENTITY_AVAILABLE 0x0002 +#define AVBTP_AECP_AEM_CMD_CONTROLLER_AVAILABLE 0x0003 +#define AVBTP_AECP_AEM_CMD_READ_DESCRIPTOR 0x0004 +#define AVBTP_AECP_AEM_CMD_WRITE_DESCRIPTOR 0x0005 +#define AVBTP_AECP_AEM_CMD_SET_CONFIGURATION 0x0006 +#define AVBTP_AECP_AEM_CMD_GET_CONFIGURATION 0x0007 +#define AVBTP_AECP_AEM_CMD_SET_STREAM_FORMAT 0x0008 +#define AVBTP_AECP_AEM_CMD_GET_STREAM_FORMAT 0x0009 +#define AVBTP_AECP_AEM_CMD_SET_VIDEO_FORMAT 0x000a +#define AVBTP_AECP_AEM_CMD_GET_VIDEO_FORMAT 0x000b +#define AVBTP_AECP_AEM_CMD_SET_SENSOR_FORMAT 0x000c +#define AVBTP_AECP_AEM_CMD_GET_SENSOR_FORMAT 0x000d +#define AVBTP_AECP_AEM_CMD_SET_STREAM_INFO 0x000e +#define AVBTP_AECP_AEM_CMD_GET_STREAM_INFO 0x000f +#define AVBTP_AECP_AEM_CMD_SET_NAME 0x0010 +#define AVBTP_AECP_AEM_CMD_GET_NAME 0x0011 +#define AVBTP_AECP_AEM_CMD_SET_ASSOCIATION_ID 0x0012 +#define AVBTP_AECP_AEM_CMD_GET_ASSOCIATION_ID 0x0013 +#define AVBTP_AECP_AEM_CMD_SET_SAMPLING_RATE 0x0014 +#define AVBTP_AECP_AEM_CMD_GET_SAMPLING_RATE 0x0015 +#define AVBTP_AECP_AEM_CMD_SET_CLOCK_SOURCE 0x0016 +#define AVBTP_AECP_AEM_CMD_GET_CLOCK_SOURCE 0x0017 +#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 */ diff --git a/src/modules/module-avbtp/aecp.c b/src/modules/module-avbtp/aecp.c index fc0eaa18f..7a4e56309 100644 --- a/src/modules/module-avbtp/aecp.c +++ b/src/modules/module-avbtp/aecp.c @@ -31,183 +31,71 @@ #include "aecp-aem.h" #include "internal.h" -struct aecp { - struct server *server; - struct spa_hook server_listener; - - uint64_t now; +struct msg_info { + uint16_t type; + const char *name; + const char *description; + 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_status(struct aecp *aecp, const uint8_t dest[6], int status, - const void *p, int len) +static int reply_not_implemented(struct aecp *aecp, const void *p, 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, p, len); - AVBTP_PACKET_AECP_SET_MESSAGE_TYPE(reply, AVBTP_AECP_MESSAGE_TYPE_AEM_RESPONSE); - AVBTP_PACKET_AECP_SET_STATUS(reply, status); + AVBTP_PACKET_AECP_SET_STATUS(reply, AVBTP_AECP_STATUS_NOT_IMPLEMENTED); - 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], - const void *p, int len) -{ - return reply_status(aecp, dest, AVBTP_AECP_AEM_STATUS_NOT_IMPLEMENTED, p, len); -} - -static int reply_success(struct aecp *aecp, const uint8_t dest[6], - const void *p, int len) -{ - return reply_status(aecp, dest, AVBTP_AECP_AEM_STATUS_SUCCESS, p, len); -} - -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); +static const struct msg_info msg_info[] = { + { 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, }, + { 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, }, + { AVBTP_AECP_MESSAGE_TYPE_AVC_RESPONSE, "avc-response", "AVC Response", NULL, }, + { 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, }, + { AVBTP_AECP_MESSAGE_TYPE_EXTENDED_COMMAND, "extended-command", "Extended Command", NULL, }, + { AVBTP_AECP_MESSAGE_TYPE_EXTENDED_RESPONSE, "extended-response", "Extended Response", NULL, }, }; -const struct desc_info desc_info[] = { - { 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) +static inline const struct msg_info *find_msg_info(uint16_t type, const char *name) { uint32_t i; - for (i = 0; i < SPA_N_ELEMENTS(desc_info); i++) { - if ((name == NULL && type == desc_info[i].type) || - (name != NULL && spa_streq(name, desc_info[i].name))) - return &desc_info[i]; + for (i = 0; i < SPA_N_ELEMENTS(msg_info); i++) { + if ((name == NULL && type == msg_info[i].type) || + (name != NULL && spa_streq(name, msg_info[i].name))) + return &msg_info[i]; } return NULL; } -static int handle_aem_command_read_descriptor(struct aecp *aecp, const uint8_t src[6], - 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) +static int aecp_message(void *data, uint64_t now, const void *message, int len) { struct aecp *aecp = data; const struct avbtp_packet_aecp_header *p = message; + const struct msg_info *info; int message_type; if (AVBTP_PACKET_GET_SUBTYPE(&p->hdr) != AVBTP_SUBTYPE_AECP) return 0; 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) { - case AVBTP_AECP_MESSAGE_TYPE_AEM_COMMAND: - handle_aem_command(aecp, src, p, len); - break; - case AVBTP_AECP_MESSAGE_TYPE_AEM_RESPONSE: - break; - case AVBTP_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_COMMAND: - break; - case AVBTP_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_RESPONSE: - break; - 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; + info = find_msg_info(message_type, NULL); + if (info == NULL) + return reply_not_implemented(aecp, p, len); + + pw_log_info("got AECP message %s", info->name); + + if (info->handle == NULL) + return reply_not_implemented(aecp, p, len); + + return info->handle(aecp, p, len); } static void aecp_destroy(void *data) diff --git a/src/modules/module-avbtp/aecp.h b/src/modules/module-avbtp/aecp.h index 57af5069d..0fca3e33a 100644 --- a/src/modules/module-avbtp/aecp.h +++ b/src/modules/module-avbtp/aecp.h @@ -28,7 +28,6 @@ #include "packets.h" #include "internal.h" - #define AVBTP_AECP_MESSAGE_TYPE_AEM_COMMAND 0 #define AVBTP_AECP_MESSAGE_TYPE_AEM_RESPONSE 1 #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_RESPONSE 15 -#define AVBTP_AECP_AEM_STATUS_SUCCESS 0 -#define AVBTP_AECP_AEM_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 +#define AVBTP_AECP_STATUS_SUCCESS 0 +#define AVBTP_AECP_STATUS_NOT_IMPLEMENTED 1 struct avbtp_packet_aecp_header { 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_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); #endif /* AVBTP_AECP_H */ diff --git a/src/modules/module-avbtp/avdecc.c b/src/modules/module-avbtp/avdecc.c index 0167a5de3..1377cad6c 100644 --- a/src/modules/module-avbtp/avdecc.c +++ b/src/modules/module-avbtp/avdecc.c @@ -42,12 +42,15 @@ #include "adp.h" #include "aecp.h" #include "maap.h" +#include "descriptors.h" #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_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_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; if (mask & SPA_IO_IN) { - int len, count; - struct sockaddr_ll sll; + int len; uint8_t buffer[2048]; - socklen_t sl; - sl = sizeof(sll); - len = recvfrom(fd, buffer, sizeof(buffer), 0, - (struct sockaddr *)&sll, &sl); - - if (sll.sll_protocol != htons(ETH_P_TSN)) - return; + len = recv(fd, buffer, sizeof(buffer), 0); if (len < 0) { 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, (int)sizeof(struct avbtp_packet_header)); } 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); - server_emit_message(server, SPA_TIMESPEC_TO_NSEC(&now), - sll.sll_addr, buffer, len); + server_emit_message(server, SPA_TIMESPEC_TO_NSEC(&now), buffer, len); } } } 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; - spa_zero(sll); - sll.sll_family = AF_PACKET; - sll.sll_protocol = htons(ETH_P_TSN); - sll.sll_ifindex = server->ifindex; - sll.sll_halen = ETH_ALEN; - memcpy(sll.sll_addr, dest, ETH_ALEN); + memcpy(hdr->dest, dest, ETH_ALEN); + memcpy(hdr->src, server->mac_addr, ETH_ALEN); + hdr->type = htons(ETH_P_TSN); - if ((res = sendto(server->source->fd, data, size, 0, - (struct sockaddr *)&sll, sizeof(sll))) < 0) { + if (send(server->source->fd, data, size, 0) < 0) { res = -errno; 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) { - static const uint8_t dest[6] = { 0x91, 0xe0, 0xf0, 0x01, 0x00, 0x00 }; - return avbtp_server_send_packet(server, dest, data, size); + return avbtp_server_send_packet(server, AVB_MAC_BROADCAST, data, size); } static int setup_socket(struct server *server) @@ -126,7 +124,7 @@ static int setup_socket(struct server *server) struct sockaddr_ll sll; 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) { pw_log_error("socket() failed: %m"); 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) goto error_free; + init_descriptors(server); + avbtp_adp_register(server); avbtp_aecp_register(server); avbtp_maap_register(server); + clock_gettime(CLOCK_REALTIME, &now); server_emit_command(server, SPA_TIMESPEC_TO_NSEC(&now), "/adp/advertise", diff --git a/src/modules/module-avbtp/descriptors.h b/src/modules/module-avbtp/descriptors.h new file mode 100644 index 000000000..793e25b4b --- /dev/null +++ b/src/modules/module-avbtp/descriptors.h @@ -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); + +} diff --git a/src/modules/module-avbtp/internal.h b/src/modules/module-avbtp/internal.h index 2a0d4d942..2b004b3db 100644 --- a/src/modules/module-avbtp/internal.h +++ b/src/modules/module-avbtp/internal.h @@ -49,13 +49,20 @@ struct server_events { /** the server is destroyed */ 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); 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 spa_list link; struct impl *impl; @@ -70,9 +77,23 @@ struct server { struct spa_hook_list listener_list; + const struct descriptor *descriptors[512]; + uint32_t n_descriptors; + 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); 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_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 } /* extern "C" */ #endif diff --git a/src/modules/module-avbtp/maap.c b/src/modules/module-avbtp/maap.c index 2203eb79b..c17edb19f 100644 --- a/src/modules/module-avbtp/maap.c +++ b/src/modules/module-avbtp/maap.c @@ -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); 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(" 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)); 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)); } -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; 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; if (maap->server->debug_messages) diff --git a/src/modules/module-avbtp/maap.h b/src/modules/module-avbtp/maap.h index af0b9cff2..ca0ca77d5 100644 --- a/src/modules/module-avbtp/maap.h +++ b/src/modules/module-avbtp/maap.h @@ -33,23 +33,7 @@ #define AVBTP_MAAP_MESSAGE_TYPE_ANNOUNCE 3 struct avbtp_packet_maap { - uint8_t subtype; -#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; + struct avbtp_packet_header hdr; uint64_t stream_id; uint8_t request_start[6]; uint16_t request_count; @@ -57,24 +41,15 @@ struct avbtp_packet_maap { uint16_t conflict_count; } __attribute__ ((__packed__)); -#define AVBTP_PACKET_MAAP_SET_SUBTYPE(p,v) ((p)->subtype = (v)) -#define AVBTP_PACKET_MAAP_SET_SV(p,v) ((p)->sv = (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_MESSAGE_TYPE(p,v) AVBTP_PACKET_SET_SUB1(&(p)->hdr, v) +#define AVBTP_PACKET_MAAP_SET_MAAP_VERSION(p,v) AVBTP_PACKET_SET_SUB2(&(p)->hdr, 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_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_COUNT(p,v) ((p)->conflict_count = htons(v)) - -#define AVBTP_PACKET_MAAP_GET_SUBTYPE(p) ((p)->subtype) -#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_MESSAGE_TYPE(p) AVBTP_PACKET_GET_SUB1(&(p)->hdr) +#define AVBTP_PACKET_MAAP_GET_MAAP_VERSION(p) AVBTP_PACKET_GET_SUB2(&(p)->hdr) #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_COUNT(p) ntohs((p)->request_count) diff --git a/src/modules/module-avbtp/packets.h b/src/modules/module-avbtp/packets.h index c2721b1ab..9e5e53659 100644 --- a/src/modules/module-avbtp/packets.h +++ b/src/modules/module-avbtp/packets.h @@ -48,13 +48,14 @@ #define AVBTP_SUBTYPE_MAAP 0xFE #define AVBTP_SUBTYPE_EF_CONTROL 0xFF -struct avbtp_ehternet_header { +struct avbtp_ethernet_header { uint8_t dest[6]; uint8_t src[6]; uint16_t type; } __attribute__ ((__packed__)); struct avbtp_packet_header { + struct avbtp_ethernet_header eth; uint8_t subtype; #if __BYTE_ORDER == __BIG_ENDIAN unsigned sv:1; /* stream_id valid */