1/*
2 *  PCM - Direct Stream Mixing
3 *  Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
4 *
5 *
6 *   This library is free software; you can redistribute it and/or modify
7 *   it under the terms of the GNU Lesser General Public License as
8 *   published by the Free Software Foundation; either version 2.1 of
9 *   the License, or (at your option) any later version.
10 *
11 *   This program is distributed in the hope that it will be useful,
12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *   GNU Lesser General Public License for more details.
15 *
16 *   You should have received a copy of the GNU Lesser General Public
17 *   License along with this library; if not, write to the Free Software
18 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 *
20 */
21
22#include "pcm_local.h"
23
24#define DIRECT_IPC_SEMS         1
25#define DIRECT_IPC_SEM_CLIENT   0
26
27typedef void (mix_areas_t)(unsigned int size,
28			   volatile void *dst, void *src,
29			   volatile signed int *sum, size_t dst_step,
30			   size_t src_step, size_t sum_step);
31
32typedef void (mix_areas_16_t)(unsigned int size,
33			      volatile signed short *dst, signed short *src,
34			      volatile signed int *sum, size_t dst_step,
35			      size_t src_step, size_t sum_step);
36
37typedef void (mix_areas_32_t)(unsigned int size,
38			      volatile signed int *dst, signed int *src,
39			      volatile signed int *sum, size_t dst_step,
40			      size_t src_step, size_t sum_step);
41
42typedef void (mix_areas_24_t)(unsigned int size,
43			      volatile unsigned char *dst, unsigned char *src,
44			      volatile signed int *sum, size_t dst_step,
45			      size_t src_step, size_t sum_step);
46
47typedef void (mix_areas_u8_t)(unsigned int size,
48			      volatile unsigned char *dst, unsigned char *src,
49			      volatile signed int *sum, size_t dst_step,
50			      size_t src_step, size_t sum_step);
51
52struct slave_params {
53	snd_pcm_format_t format;
54	int rate;
55	int channels;
56	int period_time;
57	int buffer_time;
58	snd_pcm_sframes_t period_size;
59	snd_pcm_sframes_t buffer_size;
60	unsigned int periods;
61};
62
63/* shared among direct plugin clients - be careful to be 32/64bit compatible! */
64typedef struct {
65	unsigned int magic;			/* magic number */
66	char socket_name[256];			/* name of communication socket */
67	snd_pcm_type_t type;			/* PCM type (currently only hw) */
68	int use_server;
69	struct {
70		unsigned int format;
71		snd_interval_t rate;
72		snd_interval_t buffer_size;
73		snd_interval_t buffer_time;
74		snd_interval_t period_size;
75		snd_interval_t period_time;
76		snd_interval_t periods;
77	} hw;
78	struct {
79		/* copied to slave PCMs */
80		snd_pcm_access_t access;
81		snd_pcm_format_t format;
82		snd_pcm_subformat_t subformat;
83		unsigned int channels;
84		unsigned int rate;
85		unsigned int period_size;
86		unsigned int period_time;
87		snd_interval_t periods;
88		unsigned int monotonic;
89		snd_pcm_tstamp_t tstamp_mode;
90		unsigned int period_step;
91		unsigned int sleep_min; /* not used */
92		unsigned int avail_min;
93		unsigned int start_threshold;
94		unsigned int stop_threshold;
95		unsigned int silence_threshold;
96		unsigned int silence_size;
97		unsigned int xfer_align; /* not used */
98		unsigned long long boundary;
99		unsigned int info;
100		unsigned int msbits;
101		unsigned int rate_num;
102		unsigned int rate_den;
103		unsigned int hw_flags;
104		unsigned int fifo_size;
105		unsigned int buffer_size;
106		snd_interval_t buffer_time;
107		unsigned int sample_bits;
108		unsigned int frame_bits;
109	} s;
110	union {
111		struct {
112			unsigned long long chn_mask;
113		} dshare;
114	} u;
115} snd_pcm_direct_share_t;
116
117typedef struct snd_pcm_direct snd_pcm_direct_t;
118
119struct snd_pcm_direct {
120	snd_pcm_type_t type;		/* type (dmix, dsnoop, dshare) */
121	key_t ipc_key;			/* IPC key for semaphore and memory */
122	mode_t ipc_perm;		/* IPC socket permissions */
123	int ipc_gid;			/* IPC socket gid */
124	int semid;			/* IPC global semaphore identification */
125	int shmid;			/* IPC global shared memory identification */
126	snd_pcm_direct_share_t *shmptr;	/* pointer to shared memory area */
127	snd_pcm_t *spcm; 		/* slave PCM handle */
128	snd_pcm_uframes_t appl_ptr;
129	snd_pcm_uframes_t last_appl_ptr;
130	snd_pcm_uframes_t hw_ptr;
131	snd_pcm_uframes_t avail_max;
132	snd_pcm_uframes_t slave_appl_ptr;
133	snd_pcm_uframes_t slave_hw_ptr;
134	snd_pcm_uframes_t slave_period_size;
135	snd_pcm_uframes_t slave_buffer_size;
136	snd_pcm_uframes_t slave_boundary;
137	int (*sync_ptr)(snd_pcm_t *pcm);
138	snd_pcm_state_t state;
139	snd_htimestamp_t trigger_tstamp;
140	snd_htimestamp_t update_tstamp;
141	int server, client;
142	int comm_fd;			/* communication file descriptor (socket) */
143	int hw_fd;			/* hardware file descriptor */
144	struct pollfd timer_fd;
145	int poll_fd;
146	int tread: 1;
147	int timer_need_poll: 1;
148	unsigned int timer_events;
149	int server_fd;
150	pid_t server_pid;
151	snd_timer_t *timer; 		/* timer used as poll_fd */
152	int interleaved;	 	/* we have interleaved buffer */
153	int slowptr;			/* use slow but more precise ptr updates */
154	int max_periods;		/* max periods (-1 = fixed periods, 0 = max buffer size) */
155	unsigned int channels;		/* client's channels */
156	unsigned int *bindings;
157	union {
158		struct {
159			int shmid_sum;			/* IPC global sum ring buffer memory identification */
160			signed int *sum_buffer;		/* shared sum buffer */
161			mix_areas_16_t *mix_areas_16;
162			mix_areas_32_t *mix_areas_32;
163			mix_areas_24_t *mix_areas_24;
164			mix_areas_u8_t *mix_areas_u8;
165			mix_areas_16_t *remix_areas_16;
166			mix_areas_32_t *remix_areas_32;
167			mix_areas_24_t *remix_areas_24;
168			mix_areas_u8_t *remix_areas_u8;
169		} dmix;
170		struct {
171		} dsnoop;
172		struct {
173			unsigned long long chn_mask;
174		} dshare;
175	} u;
176	void (*server_free)(snd_pcm_direct_t *direct);
177};
178
179/* make local functions really local */
180#define snd_pcm_direct_semaphore_create_or_connect \
181	snd1_pcm_direct_semaphore_create_or_connect
182#define snd_pcm_direct_shm_create_or_connect \
183	snd1_pcm_direct_shm_create_or_connect
184#define snd_pcm_direct_shm_discard \
185	snd1_pcm_direct_shm_discard
186#define snd_pcm_direct_server_create \
187	snd1_pcm_direct_server_create
188#define snd_pcm_direct_server_discard \
189	snd1_pcm_direct_server_discard
190#define snd_pcm_direct_client_connect \
191	snd1_pcm_direct_client_connect
192#define snd_pcm_direct_client_discard \
193	snd1_pcm_direct_client_discard
194#define snd_pcm_direct_initialize_slave \
195	snd1_pcm_direct_initialize_slave
196#define snd_pcm_direct_initialize_secondary_slave \
197	snd1_pcm_direct_initialize_secondary_slave
198#define snd_pcm_direct_initialize_poll_fd \
199	snd1_pcm_direct_initialize_poll_fd
200#define snd_pcm_direct_check_interleave \
201	snd1_pcm_direct_check_interleave
202#define snd_pcm_direct_parse_bindings \
203	snd1_pcm_direct_parse_bindings
204#define snd_pcm_direct_nonblock \
205	snd1_pcm_direct_nonblock
206#define snd_pcm_direct_async \
207	snd1_pcm_direct_async
208#define snd_pcm_direct_poll_revents \
209	snd1_pcm_direct_poll_revents
210#define snd_pcm_direct_info \
211	snd1_pcm_direct_info
212#define snd_pcm_direct_hw_refine \
213	snd1_pcm_direct_hw_refine
214#define snd_pcm_direct_hw_params \
215	snd1_pcm_direct_hw_params
216#define snd_pcm_direct_hw_free \
217	snd1_pcm_direct_hw_free
218#define snd_pcm_direct_sw_params \
219	snd1_pcm_direct_sw_params
220#define snd_pcm_direct_channel_info \
221	snd1_pcm_direct_channel_info
222#define snd_pcm_direct_mmap \
223	snd1_pcm_direct_mmap
224#define snd_pcm_direct_munmap \
225	snd1_pcm_direct_munmap
226#define snd_pcm_direct_resume \
227	snd1_pcm_direct_resume
228#define snd_pcm_direct_timer_stop \
229	snd1_pcm_direct_timer_stop
230#define snd_pcm_direct_clear_timer_queue \
231	snd1_pcm_direct_clear_timer_queue
232#define snd_pcm_direct_set_timer_params \
233	snd1_pcm_direct_set_timer_params
234#define snd_pcm_direct_open_secondary_client \
235	snd1_pcm_direct_open_secondary_client
236#define snd_pcm_direct_parse_open_conf \
237	snd1_pcm_direct_parse_open_conf
238
239int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix);
240
241static inline int snd_pcm_direct_semaphore_discard(snd_pcm_direct_t *dmix)
242{
243	if (dmix->semid >= 0) {
244		if (semctl(dmix->semid, 0, IPC_RMID, NULL) < 0)
245			return -errno;
246		dmix->semid = -1;
247	}
248	return 0;
249}
250
251static inline int snd_pcm_direct_semaphore_down(snd_pcm_direct_t *dmix, int sem_num)
252{
253	struct sembuf op[2] = { { sem_num, 0, 0 }, { sem_num, 1, SEM_UNDO } };
254	return semop(dmix->semid, op, 2);
255}
256
257static inline int snd_pcm_direct_semaphore_up(snd_pcm_direct_t *dmix, int sem_num)
258{
259	struct sembuf op = { sem_num, -1, SEM_UNDO | IPC_NOWAIT };
260	return semop(dmix->semid, &op, 1);
261}
262
263int snd_pcm_direct_shm_create_or_connect(snd_pcm_direct_t *dmix);
264int snd_pcm_direct_shm_discard(snd_pcm_direct_t *dmix);
265int snd_pcm_direct_server_create(snd_pcm_direct_t *dmix);
266int snd_pcm_direct_server_discard(snd_pcm_direct_t *dmix);
267int snd_pcm_direct_client_connect(snd_pcm_direct_t *dmix);
268int snd_pcm_direct_client_discard(snd_pcm_direct_t *dmix);
269int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params);
270int snd_pcm_direct_initialize_secondary_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params);
271int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix);
272int snd_pcm_direct_check_interleave(snd_pcm_direct_t *dmix, snd_pcm_t *pcm);
273int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix,
274				  struct slave_params *params,
275				  snd_config_t *cfg);
276int snd_pcm_direct_nonblock(snd_pcm_t *pcm, int nonblock);
277int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid);
278int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
279int snd_pcm_direct_info(snd_pcm_t *pcm, snd_pcm_info_t * info);
280int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
281int snd_pcm_direct_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params);
282int snd_pcm_direct_hw_free(snd_pcm_t *pcm);
283int snd_pcm_direct_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params);
284int snd_pcm_direct_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info);
285int snd_pcm_direct_mmap(snd_pcm_t *pcm);
286int snd_pcm_direct_munmap(snd_pcm_t *pcm);
287int snd_pcm_direct_resume(snd_pcm_t *pcm);
288int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix);
289void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix);
290int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix);
291int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name);
292
293int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid);
294struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm);
295
296struct snd_pcm_direct_open_conf {
297	key_t ipc_key;
298	mode_t ipc_perm;
299	int ipc_gid;
300	int slowptr;
301	int max_periods;
302	snd_config_t *slave;
303	snd_config_t *bindings;
304};
305
306int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, int stream, struct snd_pcm_direct_open_conf *rec);
307