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