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