1 /**
2 * \file pcm/pcm_dmix.c
3 * \ingroup PCM_Plugins
4 * \brief PCM Direct Stream Mixing (dmix) Plugin Interface
5 * \author Jaroslav Kysela <perex@perex.cz>
6 * \date 2003
7 */
8 /*
9 * PCM - Direct Stream Mixing
10 * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
11 *
12 *
13 * This library is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as
15 * published by the Free Software Foundation; either version 2.1 of
16 * the License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 *
27 */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stddef.h>
32 #include <unistd.h>
33 #include <signal.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <ctype.h>
37 #include <grp.h>
38 #include <sys/ioctl.h>
39 #include <sys/mman.h>
40 #include <sys/shm.h>
41 #include <sys/sem.h>
42 #include <sys/wait.h>
43 #include <sys/socket.h>
44 #include <sys/un.h>
45 #include <sys/mman.h>
46 #include "pcm_direct.h"
47
48 #ifndef PIC
49 /* entry for static linking */
50 const char *_snd_module_pcm_dmix = "";
51 #endif
52
53 #ifndef DOC_HIDDEN
54 /* start is pending - this state happens when rate plugin does a delayed commit */
55 #define STATE_RUN_PENDING 1024
56 #endif
57
58 /*
59 *
60 */
61
62 static int shm_sum_discard(snd_pcm_direct_t *dmix);
63
64 /*
65 * sum ring buffer shared memory area
66 */
shm_sum_create_or_connect(snd_pcm_direct_t * dmix)67 static int shm_sum_create_or_connect(snd_pcm_direct_t *dmix)
68 {
69 struct shmid_ds buf;
70 int tmpid, err;
71 size_t size;
72
73 size = dmix->shmptr->s.channels *
74 dmix->shmptr->s.buffer_size *
75 sizeof(signed int);
76 retryshm:
77 dmix->u.dmix.shmid_sum = shmget(dmix->ipc_key + 1, size,
78 IPC_CREAT | dmix->ipc_perm);
79 err = -errno;
80 if (dmix->u.dmix.shmid_sum < 0) {
81 if (errno == EINVAL)
82 if ((tmpid = shmget(dmix->ipc_key + 1, 0, dmix->ipc_perm)) != -1)
83 if (!shmctl(tmpid, IPC_STAT, &buf))
84 if (!buf.shm_nattch)
85 /* no users so destroy the segment */
86 if (!shmctl(tmpid, IPC_RMID, NULL))
87 goto retryshm;
88 return err;
89 }
90 if (shmctl(dmix->u.dmix.shmid_sum, IPC_STAT, &buf) < 0) {
91 err = -errno;
92 shm_sum_discard(dmix);
93 return err;
94 }
95 if (dmix->ipc_gid >= 0) {
96 buf.shm_perm.gid = dmix->ipc_gid;
97 shmctl(dmix->u.dmix.shmid_sum, IPC_SET, &buf);
98 }
99 dmix->u.dmix.sum_buffer = shmat(dmix->u.dmix.shmid_sum, 0, 0);
100 if (dmix->u.dmix.sum_buffer == (void *) -1) {
101 err = -errno;
102 shm_sum_discard(dmix);
103 return err;
104 }
105 mlock(dmix->u.dmix.sum_buffer, size);
106 return 0;
107 }
108
shm_sum_discard(snd_pcm_direct_t * dmix)109 static int shm_sum_discard(snd_pcm_direct_t *dmix)
110 {
111 struct shmid_ds buf;
112 int ret = 0;
113
114 if (dmix->u.dmix.shmid_sum < 0)
115 return -EINVAL;
116 if (dmix->u.dmix.sum_buffer != (void *) -1 && shmdt(dmix->u.dmix.sum_buffer) < 0)
117 return -errno;
118 dmix->u.dmix.sum_buffer = (void *) -1;
119 if (shmctl(dmix->u.dmix.shmid_sum, IPC_STAT, &buf) < 0)
120 return -errno;
121 if (buf.shm_nattch == 0) { /* we're the last user, destroy the segment */
122 if (shmctl(dmix->u.dmix.shmid_sum, IPC_RMID, NULL) < 0)
123 return -errno;
124 ret = 1;
125 }
126 dmix->u.dmix.shmid_sum = -1;
127 return ret;
128 }
129
dmix_server_free(snd_pcm_direct_t * dmix)130 static void dmix_server_free(snd_pcm_direct_t *dmix)
131 {
132 /* remove the memory region */
133 shm_sum_create_or_connect(dmix);
134 shm_sum_discard(dmix);
135 }
136
137 /*
138 * the main function of this plugin: mixing
139 * FIXME: optimize it for different architectures
140 */
141
142 #include "pcm_dmix_generic.c"
143 #if defined(__i386__)
144 #include "pcm_dmix_i386.c"
145 #elif defined(__x86_64__)
146 #include "pcm_dmix_x86_64.c"
147 #else
148 #ifndef DOC_HIDDEN
149 #define mix_select_callbacks(x) generic_mix_select_callbacks(x)
150 #define dmix_supported_format generic_dmix_supported_format
151 #endif
152 #endif
153
mix_areas(snd_pcm_direct_t * dmix,const snd_pcm_channel_area_t * src_areas,const snd_pcm_channel_area_t * dst_areas,snd_pcm_uframes_t src_ofs,snd_pcm_uframes_t dst_ofs,snd_pcm_uframes_t size)154 static void mix_areas(snd_pcm_direct_t *dmix,
155 const snd_pcm_channel_area_t *src_areas,
156 const snd_pcm_channel_area_t *dst_areas,
157 snd_pcm_uframes_t src_ofs,
158 snd_pcm_uframes_t dst_ofs,
159 snd_pcm_uframes_t size)
160 {
161 unsigned int src_step, dst_step;
162 unsigned int chn, dchn, channels, sample_size;
163 mix_areas_t *do_mix_areas;
164
165 channels = dmix->channels;
166 switch (dmix->shmptr->s.format) {
167 case SND_PCM_FORMAT_S16_LE:
168 case SND_PCM_FORMAT_S16_BE:
169 sample_size = 2;
170 do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_16;
171 break;
172 case SND_PCM_FORMAT_S32_LE:
173 case SND_PCM_FORMAT_S32_BE:
174 sample_size = 4;
175 do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_32;
176 break;
177 case SND_PCM_FORMAT_S24_LE:
178 sample_size = 4;
179 do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_24;
180 break;
181 case SND_PCM_FORMAT_S24_3LE:
182 sample_size = 3;
183 do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_24;
184 break;
185 case SND_PCM_FORMAT_U8:
186 sample_size = 1;
187 do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_u8;
188 break;
189 default:
190 return;
191 }
192 if (dmix->interleaved) {
193 /*
194 * process all areas in one loop
195 * it optimizes the memory accesses for this case
196 */
197 do_mix_areas(size * channels,
198 (unsigned char *)dst_areas[0].addr + sample_size * dst_ofs * channels,
199 (unsigned char *)src_areas[0].addr + sample_size * src_ofs * channels,
200 dmix->u.dmix.sum_buffer + dst_ofs * channels,
201 sample_size,
202 sample_size,
203 sizeof(signed int));
204 return;
205 }
206 for (chn = 0; chn < channels; chn++) {
207 dchn = dmix->bindings ? dmix->bindings[chn] : chn;
208 if (dchn >= dmix->shmptr->s.channels)
209 continue;
210 src_step = src_areas[chn].step / 8;
211 dst_step = dst_areas[dchn].step / 8;
212 do_mix_areas(size,
213 ((unsigned char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + dst_ofs * dst_step,
214 ((unsigned char *)src_areas[chn].addr + src_areas[chn].first / 8) + src_ofs * src_step,
215 dmix->u.dmix.sum_buffer + dmix->shmptr->s.channels * dst_ofs + dchn,
216 dst_step,
217 src_step,
218 dmix->shmptr->s.channels * sizeof(signed int));
219 }
220 }
221
remix_areas(snd_pcm_direct_t * dmix,const snd_pcm_channel_area_t * src_areas,const snd_pcm_channel_area_t * dst_areas,snd_pcm_uframes_t src_ofs,snd_pcm_uframes_t dst_ofs,snd_pcm_uframes_t size)222 static void remix_areas(snd_pcm_direct_t *dmix,
223 const snd_pcm_channel_area_t *src_areas,
224 const snd_pcm_channel_area_t *dst_areas,
225 snd_pcm_uframes_t src_ofs,
226 snd_pcm_uframes_t dst_ofs,
227 snd_pcm_uframes_t size)
228 {
229 unsigned int src_step, dst_step;
230 unsigned int chn, dchn, channels, sample_size;
231 mix_areas_t *do_remix_areas;
232
233 channels = dmix->channels;
234 switch (dmix->shmptr->s.format) {
235 case SND_PCM_FORMAT_S16_LE:
236 case SND_PCM_FORMAT_S16_BE:
237 sample_size = 2;
238 do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_16;
239 break;
240 case SND_PCM_FORMAT_S32_LE:
241 case SND_PCM_FORMAT_S32_BE:
242 sample_size = 4;
243 do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_32;
244 break;
245 case SND_PCM_FORMAT_S24_LE:
246 sample_size = 4;
247 do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_24;
248 break;
249 case SND_PCM_FORMAT_S24_3LE:
250 sample_size = 3;
251 do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_24;
252 break;
253 case SND_PCM_FORMAT_U8:
254 sample_size = 1;
255 do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_u8;
256 break;
257 default:
258 return;
259 }
260 if (dmix->interleaved) {
261 /*
262 * process all areas in one loop
263 * it optimizes the memory accesses for this case
264 */
265 do_remix_areas(size * channels,
266 (unsigned char *)dst_areas[0].addr + sample_size * dst_ofs * channels,
267 (unsigned char *)src_areas[0].addr + sample_size * src_ofs * channels,
268 dmix->u.dmix.sum_buffer + dst_ofs * channels,
269 sample_size,
270 sample_size,
271 sizeof(signed int));
272 return;
273 }
274 for (chn = 0; chn < channels; chn++) {
275 dchn = dmix->bindings ? dmix->bindings[chn] : chn;
276 if (dchn >= dmix->shmptr->s.channels)
277 continue;
278 src_step = src_areas[chn].step / 8;
279 dst_step = dst_areas[dchn].step / 8;
280 do_remix_areas(size,
281 ((unsigned char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + dst_ofs * dst_step,
282 ((unsigned char *)src_areas[chn].addr + src_areas[chn].first / 8) + src_ofs * src_step,
283 dmix->u.dmix.sum_buffer + dmix->shmptr->s.channels * dst_ofs + dchn,
284 dst_step,
285 src_step,
286 dmix->shmptr->s.channels * sizeof(signed int));
287 }
288 }
289
290 /*
291 * if no concurrent access is allowed in the mixing routines, we need to protect
292 * the area via semaphore
293 */
294 #ifndef DOC_HIDDEN
dmix_down_sem(snd_pcm_direct_t * dmix)295 static void dmix_down_sem(snd_pcm_direct_t *dmix)
296 {
297 if (dmix->u.dmix.use_sem)
298 snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
299 }
300
dmix_up_sem(snd_pcm_direct_t * dmix)301 static void dmix_up_sem(snd_pcm_direct_t *dmix)
302 {
303 if (dmix->u.dmix.use_sem)
304 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
305 }
306 #endif
307
308 /*
309 * synchronize shm ring buffer with hardware
310 */
snd_pcm_dmix_sync_area(snd_pcm_t * pcm)311 static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm)
312 {
313 snd_pcm_direct_t *dmix = pcm->private_data;
314 snd_pcm_uframes_t slave_hw_ptr, slave_appl_ptr, slave_size;
315 snd_pcm_uframes_t appl_ptr, size, transfer;
316 const snd_pcm_channel_area_t *src_areas, *dst_areas;
317
318 /* calculate the size to transfer */
319 /* check the available size in the local buffer
320 * last_appl_ptr keeps the last updated position
321 */
322 size = pcm_frame_diff2(dmix->appl_ptr, dmix->last_appl_ptr, pcm->boundary);
323 if (! size)
324 return;
325
326 /* the slave_app_ptr can be far behind the slave_hw_ptr */
327 /* reduce mixing and errors here - just skip not catched writes */
328 slave_size = pcm_frame_diff(dmix->slave_appl_ptr, dmix->slave_hw_ptr, dmix->slave_boundary);
329 if (slave_size > dmix->slave_buffer_size) {
330 transfer = dmix->slave_buffer_size - slave_size;
331 if (transfer > size)
332 transfer = size;
333 dmix->last_appl_ptr += transfer;
334 dmix->last_appl_ptr %= pcm->boundary;
335 dmix->slave_appl_ptr += transfer;
336 dmix->slave_appl_ptr %= dmix->slave_boundary;
337 size = pcm_frame_diff2(dmix->appl_ptr, dmix->last_appl_ptr, pcm->boundary);
338 if (! size)
339 return;
340 }
341
342 /* check the available size in the slave PCM buffer */
343 slave_hw_ptr = dmix->slave_hw_ptr;
344 /* don't write on the last active period - this area may be cleared
345 * by the driver during mix operation...
346 */
347 slave_hw_ptr -= slave_hw_ptr % dmix->slave_period_size;
348 slave_hw_ptr += dmix->slave_buffer_size;
349 if (slave_hw_ptr >= dmix->slave_boundary)
350 slave_hw_ptr -= dmix->slave_boundary;
351 slave_size = pcm_frame_diff(slave_hw_ptr, dmix->slave_appl_ptr, dmix->slave_boundary);
352 if (slave_size < size)
353 size = slave_size;
354 if (! size)
355 return;
356
357 /* add sample areas here */
358 src_areas = snd_pcm_mmap_areas(pcm);
359 dst_areas = snd_pcm_mmap_areas(dmix->spcm);
360 appl_ptr = dmix->last_appl_ptr % pcm->buffer_size;
361 dmix->last_appl_ptr += size;
362 dmix->last_appl_ptr %= pcm->boundary;
363 slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size;
364 dmix->slave_appl_ptr += size;
365 dmix->slave_appl_ptr %= dmix->slave_boundary;
366 dmix_down_sem(dmix);
367 for (;;) {
368 transfer = size;
369 if (appl_ptr + transfer > pcm->buffer_size)
370 transfer = pcm->buffer_size - appl_ptr;
371 if (slave_appl_ptr + transfer > dmix->slave_buffer_size)
372 transfer = dmix->slave_buffer_size - slave_appl_ptr;
373 mix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
374 size -= transfer;
375 if (! size)
376 break;
377 slave_appl_ptr += transfer;
378 slave_appl_ptr %= dmix->slave_buffer_size;
379 appl_ptr += transfer;
380 appl_ptr %= pcm->buffer_size;
381 }
382 dmix_up_sem(dmix);
383 }
384
385 /*
386 * synchronize hardware pointer (hw_ptr) with ours
387 */
snd_pcm_dmix_sync_ptr0(snd_pcm_t * pcm,snd_pcm_uframes_t slave_hw_ptr)388 static int snd_pcm_dmix_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr)
389 {
390 snd_pcm_direct_t *dmix = pcm->private_data;
391 snd_pcm_uframes_t old_slave_hw_ptr, avail;
392 snd_pcm_sframes_t diff;
393
394 old_slave_hw_ptr = dmix->slave_hw_ptr;
395 dmix->slave_hw_ptr = slave_hw_ptr;
396 diff = pcm_frame_diff(slave_hw_ptr, old_slave_hw_ptr, dmix->slave_boundary);
397 if (diff == 0) /* fast path */
398 return 0;
399 if (dmix->state != SND_PCM_STATE_RUNNING &&
400 dmix->state != SND_PCM_STATE_DRAINING)
401 /* not really started yet - don't update hw_ptr */
402 return 0;
403 dmix->hw_ptr += diff;
404 dmix->hw_ptr %= pcm->boundary;
405 if (pcm->stop_threshold >= pcm->boundary) /* don't care */
406 return 0;
407 avail = snd_pcm_mmap_playback_avail(pcm);
408 if (avail > dmix->avail_max)
409 dmix->avail_max = avail;
410 if (avail >= pcm->stop_threshold) {
411 snd_timer_stop(dmix->timer);
412 gettimestamp(&dmix->trigger_tstamp, pcm->tstamp_type);
413 if (dmix->state == SND_PCM_STATE_RUNNING) {
414 dmix->state = SND_PCM_STATE_XRUN;
415 return -EPIPE;
416 }
417 dmix->state = SND_PCM_STATE_SETUP;
418 /* clear queue to remove pending poll events */
419 snd_pcm_direct_clear_timer_queue(dmix);
420 }
421 return 0;
422 }
423
snd_pcm_dmix_sync_ptr(snd_pcm_t * pcm)424 static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm)
425 {
426 snd_pcm_direct_t *dmix = pcm->private_data;
427 int err;
428
429 switch (snd_pcm_state(dmix->spcm)) {
430 case SND_PCM_STATE_DISCONNECTED:
431 dmix->state = SND_PCM_STATE_DISCONNECTED;
432 return -ENODEV;
433 case SND_PCM_STATE_XRUN:
434 if ((err = snd_pcm_direct_slave_recover(dmix)) < 0)
435 return err;
436 break;
437 default:
438 break;
439 }
440 if (snd_pcm_direct_client_chk_xrun(dmix, pcm))
441 return -EPIPE;
442 if (dmix->slowptr)
443 snd_pcm_hwsync(dmix->spcm);
444
445 return snd_pcm_dmix_sync_ptr0(pcm, *dmix->spcm->hw.ptr);
446 }
447
448 /*
449 * plugin implementation
450 */
451
snd_pcm_dmix_state(snd_pcm_t * pcm)452 static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm)
453 {
454 snd_pcm_direct_t *dmix = pcm->private_data;
455 int err;
456 snd_pcm_state_t state;
457 state = snd_pcm_state(dmix->spcm);
458 switch (state) {
459 case SND_PCM_STATE_SUSPENDED:
460 case SND_PCM_STATE_DISCONNECTED:
461 dmix->state = state;
462 return state;
463 case SND_PCM_STATE_XRUN:
464 if ((err = snd_pcm_direct_slave_recover(dmix)) < 0)
465 return err;
466 break;
467 default:
468 break;
469 }
470 snd_pcm_direct_client_chk_xrun(dmix, pcm);
471 if (dmix->state == STATE_RUN_PENDING)
472 return SNDRV_PCM_STATE_RUNNING;
473 return dmix->state;
474 }
475
snd_pcm_dmix_status(snd_pcm_t * pcm,snd_pcm_status_t * status)476 static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
477 {
478 snd_pcm_direct_t *dmix = pcm->private_data;
479
480 memset(status, 0, sizeof(*status));
481 snd_pcm_status(dmix->spcm, status);
482
483 switch (dmix->state) {
484 case SNDRV_PCM_STATE_DRAINING:
485 case SNDRV_PCM_STATE_RUNNING:
486 snd_pcm_dmix_sync_ptr0(pcm, status->hw_ptr);
487 status->delay = snd_pcm_mmap_playback_delay(pcm);
488 break;
489 default:
490 break;
491 }
492
493 status->state = snd_pcm_dmix_state(pcm);
494 status->hw_ptr = *pcm->hw.ptr; /* boundary may be different */
495 status->appl_ptr = *pcm->appl.ptr; /* slave PCM doesn't set appl_ptr */
496 status->trigger_tstamp = dmix->trigger_tstamp;
497 status->avail = snd_pcm_mmap_playback_avail(pcm);
498 status->avail_max = status->avail > dmix->avail_max ? status->avail : dmix->avail_max;
499 dmix->avail_max = 0;
500 return 0;
501 }
502
snd_pcm_dmix_delay(snd_pcm_t * pcm,snd_pcm_sframes_t * delayp)503 static int snd_pcm_dmix_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
504 {
505 snd_pcm_direct_t *dmix = pcm->private_data;
506 int err;
507
508 switch(dmix->state) {
509 case SNDRV_PCM_STATE_DRAINING:
510 case SNDRV_PCM_STATE_RUNNING:
511 err = snd_pcm_dmix_sync_ptr(pcm);
512 if (err < 0)
513 return err;
514 /* fallthru */
515 case SNDRV_PCM_STATE_PREPARED:
516 case SNDRV_PCM_STATE_SUSPENDED:
517 case STATE_RUN_PENDING:
518 *delayp = snd_pcm_mmap_playback_delay(pcm);
519 return 0;
520 case SNDRV_PCM_STATE_XRUN:
521 return -EPIPE;
522 case SNDRV_PCM_STATE_DISCONNECTED:
523 return -ENODEV;
524 default:
525 return -EBADFD;
526 }
527 }
528
snd_pcm_dmix_hwsync(snd_pcm_t * pcm)529 static int snd_pcm_dmix_hwsync(snd_pcm_t *pcm)
530 {
531 snd_pcm_direct_t *dmix = pcm->private_data;
532
533 switch(dmix->state) {
534 case SNDRV_PCM_STATE_DRAINING:
535 case SNDRV_PCM_STATE_RUNNING:
536 /* sync slave PCM */
537 return snd_pcm_dmix_sync_ptr(pcm);
538 case SNDRV_PCM_STATE_PREPARED:
539 case SNDRV_PCM_STATE_SUSPENDED:
540 case STATE_RUN_PENDING:
541 return 0;
542 case SNDRV_PCM_STATE_XRUN:
543 return -EPIPE;
544 case SNDRV_PCM_STATE_DISCONNECTED:
545 return -ENODEV;
546 default:
547 return -EBADFD;
548 }
549 }
550
snd_pcm_dmix_reset(snd_pcm_t * pcm)551 static int snd_pcm_dmix_reset(snd_pcm_t *pcm)
552 {
553 snd_pcm_direct_t *dmix = pcm->private_data;
554 dmix->hw_ptr %= pcm->period_size;
555 dmix->appl_ptr = dmix->last_appl_ptr = dmix->hw_ptr;
556 dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
557 snd_pcm_direct_reset_slave_ptr(pcm, dmix);
558 return 0;
559 }
560
snd_pcm_dmix_start_timer(snd_pcm_t * pcm,snd_pcm_direct_t * dmix)561 static int snd_pcm_dmix_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dmix)
562 {
563 int err;
564
565 snd_pcm_hwsync(dmix->spcm);
566 dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
567 snd_pcm_direct_reset_slave_ptr(pcm, dmix);
568 err = snd_timer_start(dmix->timer);
569 if (err < 0)
570 return err;
571 dmix->state = SND_PCM_STATE_RUNNING;
572 return 0;
573 }
574
snd_pcm_dmix_start(snd_pcm_t * pcm)575 static int snd_pcm_dmix_start(snd_pcm_t *pcm)
576 {
577 snd_pcm_direct_t *dmix = pcm->private_data;
578 snd_pcm_sframes_t avail;
579 int err;
580
581 if (dmix->state != SND_PCM_STATE_PREPARED)
582 return -EBADFD;
583 avail = snd_pcm_mmap_playback_hw_avail(pcm);
584 if (avail == 0)
585 dmix->state = STATE_RUN_PENDING;
586 else if (avail < 0)
587 return 0;
588 else {
589 if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0)
590 return err;
591 snd_pcm_dmix_sync_area(pcm);
592 }
593 gettimestamp(&dmix->trigger_tstamp, pcm->tstamp_type);
594 return 0;
595 }
596
snd_pcm_dmix_drop(snd_pcm_t * pcm)597 static int snd_pcm_dmix_drop(snd_pcm_t *pcm)
598 {
599 snd_pcm_direct_t *dmix = pcm->private_data;
600 if (dmix->state == SND_PCM_STATE_OPEN)
601 return -EBADFD;
602 dmix->state = SND_PCM_STATE_SETUP;
603 snd_pcm_direct_timer_stop(dmix);
604 return 0;
605 }
606
607 /* locked version */
__snd_pcm_dmix_drain(snd_pcm_t * pcm)608 static int __snd_pcm_dmix_drain(snd_pcm_t *pcm)
609 {
610 snd_pcm_direct_t *dmix = pcm->private_data;
611 snd_pcm_uframes_t stop_threshold;
612 int err = 0;
613
614 switch (snd_pcm_state(dmix->spcm)) {
615 case SND_PCM_STATE_SUSPENDED:
616 return -ESTRPIPE;
617 default:
618 break;
619 }
620
621 if (dmix->state == SND_PCM_STATE_OPEN)
622 return -EBADFD;
623 if (dmix->state == SND_PCM_STATE_PREPARED) {
624 if (snd_pcm_mmap_playback_hw_avail(pcm) > 0)
625 snd_pcm_dmix_start(pcm);
626 else {
627 snd_pcm_dmix_drop(pcm);
628 return 0;
629 }
630 }
631
632 if (dmix->state == SND_PCM_STATE_XRUN) {
633 snd_pcm_dmix_drop(pcm);
634 return 0;
635 }
636
637 stop_threshold = pcm->stop_threshold;
638 if (pcm->stop_threshold > pcm->buffer_size)
639 pcm->stop_threshold = pcm->buffer_size;
640 dmix->state = SND_PCM_STATE_DRAINING;
641 do {
642 err = snd_pcm_dmix_sync_ptr(pcm);
643 if (err < 0) {
644 snd_pcm_dmix_drop(pcm);
645 goto done;
646 }
647 if (dmix->state == SND_PCM_STATE_DRAINING) {
648 snd_pcm_dmix_sync_area(pcm);
649 if ((pcm->mode & SND_PCM_NONBLOCK) == 0) {
650 snd_pcm_wait_nocheck(pcm, -1);
651 snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */
652 }
653
654 switch (snd_pcm_state(dmix->spcm)) {
655 case SND_PCM_STATE_SUSPENDED:
656 err = -ESTRPIPE;
657 goto done;
658 default:
659 break;
660 }
661 }
662 if (pcm->mode & SND_PCM_NONBLOCK) {
663 if (dmix->state == SND_PCM_STATE_DRAINING) {
664 err = -EAGAIN;
665 goto done;
666 }
667 }
668 } while (dmix->state == SND_PCM_STATE_DRAINING);
669 done:
670 pcm->stop_threshold = stop_threshold;
671 return err;
672 }
673
snd_pcm_dmix_drain(snd_pcm_t * pcm)674 static int snd_pcm_dmix_drain(snd_pcm_t *pcm)
675 {
676 int err;
677
678 snd_pcm_lock(pcm);
679 err = __snd_pcm_dmix_drain(pcm);
680 snd_pcm_unlock(pcm);
681 return err;
682 }
683
snd_pcm_dmix_pause(snd_pcm_t * pcm ATTRIBUTE_UNUSED,int enable ATTRIBUTE_UNUSED)684 static int snd_pcm_dmix_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
685 {
686 return -EIO;
687 }
688
snd_pcm_dmix_rewindable(snd_pcm_t * pcm)689 static snd_pcm_sframes_t snd_pcm_dmix_rewindable(snd_pcm_t *pcm)
690 {
691 return snd_pcm_mmap_playback_hw_rewindable(pcm);
692 }
693
snd_pcm_dmix_rewind(snd_pcm_t * pcm,snd_pcm_uframes_t frames)694 static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
695 {
696 snd_pcm_direct_t *dmix = pcm->private_data;
697 snd_pcm_uframes_t slave_appl_ptr, slave_size;
698 snd_pcm_uframes_t appl_ptr, size, transfer, result, frames_to_remix;
699 int err;
700 const snd_pcm_channel_area_t *src_areas, *dst_areas;
701
702 if (dmix->state == SND_PCM_STATE_RUNNING ||
703 dmix->state == SND_PCM_STATE_DRAINING) {
704 err = snd_pcm_dmix_hwsync(pcm);
705 if (err < 0)
706 return err;
707 }
708
709 /* (appl_ptr - last_appl_ptr) indicates the frames which are not
710 * already mixed
711 * (last_appl_ptr - hw_ptr) indicates the frames which are already
712 * mixed but not played yet.
713 * So they can be remixed.
714 */
715
716 size = pcm_frame_diff(dmix->last_appl_ptr, dmix->appl_ptr, pcm->boundary);
717 if (frames < size)
718 size = frames;
719 snd_pcm_mmap_appl_backward(pcm, size);
720 frames -= size;
721 if (!frames)
722 return size;
723 result = size;
724
725 /* Always at this point last_appl_ptr == appl_ptr
726 * So (appl_ptr - hw_ptr) indicates the frames which can be remixed
727 */
728 size = pcm_frame_diff(dmix->appl_ptr, dmix->hw_ptr, pcm->boundary);
729 if (size > frames)
730 size = frames;
731 slave_size = pcm_frame_diff(dmix->slave_appl_ptr, dmix->slave_hw_ptr, pcm->boundary);
732 if (slave_size < size)
733 size = slave_size;
734
735 /* frames which should be remixed will be saved
736 * to also backward the appl pointer on success
737 */
738 frames_to_remix = size;
739
740 /* add sample areas here */
741 src_areas = snd_pcm_mmap_areas(pcm);
742 dst_areas = snd_pcm_mmap_areas(dmix->spcm);
743 dmix->last_appl_ptr -= size;
744 dmix->last_appl_ptr %= pcm->boundary;
745 appl_ptr = dmix->last_appl_ptr % pcm->buffer_size;
746 dmix->slave_appl_ptr -= size;
747 dmix->slave_appl_ptr %= dmix->slave_boundary;
748 slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size;
749 dmix_down_sem(dmix);
750 for (;;) {
751 transfer = size;
752 if (appl_ptr + transfer > pcm->buffer_size)
753 transfer = pcm->buffer_size - appl_ptr;
754 if (slave_appl_ptr + transfer > dmix->slave_buffer_size)
755 transfer = dmix->slave_buffer_size - slave_appl_ptr;
756 remix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
757 size -= transfer;
758 if (! size)
759 break;
760 slave_appl_ptr += transfer;
761 slave_appl_ptr %= dmix->slave_buffer_size;
762 appl_ptr += transfer;
763 appl_ptr %= pcm->buffer_size;
764 }
765 dmix_up_sem(dmix);
766
767 snd_pcm_mmap_appl_backward(pcm, frames_to_remix);
768 result += frames_to_remix;
769 /* At this point last_appl_ptr and appl_ptr has to indicate the
770 * position of the first not mixed frame
771 */
772
773 return result;
774 }
775
snd_pcm_dmix_forwardable(snd_pcm_t * pcm)776 static snd_pcm_sframes_t snd_pcm_dmix_forwardable(snd_pcm_t *pcm)
777 {
778 return snd_pcm_mmap_avail(pcm);
779 }
780
snd_pcm_dmix_forward(snd_pcm_t * pcm,snd_pcm_uframes_t frames)781 static snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
782 {
783 snd_pcm_sframes_t avail;
784
785 avail = snd_pcm_dmix_forwardable(pcm);
786 if (frames > (snd_pcm_uframes_t)avail)
787 frames = avail;
788 snd_pcm_mmap_appl_forward(pcm, frames);
789 return frames;
790 }
791
snd_pcm_dmix_readi(snd_pcm_t * pcm ATTRIBUTE_UNUSED,void * buffer ATTRIBUTE_UNUSED,snd_pcm_uframes_t size ATTRIBUTE_UNUSED)792 static snd_pcm_sframes_t snd_pcm_dmix_readi(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
793 {
794 return -ENODEV;
795 }
796
snd_pcm_dmix_readn(snd_pcm_t * pcm ATTRIBUTE_UNUSED,void ** bufs ATTRIBUTE_UNUSED,snd_pcm_uframes_t size ATTRIBUTE_UNUSED)797 static snd_pcm_sframes_t snd_pcm_dmix_readn(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
798 {
799 return -ENODEV;
800 }
801
snd_pcm_dmix_close(snd_pcm_t * pcm)802 static int snd_pcm_dmix_close(snd_pcm_t *pcm)
803 {
804 snd_pcm_direct_t *dmix = pcm->private_data;
805
806 if (dmix->timer)
807 snd_timer_close(dmix->timer);
808 snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
809 snd_pcm_close(dmix->spcm);
810 if (dmix->server)
811 snd_pcm_direct_server_discard(dmix);
812 if (dmix->client)
813 snd_pcm_direct_client_discard(dmix);
814 shm_sum_discard(dmix);
815 if (snd_pcm_direct_shm_discard(dmix)) {
816 if (snd_pcm_direct_semaphore_discard(dmix))
817 snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT);
818 } else
819 snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT);
820 free(dmix->bindings);
821 pcm->private_data = NULL;
822 free(dmix);
823 return 0;
824 }
825
snd_pcm_dmix_mmap_commit(snd_pcm_t * pcm,snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,snd_pcm_uframes_t size)826 static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm,
827 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
828 snd_pcm_uframes_t size)
829 {
830 snd_pcm_direct_t *dmix = pcm->private_data;
831 int err;
832
833 switch (snd_pcm_state(dmix->spcm)) {
834 case SND_PCM_STATE_XRUN:
835 if ((err = snd_pcm_direct_slave_recover(dmix)) < 0)
836 return err;
837 break;
838 case SND_PCM_STATE_SUSPENDED:
839 return -ESTRPIPE;
840 default:
841 break;
842 }
843 if (snd_pcm_direct_client_chk_xrun(dmix, pcm))
844 return -EPIPE;
845 if (! size)
846 return 0;
847 snd_pcm_mmap_appl_forward(pcm, size);
848 if (dmix->state == STATE_RUN_PENDING) {
849 if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0)
850 return err;
851 } else if (dmix->state == SND_PCM_STATE_RUNNING ||
852 dmix->state == SND_PCM_STATE_DRAINING) {
853 if ((err = snd_pcm_dmix_sync_ptr(pcm)) < 0)
854 return err;
855 }
856 if (dmix->state == SND_PCM_STATE_RUNNING ||
857 dmix->state == SND_PCM_STATE_DRAINING) {
858 /* ok, we commit the changes after the validation of area */
859 /* it's intended, although the result might be crappy */
860 snd_pcm_dmix_sync_area(pcm);
861 /* clear timer queue to avoid a bogus return from poll */
862 if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min)
863 snd_pcm_direct_clear_timer_queue(dmix);
864 }
865 return size;
866 }
867
snd_pcm_dmix_avail_update(snd_pcm_t * pcm)868 static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm)
869 {
870 snd_pcm_direct_t *dmix = pcm->private_data;
871 int err;
872
873 if (dmix->state == SND_PCM_STATE_RUNNING ||
874 dmix->state == SND_PCM_STATE_DRAINING) {
875 if ((err = snd_pcm_dmix_sync_ptr(pcm)) < 0)
876 return err;
877 }
878 if (dmix->state == SND_PCM_STATE_XRUN)
879 return -EPIPE;
880
881 return snd_pcm_mmap_playback_avail(pcm);
882 }
883
snd_pcm_dmix_htimestamp(snd_pcm_t * pcm,snd_pcm_uframes_t * avail,snd_htimestamp_t * tstamp)884 static int snd_pcm_dmix_htimestamp(snd_pcm_t *pcm,
885 snd_pcm_uframes_t *avail,
886 snd_htimestamp_t *tstamp)
887 {
888 snd_pcm_direct_t *dmix = pcm->private_data;
889 snd_pcm_uframes_t avail1;
890 int ok = 0;
891
892 while (1) {
893 if (dmix->state == SND_PCM_STATE_RUNNING ||
894 dmix->state == SND_PCM_STATE_DRAINING)
895 snd_pcm_dmix_sync_ptr(pcm);
896 avail1 = snd_pcm_mmap_playback_avail(pcm);
897 if (ok && *avail == avail1)
898 break;
899 *avail = avail1;
900 *tstamp = snd_pcm_hw_fast_tstamp(dmix->spcm);
901 ok = 1;
902 }
903 return 0;
904 }
905
snd_pcm_dmix_poll_revents(snd_pcm_t * pcm,struct pollfd * pfds,unsigned int nfds,unsigned short * revents)906 static int snd_pcm_dmix_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
907 {
908 snd_pcm_direct_t *dmix = pcm->private_data;
909 if (dmix->state == SND_PCM_STATE_RUNNING)
910 snd_pcm_dmix_sync_area(pcm);
911 return snd_pcm_direct_poll_revents(pcm, pfds, nfds, revents);
912 }
913
914
snd_pcm_dmix_dump(snd_pcm_t * pcm,snd_output_t * out)915 static void snd_pcm_dmix_dump(snd_pcm_t *pcm, snd_output_t *out)
916 {
917 snd_pcm_direct_t *dmix = pcm->private_data;
918
919 snd_output_printf(out, "Direct Stream Mixing PCM\n");
920 if (pcm->setup) {
921 snd_output_printf(out, "Its setup is:\n");
922 snd_pcm_dump_setup(pcm, out);
923 }
924 if (dmix->spcm)
925 snd_pcm_dump(dmix->spcm, out);
926 }
927
928 static const snd_pcm_ops_t snd_pcm_dmix_ops = {
929 .close = snd_pcm_dmix_close,
930 .info = snd_pcm_direct_info,
931 .hw_refine = snd_pcm_direct_hw_refine,
932 .hw_params = snd_pcm_direct_hw_params,
933 .hw_free = snd_pcm_direct_hw_free,
934 .sw_params = snd_pcm_direct_sw_params,
935 .channel_info = snd_pcm_direct_channel_info,
936 .dump = snd_pcm_dmix_dump,
937 .nonblock = snd_pcm_direct_nonblock,
938 .async = snd_pcm_direct_async,
939 .mmap = snd_pcm_direct_mmap,
940 .munmap = snd_pcm_direct_munmap,
941 .query_chmaps = snd_pcm_direct_query_chmaps,
942 .get_chmap = snd_pcm_direct_get_chmap,
943 .set_chmap = snd_pcm_direct_set_chmap,
944 };
945
946 static const snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
947 .status = snd_pcm_dmix_status,
948 .state = snd_pcm_dmix_state,
949 .hwsync = snd_pcm_dmix_hwsync,
950 .delay = snd_pcm_dmix_delay,
951 .prepare = snd_pcm_direct_prepare,
952 .reset = snd_pcm_dmix_reset,
953 .start = snd_pcm_dmix_start,
954 .drop = snd_pcm_dmix_drop,
955 .drain = snd_pcm_dmix_drain,
956 .pause = snd_pcm_dmix_pause,
957 .rewindable = snd_pcm_dmix_rewindable,
958 .rewind = snd_pcm_dmix_rewind,
959 .forwardable = snd_pcm_dmix_forwardable,
960 .forward = snd_pcm_dmix_forward,
961 .resume = snd_pcm_direct_resume,
962 .link = NULL,
963 .link_slaves = NULL,
964 .unlink = NULL,
965 .writei = snd_pcm_mmap_writei,
966 .writen = snd_pcm_mmap_writen,
967 .readi = snd_pcm_dmix_readi,
968 .readn = snd_pcm_dmix_readn,
969 .avail_update = snd_pcm_dmix_avail_update,
970 .mmap_commit = snd_pcm_dmix_mmap_commit,
971 .htimestamp = snd_pcm_dmix_htimestamp,
972 .poll_descriptors = snd_pcm_direct_poll_descriptors,
973 .poll_descriptors_count = NULL,
974 .poll_revents = snd_pcm_dmix_poll_revents,
975 };
976
977 /**
978 * \brief Creates a new dmix PCM
979 * \param pcmp Returns created PCM handle
980 * \param name Name of PCM
981 * \param opts Direct PCM configurations
982 * \param params Parameters for slave
983 * \param root Configuration root
984 * \param sconf Slave configuration
985 * \param stream PCM Direction (stream)
986 * \param mode PCM Mode
987 * \retval zero on success otherwise a negative error code
988 * \warning Using of this function might be dangerous in the sense
989 * of compatibility reasons. The prototype might be freely
990 * changed in future.
991 */
snd_pcm_dmix_open(snd_pcm_t ** pcmp,const char * name,struct snd_pcm_direct_open_conf * opts,struct slave_params * params,snd_config_t * root,snd_config_t * sconf,snd_pcm_stream_t stream,int mode)992 int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
993 struct snd_pcm_direct_open_conf *opts,
994 struct slave_params *params,
995 snd_config_t *root, snd_config_t *sconf,
996 snd_pcm_stream_t stream, int mode)
997 {
998 snd_pcm_t *pcm, *spcm = NULL;
999 snd_pcm_direct_t *dmix;
1000 int ret, first_instance;
1001
1002 assert(pcmp);
1003
1004 if (stream != SND_PCM_STREAM_PLAYBACK) {
1005 SNDERR("The dmix plugin supports only playback stream");
1006 return -EINVAL;
1007 }
1008
1009 ret = _snd_pcm_direct_new(&pcm, &dmix, SND_PCM_TYPE_DMIX, name, opts, params, stream, mode);
1010 if (ret < 0)
1011 return ret;
1012 first_instance = ret;
1013
1014 pcm->ops = &snd_pcm_dmix_ops;
1015 pcm->fast_ops = &snd_pcm_dmix_fast_ops;
1016 pcm->private_data = dmix;
1017 dmix->state = SND_PCM_STATE_OPEN;
1018 dmix->slowptr = opts->slowptr;
1019 dmix->max_periods = opts->max_periods;
1020 dmix->var_periodsize = opts->var_periodsize;
1021 dmix->hw_ptr_alignment = opts->hw_ptr_alignment;
1022 dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
1023 dmix->direct_memory_access = opts->direct_memory_access;
1024
1025 retry:
1026 if (first_instance) {
1027 /* recursion is already checked in
1028 snd_pcm_direct_get_slave_ipc_offset() */
1029 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
1030 mode | SND_PCM_NONBLOCK, NULL);
1031 if (ret < 0) {
1032 SNDERR("unable to open slave");
1033 goto _err;
1034 }
1035
1036 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
1037 SNDERR("dmix plugin can be only connected to hw plugin");
1038 ret = -EINVAL;
1039 goto _err;
1040 }
1041
1042 ret = snd_pcm_direct_initialize_slave(dmix, spcm, params);
1043 if (ret < 0) {
1044 SNDERR("unable to initialize slave");
1045 goto _err;
1046 }
1047
1048 dmix->spcm = spcm;
1049
1050 if (dmix->shmptr->use_server) {
1051 dmix->server_free = dmix_server_free;
1052
1053 ret = snd_pcm_direct_server_create(dmix);
1054 if (ret < 0) {
1055 SNDERR("unable to create server");
1056 goto _err;
1057 }
1058 }
1059
1060 dmix->shmptr->type = spcm->type;
1061 } else {
1062 if (dmix->shmptr->use_server) {
1063 /* up semaphore to avoid deadlock */
1064 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1065 ret = snd_pcm_direct_client_connect(dmix);
1066 if (ret < 0) {
1067 SNDERR("unable to connect client");
1068 goto _err_nosem;
1069 }
1070
1071 snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
1072 ret = snd_pcm_direct_open_secondary_client(&spcm, dmix, "dmix_client");
1073 if (ret < 0)
1074 goto _err;
1075 } else {
1076
1077 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
1078 mode | SND_PCM_NONBLOCK |
1079 SND_PCM_APPEND,
1080 NULL);
1081 if (ret < 0) {
1082 /* all other streams have been closed;
1083 * retry as the first instance
1084 */
1085 if (ret == -EBADFD) {
1086 first_instance = 1;
1087 goto retry;
1088 }
1089 SNDERR("unable to open slave");
1090 goto _err;
1091 }
1092 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
1093 SNDERR("dmix plugin can be only connected to hw plugin");
1094 ret = -EINVAL;
1095 goto _err;
1096 }
1097
1098 ret = snd_pcm_direct_initialize_secondary_slave(dmix, spcm, params);
1099 if (ret < 0) {
1100 SNDERR("unable to initialize slave");
1101 goto _err;
1102 }
1103 }
1104
1105 dmix->spcm = spcm;
1106 }
1107
1108 ret = shm_sum_create_or_connect(dmix);
1109 if (ret < 0) {
1110 SNDERR("unable to initialize sum ring buffer");
1111 goto _err;
1112 }
1113
1114 ret = snd_pcm_direct_initialize_poll_fd(dmix);
1115 if (ret < 0) {
1116 SNDERR("unable to initialize poll_fd");
1117 goto _err;
1118 }
1119
1120 mix_select_callbacks(dmix);
1121
1122 pcm->poll_fd = dmix->poll_fd;
1123 pcm->poll_events = POLLIN; /* it's different than other plugins */
1124 pcm->tstamp_type = spcm->tstamp_type;
1125 pcm->mmap_rw = 1;
1126 snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0);
1127 snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0);
1128
1129 if (dmix->channels == UINT_MAX)
1130 dmix->channels = dmix->shmptr->s.channels;
1131
1132 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1133
1134 *pcmp = pcm;
1135 return 0;
1136
1137 _err:
1138 if (dmix->timer)
1139 snd_timer_close(dmix->timer);
1140 if (dmix->server)
1141 snd_pcm_direct_server_discard(dmix);
1142 if (dmix->client)
1143 snd_pcm_direct_client_discard(dmix);
1144 if (spcm)
1145 snd_pcm_close(spcm);
1146 if (dmix->u.dmix.shmid_sum >= 0)
1147 shm_sum_discard(dmix);
1148 if ((dmix->shmid >= 0) && (snd_pcm_direct_shm_discard(dmix))) {
1149 if (snd_pcm_direct_semaphore_discard(dmix))
1150 snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT);
1151 } else
1152 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1153 _err_nosem:
1154 free(dmix->bindings);
1155 free(dmix);
1156 snd_pcm_free(pcm);
1157 return ret;
1158 }
1159
1160 /*! \page pcm_plugins
1161
1162 \section pcm_plugins_dmix Plugin: dmix
1163
1164 This plugin provides direct mixing of multiple streams. The resolution
1165 for 32-bit mixing is only 24-bit. The low significant byte is filled with
1166 zeros. The extra 8 bits are used for the saturation.
1167
1168 \code
1169 pcm.name {
1170 type dmix # Direct mix
1171 ipc_key INT # unique IPC key
1172 ipc_key_add_uid BOOL # add current uid to unique IPC key
1173 ipc_perm INT # IPC permissions (octal, default 0600)
1174 hw_ptr_alignment STR # Slave application and hw pointer alignment type
1175 # STR can be one of the below strings :
1176 # no
1177 # roundup
1178 # rounddown
1179 # auto (default)
1180 tstamp_type STR # timestamp type
1181 # STR can be one of the below strings :
1182 # default, gettimeofday, monotonic, monotonic_raw
1183 slave STR
1184 # or
1185 slave { # Slave definition
1186 pcm STR # slave PCM name
1187 # or
1188 pcm { } # slave PCM definition
1189 format STR # format definition
1190 rate INT # rate definition
1191 channels INT
1192 period_time INT # in usec
1193 # or
1194 period_size INT # in frames
1195 buffer_time INT # in usec
1196 # or
1197 buffer_size INT # in frames
1198 periods INT # when buffer_size or buffer_time is not specified
1199 }
1200 bindings { # note: this is client independent!!!
1201 N INT # maps slave channel to client channel N
1202 }
1203 slowptr BOOL # slow but more precise pointer updates
1204 }
1205 \endcode
1206
1207 <code>ipc_key</code> specfies the unique IPC key in integer.
1208 This number must be unique for each different dmix definition,
1209 since the shared memory is created with this key number.
1210 When <code>ipc_key_add_uid</code> is set true, the uid value is
1211 added to the value set in <code>ipc_key</code>. This will
1212 avoid the confliction of the same IPC key with different users
1213 concurrently.
1214
1215 <code>hw_ptr_alignment</code> specifies slave application and hw
1216 pointer alignment type. By default hw_ptr_alignment is auto. Below are
1217 the possible configurations:
1218 - no: minimal latency with minimal frames dropped at startup. But
1219 wakeup of application (return from snd_pcm_wait() or poll()) can
1220 take up to 2 * period.
1221 - roundup: It is guaranteed that all frames will be played at
1222 startup. But the latency will increase upto period-1 frames.
1223 - rounddown: It is guaranteed that a wakeup will happen for each
1224 period and frames can be written from application. But on startup
1225 upto period-1 frames will be dropped.
1226 - auto: Selects the best approach depending on the used period and
1227 buffer size.
1228 If the application buffer size is < 2 * application period,
1229 "roundup" will be selected to avoid under runs. If the slave_period
1230 is < 10ms we could expect that there are low latency
1231 requirements. Therefore "rounddown" will be chosen to avoid long
1232 wakeup times. Such wakeup delay could otherwise end up with Xruns in
1233 case of a dependency to another sound device (e.g. forwarding of
1234 microphone to speaker). Else "no" will be chosen.
1235
1236 Note that the dmix plugin itself supports only a single configuration.
1237 That is, it supports only the fixed rate (default 48000), format
1238 (\c S16), channels (2), and period_time (125000).
1239 For using other configuration, you have to set the value explicitly
1240 in the slave PCM definition. The rate, format and channels can be
1241 covered by an additional \ref pcm_plugins_dmix "plug plugin",
1242 but there is only one base configuration, anyway.
1243
1244 An example configuration for setting 44100 Hz, \c S32_LE format
1245 as the slave PCM of "hw:0" is like below:
1246 \code
1247 pcm.dmix_44 {
1248 type dmix
1249 ipc_key 321456 # any unique value
1250 ipc_key_add_uid true
1251 slave {
1252 pcm "hw:0"
1253 format S32_LE
1254 rate 44100
1255 }
1256 }
1257 \endcode
1258 You can hear 48000 Hz samples still using this dmix pcm via plug plugin
1259 like:
1260 \code
1261 % aplay -Dplug:dmix_44 foo_48k.wav
1262 \endcode
1263
1264 For using the dmix plugin for OSS emulation device, you have to set
1265 the period and the buffer sizes in power of two. For example,
1266 \code
1267 pcm.dmixoss {
1268 type dmix
1269 ipc_key 321456 # any unique value
1270 ipc_key_add_uid true
1271 slave {
1272 pcm "hw:0"
1273 period_time 0
1274 period_size 1024 # must be power of 2
1275 buffer_size 8192 # ditto
1276 }
1277 }
1278 \endcode
1279 <code>period_time 0</code> must be set, too, for resetting the
1280 default value. In the case of soundcards with multi-channel IO,
1281 adding the bindings would help
1282 \code
1283 pcm.dmixoss {
1284 ...
1285 bindings {
1286 0 0 # map from 0 to 0
1287 1 1 # map from 1 to 1
1288 }
1289 }
1290 \endcode
1291 so that only the first two channels are used by dmix.
1292 Also, note that ICE1712 have the limited buffer size, 5513 frames
1293 (corresponding to 640 kB). In this case, reduce the buffer_size
1294 to 4096.
1295
1296 \subsection pcm_plugins_dmix_funcref Function reference
1297
1298 <UL>
1299 <LI>snd_pcm_dmix_open()
1300 <LI>_snd_pcm_dmix_open()
1301 </UL>
1302
1303 */
1304
1305 /**
1306 * \brief Creates a new dmix PCM
1307 * \param pcmp Returns created PCM handle
1308 * \param name Name of PCM
1309 * \param root Root configuration node
1310 * \param conf Configuration node with dmix PCM description
1311 * \param stream PCM Stream
1312 * \param mode PCM Mode
1313 * \warning Using of this function might be dangerous in the sense
1314 * of compatibility reasons. The prototype might be freely
1315 * changed in future.
1316 */
_snd_pcm_dmix_open(snd_pcm_t ** pcmp,const char * name,snd_config_t * root,snd_config_t * conf,snd_pcm_stream_t stream,int mode)1317 int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
1318 snd_config_t *root, snd_config_t *conf,
1319 snd_pcm_stream_t stream, int mode)
1320 {
1321 snd_config_t *sconf;
1322 struct slave_params params;
1323 struct snd_pcm_direct_open_conf dopen;
1324 int bsize, psize;
1325 int err;
1326
1327 err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen);
1328 if (err < 0)
1329 return err;
1330
1331 /* the default settings, it might be invalid for some hardware */
1332 params.format = SND_PCM_FORMAT_S16;
1333 params.rate = 48000;
1334 params.channels = 2;
1335 params.period_time = -1;
1336 params.buffer_time = -1;
1337 bsize = psize = -1;
1338 params.periods = 3;
1339
1340 err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8,
1341 SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, ¶ms.format,
1342 SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate,
1343 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
1344 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
1345 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
1346 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
1347 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
1348 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
1349 if (err < 0)
1350 return err;
1351
1352 /* set a reasonable default */
1353 if (psize == -1 && params.period_time == -1)
1354 params.period_time = 125000; /* 0.125 seconds */
1355
1356 if (params.format == -2)
1357 params.format = SND_PCM_FORMAT_UNKNOWN;
1358 else if (!(dmix_supported_format & (1ULL << params.format))) {
1359 /* sorry, limited features */
1360 SNDERR("Unsupported format");
1361 snd_config_delete(sconf);
1362 return -EINVAL;
1363 }
1364
1365 params.period_size = psize;
1366 params.buffer_size = bsize;
1367
1368 err = snd_pcm_dmix_open(pcmp, name, &dopen, ¶ms,
1369 root, sconf, stream, mode);
1370 snd_config_delete(sconf);
1371 return err;
1372 }
1373 #ifndef DOC_HIDDEN
1374 SND_DLSYM_BUILD_VERSION(_snd_pcm_dmix_open, SND_PCM_DLSYM_VERSION);
1375 #endif
1376