Imported Upstream version 1.0.25
[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_up(dmix, DIRECT_IPC_SEM_CLIENT);
785         } else
786                 snd_pcm_direct_semaphore_up(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         }
857         return 0;
858 }
859
860 static int snd_pcm_dmix_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
861 {
862         snd_pcm_direct_t *dmix = pcm->private_data;
863         if (dmix->state == SND_PCM_STATE_RUNNING)
864                 snd_pcm_dmix_sync_area(pcm);
865         return snd_pcm_direct_poll_revents(pcm, pfds, nfds, revents);
866 }
867
868
869 static void snd_pcm_dmix_dump(snd_pcm_t *pcm, snd_output_t *out)
870 {
871         snd_pcm_direct_t *dmix = pcm->private_data;
872
873         snd_output_printf(out, "Direct Stream Mixing PCM\n");
874         if (pcm->setup) {
875                 snd_output_printf(out, "Its setup is:\n");
876                 snd_pcm_dump_setup(pcm, out);
877         }
878         if (dmix->spcm)
879                 snd_pcm_dump(dmix->spcm, out);
880 }
881
882 static const snd_pcm_ops_t snd_pcm_dmix_ops = {
883         .close = snd_pcm_dmix_close,
884         .info = snd_pcm_direct_info,
885         .hw_refine = snd_pcm_direct_hw_refine,
886         .hw_params = snd_pcm_direct_hw_params,
887         .hw_free = snd_pcm_direct_hw_free,
888         .sw_params = snd_pcm_direct_sw_params,
889         .channel_info = snd_pcm_direct_channel_info,
890         .dump = snd_pcm_dmix_dump,
891         .nonblock = snd_pcm_direct_nonblock,
892         .async = snd_pcm_direct_async,
893         .mmap = snd_pcm_direct_mmap,
894         .munmap = snd_pcm_direct_munmap,
895 };
896
897 static const snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
898         .status = snd_pcm_dmix_status,
899         .state = snd_pcm_dmix_state,
900         .hwsync = snd_pcm_dmix_hwsync,
901         .delay = snd_pcm_dmix_delay,
902         .prepare = snd_pcm_dmix_prepare,
903         .reset = snd_pcm_dmix_reset,
904         .start = snd_pcm_dmix_start,
905         .drop = snd_pcm_dmix_drop,
906         .drain = snd_pcm_dmix_drain,
907         .pause = snd_pcm_dmix_pause,
908         .rewindable = snd_pcm_dmix_rewindable,
909         .rewind = snd_pcm_dmix_rewind,
910         .forwardable = snd_pcm_dmix_forwardable,
911         .forward = snd_pcm_dmix_forward,
912         .resume = snd_pcm_direct_resume,
913         .link = NULL,
914         .link_slaves = NULL,
915         .unlink = NULL,
916         .writei = snd_pcm_mmap_writei,
917         .writen = snd_pcm_mmap_writen,
918         .readi = snd_pcm_dmix_readi,
919         .readn = snd_pcm_dmix_readn,
920         .avail_update = snd_pcm_dmix_avail_update,
921         .mmap_commit = snd_pcm_dmix_mmap_commit,
922         .htimestamp = snd_pcm_dmix_htimestamp,
923         .poll_descriptors = NULL,
924         .poll_descriptors_count = NULL,
925         .poll_revents = snd_pcm_dmix_poll_revents,
926 };
927
928 /**
929  * \brief Creates a new dmix PCM
930  * \param pcmp Returns created PCM handle
931  * \param name Name of PCM
932  * \param opts Direct PCM configurations
933  * \param params Parameters for slave
934  * \param root Configuration root
935  * \param sconf Slave configuration
936  * \param stream PCM Direction (stream)
937  * \param mode PCM Mode
938  * \retval zero on success otherwise a negative error code
939  * \warning Using of this function might be dangerous in the sense
940  *          of compatibility reasons. The prototype might be freely
941  *          changed in future.
942  */
943 int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
944                       struct snd_pcm_direct_open_conf *opts,
945                       struct slave_params *params,
946                       snd_config_t *root, snd_config_t *sconf,
947                       snd_pcm_stream_t stream, int mode)
948 {
949         snd_pcm_t *pcm = NULL, *spcm = NULL;
950         snd_pcm_direct_t *dmix = NULL;
951         int ret, first_instance;
952         int fail_sem_loop = 10;
953
954         assert(pcmp);
955
956         if (stream != SND_PCM_STREAM_PLAYBACK) {
957                 SNDERR("The dmix plugin supports only playback stream");
958                 return -EINVAL;
959         }
960
961         dmix = calloc(1, sizeof(snd_pcm_direct_t));
962         if (!dmix) {
963                 ret = -ENOMEM;
964                 goto _err_nosem;
965         }
966         
967         ret = snd_pcm_direct_parse_bindings(dmix, params, opts->bindings);
968         if (ret < 0)
969                 goto _err_nosem;
970         
971         dmix->ipc_key = opts->ipc_key;
972         dmix->ipc_perm = opts->ipc_perm;
973         dmix->ipc_gid = opts->ipc_gid;
974         dmix->semid = -1;
975         dmix->shmid = -1;
976
977         ret = snd_pcm_new(&pcm, dmix->type = SND_PCM_TYPE_DMIX, name, stream, mode);
978         if (ret < 0)
979                 goto _err;
980
981         
982         while (1) {
983                 ret = snd_pcm_direct_semaphore_create_or_connect(dmix);
984                 if (ret < 0) {
985                         SNDERR("unable to create IPC semaphore");
986                         goto _err_nosem;
987                 }
988                 ret = snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
989                 if (ret < 0) {
990                         snd_pcm_direct_semaphore_discard(dmix);
991                         if (--fail_sem_loop <= 0)
992                                 goto _err_nosem;
993                         continue;
994                 }
995                 break;
996         }
997                 
998         first_instance = ret = snd_pcm_direct_shm_create_or_connect(dmix);
999         if (ret < 0) {
1000                 SNDERR("unable to create IPC shm instance");
1001                 goto _err;
1002         }
1003                 
1004         pcm->ops = &snd_pcm_dmix_ops;
1005         pcm->fast_ops = &snd_pcm_dmix_fast_ops;
1006         pcm->private_data = dmix;
1007         dmix->state = SND_PCM_STATE_OPEN;
1008         dmix->slowptr = opts->slowptr;
1009         dmix->max_periods = opts->max_periods;
1010         dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
1011
1012         if (first_instance) {
1013                 /* recursion is already checked in
1014                    snd_pcm_direct_get_slave_ipc_offset() */
1015                 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
1016                                          mode | SND_PCM_NONBLOCK, NULL);
1017                 if (ret < 0) {
1018                         SNDERR("unable to open slave");
1019                         goto _err;
1020                 }
1021         
1022                 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
1023                         SNDERR("dmix plugin can be only connected to hw plugin");
1024                         ret = -EINVAL;
1025                         goto _err;
1026                 }
1027                 
1028                 ret = snd_pcm_direct_initialize_slave(dmix, spcm, params);
1029                 if (ret < 0) {
1030                         SNDERR("unable to initialize slave");
1031                         goto _err;
1032                 }
1033
1034                 dmix->spcm = spcm;
1035
1036                 if (dmix->shmptr->use_server) {
1037                         dmix->server_free = dmix_server_free;
1038                 
1039                         ret = snd_pcm_direct_server_create(dmix);
1040                         if (ret < 0) {
1041                                 SNDERR("unable to create server");
1042                                 goto _err;
1043                         }
1044                 }
1045
1046                 dmix->shmptr->type = spcm->type;
1047         } else {
1048                 if (dmix->shmptr->use_server) {
1049                         /* up semaphore to avoid deadlock */
1050                         snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1051                         ret = snd_pcm_direct_client_connect(dmix);
1052                         if (ret < 0) {
1053                                 SNDERR("unable to connect client");
1054                                 goto _err_nosem;
1055                         }
1056                         
1057                         snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
1058                         ret = snd_pcm_direct_open_secondary_client(&spcm, dmix, "dmix_client");
1059                         if (ret < 0)
1060                                 goto _err;
1061                 } else {
1062
1063                         ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
1064                                                  mode | SND_PCM_NONBLOCK |
1065                                                  SND_PCM_APPEND,
1066                                                  NULL);
1067                         if (ret < 0) {
1068                                 SNDERR("unable to open slave");
1069                                 goto _err;
1070                         }
1071                         if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
1072                                 SNDERR("dmix plugin can be only connected to hw plugin");
1073                                 ret = -EINVAL;
1074                                 goto _err;
1075                         }
1076                 
1077                         ret = snd_pcm_direct_initialize_secondary_slave(dmix, spcm, params);
1078                         if (ret < 0) {
1079                                 SNDERR("unable to initialize slave");
1080                                 goto _err;
1081                         }
1082                 }
1083
1084                 dmix->spcm = spcm;
1085         }
1086
1087         ret = shm_sum_create_or_connect(dmix);
1088         if (ret < 0) {
1089                 SNDERR("unable to initialize sum ring buffer");
1090                 goto _err;
1091         }
1092
1093         ret = snd_pcm_direct_initialize_poll_fd(dmix);
1094         if (ret < 0) {
1095                 SNDERR("unable to initialize poll_fd");
1096                 goto _err;
1097         }
1098
1099         mix_select_callbacks(dmix);
1100                 
1101         pcm->poll_fd = dmix->poll_fd;
1102         pcm->poll_events = POLLIN;      /* it's different than other plugins */
1103                 
1104         pcm->mmap_rw = 1;
1105         snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0);
1106         snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0);
1107         
1108         if (dmix->channels == UINT_MAX)
1109                 dmix->channels = dmix->shmptr->s.channels;
1110
1111         snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1112
1113         *pcmp = pcm;
1114         return 0;
1115         
1116  _err:
1117         if (dmix->timer)
1118                 snd_timer_close(dmix->timer);
1119         if (dmix->server)
1120                 snd_pcm_direct_server_discard(dmix);
1121         if (dmix->client)
1122                 snd_pcm_direct_client_discard(dmix);
1123         if (spcm)
1124                 snd_pcm_close(spcm);
1125         if (dmix->u.dmix.shmid_sum >= 0)
1126                 shm_sum_discard(dmix);
1127         if (dmix->shmid >= 0)
1128                 snd_pcm_direct_shm_discard(dmix);
1129         if (snd_pcm_direct_semaphore_discard(dmix) < 0)
1130                 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1131  _err_nosem:
1132         if (dmix) {
1133                 free(dmix->bindings);
1134                 free(dmix);
1135         }
1136         if (pcm)
1137                 snd_pcm_free(pcm);
1138         return ret;
1139 }
1140
1141 /*! \page pcm_plugins
1142
1143 \section pcm_plugins_dmix Plugin: dmix
1144
1145 This plugin provides direct mixing of multiple streams. The resolution
1146 for 32-bit mixing is only 24-bit. The low significant byte is filled with
1147 zeros. The extra 8 bits are used for the saturation.
1148
1149 \code
1150 pcm.name {
1151         type dmix               # Direct mix
1152         ipc_key INT             # unique IPC key
1153         ipc_key_add_uid BOOL    # add current uid to unique IPC key
1154         ipc_perm INT            # IPC permissions (octal, default 0600)
1155         slave STR
1156         # or
1157         slave {                 # Slave definition
1158                 pcm STR         # slave PCM name
1159                 # or
1160                 pcm { }         # slave PCM definition
1161                 format STR      # format definition
1162                 rate INT        # rate definition
1163                 channels INT
1164                 period_time INT # in usec
1165                 # or
1166                 period_size INT # in bytes
1167                 buffer_time INT # in usec
1168                 # or
1169                 buffer_size INT # in bytes
1170                 periods INT     # when buffer_size or buffer_time is not specified
1171         }
1172         bindings {              # note: this is client independent!!!
1173                 N INT           # maps slave channel to client channel N
1174         }
1175         slowptr BOOL            # slow but more precise pointer updates
1176 }
1177 \endcode
1178
1179 <code>ipc_key</code> specfies the unique IPC key in integer.
1180 This number must be unique for each different dmix definition,
1181 since the shared memory is created with this key number.
1182 When <code>ipc_key_add_uid</code> is set true, the uid value is
1183 added to the value set in <code>ipc_key</code>.  This will
1184 avoid the confliction of the same IPC key with different users
1185 concurrently.
1186
1187 Note that the dmix plugin itself supports only a single configuration.
1188 That is, it supports only the fixed rate (default 48000), format
1189 (\c S16), channels (2), and period_time (125000).
1190 For using other configuration, you have to set the value explicitly
1191 in the slave PCM definition.  The rate, format and channels can be
1192 covered by an additional \ref pcm_plugins_dmix "plug plugin",
1193 but there is only one base configuration, anyway.
1194
1195 An example configuration for setting 44100 Hz, \c S32_LE format
1196 as the slave PCM of "hw:0" is like below:
1197 \code
1198 pcm.dmix_44 {
1199         type dmix
1200         ipc_key 321456  # any unique value
1201         ipc_key_add_uid true
1202         slave {
1203                 pcm "hw:0"
1204                 format S32_LE
1205                 rate 44100
1206         }
1207 }
1208 \endcode
1209 You can hear 48000 Hz samples still using this dmix pcm via plug plugin
1210 like:
1211 \code
1212 % aplay -Dplug:dmix_44 foo_48k.wav
1213 \endcode
1214
1215 For using the dmix plugin for OSS emulation device, you have to set
1216 the period and the buffer sizes in power of two.  For example,
1217 \code
1218 pcm.dmixoss {
1219         type dmix
1220         ipc_key 321456  # any unique value
1221         ipc_key_add_uid true
1222         slave {
1223                 pcm "hw:0"
1224                 period_time 0
1225                 period_size 1024  # must be power of 2
1226                 buffer_size 8192  # ditto
1227         }
1228 }
1229 \endcode
1230 <code>period_time 0</code> must be set, too, for resetting the
1231 default value.  In the case of soundcards with multi-channel IO,
1232 adding the bindings would help
1233 \code
1234 pcm.dmixoss {
1235         ...
1236         bindings {
1237                 0 0   # map from 0 to 0
1238                 1 1   # map from 1 to 1
1239         }
1240 }
1241 \endcode
1242 so that only the first two channels are used by dmix.
1243 Also, note that ICE1712 have the limited buffer size, 5513 frames
1244 (corresponding to 640 kB).  In this case, reduce the buffer_size
1245 to 4096.
1246
1247 \subsection pcm_plugins_dmix_funcref Function reference
1248
1249 <UL>
1250   <LI>snd_pcm_dmix_open()
1251   <LI>_snd_pcm_dmix_open()
1252 </UL>
1253
1254 */
1255
1256 /**
1257  * \brief Creates a new dmix PCM
1258  * \param pcmp Returns created PCM handle
1259  * \param name Name of PCM
1260  * \param root Root configuration node
1261  * \param conf Configuration node with dmix PCM description
1262  * \param stream PCM Stream
1263  * \param mode PCM Mode
1264  * \warning Using of this function might be dangerous in the sense
1265  *          of compatibility reasons. The prototype might be freely
1266  *          changed in future.
1267  */
1268 int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
1269                        snd_config_t *root, snd_config_t *conf,
1270                        snd_pcm_stream_t stream, int mode)
1271 {
1272         snd_config_t *sconf;
1273         struct slave_params params;
1274         struct snd_pcm_direct_open_conf dopen;
1275         int bsize, psize;
1276         int err;
1277
1278         err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen);
1279         if (err < 0)
1280                 return err;
1281
1282         /* the default settings, it might be invalid for some hardware */
1283         params.format = SND_PCM_FORMAT_S16;
1284         params.rate = 48000;
1285         params.channels = 2;
1286         params.period_time = -1;
1287         params.buffer_time = -1;
1288         bsize = psize = -1;
1289         params.periods = 3;
1290
1291         err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8,
1292                                  SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, &params.format,
1293                                  SND_PCM_HW_PARAM_RATE, 0, &params.rate,
1294                                  SND_PCM_HW_PARAM_CHANNELS, 0, &params.channels,
1295                                  SND_PCM_HW_PARAM_PERIOD_TIME, 0, &params.period_time,
1296                                  SND_PCM_HW_PARAM_BUFFER_TIME, 0, &params.buffer_time,
1297                                  SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
1298                                  SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
1299                                  SND_PCM_HW_PARAM_PERIODS, 0, &params.periods);
1300         if (err < 0)
1301                 return err;
1302
1303         /* set a reasonable default */  
1304         if (psize == -1 && params.period_time == -1)
1305                 params.period_time = 125000;    /* 0.125 seconds */
1306
1307         if (params.format == -2)
1308                 params.format = SND_PCM_FORMAT_UNKNOWN;
1309         else if (!(dmix_supported_format & (1ULL << params.format))) {
1310                 /* sorry, limited features */
1311                 SNDERR("Unsupported format");
1312                 snd_config_delete(sconf);
1313                 return -EINVAL;
1314         }
1315
1316         params.period_size = psize;
1317         params.buffer_size = bsize;
1318
1319         err = snd_pcm_dmix_open(pcmp, name, &dopen, &params,
1320                                 root, sconf, stream, mode);
1321         snd_config_delete(sconf);
1322         return err;
1323 }
1324 #ifndef DOC_HIDDEN
1325 SND_DLSYM_BUILD_VERSION(_snd_pcm_dmix_open, SND_PCM_DLSYM_VERSION);
1326 #endif