summaryrefslogtreecommitdiffstats
path: root/spa/plugins/alsa/alsa-seq.h
blob: 5d5ed51378de2fe6ea95c9585a898b6341a833bd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/* Spa ALSA Sequencer
 *
 * Copyright © 2019 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 SPA_ALSA_SEQ_H
#define SPA_ALSA_SEQ_H

#ifdef __cplusplus
extern "C" {
#endif

#include <stddef.h>
#include <math.h>

#include <alsa/asoundlib.h>

#include <spa/support/plugin.h>
#include <spa/support/loop.h>
#include <spa/utils/list.h>
#include <spa/utils/dll.h>

#include <spa/node/node.h>
#include <spa/node/utils.h>
#include <spa/node/io.h>
#include <spa/param/param.h>
#include <spa/param/audio/format-utils.h>
#include <spa/param/latency-utils.h>

#include "alsa.h"


struct props {
	char device[64];
	char clock_name[64];
	bool disable_longname;
};

#define MAX_EVENT_SIZE 1024
#define MAX_PORTS 256
#define MAX_BUFFERS 32

struct buffer {
	uint32_t id;
#define BUFFER_FLAG_OUT	(1<<0)
	uint32_t flags;
	struct spa_buffer *buf;
	struct spa_meta_header *h;
	struct spa_list link;
};

struct seq_port {
	uint32_t id;
	enum spa_direction direction;
	snd_seq_addr_t addr;

	uint64_t info_all;
	struct spa_port_info info;
#define PORT_EnumFormat	0
#define PORT_Meta	1
#define PORT_IO		2
#define PORT_Format	3
#define PORT_Buffers	4
#define PORT_Latency	5
#define N_PORT_PARAMS	6
	struct spa_param_info params[N_PORT_PARAMS];

	struct spa_io_buffers *io;

	struct buffer buffers[MAX_BUFFERS];
	unsigned int n_buffers;

	struct spa_list free;
	struct spa_list ready;

	struct buffer *buffer;
	struct spa_pod_builder builder;
	struct spa_pod_frame frame;

	struct spa_audio_info current_format;
	unsigned int have_format:1;
	unsigned int valid:1;
	unsigned int active:1;

	struct spa_latency_info latency[2];
};

struct seq_stream {
	enum spa_direction direction;
	unsigned int caps;
	snd_midi_event_t *codec;
	struct seq_port ports[MAX_PORTS];
	uint32_t last_port;
};

struct seq_conn {
	snd_seq_t *hndl;
	snd_seq_addr_t addr;
	int queue_id;
	int fd;
	struct spa_source source;
};

#define BW_PERIOD	(3 * SPA_NSEC_PER_SEC)

struct seq_state {
	struct spa_handle handle;
	struct spa_node node;

	struct spa_log *log;
	struct spa_system *data_system;
	struct spa_loop *data_loop;
	struct spa_loop *main_loop;

	struct seq_conn sys;
	struct seq_conn event;
	int (*port_info) (void *data, const snd_seq_addr_t *addr, const snd_seq_port_info_t *info);
	void *port_info_data;

	struct spa_hook_list hooks;
	struct spa_callbacks callbacks;

	uint64_t info_all;
	struct spa_node_info info;
#define NODE_PropInfo	0
#define NODE_Props	1
#define NODE_IO		2
#define N_NODE_PARAMS	3
	struct spa_param_info params[N_NODE_PARAMS];
	struct props props;

	struct spa_io_clock *clock;
	struct spa_io_position *position;

	int rate_denom;
	uint32_t duration;
	uint32_t threshold;
	struct spa_fraction rate;

	struct spa_source source;
	int timerfd;
	uint64_t current_time;
	uint64_t next_time;
	uint64_t base_time;
	uint64_t queue_time;

	unsigned int opened:1;
	unsigned int started:1;
	unsigned int following:1;

	struct seq_stream streams[2];

	struct spa_dll dll;
};

#define VALID_DIRECTION(this,d)		((d) == SPA_DIRECTION_INPUT || (d) == SPA_DIRECTION_OUTPUT)
#define VALID_PORT(this,d,p)		((p) < MAX_PORTS && this->streams[d].ports[p].id == (p))
#define CHECK_IN_PORT(this,d,p)		((d) == SPA_DIRECTION_INPUT && VALID_PORT(this,d,p))
#define CHECK_OUT_PORT(this,d,p)	((d) == SPA_DIRECTION_OUTPUT && VALID_PORT(this,d,p))
#define CHECK_PORT(this,d,p)		(VALID_DIRECTION(this,d) && VALID_PORT(this,d,p))

#define GET_PORT(this,d,p)		(&this->streams[d].ports[p])

int spa_alsa_seq_open(struct seq_state *state);
int spa_alsa_seq_close(struct seq_state *state);

int spa_alsa_seq_start(struct seq_state *state);
int spa_alsa_seq_pause(struct seq_state *state);
int spa_alsa_seq_reassign_follower(struct seq_state *state);

int spa_alsa_seq_activate_port(struct seq_state *state, struct seq_port *port, bool active);
int spa_alsa_seq_recycle_buffer(struct seq_state *state, struct seq_port *port, uint32_t buffer_id);

int spa_alsa_seq_process(struct seq_state *state);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* SPA_ALSA_SEQ_H */