mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05: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