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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21 
22 #include "pcm_local.h"
23 #include "../timer/timer_local.h"
24 
25 #define DIRECT_IPC_SEMS         1
26 #define DIRECT_IPC_SEM_CLIENT   0
27 /* Seconds representing in Milli seconds */
28 #define SEC_TO_MS               1000
29 /* slave_period time for low latency requirements in ms */
30 #define LOW_LATENCY_PERIOD_TIME 10
31 
32 
33 typedef void (mix_areas_t)(unsigned int size,
34 			   volatile void *dst, void *src,
35 			   volatile signed int *sum, size_t dst_step,
36 			   size_t src_step, size_t sum_step);
37 
38 typedef void (mix_areas_16_t)(unsigned int size,
39 			      volatile signed short *dst, signed short *src,
40 			      volatile signed int *sum, size_t dst_step,
41 			      size_t src_step, size_t sum_step);
42 
43 typedef void (mix_areas_32_t)(unsigned int size,
44 			      volatile signed int *dst, signed int *src,
45 			      volatile signed int *sum, size_t dst_step,
46 			      size_t src_step, size_t sum_step);
47 
48 typedef void (mix_areas_24_t)(unsigned int size,
49 			      volatile unsigned char *dst, unsigned char *src,
50 			      volatile signed int *sum, size_t dst_step,
51 			      size_t src_step, size_t sum_step);
52 
53 typedef void (mix_areas_u8_t)(unsigned int size,
54 			      volatile unsigned char *dst, unsigned char *src,
55 			      volatile signed int *sum, size_t dst_step,
56 			      size_t src_step, size_t sum_step);
57 
58 typedef enum snd_pcm_direct_hw_ptr_alignment {
59 	SND_PCM_HW_PTR_ALIGNMENT_NO = 0,	/* use the hw_ptr as is and do no rounding */
60 	SND_PCM_HW_PTR_ALIGNMENT_ROUNDUP = 1,	/* round the slave_appl_ptr up to slave_period */
61 	SND_PCM_HW_PTR_ALIGNMENT_ROUNDDOWN = 2,	/* round slave_hw_ptr and slave_appl_ptr down to slave_period */
62 	SND_PCM_HW_PTR_ALIGNMENT_AUTO = 3	/* automatic selection */
63 } snd_pcm_direct_hw_ptr_alignment_t;
64 
65 struct slave_params {
66 	snd_pcm_format_t format;
67 	int rate;
68 	int channels;
69 	int period_time;
70 	int buffer_time;
71 	snd_pcm_sframes_t period_size;
72 	snd_pcm_sframes_t buffer_size;
73 	unsigned int periods;
74 };
75 
76 /* shared among direct plugin clients - be careful to be 32/64bit compatible! */
77 typedef struct {
78 	unsigned int magic;			/* magic number */
79 	char socket_name[256];			/* name of communication socket */
80 	snd_pcm_type_t type;			/* PCM type (currently only hw) */
81 	int use_server;
82 	struct {
83 		unsigned int format;
84 		snd_interval_t rate;
85 		snd_interval_t buffer_size;
86 		snd_interval_t buffer_time;
87 		snd_interval_t period_size;
88 		snd_interval_t period_time;
89 		snd_interval_t periods;
90 	} hw;
91 	struct {
92 		/* copied to slave PCMs */
93 		snd_pcm_access_t access;
94 		snd_pcm_format_t format;
95 		snd_pcm_subformat_t subformat;
96 		unsigned int channels;
97 		unsigned int rate;
98 		unsigned int period_size;
99 		unsigned int period_time;
100 		snd_interval_t periods;
101 		snd_pcm_tstamp_t tstamp_mode;
102 		snd_pcm_tstamp_type_t tstamp_type;
103 		unsigned int period_step;
104 		unsigned int sleep_min; /* not used */
105 		unsigned int avail_min;
106 		unsigned int start_threshold;
107 		unsigned int stop_threshold;
108 		unsigned int silence_threshold;
109 		unsigned int silence_size;
110 		unsigned int recoveries;	/* no of executed recoveries on slave*/
111 		unsigned long long boundary;
112 		unsigned int info;
113 		unsigned int msbits;
114 		unsigned int rate_num;
115 		unsigned int rate_den;
116 		unsigned int hw_flags;
117 		unsigned int fifo_size;
118 		unsigned int buffer_size;
119 		snd_interval_t buffer_time;
120 		unsigned int sample_bits;
121 		unsigned int frame_bits;
122 	} s;
123 	union {
124 		struct {
125 			unsigned long long chn_mask;
126 		} dshare;
127 	} u;
128 } snd_pcm_direct_share_t;
129 
130 typedef struct snd_pcm_direct snd_pcm_direct_t;
131 
132 struct snd_pcm_direct {
133 	snd_pcm_type_t type;		/* type (dmix, dsnoop, dshare) */
134 	key_t ipc_key;			/* IPC key for semaphore and memory */
135 	mode_t ipc_perm;		/* IPC socket permissions */
136 	int ipc_gid;			/* IPC socket gid */
137 	int semid;			/* IPC global semaphore identification */
138 	int locked[DIRECT_IPC_SEMS];	/* local lock counter */
139 	int shmid;			/* IPC global shared memory identification */
140 	snd_pcm_direct_share_t *shmptr;	/* pointer to shared memory area */
141 	snd_pcm_t *spcm; 		/* slave PCM handle */
142 	snd_pcm_uframes_t appl_ptr;
143 	snd_pcm_uframes_t last_appl_ptr;
144 	snd_pcm_uframes_t hw_ptr;
145 	snd_pcm_uframes_t avail_max;
146 	snd_pcm_uframes_t slave_appl_ptr;
147 	snd_pcm_uframes_t slave_hw_ptr;
148 	snd_pcm_uframes_t slave_period_size;
149 	snd_pcm_uframes_t slave_buffer_size;
150 	snd_pcm_uframes_t slave_boundary;
151 	int (*sync_ptr)(snd_pcm_t *pcm);
152 	snd_pcm_state_t state;
153 	snd_htimestamp_t trigger_tstamp;
154 	snd_htimestamp_t update_tstamp;
155 	int server, client;
156 	int comm_fd;			/* communication file descriptor (socket) */
157 	int hw_fd;			/* hardware file descriptor */
158 	struct pollfd timer_fd;
159 	int poll_fd;
160 	int tread: 1;
161 	int timer_need_poll: 1;
162 	unsigned int timer_events;
163 	unsigned int timer_ticks;
164 	int server_fd;
165 	pid_t server_pid;
166 	snd_timer_t *timer; 		/* timer used as poll_fd */
167 	int interleaved;	 	/* we have interleaved buffer */
168 	int slowptr;			/* use slow but more precise ptr updates */
169 	int max_periods;		/* max periods (-1 = fixed periods, 0 = max buffer size) */
170 	int var_periodsize;		/* allow variable period size if max_periods is != -1*/
171 	unsigned int channels;		/* client's channels */
172 	unsigned int *bindings;
173 	unsigned int recoveries;	/* mirror of executed recoveries on slave */
174 	int direct_memory_access;	/* use arch-optimized buffer RW */
175 	snd_pcm_direct_hw_ptr_alignment_t hw_ptr_alignment;
176 	union {
177 		struct {
178 			int shmid_sum;			/* IPC global sum ring buffer memory identification */
179 			signed int *sum_buffer;		/* shared sum buffer */
180 			mix_areas_16_t *mix_areas_16;
181 			mix_areas_32_t *mix_areas_32;
182 			mix_areas_24_t *mix_areas_24;
183 			mix_areas_u8_t *mix_areas_u8;
184 			mix_areas_16_t *remix_areas_16;
185 			mix_areas_32_t *remix_areas_32;
186 			mix_areas_24_t *remix_areas_24;
187 			mix_areas_u8_t *remix_areas_u8;
188 		} dmix;
189 		struct {
190 			unsigned long long chn_mask;
191 		} dshare;
192 	} u;
193 	void (*server_free)(snd_pcm_direct_t *direct);
194 };
195 
196 /* make local functions really local */
197 #define snd_pcm_direct_semaphore_create_or_connect \
198 	snd1_pcm_direct_semaphore_create_or_connect
199 #define snd_pcm_direct_shm_create_or_connect \
200 	snd1_pcm_direct_shm_create_or_connect
201 #define snd_pcm_direct_shm_discard \
202 	snd1_pcm_direct_shm_discard
203 #define snd_pcm_direct_server_create \
204 	snd1_pcm_direct_server_create
205 #define snd_pcm_direct_server_discard \
206 	snd1_pcm_direct_server_discard
207 #define snd_pcm_direct_client_connect \
208 	snd1_pcm_direct_client_connect
209 #define snd_pcm_direct_client_discard \
210 	snd1_pcm_direct_client_discard
211 #define snd_pcm_direct_initialize_slave \
212 	snd1_pcm_direct_initialize_slave
213 #define snd_pcm_direct_initialize_secondary_slave \
214 	snd1_pcm_direct_initialize_secondary_slave
215 #define snd_pcm_direct_initialize_poll_fd \
216 	snd1_pcm_direct_initialize_poll_fd
217 #define snd_pcm_direct_check_interleave \
218 	snd1_pcm_direct_check_interleave
219 #define snd_pcm_direct_parse_bindings \
220 	snd1_pcm_direct_parse_bindings
221 #define snd_pcm_direct_nonblock \
222 	snd1_pcm_direct_nonblock
223 #define snd_pcm_direct_async \
224 	snd1_pcm_direct_async
225 #define snd_pcm_direct_poll_revents \
226 	snd1_pcm_direct_poll_revents
227 #define snd_pcm_direct_info \
228 	snd1_pcm_direct_info
229 #define snd_pcm_direct_hw_refine \
230 	snd1_pcm_direct_hw_refine
231 #define snd_pcm_direct_hw_params \
232 	snd1_pcm_direct_hw_params
233 #define snd_pcm_direct_hw_free \
234 	snd1_pcm_direct_hw_free
235 #define snd_pcm_direct_sw_params \
236 	snd1_pcm_direct_sw_params
237 #define snd_pcm_direct_channel_info \
238 	snd1_pcm_direct_channel_info
239 #define snd_pcm_direct_mmap \
240 	snd1_pcm_direct_mmap
241 #define snd_pcm_direct_munmap \
242 	snd1_pcm_direct_munmap
243 #define snd_pcm_direct_prepare \
244 	snd1_pcm_direct_prepare
245 #define snd_pcm_direct_resume \
246 	snd1_pcm_direct_resume
247 #define snd_pcm_direct_timer_stop \
248 	snd1_pcm_direct_timer_stop
249 #define snd_pcm_direct_clear_timer_queue \
250 	snd1_pcm_direct_clear_timer_queue
251 #define snd_pcm_direct_set_timer_params \
252 	snd1_pcm_direct_set_timer_params
253 #define snd_pcm_direct_open_secondary_client \
254 	snd1_pcm_direct_open_secondary_client
255 #define snd_pcm_direct_parse_open_conf \
256 	snd1_pcm_direct_parse_open_conf
257 #define snd_pcm_direct_query_chmaps \
258 	snd1_pcm_direct_query_chmaps
259 #define snd_pcm_direct_get_chmap \
260 	snd1_pcm_direct_get_chmap
261 #define snd_pcm_direct_set_chmap \
262 	snd1_pcm_direct_set_chmap
263 #define snd_pcm_direct_reset_slave_ptr \
264 	snd1_pcm_direct_reset_slave_ptr
265 
266 int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix);
267 
snd_pcm_direct_semaphore_discard(snd_pcm_direct_t * dmix)268 static inline int snd_pcm_direct_semaphore_discard(snd_pcm_direct_t *dmix)
269 {
270 	if (dmix->semid >= 0) {
271 		if (semctl(dmix->semid, 0, IPC_RMID, NULL) < 0)
272 			return -errno;
273 		dmix->semid = -1;
274 	}
275 	return 0;
276 }
277 
snd_pcm_direct_semaphore_down(snd_pcm_direct_t * dmix,int sem_num)278 static inline int snd_pcm_direct_semaphore_down(snd_pcm_direct_t *dmix, int sem_num)
279 {
280 	struct sembuf op[2] = { { sem_num, 0, 0 }, { sem_num, 1, SEM_UNDO } };
281 	int err = semop(dmix->semid, op, 2);
282 	if (err == 0)
283 		dmix->locked[sem_num]++;
284 	else if (err == -1)
285 		err = -errno;
286 	return err;
287 }
288 
snd_pcm_direct_semaphore_up(snd_pcm_direct_t * dmix,int sem_num)289 static inline int snd_pcm_direct_semaphore_up(snd_pcm_direct_t *dmix, int sem_num)
290 {
291 	struct sembuf op = { sem_num, -1, SEM_UNDO | IPC_NOWAIT };
292 	int err = semop(dmix->semid, &op, 1);
293 	if (err == 0)
294 		dmix->locked[sem_num]--;
295 	else if (err == -1)
296 		err = -errno;
297 	return err;
298 }
299 
snd_pcm_direct_semaphore_final(snd_pcm_direct_t * dmix,int sem_num)300 static inline int snd_pcm_direct_semaphore_final(snd_pcm_direct_t *dmix, int sem_num)
301 {
302 	if (dmix->locked[sem_num] != 1) {
303 		SNDMSG("invalid semaphore count to finalize %d: %d", sem_num, dmix->locked[sem_num]);
304 		return -EBUSY;
305 	}
306 	return snd_pcm_direct_semaphore_up(dmix, sem_num);
307 }
308 
309 int snd_pcm_direct_shm_create_or_connect(snd_pcm_direct_t *dmix);
310 int snd_pcm_direct_shm_discard(snd_pcm_direct_t *dmix);
311 int snd_pcm_direct_server_create(snd_pcm_direct_t *dmix);
312 int snd_pcm_direct_server_discard(snd_pcm_direct_t *dmix);
313 int snd_pcm_direct_client_connect(snd_pcm_direct_t *dmix);
314 int snd_pcm_direct_client_discard(snd_pcm_direct_t *dmix);
315 int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params);
316 int snd_pcm_direct_initialize_secondary_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params);
317 int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix);
318 int snd_pcm_direct_check_interleave(snd_pcm_direct_t *dmix, snd_pcm_t *pcm);
319 int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix,
320 				  struct slave_params *params,
321 				  snd_config_t *cfg);
322 int snd_pcm_direct_nonblock(snd_pcm_t *pcm, int nonblock);
323 int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid);
324 int snd_pcm_direct_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds,
325 				    unsigned int space);
326 int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
327 int snd_pcm_direct_info(snd_pcm_t *pcm, snd_pcm_info_t * info);
328 int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
329 int snd_pcm_direct_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params);
330 int snd_pcm_direct_hw_free(snd_pcm_t *pcm);
331 int snd_pcm_direct_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params);
332 int snd_pcm_direct_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info);
333 int snd_pcm_direct_mmap(snd_pcm_t *pcm);
334 int snd_pcm_direct_munmap(snd_pcm_t *pcm);
335 int snd_pcm_direct_prepare(snd_pcm_t *pcm);
336 int snd_pcm_direct_resume(snd_pcm_t *pcm);
337 int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix);
338 int snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix);
339 int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix);
340 int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name);
341 
342 snd_pcm_chmap_query_t **snd_pcm_direct_query_chmaps(snd_pcm_t *pcm);
343 snd_pcm_chmap_t *snd_pcm_direct_get_chmap(snd_pcm_t *pcm);
344 int snd_pcm_direct_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map);
345 int snd_pcm_direct_slave_recover(snd_pcm_direct_t *direct);
346 int snd_pcm_direct_client_chk_xrun(snd_pcm_direct_t *direct, snd_pcm_t *pcm);
347 int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid);
348 struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm);
349 void snd_pcm_direct_reset_slave_ptr(snd_pcm_t *pcm, snd_pcm_direct_t *dmix);
350 
351 struct snd_pcm_direct_open_conf {
352 	key_t ipc_key;
353 	mode_t ipc_perm;
354 	int ipc_gid;
355 	int slowptr;
356 	int max_periods;
357 	int var_periodsize;
358 	int direct_memory_access;
359 	snd_pcm_direct_hw_ptr_alignment_t hw_ptr_alignment;
360 	snd_config_t *slave;
361 	snd_config_t *bindings;
362 };
363 
364 int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, int stream, struct snd_pcm_direct_open_conf *rec);
365