mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	avb: implement some more AEM
This commit is contained in:
		
							parent
							
								
									287e8cfe51
								
							
						
					
					
						commit
						da14e9f59d
					
				
					 4 changed files with 199 additions and 14 deletions
				
			
		
							
								
								
									
										70
									
								
								src/modules/module-avbtp/aecp-aem.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/modules/module-avbtp/aecp-aem.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,70 @@
 | 
			
		|||
/* 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_AEM_H
 | 
			
		||||
#define AVBTP_AEM_H
 | 
			
		||||
 | 
			
		||||
#include "packets.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
 | 
			
		||||
 | 
			
		||||
#endif /* AVBTP_AEM_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -28,6 +28,7 @@
 | 
			
		|||
#include <pipewire/pipewire.h>
 | 
			
		||||
 | 
			
		||||
#include "aecp.h"
 | 
			
		||||
#include "aecp-aem.h"
 | 
			
		||||
#include "internal.h"
 | 
			
		||||
 | 
			
		||||
struct aecp {
 | 
			
		||||
| 
						 | 
				
			
			@ -41,21 +42,135 @@ static void aecp_message_debug(struct aecp *aecp, const struct avbtp_packet_aecp
 | 
			
		|||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int reply_not_implemented(struct aecp *aecp, const uint8_t dest[6],
 | 
			
		||||
		const struct avbtp_packet_aecp_header *p, int len)
 | 
			
		||||
static int reply_status(struct aecp *aecp, const uint8_t dest[6], int status,
 | 
			
		||||
		const void *p, int len)
 | 
			
		||||
{
 | 
			
		||||
	struct server *server = aecp->server;
 | 
			
		||||
	uint8_t buf[len];
 | 
			
		||||
	struct avbtp_packet_aecp_header *reply = (struct avbtp_packet_aecp_header*)buf;
 | 
			
		||||
 | 
			
		||||
	pw_log_info("reply");
 | 
			
		||||
	memcpy(reply, p, len);
 | 
			
		||||
	AVBTP_PACKET_AECP_SET_MESSAGE_TYPE(reply, AVBTP_AECP_MESSAGE_TYPE_AEM_RESPONSE);
 | 
			
		||||
	AVBTP_PACKET_AECP_SET_STATUS(reply, AVBTP_AECP_AEM_STATUS_NOT_IMPLEMENTED);
 | 
			
		||||
	AVBTP_PACKET_AECP_SET_STATUS(reply, status);
 | 
			
		||||
 | 
			
		||||
	return avbtp_server_send_packet(server, dest, 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);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
	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];
 | 
			
		||||
	}
 | 
			
		||||
	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)
 | 
			
		||||
{
 | 
			
		||||
	struct aecp *aecp = data;
 | 
			
		||||
| 
						 | 
				
			
			@ -66,11 +181,12 @@ static int aecp_message(void *data, uint64_t now, const uint8_t src[6], const vo
 | 
			
		|||
		return 0;
 | 
			
		||||
 | 
			
		||||
	message_type = AVBTP_PACKET_AECP_GET_MESSAGE_TYPE(p);
 | 
			
		||||
	pw_log_info("got AECP message %02x", message_type);
 | 
			
		||||
	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:
 | 
			
		||||
		reply_not_implemented(aecp, src, p, len);
 | 
			
		||||
		handle_aem_command(aecp, src, p, len);
 | 
			
		||||
		break;
 | 
			
		||||
	case AVBTP_AECP_MESSAGE_TYPE_AEM_RESPONSE:
 | 
			
		||||
		break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -243,15 +243,15 @@ struct avbtp_packet_aecp_aem {
 | 
			
		|||
	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_command;
 | 
			
		||||
		struct avbtp_packet_aecp_aem_read_descriptor_r read_descriptor_response;
 | 
			
		||||
		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_command;
 | 
			
		||||
		struct avbtp_packet_aecp_aem_get_avb_info_r avb_info_response;
 | 
			
		||||
		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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -242,15 +242,14 @@ struct server *avdecc_server_new(struct impl *impl, const char *ifname, struct s
 | 
			
		|||
			"                         gptp-supported "
 | 
			
		||||
			"                         aem-identify-control-index-valid "
 | 
			
		||||
			"                         aem-interface-index-valid ] "
 | 
			
		||||
			"  talker-stream-sources = 5 "
 | 
			
		||||
			"  talker-stream-sources = 8 "
 | 
			
		||||
			"  talker-capabilities = [ implemented audio-source ] "
 | 
			
		||||
			"  listener-stream-sinks = 4 "
 | 
			
		||||
			"  listener-stream-sinks = 8 "
 | 
			
		||||
			"  listener-capabilities = [ implemented audio-sink ] "
 | 
			
		||||
			"  controller-capabilities = [ ] "
 | 
			
		||||
			"  available-index = 10 "
 | 
			
		||||
			"  gptp-grandmaster-id = \"10:20:30:40:50:60:0001\" "
 | 
			
		||||
			"  gptp-domain-number = 6 "
 | 
			
		||||
			"  association-id = 0001 "
 | 
			
		||||
			"  association-id = 0 "
 | 
			
		||||
			"}");
 | 
			
		||||
	return server;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue