Imported Upstream version 1.0.28
[platform/upstream/alsa-lib.git] / src / pcm / pcm_dmix.c
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 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  */
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
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
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
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 + channels * dst_ofs + chn,
216                              dst_step,
217                              src_step,
218                              channels * sizeof(signed int));
219         }
220 }
221
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 + channels * dst_ofs + chn,
284                                dst_step,
285                                src_step,
286                                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
295 #ifdef NO_CONCURRENT_ACCESS
296 #define dmix_down_sem(dmix) snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT)
297 #define dmix_up_sem(dmix) snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT)
298 #else
299 #define dmix_down_sem(dmix)
300 #define dmix_up_sem(dmix)
301 #endif
302 #endif
303
304 /*
305  *  synchronize shm ring buffer with hardware
306  */
307 static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm)
308 {
309         snd_pcm_direct_t *dmix = pcm->private_data;
310         snd_pcm_uframes_t slave_hw_ptr, slave_appl_ptr, slave_size;
311         snd_pcm_uframes_t appl_ptr, size, transfer;
312         const snd_pcm_channel_area_t *src_areas, *dst_areas;
313         
314         /* calculate the size to transfer */
315         /* check the available size in the local buffer
316          * last_appl_ptr keeps the last updated position
317          */
318         size = dmix->appl_ptr - dmix->last_appl_ptr;
319         if (! size)
320                 return;
321         if (size >= pcm->boundary / 2)
322                 size = pcm->boundary - size;
323
324         /* the slave_app_ptr can be far behind the slave_hw_ptr */
325         /* reduce mixing and errors here - just skip not catched writes */
326         if (dmix->slave_hw_ptr <= dmix->slave_appl_ptr)
327                 slave_size = dmix->slave_appl_ptr - dmix->slave_hw_ptr;
328         else
329                 slave_size = dmix->slave_appl_ptr + (dmix->slave_boundary - dmix->slave_hw_ptr);
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 = dmix->appl_ptr - dmix->last_appl_ptr;
339                 if (! size)
340                         return;
341                 if (size >= pcm->boundary / 2)
342                         size = pcm->boundary - size;
343         }
344
345         /* check the available size in the slave PCM buffer */
346         slave_hw_ptr = dmix->slave_hw_ptr;
347         /* don't write on the last active period - this area may be cleared
348          * by the driver during mix operation...
349          */
350         slave_hw_ptr -= slave_hw_ptr % dmix->slave_period_size;
351         slave_hw_ptr += dmix->slave_buffer_size;
352         if (slave_hw_ptr >= dmix->slave_boundary)
353                 slave_hw_ptr -= dmix->slave_boundary;
354         if (slave_hw_ptr < dmix->slave_appl_ptr)
355                 slave_size = slave_hw_ptr + (dmix->slave_boundary - dmix->slave_appl_ptr);
356         else
357                 slave_size = slave_hw_ptr - dmix->slave_appl_ptr;
358         if (slave_size < size)
359                 size = slave_size;
360         if (! size)
361                 return;
362
363         /* add sample areas here */
364         src_areas = snd_pcm_mmap_areas(pcm);
365         dst_areas = snd_pcm_mmap_areas(dmix->spcm);
366         appl_ptr = dmix->last_appl_ptr % pcm->buffer_size;
367         dmix->last_appl_ptr += size;
368         dmix->last_appl_ptr %= pcm->boundary;
369         slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size;
370         dmix->slave_appl_ptr += size;
371         dmix->slave_appl_ptr %= dmix->slave_boundary;
372         dmix_down_sem(dmix);
373         for (;;) {
374                 transfer = size;
375                 if (appl_ptr + transfer > pcm->buffer_size)
376                         transfer = pcm->buffer_size - appl_ptr;
377                 if (slave_appl_ptr + transfer > dmix->slave_buffer_size)
378                         transfer = dmix->slave_buffer_size - slave_appl_ptr;
379                 mix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
380                 size -= transfer;
381                 if (! size)
382                         break;
383                 slave_appl_ptr += transfer;
384                 slave_appl_ptr %= dmix->slave_buffer_size;
385                 appl_ptr += transfer;
386                 appl_ptr %= pcm->buffer_size;
387         }
388         dmix_up_sem(dmix);
389 }
390
391 /*
392  *  synchronize hardware pointer (hw_ptr) with ours
393  */
394 static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm)
395 {
396         snd_pcm_direct_t *dmix = pcm->private_data;
397         snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail;
398         snd_pcm_sframes_t diff;
399         
400         switch (snd_pcm_state(dmix->spcm)) {
401         case SND_PCM_STATE_DISCONNECTED:
402                 dmix->state = SND_PCM_STATE_DISCONNECTED;
403                 return -ENODEV;
404         default:
405                 break;
406         }
407         if (dmix->slowptr)
408                 snd_pcm_hwsync(dmix->spcm);
409         old_slave_hw_ptr = dmix->slave_hw_ptr;
410         slave_hw_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
411         diff = slave_hw_ptr - old_slave_hw_ptr;
412         if (diff == 0)          /* fast path */
413                 return 0;
414         if (dmix->state != SND_PCM_STATE_RUNNING &&
415             dmix->state != SND_PCM_STATE_DRAINING)
416                 /* not really started yet - don't update hw_ptr */
417                 return 0;
418         if (diff < 0) {
419                 slave_hw_ptr += dmix->slave_boundary;
420                 diff = slave_hw_ptr - old_slave_hw_ptr;
421         }
422         dmix->hw_ptr += diff;
423         dmix->hw_ptr %= pcm->boundary;
424         if (pcm->stop_threshold >= pcm->boundary)       /* don't care */
425                 return 0;
426         avail = snd_pcm_mmap_playback_avail(pcm);
427         if (avail > dmix->avail_max)
428                 dmix->avail_max = avail;
429         if (avail >= pcm->stop_threshold) {
430                 snd_timer_stop(dmix->timer);
431                 gettimestamp(&dmix->trigger_tstamp, pcm->monotonic);
432                 if (dmix->state == SND_PCM_STATE_RUNNING) {
433                         dmix->state = SND_PCM_STATE_XRUN;
434                         return -EPIPE;
435                 }
436                 dmix->state = SND_PCM_STATE_SETUP;
437                 /* clear queue to remove pending poll events */
438                 snd_pcm_direct_clear_timer_queue(dmix);
439         }
440         return 0;
441 }
442
443 /*
444  *  plugin implementation
445  */
446
447 static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm)
448 {
449         snd_pcm_direct_t *dmix = pcm->private_data;
450         snd_pcm_state_t state;
451         state = snd_pcm_state(dmix->spcm);
452         switch (state) {
453         case SND_PCM_STATE_SUSPENDED:
454                 return state;
455         case SND_PCM_STATE_DISCONNECTED:
456                 return state;
457         default:
458                 break;
459         }
460         if (dmix->state == STATE_RUN_PENDING)
461                 return SNDRV_PCM_STATE_RUNNING;
462         return dmix->state;
463 }
464
465 static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
466 {
467         snd_pcm_direct_t *dmix = pcm->private_data;
468
469         switch (dmix->state) {
470         case SNDRV_PCM_STATE_DRAINING:
471         case SNDRV_PCM_STATE_RUNNING:
472                 snd_pcm_dmix_sync_ptr(pcm);
473                 break;
474         default:
475                 break;
476         }
477         memset(status, 0, sizeof(*status));
478         status->state = snd_pcm_dmix_state(pcm);
479         status->trigger_tstamp = dmix->trigger_tstamp;
480         gettimestamp(&status->tstamp, pcm->monotonic);
481         status->avail = snd_pcm_mmap_playback_avail(pcm);
482         status->avail_max = status->avail > dmix->avail_max ? status->avail : dmix->avail_max;
483         dmix->avail_max = 0;
484         return 0;
485 }
486
487 static int snd_pcm_dmix_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
488 {
489         snd_pcm_direct_t *dmix = pcm->private_data;
490         int err;
491         
492         switch(dmix->state) {
493         case SNDRV_PCM_STATE_DRAINING:
494         case SNDRV_PCM_STATE_RUNNING:
495                 err = snd_pcm_dmix_sync_ptr(pcm);
496                 if (err < 0)
497                         return err;
498                 /* fallthru */
499         case SNDRV_PCM_STATE_PREPARED:
500         case SNDRV_PCM_STATE_SUSPENDED:
501         case STATE_RUN_PENDING:
502                 *delayp = snd_pcm_mmap_playback_hw_avail(pcm);
503                 return 0;
504         case SNDRV_PCM_STATE_XRUN:
505                 return -EPIPE;
506         case SNDRV_PCM_STATE_DISCONNECTED:
507                 return -ENODEV;
508         default:
509                 return -EBADFD;
510         }
511 }
512
513 static int snd_pcm_dmix_hwsync(snd_pcm_t *pcm)
514 {
515         snd_pcm_direct_t *dmix = pcm->private_data;
516
517         switch(dmix->state) {
518         case SNDRV_PCM_STATE_DRAINING:
519         case SNDRV_PCM_STATE_RUNNING:
520                 /* sync slave PCM */
521                 return snd_pcm_dmix_sync_ptr(pcm);
522         case SNDRV_PCM_STATE_PREPARED:
523         case SNDRV_PCM_STATE_SUSPENDED:
524         case STATE_RUN_PENDING:
525                 return 0;
526         case SNDRV_PCM_STATE_XRUN:
527                 return -EPIPE;
528         case SNDRV_PCM_STATE_DISCONNECTED:
529                 return -ENODEV;
530         default:
531                 return -EBADFD;
532         }
533 }
534
535 static int snd_pcm_dmix_prepare(snd_pcm_t *pcm)
536 {
537         snd_pcm_direct_t *dmix = pcm->private_data;
538
539         snd_pcm_direct_check_interleave(dmix, pcm);
540         dmix->state = SND_PCM_STATE_PREPARED;
541         dmix->appl_ptr = dmix->last_appl_ptr = 0;
542         dmix->hw_ptr = 0;
543         return snd_pcm_direct_set_timer_params(dmix);
544 }
545
546 static void reset_slave_ptr(snd_pcm_t *pcm, snd_pcm_direct_t *dmix)
547 {
548         dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
549         if (pcm->buffer_size > pcm->period_size * 2)
550                 return;
551         /* If we have too litte periods, better to align the start position
552          * to the period boundary so that the interrupt can be handled properly
553          * at the right time.
554          */
555         dmix->slave_appl_ptr = ((dmix->slave_appl_ptr + dmix->slave_period_size - 1)
556                                 / dmix->slave_period_size) * dmix->slave_period_size;
557 }
558
559 static int snd_pcm_dmix_reset(snd_pcm_t *pcm)
560 {
561         snd_pcm_direct_t *dmix = pcm->private_data;
562         dmix->hw_ptr %= pcm->period_size;
563         dmix->appl_ptr = dmix->last_appl_ptr = dmix->hw_ptr;
564         reset_slave_ptr(pcm, dmix);
565         return 0;
566 }
567
568 static int snd_pcm_dmix_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dmix)
569 {
570         int err;
571
572         snd_pcm_hwsync(dmix->spcm);
573         reset_slave_ptr(pcm, dmix);
574         err = snd_timer_start(dmix->timer);
575         if (err < 0)
576                 return err;
577         dmix->state = SND_PCM_STATE_RUNNING;
578         return 0;
579 }
580
581 static int snd_pcm_dmix_start(snd_pcm_t *pcm)
582 {
583         snd_pcm_direct_t *dmix = pcm->private_data;
584         snd_pcm_sframes_t avail;
585         int err;
586         
587         if (dmix->state != SND_PCM_STATE_PREPARED)
588                 return -EBADFD;
589         avail = snd_pcm_mmap_playback_hw_avail(pcm);
590         if (avail == 0)
591                 dmix->state = STATE_RUN_PENDING;
592         else if (avail < 0)
593                 return 0;
594         else {
595                 if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0)
596                         return err;
597                 snd_pcm_dmix_sync_area(pcm);
598         }
599         gettimestamp(&dmix->trigger_tstamp, pcm->monotonic);
600         return 0;
601 }
602
603 static int snd_pcm_dmix_drop(snd_pcm_t *pcm)
604 {
605         snd_pcm_direct_t *dmix = pcm->private_data;
606         if (dmix->state == SND_PCM_STATE_OPEN)
607                 return -EBADFD;
608         dmix->state = SND_PCM_STATE_SETUP;
609         snd_pcm_direct_timer_stop(dmix);
610         return 0;
611 }
612
613 static int snd_pcm_dmix_drain(snd_pcm_t *pcm)
614 {
615         snd_pcm_direct_t *dmix = pcm->private_data;
616         snd_pcm_uframes_t stop_threshold;
617         int err;
618
619         if (dmix->state == SND_PCM_STATE_OPEN)
620                 return -EBADFD;
621         if (pcm->mode & SND_PCM_NONBLOCK)
622                 return -EAGAIN;
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                         return err;
646                 }
647                 if (dmix->state == SND_PCM_STATE_DRAINING) {
648                         snd_pcm_dmix_sync_area(pcm);
649                         snd_pcm_wait_nocheck(pcm, -1);
650                         snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */
651                 }
652         } while (dmix->state == SND_PCM_STATE_DRAINING);
653         pcm->stop_threshold = stop_threshold;
654         return 0;
655 }
656
657 static int snd_pcm_dmix_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
658 {
659         return -EIO;
660 }
661
662 static snd_pcm_sframes_t snd_pcm_dmix_rewindable(snd_pcm_t *pcm)
663 {
664         return snd_pcm_mmap_hw_avail(pcm);
665 }
666
667 static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
668 {
669         snd_pcm_direct_t *dmix = pcm->private_data;
670         snd_pcm_uframes_t slave_appl_ptr, slave_size;
671         snd_pcm_uframes_t appl_ptr, size, transfer, result;
672         const snd_pcm_channel_area_t *src_areas, *dst_areas;
673
674         if (dmix->state == SND_PCM_STATE_RUNNING ||
675             dmix->state == SND_PCM_STATE_DRAINING)
676                 return snd_pcm_dmix_hwsync(pcm);
677
678         if (dmix->last_appl_ptr < dmix->appl_ptr)
679                 size = dmix->appl_ptr - dmix->last_appl_ptr;
680         else
681                 size = dmix->appl_ptr + (pcm->boundary - dmix->last_appl_ptr);
682         if (frames < size)
683                 size = frames;
684         snd_pcm_mmap_appl_backward(pcm, size);
685         frames -= size;
686         if (!frames)
687                 return size;
688         result = size;
689
690         if (dmix->hw_ptr < dmix->appl_ptr)
691                 size = dmix->appl_ptr - dmix->hw_ptr;
692         else
693                 size = dmix->appl_ptr + (pcm->boundary - dmix->hw_ptr);
694         if (size > frames)
695                 size = frames;
696         if (dmix->slave_hw_ptr < dmix->slave_appl_ptr)
697                 slave_size = dmix->slave_appl_ptr - dmix->slave_hw_ptr;
698         else
699                 slave_size = dmix->slave_appl_ptr + (pcm->boundary - dmix->slave_hw_ptr);
700         if (slave_size < size)
701                 size = slave_size;
702         frames -= size;
703         result += size;
704                 
705         /* add sample areas here */
706         src_areas = snd_pcm_mmap_areas(pcm);
707         dst_areas = snd_pcm_mmap_areas(dmix->spcm);
708         dmix->last_appl_ptr -= size;
709         dmix->last_appl_ptr %= pcm->boundary;
710         appl_ptr = dmix->last_appl_ptr % pcm->buffer_size;
711         dmix->slave_appl_ptr -= size;
712         dmix->slave_appl_ptr %= dmix->slave_boundary;
713         slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size;
714         dmix_down_sem(dmix);
715         for (;;) {
716                 transfer = size;
717                 if (appl_ptr + transfer > pcm->buffer_size)
718                         transfer = pcm->buffer_size - appl_ptr;
719                 if (slave_appl_ptr + transfer > dmix->slave_buffer_size)
720                         transfer = dmix->slave_buffer_size - slave_appl_ptr;
721                 remix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
722                 size -= transfer;
723                 if (! size)
724                         break;
725                 slave_appl_ptr += transfer;
726                 slave_appl_ptr %= dmix->slave_buffer_size;
727                 appl_ptr += transfer;
728                 appl_ptr %= pcm->buffer_size;
729         }
730         dmix->last_appl_ptr -= frames;
731         dmix->last_appl_ptr %= pcm->boundary;
732         dmix->slave_appl_ptr -= frames;
733         dmix->slave_appl_ptr %= dmix->slave_boundary;
734         dmix_up_sem(dmix);
735
736         snd_pcm_mmap_appl_backward(pcm, frames);
737
738         return result + frames;
739 }
740
741 static snd_pcm_sframes_t snd_pcm_dmix_forwardable(snd_pcm_t *pcm)
742 {
743         return snd_pcm_mmap_avail(pcm);
744 }
745
746 static snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
747 {
748         snd_pcm_sframes_t avail;
749
750         avail = snd_pcm_mmap_playback_avail(pcm);
751         if (avail < 0)
752                 return 0;
753         if (frames > (snd_pcm_uframes_t)avail)
754                 frames = avail;
755         snd_pcm_mmap_appl_forward(pcm, frames);
756         return frames;
757 }
758
759 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)
760 {
761         return -ENODEV;
762 }
763
764 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)
765 {
766         return -ENODEV;
767 }
768
769 static int snd_pcm_dmix_close(snd_pcm_t *pcm)
770 {
771         snd_pcm_direct_t *dmix = pcm->private_data;
772
773         if (dmix->timer)
774                 snd_timer_close(dmix->timer);
775         snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
776         snd_pcm_close(dmix->spcm);
777         if (dmix->server)
778                 snd_pcm_direct_server_discard(dmix);
779         if (dmix->client)
780                 snd_pcm_direct_client_discard(dmix);
781         shm_sum_discard(dmix);
782         if (snd_pcm_direct_shm_discard(dmix)) {
783                 if (snd_pcm_direct_semaphore_discard(dmix))
784                         snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT);
785         } else
786                 snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT);
787         free(dmix->bindings);
788         pcm->private_data = NULL;
789         free(dmix);
790         return 0;
791 }
792
793 static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm,
794                                                   snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
795                                                   snd_pcm_uframes_t size)
796 {
797         snd_pcm_direct_t *dmix = pcm->private_data;
798         int err;
799
800         switch (snd_pcm_state(dmix->spcm)) {
801         case SND_PCM_STATE_XRUN:
802                 return -EPIPE;
803         case SND_PCM_STATE_SUSPENDED:
804                 return -ESTRPIPE;
805         default:
806                 break;
807         }
808         if (! size)
809                 return 0;
810         snd_pcm_mmap_appl_forward(pcm, size);
811         if (dmix->state == STATE_RUN_PENDING) {
812                 if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0)
813                         return err;
814         } else if (dmix->state == SND_PCM_STATE_RUNNING ||
815                    dmix->state == SND_PCM_STATE_DRAINING)
816                 snd_pcm_dmix_sync_ptr(pcm);
817         if (dmix->state == SND_PCM_STATE_RUNNING ||
818             dmix->state == SND_PCM_STATE_DRAINING) {
819                 /* ok, we commit the changes after the validation of area */
820                 /* it's intended, although the result might be crappy */
821                 snd_pcm_dmix_sync_area(pcm);
822                 /* clear timer queue to avoid a bogus return from poll */
823                 if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min)
824                         snd_pcm_direct_clear_timer_queue(dmix);
825         }
826         return size;
827 }
828
829 static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm)
830 {
831         snd_pcm_direct_t *dmix = pcm->private_data;
832         
833         if (dmix->state == SND_PCM_STATE_RUNNING ||
834             dmix->state == SND_PCM_STATE_DRAINING)
835                 snd_pcm_dmix_sync_ptr(pcm);
836         return snd_pcm_mmap_playback_avail(pcm);
837 }
838
839 static int snd_pcm_dmix_htimestamp(snd_pcm_t *pcm,
840                                    snd_pcm_uframes_t *avail,
841                                    snd_htimestamp_t *tstamp)
842 {
843         snd_pcm_direct_t *dmix = pcm->private_data;
844         snd_pcm_uframes_t avail1;
845         int ok = 0;
846         
847         while (1) {
848                 if (dmix->state == SND_PCM_STATE_RUNNING ||
849                     dmix->state == SND_PCM_STATE_DRAINING)
850                         snd_pcm_dmix_sync_ptr(pcm);
851                 avail1 = snd_pcm_mmap_playback_avail(pcm);
852                 if (ok && *avail == avail1)
853                         break;
854                 *avail = avail1;
855                 *tstamp = snd_pcm_hw_fast_tstamp(dmix->spcm);
856                 ok = 1;
857         }
858         return 0;
859 }
860
861 static int snd_pcm_dmix_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
862 {
863         snd_pcm_direct_t *dmix = pcm->private_data;
864         if (dmix->state == SND_PCM_STATE_RUNNING)
865                 snd_pcm_dmix_sync_area(pcm);
866         return snd_pcm_direct_poll_revents(pcm, pfds, nfds, revents);
867 }
868
869
870 static void snd_pcm_dmix_dump(snd_pcm_t *pcm, snd_output_t *out)
871 {
872         snd_pcm_direct_t *dmix = pcm->private_data;
873
874         snd_output_printf(out, "Direct Stream Mixing PCM\n");
875         if (pcm->setup) {
876                 snd_output_printf(out, "Its setup is:\n");
877                 snd_pcm_dump_setup(pcm, out);
878         }
879         if (dmix->spcm)
880                 snd_pcm_dump(dmix->spcm, out);
881 }
882
883 static const snd_pcm_ops_t snd_pcm_dmix_ops = {
884         .close = snd_pcm_dmix_close,
885         .info = snd_pcm_direct_info,
886         .hw_refine = snd_pcm_direct_hw_refine,
887         .hw_params = snd_pcm_direct_hw_params,
888         .hw_free = snd_pcm_direct_hw_free,
889         .sw_params = snd_pcm_direct_sw_params,
890         .channel_info = snd_pcm_direct_channel_info,
891         .dump = snd_pcm_dmix_dump,
892         .nonblock = snd_pcm_direct_nonblock,
893         .async = snd_pcm_direct_async,
894         .mmap = snd_pcm_direct_mmap,
895         .munmap = snd_pcm_direct_munmap,
896         .query_chmaps = snd_pcm_direct_query_chmaps,
897         .get_chmap = snd_pcm_direct_get_chmap,
898         .set_chmap = snd_pcm_direct_set_chmap,
899 };
900
901 static const snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
902         .status = snd_pcm_dmix_status,
903         .state = snd_pcm_dmix_state,
904         .hwsync = snd_pcm_dmix_hwsync,
905         .delay = snd_pcm_dmix_delay,
906         .prepare = snd_pcm_dmix_prepare,
907         .reset = snd_pcm_dmix_reset,
908         .start = snd_pcm_dmix_start,
909         .drop = snd_pcm_dmix_drop,
910         .drain = snd_pcm_dmix_drain,
911         .pause = snd_pcm_dmix_pause,
912         .rewindable = snd_pcm_dmix_rewindable,
913         .rewind = snd_pcm_dmix_rewind,
914         .forwardable = snd_pcm_dmix_forwardable,
915         .forward = snd_pcm_dmix_forward,
916         .resume = snd_pcm_direct_resume,
917         .link = NULL,
918         .link_slaves = NULL,
919         .unlink = NULL,
920         .writei = snd_pcm_mmap_writei,
921         .writen = snd_pcm_mmap_writen,
922         .readi = snd_pcm_dmix_readi,
923         .readn = snd_pcm_dmix_readn,
924         .avail_update = snd_pcm_dmix_avail_update,
925         .mmap_commit = snd_pcm_dmix_mmap_commit,
926         .htimestamp = snd_pcm_dmix_htimestamp,
927         .poll_descriptors = NULL,
928         .poll_descriptors_count = NULL,
929         .poll_revents = snd_pcm_dmix_poll_revents,
930 };
931
932 /**
933  * \brief Creates a new dmix PCM
934  * \param pcmp Returns created PCM handle
935  * \param name Name of PCM
936  * \param opts Direct PCM configurations
937  * \param params Parameters for slave
938  * \param root Configuration root
939  * \param sconf Slave configuration
940  * \param stream PCM Direction (stream)
941  * \param mode PCM Mode
942  * \retval zero on success otherwise a negative error code
943  * \warning Using of this function might be dangerous in the sense
944  *          of compatibility reasons. The prototype might be freely
945  *          changed in future.
946  */
947 int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
948                       struct snd_pcm_direct_open_conf *opts,
949                       struct slave_params *params,
950                       snd_config_t *root, snd_config_t *sconf,
951                       snd_pcm_stream_t stream, int mode)
952 {
953         snd_pcm_t *pcm = NULL, *spcm = NULL;
954         snd_pcm_direct_t *dmix = NULL;
955         int ret, first_instance;
956         int fail_sem_loop = 10;
957
958         assert(pcmp);
959
960         if (stream != SND_PCM_STREAM_PLAYBACK) {
961                 SNDERR("The dmix plugin supports only playback stream");
962                 return -EINVAL;
963         }
964
965         dmix = calloc(1, sizeof(snd_pcm_direct_t));
966         if (!dmix) {
967                 ret = -ENOMEM;
968                 goto _err_nosem;
969         }
970         
971         ret = snd_pcm_direct_parse_bindings(dmix, params, opts->bindings);
972         if (ret < 0)
973                 goto _err_nosem;
974         
975         dmix->ipc_key = opts->ipc_key;
976         dmix->ipc_perm = opts->ipc_perm;
977         dmix->ipc_gid = opts->ipc_gid;
978         dmix->semid = -1;
979         dmix->shmid = -1;
980
981         ret = snd_pcm_new(&pcm, dmix->type = SND_PCM_TYPE_DMIX, name, stream, mode);
982         if (ret < 0)
983                 goto _err;
984
985         
986         while (1) {
987                 ret = snd_pcm_direct_semaphore_create_or_connect(dmix);
988                 if (ret < 0) {
989                         SNDERR("unable to create IPC semaphore");
990                         goto _err_nosem;
991                 }
992                 ret = snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
993                 if (ret < 0) {
994                         snd_pcm_direct_semaphore_discard(dmix);
995                         if (--fail_sem_loop <= 0)
996                                 goto _err_nosem;
997                         continue;
998                 }
999                 break;
1000         }
1001                 
1002         first_instance = ret = snd_pcm_direct_shm_create_or_connect(dmix);
1003         if (ret < 0) {
1004                 SNDERR("unable to create IPC shm instance");
1005                 goto _err;
1006         }
1007                 
1008         pcm->ops = &snd_pcm_dmix_ops;
1009         pcm->fast_ops = &snd_pcm_dmix_fast_ops;
1010         pcm->private_data = dmix;
1011         dmix->state = SND_PCM_STATE_OPEN;
1012         dmix->slowptr = opts->slowptr;
1013         dmix->max_periods = opts->max_periods;
1014         dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
1015
1016         if (first_instance) {
1017                 /* recursion is already checked in
1018                    snd_pcm_direct_get_slave_ipc_offset() */
1019                 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
1020                                          mode | SND_PCM_NONBLOCK, NULL);
1021                 if (ret < 0) {
1022                         SNDERR("unable to open slave");
1023                         goto _err;
1024                 }
1025         
1026                 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
1027                         SNDERR("dmix plugin can be only connected to hw plugin");
1028                         ret = -EINVAL;
1029                         goto _err;
1030                 }
1031                 
1032                 ret = snd_pcm_direct_initialize_slave(dmix, spcm, params);
1033                 if (ret < 0) {
1034                         SNDERR("unable to initialize slave");
1035                         goto _err;
1036                 }
1037
1038                 dmix->spcm = spcm;
1039
1040                 if (dmix->shmptr->use_server) {
1041                         dmix->server_free = dmix_server_free;
1042                 
1043                         ret = snd_pcm_direct_server_create(dmix);
1044                         if (ret < 0) {
1045                                 SNDERR("unable to create server");
1046                                 goto _err;
1047                         }
1048                 }
1049
1050                 dmix->shmptr->type = spcm->type;
1051         } else {
1052                 if (dmix->shmptr->use_server) {
1053                         /* up semaphore to avoid deadlock */
1054                         snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1055                         ret = snd_pcm_direct_client_connect(dmix);
1056                         if (ret < 0) {
1057                                 SNDERR("unable to connect client");
1058                                 goto _err_nosem;
1059                         }
1060                         
1061                         snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
1062                         ret = snd_pcm_direct_open_secondary_client(&spcm, dmix, "dmix_client");
1063                         if (ret < 0)
1064                                 goto _err;
1065                 } else {
1066
1067                         ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
1068                                                  mode | SND_PCM_NONBLOCK |
1069                                                  SND_PCM_APPEND,
1070                                                  NULL);
1071                         if (ret < 0) {
1072                                 SNDERR("unable to open slave");
1073                                 goto _err;
1074                         }
1075                         if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
1076                                 SNDERR("dmix plugin can be only connected to hw plugin");
1077                                 ret = -EINVAL;
1078                                 goto _err;
1079                         }
1080                 
1081                         ret = snd_pcm_direct_initialize_secondary_slave(dmix, spcm, params);
1082                         if (ret < 0) {
1083                                 SNDERR("unable to initialize slave");
1084                                 goto _err;
1085                         }
1086                 }
1087
1088                 dmix->spcm = spcm;
1089         }
1090
1091         ret = shm_sum_create_or_connect(dmix);
1092         if (ret < 0) {
1093                 SNDERR("unable to initialize sum ring buffer");
1094                 goto _err;
1095         }
1096
1097         ret = snd_pcm_direct_initialize_poll_fd(dmix);
1098         if (ret < 0) {
1099                 SNDERR("unable to initialize poll_fd");
1100                 goto _err;
1101         }
1102
1103         mix_select_callbacks(dmix);
1104                 
1105         pcm->poll_fd = dmix->poll_fd;
1106         pcm->poll_events = POLLIN;      /* it's different than other plugins */
1107         pcm->monotonic = spcm->monotonic;
1108         pcm->mmap_rw = 1;
1109         snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0);
1110         snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0);
1111         
1112         if (dmix->channels == UINT_MAX)
1113                 dmix->channels = dmix->shmptr->s.channels;
1114
1115         snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1116
1117         *pcmp = pcm;
1118         return 0;
1119         
1120  _err:
1121         if (dmix->timer)
1122                 snd_timer_close(dmix->timer);
1123         if (dmix->server)
1124                 snd_pcm_direct_server_discard(dmix);
1125         if (dmix->client)
1126                 snd_pcm_direct_client_discard(dmix);
1127         if (spcm)
1128                 snd_pcm_close(spcm);
1129         if (dmix->u.dmix.shmid_sum >= 0)
1130                 shm_sum_discard(dmix);
1131         if (dmix->shmid >= 0)
1132                 snd_pcm_direct_shm_discard(dmix);
1133         if (snd_pcm_direct_semaphore_discard(dmix) < 0)
1134                 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1135  _err_nosem:
1136         if (dmix) {
1137                 free(dmix->bindings);
1138                 free(dmix);
1139         }
1140         if (pcm)
1141                 snd_pcm_free(pcm);
1142         return ret;
1143 }
1144
1145 /*! \page pcm_plugins
1146
1147 \section pcm_plugins_dmix Plugin: dmix
1148
1149 This plugin provides direct mixing of multiple streams. The resolution
1150 for 32-bit mixing is only 24-bit. The low significant byte is filled with
1151 zeros. The extra 8 bits are used for the saturation.
1152
1153 \code
1154 pcm.name {
1155         type dmix               # Direct mix
1156         ipc_key INT             # unique IPC key
1157         ipc_key_add_uid BOOL    # add current uid to unique IPC key
1158         ipc_perm INT            # IPC permissions (octal, default 0600)
1159         slave STR
1160         # or
1161         slave {                 # Slave definition
1162                 pcm STR         # slave PCM name
1163                 # or
1164                 pcm { }         # slave PCM definition
1165                 format STR      # format definition
1166                 rate INT        # rate definition
1167                 channels INT
1168                 period_time INT # in usec
1169                 # or
1170                 period_size INT # in bytes
1171                 buffer_time INT # in usec
1172                 # or
1173                 buffer_size INT # in bytes
1174                 periods INT     # when buffer_size or buffer_time is not specified
1175         }
1176         bindings {              # note: this is client independent!!!
1177                 N INT           # maps slave channel to client channel N
1178         }
1179         slowptr BOOL            # slow but more precise pointer updates
1180 }
1181 \endcode
1182
1183 <code>ipc_key</code> specfies the unique IPC key in integer.
1184 This number must be unique for each different dmix definition,
1185 since the shared memory is created with this key number.
1186 When <code>ipc_key_add_uid</code> is set true, the uid value is
1187 added to the value set in <code>ipc_key</code>.  This will
1188 avoid the confliction of the same IPC key with different users
1189 concurrently.
1190
1191 Note that the dmix plugin itself supports only a single configuration.
1192 That is, it supports only the fixed rate (default 48000), format
1193 (\c S16), channels (2), and period_time (125000).
1194 For using other configuration, you have to set the value explicitly
1195 in the slave PCM definition.  The rate, format and channels can be
1196 covered by an additional \ref pcm_plugins_dmix "plug plugin",
1197 but there is only one base configuration, anyway.
1198
1199 An example configuration for setting 44100 Hz, \c S32_LE format
1200 as the slave PCM of "hw:0" is like below:
1201 \code
1202 pcm.dmix_44 {
1203         type dmix
1204         ipc_key 321456  # any unique value
1205         ipc_key_add_uid true
1206         slave {
1207                 pcm "hw:0"
1208                 format S32_LE
1209                 rate 44100
1210         }
1211 }
1212 \endcode
1213 You can hear 48000 Hz samples still using this dmix pcm via plug plugin
1214 like:
1215 \code
1216 % aplay -Dplug:dmix_44 foo_48k.wav
1217 \endcode
1218
1219 For using the dmix plugin for OSS emulation device, you have to set
1220 the period and the buffer sizes in power of two.  For example,
1221 \code
1222 pcm.dmixoss {
1223         type dmix
1224         ipc_key 321456  # any unique value
1225         ipc_key_add_uid true
1226         slave {
1227                 pcm "hw:0"
1228                 period_time 0
1229                 period_size 1024  # must be power of 2
1230                 buffer_size 8192  # ditto
1231         }
1232 }
1233 \endcode
1234 <code>period_time 0</code> must be set, too, for resetting the
1235 default value.  In the case of soundcards with multi-channel IO,
1236 adding the bindings would help
1237 \code
1238 pcm.dmixoss {
1239         ...
1240         bindings {
1241                 0 0   # map from 0 to 0
1242                 1 1   # map from 1 to 1
1243         }
1244 }
1245 \endcode
1246 so that only the first two channels are used by dmix.
1247 Also, note that ICE1712 have the limited buffer size, 5513 frames
1248 (corresponding to 640 kB).  In this case, reduce the buffer_size
1249 to 4096.
1250
1251 \subsection pcm_plugins_dmix_funcref Function reference
1252
1253 <UL>
1254   <LI>snd_pcm_dmix_open()
1255   <LI>_snd_pcm_dmix_open()
1256 </UL>
1257
1258 */
1259
1260 /**
1261  * \brief Creates a new dmix PCM
1262  * \param pcmp Returns created PCM handle
1263  * \param name Name of PCM
1264  * \param root Root configuration node
1265  * \param conf Configuration node with dmix PCM description
1266  * \param stream PCM Stream
1267  * \param mode PCM Mode
1268  * \warning Using of this function might be dangerous in the sense
1269  *          of compatibility reasons. The prototype might be freely
1270  *          changed in future.
1271  */
1272 int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
1273                        snd_config_t *root, snd_config_t *conf,
1274                        snd_pcm_stream_t stream, int mode)
1275 {
1276         snd_config_t *sconf;
1277         struct slave_params params;
1278         struct snd_pcm_direct_open_conf dopen;
1279         int bsize, psize;
1280         int err;
1281
1282         err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen);
1283         if (err < 0)
1284                 return err;
1285
1286         /* the default settings, it might be invalid for some hardware */
1287         params.format = SND_PCM_FORMAT_S16;
1288         params.rate = 48000;
1289         params.channels = 2;
1290         params.period_time = -1;
1291         params.buffer_time = -1;
1292         bsize = psize = -1;
1293         params.periods = 3;
1294
1295         err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8,
1296                                  SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, &params.format,
1297                                  SND_PCM_HW_PARAM_RATE, 0, &params.rate,
1298                                  SND_PCM_HW_PARAM_CHANNELS, 0, &params.channels,
1299                                  SND_PCM_HW_PARAM_PERIOD_TIME, 0, &params.period_time,
1300                                  SND_PCM_HW_PARAM_BUFFER_TIME, 0, &params.buffer_time,
1301                                  SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
1302                                  SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
1303                                  SND_PCM_HW_PARAM_PERIODS, 0, &params.periods);
1304         if (err < 0)
1305                 return err;
1306
1307         /* set a reasonable default */  
1308         if (psize == -1 && params.period_time == -1)
1309                 params.period_time = 125000;    /* 0.125 seconds */
1310
1311         if (params.format == -2)
1312                 params.format = SND_PCM_FORMAT_UNKNOWN;
1313         else if (!(dmix_supported_format & (1ULL << params.format))) {
1314                 /* sorry, limited features */
1315                 SNDERR("Unsupported format");
1316                 snd_config_delete(sconf);
1317                 return -EINVAL;
1318         }
1319
1320         params.period_size = psize;
1321         params.buffer_size = bsize;
1322
1323         err = snd_pcm_dmix_open(pcmp, name, &dopen, &params,
1324                                 root, sconf, stream, mode);
1325         snd_config_delete(sconf);
1326         return err;
1327 }
1328 #ifndef DOC_HIDDEN
1329 SND_DLSYM_BUILD_VERSION(_snd_pcm_dmix_open, SND_PCM_DLSYM_VERSION);
1330 #endif