mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-01 22:58:50 -04:00
avb: implement some descriptors
Work on raw ethernet frames.
This commit is contained in:
parent
da14e9f59d
commit
4613c7822f
14 changed files with 1052 additions and 452 deletions
|
|
@ -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],
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
191
src/modules/module-avbtp/aecp-aem-descriptors.h
Normal file
191
src/modules/module-avbtp/aecp-aem-descriptors.h
Normal 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 */
|
||||
230
src/modules/module-avbtp/aecp-aem.c
Normal file
230
src/modules/module-avbtp/aecp-aem.c
Normal 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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
220
src/modules/module-avbtp/descriptors.h
Normal file
220
src/modules/module-avbtp/descriptors.h
Normal 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);
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue