• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 	int tstamp_type;		/* cached from conf, can be -1(default) on top of real types */
177 	union {
178 		struct {
179 			int shmid_sum;			/* IPC global sum ring buffer memory identification */
180 			signed int *sum_buffer;		/* shared sum buffer */
181 			mix_areas_16_t *mix_areas_16;
182 			mix_areas_32_t *mix_areas_32;
183 			mix_areas_24_t *mix_areas_24;
184 			mix_areas_u8_t *mix_areas_u8;
185 			mix_areas_16_t *remix_areas_16;
186 			mix_areas_32_t *remix_areas_32;
187 			mix_areas_24_t *remix_areas_24;
188 			mix_areas_u8_t *remix_areas_u8;
189 			unsigned int use_sem;
190 		} dmix;
191 		struct {
192 			unsigned long long chn_mask;
193 		} dshare;
194 	} u;
195 	void (*server_free)(snd_pcm_direct_t *direct);
196 };
197 
198 /* make local functions really local */
199 #define snd_pcm_direct_semaphore_create_or_connect \
200 	snd1_pcm_direct_semaphore_create_or_connect
201 #define snd_pcm_direct_shm_create_or_connect \
202 	snd1_pcm_direct_shm_create_or_connect
203 #define snd_pcm_direct_shm_discard \
204 	snd1_pcm_direct_shm_discard
205 #define snd_pcm_direct_server_create \
206 	snd1_pcm_direct_server_create
207 #define snd_pcm_direct_server_discard \
208 	snd1_pcm_direct_server_discard
209 #define snd_pcm_direct_client_connect \
210 	snd1_pcm_direct_client_connect
211 #define snd_pcm_direct_client_discard \
212 	snd1_pcm_direct_client_discard
213 #define snd_pcm_direct_initialize_slave \
214 	snd1_pcm_direct_initialize_slave
215 #define snd_pcm_direct_initialize_secondary_slave \
216 	snd1_pcm_direct_initialize_secondary_slave
217 #define snd_pcm_direct_initialize_poll_fd \
218 	snd1_pcm_direct_initialize_poll_fd
219 #define snd_pcm_direct_check_interleave \
220 	snd1_pcm_direct_check_interleave
221 #define snd_pcm_direct_parse_bindings \
222 	snd1_pcm_direct_parse_bindings
223 #define snd_pcm_direct_nonblock \
224 	snd1_pcm_direct_nonblock
225 #define snd_pcm_direct_async \
226 	snd1_pcm_direct_async
227 #define snd_pcm_direct_poll_revents \
228 	snd1_pcm_direct_poll_revents
229 #define snd_pcm_direct_info \
230 	snd1_pcm_direct_info
231 #define snd_pcm_direct_hw_refine \
232 	snd1_pcm_direct_hw_refine
233 #define snd_pcm_direct_hw_params \
234 	snd1_pcm_direct_hw_params
235 #define snd_pcm_direct_hw_free \
236 	snd1_pcm_direct_hw_free
237 #define snd_pcm_direct_sw_params \
238 	snd1_pcm_direct_sw_params
239 #define snd_pcm_direct_channel_info \
240 	snd1_pcm_direct_channel_info
241 #define snd_pcm_direct_mmap \
242 	snd1_pcm_direct_mmap
243 #define snd_pcm_direct_munmap \
244 	snd1_pcm_direct_munmap
245 #define snd_pcm_direct_prepare \
246 	snd1_pcm_direct_prepare
247 #define snd_pcm_direct_resume \
248 	snd1_pcm_direct_resume
249 #define snd_pcm_direct_timer_stop \
250 	snd1_pcm_direct_timer_stop
251 #define snd_pcm_direct_clear_timer_queue \
252 	snd1_pcm_direct_clear_timer_queue
253 #define snd_pcm_direct_set_timer_params \
254 	snd1_pcm_direct_set_timer_params
255 #define snd_pcm_direct_open_secondary_client \
256 	snd1_pcm_direct_open_secondary_client
257 #define snd_pcm_direct_parse_open_conf \
258 	snd1_pcm_direct_parse_open_conf
259 #define snd_pcm_direct_query_chmaps \
260 	snd1_pcm_direct_query_chmaps
261 #define snd_pcm_direct_get_chmap \
262 	snd1_pcm_direct_get_chmap
263 #define snd_pcm_direct_set_chmap \
264 	snd1_pcm_direct_set_chmap
265 #define snd_pcm_direct_reset_slave_ptr \
266 	snd1_pcm_direct_reset_slave_ptr
267 
268 int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix);
269 
snd_pcm_direct_semaphore_discard(snd_pcm_direct_t * dmix)270 static inline int snd_pcm_direct_semaphore_discard(snd_pcm_direct_t *dmix)
271 {
272 	if (dmix->semid >= 0) {
273 		if (semctl(dmix->semid, 0, IPC_RMID, NULL) < 0)
274 			return -errno;
275 		dmix->semid = -1;
276 	}
277 	return 0;
278 }
279 
snd_pcm_direct_semaphore_down(snd_pcm_direct_t * dmix,int sem_num)280 static inline int snd_pcm_direct_semaphore_down(snd_pcm_direct_t *dmix, int sem_num)
281 {
282 	struct sembuf op[2] = { { sem_num, 0, 0 }, { sem_num, 1, SEM_UNDO } };
283 	int err = semop(dmix->semid, op, 2);
284 	if (err == 0)
285 		dmix->locked[sem_num]++;
286 	else if (err == -1)
287 		err = -errno;
288 	return err;
289 }
290 
snd_pcm_direct_semaphore_up(snd_pcm_direct_t * dmix,int sem_num)291 static inline int snd_pcm_direct_semaphore_up(snd_pcm_direct_t *dmix, int sem_num)
292 {
293 	struct sembuf op = { sem_num, -1, SEM_UNDO | IPC_NOWAIT };
294 	int err = semop(dmix->semid, &op, 1);
295 	if (err == 0)
296 		dmix->locked[sem_num]--;
297 	else if (err == -1)
298 		err = -errno;
299 	return err;
300 }
301 
snd_pcm_direct_semaphore_final(snd_pcm_direct_t * dmix,int sem_num)302 static inline int snd_pcm_direct_semaphore_final(snd_pcm_direct_t *dmix, int sem_num)
303 {
304 	if (dmix->locked[sem_num] != 1) {
305 		SNDMSG("invalid semaphore count to finalize %d: %d", sem_num, dmix->locked[sem_num]);
306 		return -EBUSY;
307 	}
308 	return snd_pcm_direct_semaphore_up(dmix, sem_num);
309 }
310 
311 int snd_pcm_direct_shm_create_or_connect(snd_pcm_direct_t *dmix);
312 int snd_pcm_direct_shm_discard(snd_pcm_direct_t *dmix);
313 int snd_pcm_direct_server_create(snd_pcm_direct_t *dmix);
314 int snd_pcm_direct_server_discard(snd_pcm_direct_t *dmix);
315 int snd_pcm_direct_client_connect(snd_pcm_direct_t *dmix);
316 int snd_pcm_direct_client_discard(snd_pcm_direct_t *dmix);
317 int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params);
318 int snd_pcm_direct_initialize_secondary_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params);
319 int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix);
320 int snd_pcm_direct_check_interleave(snd_pcm_direct_t *dmix, snd_pcm_t *pcm);
321 int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix,
322 				  struct slave_params *params,
323 				  snd_config_t *cfg);
324 int snd_pcm_direct_nonblock(snd_pcm_t *pcm, int nonblock);
325 int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid);
326 int snd_pcm_direct_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds,
327 				    unsigned int space);
328 int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
329 int snd_pcm_direct_info(snd_pcm_t *pcm, snd_pcm_info_t * info);
330 int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
331 int snd_pcm_direct_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params);
332 int snd_pcm_direct_hw_free(snd_pcm_t *pcm);
333 int snd_pcm_direct_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params);
334 int snd_pcm_direct_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info);
335 int snd_pcm_direct_mmap(snd_pcm_t *pcm);
336 int snd_pcm_direct_munmap(snd_pcm_t *pcm);
337 int snd_pcm_direct_prepare(snd_pcm_t *pcm);
338 int snd_pcm_direct_resume(snd_pcm_t *pcm);
339 int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix);
340 int snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix);
341 int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix);
342 int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name);
343 
344 snd_pcm_chmap_query_t **snd_pcm_direct_query_chmaps(snd_pcm_t *pcm);
345 snd_pcm_chmap_t *snd_pcm_direct_get_chmap(snd_pcm_t *pcm);
346 int snd_pcm_direct_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map);
347 int snd_pcm_direct_slave_recover(snd_pcm_direct_t *direct);
348 int snd_pcm_direct_client_chk_xrun(snd_pcm_direct_t *direct, snd_pcm_t *pcm);
349 int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid);
350 struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm);
351 void snd_pcm_direct_reset_slave_ptr(snd_pcm_t *pcm, snd_pcm_direct_t *dmix);
352 
353 struct snd_pcm_direct_open_conf {
354 	key_t ipc_key;
355 	mode_t ipc_perm;
356 	int ipc_gid;
357 	int slowptr;
358 	int max_periods;
359 	int var_periodsize;
360 	int direct_memory_access;
361 	snd_pcm_direct_hw_ptr_alignment_t hw_ptr_alignment;
362 	int tstamp_type;
363 	snd_config_t *slave;
364 	snd_config_t *bindings;
365 };
366 
367 int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, int stream, struct snd_pcm_direct_open_conf *rec);
368 
369 int _snd_pcm_direct_new(snd_pcm_t **pcmp, snd_pcm_direct_t **_dmix, int type,
370 			const char *name, struct snd_pcm_direct_open_conf *opts,
371 			struct slave_params *params, snd_pcm_stream_t stream, int mode);
372