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