Update /hal/etc/asound.conf to load as well
[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->tstamp_type);
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->tstamp_type);
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->tstamp_type);
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_playback_hw_rewindable(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         int err;
673         const snd_pcm_channel_area_t *src_areas, *dst_areas;
674
675         if (dmix->state == SND_PCM_STATE_RUNNING ||
676             dmix->state == SND_PCM_STATE_DRAINING) {
677                 err = snd_pcm_dmix_hwsync(pcm);
678                 if (err < 0)
679                         return err;
680         }
681
682         if (dmix->last_appl_ptr < dmix->appl_ptr)
683                 size = dmix->appl_ptr - dmix->last_appl_ptr;
684         else
685                 size = dmix->appl_ptr + (pcm->boundary - dmix->last_appl_ptr);
686         if (frames < size)
687                 size = frames;
688         snd_pcm_mmap_appl_backward(pcm, size);
689         frames -= size;
690         if (!frames)
691                 return size;
692         result = size;
693
694         if (dmix->hw_ptr < dmix->appl_ptr)
695                 size = dmix->appl_ptr - dmix->hw_ptr;
696         else
697                 size = dmix->appl_ptr + (pcm->boundary - dmix->hw_ptr);
698         if (size > frames)
699                 size = frames;
700         if (dmix->slave_hw_ptr < dmix->slave_appl_ptr)
701                 slave_size = dmix->slave_appl_ptr - dmix->slave_hw_ptr;
702         else
703                 slave_size = dmix->slave_appl_ptr + (pcm->boundary - dmix->slave_hw_ptr);
704         if (slave_size < size)
705                 size = slave_size;
706         frames -= size;
707         result += size;
708                 
709         /* add sample areas here */
710         src_areas = snd_pcm_mmap_areas(pcm);
711         dst_areas = snd_pcm_mmap_areas(dmix->spcm);
712         dmix->last_appl_ptr -= size;
713         dmix->last_appl_ptr %= pcm->boundary;
714         appl_ptr = dmix->last_appl_ptr % pcm->buffer_size;
715         dmix->slave_appl_ptr -= size;
716         dmix->slave_appl_ptr %= dmix->slave_boundary;
717         slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size;
718         dmix_down_sem(dmix);
719         for (;;) {
720                 transfer = size;
721                 if (appl_ptr + transfer > pcm->buffer_size)
722                         transfer = pcm->buffer_size - appl_ptr;
723                 if (slave_appl_ptr + transfer > dmix->slave_buffer_size)
724                         transfer = dmix->slave_buffer_size - slave_appl_ptr;
725                 remix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
726                 size -= transfer;
727                 if (! size)
728                         break;
729                 slave_appl_ptr += transfer;
730                 slave_appl_ptr %= dmix->slave_buffer_size;
731                 appl_ptr += transfer;
732                 appl_ptr %= pcm->buffer_size;
733         }
734         dmix->last_appl_ptr -= frames;
735         dmix->last_appl_ptr %= pcm->boundary;
736         dmix->slave_appl_ptr -= frames;
737         dmix->slave_appl_ptr %= dmix->slave_boundary;
738         dmix_up_sem(dmix);
739
740         snd_pcm_mmap_appl_backward(pcm, frames);
741
742         return result + frames;
743 }
744
745 static snd_pcm_sframes_t snd_pcm_dmix_forwardable(snd_pcm_t *pcm)
746 {
747         return snd_pcm_mmap_avail(pcm);
748 }
749
750 static snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
751 {
752         snd_pcm_sframes_t avail;
753
754         avail = snd_pcm_dmix_forwardable(pcm);
755         if (frames > (snd_pcm_uframes_t)avail)
756                 frames = avail;
757         snd_pcm_mmap_appl_forward(pcm, frames);
758         return frames;
759 }
760
761 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)
762 {
763         return -ENODEV;
764 }
765
766 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)
767 {
768         return -ENODEV;
769 }
770
771 static int snd_pcm_dmix_close(snd_pcm_t *pcm)
772 {
773         snd_pcm_direct_t *dmix = pcm->private_data;
774
775         if (dmix->timer)
776                 snd_timer_close(dmix->timer);
777         snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
778         snd_pcm_close(dmix->spcm);
779         if (dmix->server)
780                 snd_pcm_direct_server_discard(dmix);
781         if (dmix->client)
782                 snd_pcm_direct_client_discard(dmix);
783         shm_sum_discard(dmix);
784         if (snd_pcm_direct_shm_discard(dmix)) {
785                 if (snd_pcm_direct_semaphore_discard(dmix))
786                         snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT);
787         } else
788                 snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT);
789         free(dmix->bindings);
790         pcm->private_data = NULL;
791         free(dmix);
792         return 0;
793 }
794
795 static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm,
796                                                   snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
797                                                   snd_pcm_uframes_t size)
798 {
799         snd_pcm_direct_t *dmix = pcm->private_data;
800         int err;
801
802         switch (snd_pcm_state(dmix->spcm)) {
803         case SND_PCM_STATE_XRUN:
804                 return -EPIPE;
805         case SND_PCM_STATE_SUSPENDED:
806                 return -ESTRPIPE;
807         default:
808                 break;
809         }
810         if (! size)
811                 return 0;
812         snd_pcm_mmap_appl_forward(pcm, size);
813         if (dmix->state == STATE_RUN_PENDING) {
814                 if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0)
815                         return err;
816         } else if (dmix->state == SND_PCM_STATE_RUNNING ||
817                    dmix->state == SND_PCM_STATE_DRAINING)
818                 snd_pcm_dmix_sync_ptr(pcm);
819         if (dmix->state == SND_PCM_STATE_RUNNING ||
820             dmix->state == SND_PCM_STATE_DRAINING) {
821                 /* ok, we commit the changes after the validation of area */
822                 /* it's intended, although the result might be crappy */
823                 snd_pcm_dmix_sync_area(pcm);
824                 /* clear timer queue to avoid a bogus return from poll */
825                 if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min)
826                         snd_pcm_direct_clear_timer_queue(dmix);
827         }
828         return size;
829 }
830
831 static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm)
832 {
833         snd_pcm_direct_t *dmix = pcm->private_data;
834         
835         if (dmix->state == SND_PCM_STATE_RUNNING ||
836             dmix->state == SND_PCM_STATE_DRAINING)
837                 snd_pcm_dmix_sync_ptr(pcm);
838         return snd_pcm_mmap_playback_avail(pcm);
839 }
840
841 static int snd_pcm_dmix_htimestamp(snd_pcm_t *pcm,
842                                    snd_pcm_uframes_t *avail,
843                                    snd_htimestamp_t *tstamp)
844 {
845         snd_pcm_direct_t *dmix = pcm->private_data;
846         snd_pcm_uframes_t avail1;
847         int ok = 0;
848         
849         while (1) {
850                 if (dmix->state == SND_PCM_STATE_RUNNING ||
851                     dmix->state == SND_PCM_STATE_DRAINING)
852                         snd_pcm_dmix_sync_ptr(pcm);
853                 avail1 = snd_pcm_mmap_playback_avail(pcm);
854                 if (ok && *avail == avail1)
855                         break;
856                 *avail = avail1;
857                 *tstamp = snd_pcm_hw_fast_tstamp(dmix->spcm);
858                 ok = 1;
859         }
860         return 0;
861 }
862
863 static int snd_pcm_dmix_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
864 {
865         snd_pcm_direct_t *dmix = pcm->private_data;
866         if (dmix->state == SND_PCM_STATE_RUNNING)
867                 snd_pcm_dmix_sync_area(pcm);
868         return snd_pcm_direct_poll_revents(pcm, pfds, nfds, revents);
869 }
870
871
872 static void snd_pcm_dmix_dump(snd_pcm_t *pcm, snd_output_t *out)
873 {
874         snd_pcm_direct_t *dmix = pcm->private_data;
875
876         snd_output_printf(out, "Direct Stream Mixing PCM\n");
877         if (pcm->setup) {
878                 snd_output_printf(out, "Its setup is:\n");
879                 snd_pcm_dump_setup(pcm, out);
880         }
881         if (dmix->spcm)
882                 snd_pcm_dump(dmix->spcm, out);
883 }
884
885 static const snd_pcm_ops_t snd_pcm_dmix_ops = {
886         .close = snd_pcm_dmix_close,
887         .info = snd_pcm_direct_info,
888         .hw_refine = snd_pcm_direct_hw_refine,
889         .hw_params = snd_pcm_direct_hw_params,
890         .hw_free = snd_pcm_direct_hw_free,
891         .sw_params = snd_pcm_direct_sw_params,
892         .channel_info = snd_pcm_direct_channel_info,
893         .dump = snd_pcm_dmix_dump,
894         .nonblock = snd_pcm_direct_nonblock,
895         .async = snd_pcm_direct_async,
896         .mmap = snd_pcm_direct_mmap,
897         .munmap = snd_pcm_direct_munmap,
898         .query_chmaps = snd_pcm_direct_query_chmaps,
899         .get_chmap = snd_pcm_direct_get_chmap,
900         .set_chmap = snd_pcm_direct_set_chmap,
901 };
902
903 static const snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
904         .status = snd_pcm_dmix_status,
905         .state = snd_pcm_dmix_state,
906         .hwsync = snd_pcm_dmix_hwsync,
907         .delay = snd_pcm_dmix_delay,
908         .prepare = snd_pcm_dmix_prepare,
909         .reset = snd_pcm_dmix_reset,
910         .start = snd_pcm_dmix_start,
911         .drop = snd_pcm_dmix_drop,
912         .drain = snd_pcm_dmix_drain,
913         .pause = snd_pcm_dmix_pause,
914         .rewindable = snd_pcm_dmix_rewindable,
915         .rewind = snd_pcm_dmix_rewind,
916         .forwardable = snd_pcm_dmix_forwardable,
917         .forward = snd_pcm_dmix_forward,
918         .resume = snd_pcm_direct_resume,
919         .link = NULL,
920         .link_slaves = NULL,
921         .unlink = NULL,
922         .writei = snd_pcm_mmap_writei,
923         .writen = snd_pcm_mmap_writen,
924         .readi = snd_pcm_dmix_readi,
925         .readn = snd_pcm_dmix_readn,
926         .avail_update = snd_pcm_dmix_avail_update,
927         .mmap_commit = snd_pcm_dmix_mmap_commit,
928         .htimestamp = snd_pcm_dmix_htimestamp,
929         .poll_descriptors = NULL,
930         .poll_descriptors_count = NULL,
931         .poll_revents = snd_pcm_dmix_poll_revents,
932 };
933
934 /**
935  * \brief Creates a new dmix PCM
936  * \param pcmp Returns created PCM handle
937  * \param name Name of PCM
938  * \param opts Direct PCM configurations
939  * \param params Parameters for slave
940  * \param root Configuration root
941  * \param sconf Slave configuration
942  * \param stream PCM Direction (stream)
943  * \param mode PCM Mode
944  * \retval zero on success otherwise a negative error code
945  * \warning Using of this function might be dangerous in the sense
946  *          of compatibility reasons. The prototype might be freely
947  *          changed in future.
948  */
949 int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
950                       struct snd_pcm_direct_open_conf *opts,
951                       struct slave_params *params,
952                       snd_config_t *root, snd_config_t *sconf,
953                       snd_pcm_stream_t stream, int mode)
954 {
955         snd_pcm_t *pcm = NULL, *spcm = NULL;
956         snd_pcm_direct_t *dmix = NULL;
957         int ret, first_instance;
958         int fail_sem_loop = 10;
959
960         assert(pcmp);
961
962         if (stream != SND_PCM_STREAM_PLAYBACK) {
963                 SNDERR("The dmix plugin supports only playback stream");
964                 return -EINVAL;
965         }
966
967         dmix = calloc(1, sizeof(snd_pcm_direct_t));
968         if (!dmix) {
969                 ret = -ENOMEM;
970                 goto _err_nosem;
971         }
972         
973         ret = snd_pcm_direct_parse_bindings(dmix, params, opts->bindings);
974         if (ret < 0)
975                 goto _err_nosem;
976         
977         dmix->ipc_key = opts->ipc_key;
978         dmix->ipc_perm = opts->ipc_perm;
979         dmix->ipc_gid = opts->ipc_gid;
980         dmix->semid = -1;
981         dmix->shmid = -1;
982
983         ret = snd_pcm_new(&pcm, dmix->type = SND_PCM_TYPE_DMIX, name, stream, mode);
984         if (ret < 0)
985                 goto _err;
986
987         
988         while (1) {
989                 ret = snd_pcm_direct_semaphore_create_or_connect(dmix);
990                 if (ret < 0) {
991                         SNDERR("unable to create IPC semaphore");
992                         goto _err_nosem;
993                 }
994                 ret = snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
995                 if (ret < 0) {
996                         snd_pcm_direct_semaphore_discard(dmix);
997                         if (--fail_sem_loop <= 0)
998                                 goto _err_nosem;
999                         continue;
1000                 }
1001                 break;
1002         }
1003                 
1004         first_instance = ret = snd_pcm_direct_shm_create_or_connect(dmix);
1005         if (ret < 0) {
1006                 SNDERR("unable to create IPC shm instance");
1007                 goto _err;
1008         }
1009                 
1010         pcm->ops = &snd_pcm_dmix_ops;
1011         pcm->fast_ops = &snd_pcm_dmix_fast_ops;
1012         pcm->private_data = dmix;
1013         dmix->state = SND_PCM_STATE_OPEN;
1014         dmix->slowptr = opts->slowptr;
1015         dmix->max_periods = opts->max_periods;
1016         dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
1017
1018         if (first_instance) {
1019                 /* recursion is already checked in
1020                    snd_pcm_direct_get_slave_ipc_offset() */
1021                 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
1022                                          mode | SND_PCM_NONBLOCK, NULL);
1023                 if (ret < 0) {
1024                         SNDERR("unable to open slave");
1025                         goto _err;
1026                 }
1027         
1028                 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
1029                         SNDERR("dmix plugin can be only connected to hw plugin");
1030                         ret = -EINVAL;
1031                         goto _err;
1032                 }
1033                 
1034                 ret = snd_pcm_direct_initialize_slave(dmix, spcm, params);
1035                 if (ret < 0) {
1036                         SNDERR("unable to initialize slave");
1037                         goto _err;
1038                 }
1039
1040                 dmix->spcm = spcm;
1041
1042                 if (dmix->shmptr->use_server) {
1043                         dmix->server_free = dmix_server_free;
1044                 
1045                         ret = snd_pcm_direct_server_create(dmix);
1046                         if (ret < 0) {
1047                                 SNDERR("unable to create server");
1048                                 goto _err;
1049                         }
1050                 }
1051
1052                 dmix->shmptr->type = spcm->type;
1053         } else {
1054                 if (dmix->shmptr->use_server) {
1055                         /* up semaphore to avoid deadlock */
1056                         snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1057                         ret = snd_pcm_direct_client_connect(dmix);
1058                         if (ret < 0) {
1059                                 SNDERR("unable to connect client");
1060                                 goto _err_nosem;
1061                         }
1062                         
1063                         snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
1064                         ret = snd_pcm_direct_open_secondary_client(&spcm, dmix, "dmix_client");
1065                         if (ret < 0)
1066                                 goto _err;
1067                 } else {
1068
1069                         ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
1070                                                  mode | SND_PCM_NONBLOCK |
1071                                                  SND_PCM_APPEND,
1072                                                  NULL);
1073                         if (ret < 0) {
1074                                 SNDERR("unable to open slave");
1075                                 goto _err;
1076                         }
1077                         if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
1078                                 SNDERR("dmix plugin can be only connected to hw plugin");
1079                                 ret = -EINVAL;
1080                                 goto _err;
1081                         }
1082                 
1083                         ret = snd_pcm_direct_initialize_secondary_slave(dmix, spcm, params);
1084                         if (ret < 0) {
1085                                 SNDERR("unable to initialize slave");
1086                                 goto _err;
1087                         }
1088                 }
1089
1090                 dmix->spcm = spcm;
1091         }
1092
1093         ret = shm_sum_create_or_connect(dmix);
1094         if (ret < 0) {
1095                 SNDERR("unable to initialize sum ring buffer");
1096                 goto _err;
1097         }
1098
1099         ret = snd_pcm_direct_initialize_poll_fd(dmix);
1100         if (ret < 0) {
1101                 SNDERR("unable to initialize poll_fd");
1102                 goto _err;
1103         }
1104
1105         mix_select_callbacks(dmix);
1106                 
1107         pcm->poll_fd = dmix->poll_fd;
1108         pcm->poll_events = POLLIN;      /* it's different than other plugins */
1109         pcm->tstamp_type = spcm->tstamp_type;
1110         pcm->mmap_rw = 1;
1111         snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0);
1112         snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0);
1113         
1114         if (dmix->channels == UINT_MAX)
1115                 dmix->channels = dmix->shmptr->s.channels;
1116
1117         snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1118
1119         *pcmp = pcm;
1120         return 0;
1121         
1122  _err:
1123         if (dmix->timer)
1124                 snd_timer_close(dmix->timer);
1125         if (dmix->server)
1126                 snd_pcm_direct_server_discard(dmix);
1127         if (dmix->client)
1128                 snd_pcm_direct_client_discard(dmix);
1129         if (spcm)
1130                 snd_pcm_close(spcm);
1131         if (dmix->u.dmix.shmid_sum >= 0)
1132                 shm_sum_discard(dmix);
1133         if (dmix->shmid >= 0)
1134                 snd_pcm_direct_shm_discard(dmix);
1135         if (snd_pcm_direct_semaphore_discard(dmix) < 0)
1136                 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1137  _err_nosem:
1138         if (dmix) {
1139                 free(dmix->bindings);
1140                 free(dmix);
1141         }
1142         if (pcm)
1143                 snd_pcm_free(pcm);
1144         return ret;
1145 }
1146
1147 /*! \page pcm_plugins
1148
1149 \section pcm_plugins_dmix Plugin: dmix
1150
1151 This plugin provides direct mixing of multiple streams. The resolution
1152 for 32-bit mixing is only 24-bit. The low significant byte is filled with
1153 zeros. The extra 8 bits are used for the saturation.
1154
1155 \code
1156 pcm.name {
1157         type dmix               # Direct mix
1158         ipc_key INT             # unique IPC key
1159         ipc_key_add_uid BOOL    # add current uid to unique IPC key
1160         ipc_perm INT            # IPC permissions (octal, default 0600)
1161         slave STR
1162         # or
1163         slave {                 # Slave definition
1164                 pcm STR         # slave PCM name
1165                 # or
1166                 pcm { }         # slave PCM definition
1167                 format STR      # format definition
1168                 rate INT        # rate definition
1169                 channels INT
1170                 period_time INT # in usec
1171                 # or
1172                 period_size INT # in bytes
1173                 buffer_time INT # in usec
1174                 # or
1175                 buffer_size INT # in bytes
1176                 periods INT     # when buffer_size or buffer_time is not specified
1177         }
1178         bindings {              # note: this is client independent!!!
1179                 N INT           # maps slave channel to client channel N
1180         }
1181         slowptr BOOL            # slow but more precise pointer updates
1182 }
1183 \endcode
1184
1185 <code>ipc_key</code> specfies the unique IPC key in integer.
1186 This number must be unique for each different dmix definition,
1187 since the shared memory is created with this key number.
1188 When <code>ipc_key_add_uid</code> is set true, the uid value is
1189 added to the value set in <code>ipc_key</code>.  This will
1190 avoid the confliction of the same IPC key with different users
1191 concurrently.
1192
1193 Note that the dmix plugin itself supports only a single configuration.
1194 That is, it supports only the fixed rate (default 48000), format
1195 (\c S16), channels (2), and period_time (125000).
1196 For using other configuration, you have to set the value explicitly
1197 in the slave PCM definition.  The rate, format and channels can be
1198 covered by an additional \ref pcm_plugins_dmix "plug plugin",
1199 but there is only one base configuration, anyway.
1200
1201 An example configuration for setting 44100 Hz, \c S32_LE format
1202 as the slave PCM of "hw:0" is like below:
1203 \code
1204 pcm.dmix_44 {
1205         type dmix
1206         ipc_key 321456  # any unique value
1207         ipc_key_add_uid true
1208         slave {
1209                 pcm "hw:0"
1210                 format S32_LE
1211                 rate 44100
1212         }
1213 }
1214 \endcode
1215 You can hear 48000 Hz samples still using this dmix pcm via plug plugin
1216 like:
1217 \code
1218 % aplay -Dplug:dmix_44 foo_48k.wav
1219 \endcode
1220
1221 For using the dmix plugin for OSS emulation device, you have to set
1222 the period and the buffer sizes in power of two.  For example,
1223 \code
1224 pcm.dmixoss {
1225         type dmix
1226         ipc_key 321456  # any unique value
1227         ipc_key_add_uid true
1228         slave {
1229                 pcm "hw:0"
1230                 period_time 0
1231                 period_size 1024  # must be power of 2
1232                 buffer_size 8192  # ditto
1233         }
1234 }
1235 \endcode
1236 <code>period_time 0</code> must be set, too, for resetting the
1237 default value.  In the case of soundcards with multi-channel IO,
1238 adding the bindings would help
1239 \code
1240 pcm.dmixoss {
1241         ...
1242         bindings {
1243                 0 0   # map from 0 to 0
1244                 1 1   # map from 1 to 1
1245         }
1246 }
1247 \endcode
1248 so that only the first two channels are used by dmix.
1249 Also, note that ICE1712 have the limited buffer size, 5513 frames
1250 (corresponding to 640 kB).  In this case, reduce the buffer_size
1251 to 4096.
1252
1253 \subsection pcm_plugins_dmix_funcref Function reference
1254
1255 <UL>
1256   <LI>snd_pcm_dmix_open()
1257   <LI>_snd_pcm_dmix_open()
1258 </UL>
1259
1260 */
1261
1262 /**
1263  * \brief Creates a new dmix PCM
1264  * \param pcmp Returns created PCM handle
1265  * \param name Name of PCM
1266  * \param root Root configuration node
1267  * \param conf Configuration node with dmix PCM description
1268  * \param stream PCM Stream
1269  * \param mode PCM Mode
1270  * \warning Using of this function might be dangerous in the sense
1271  *          of compatibility reasons. The prototype might be freely
1272  *          changed in future.
1273  */
1274 int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
1275                        snd_config_t *root, snd_config_t *conf,
1276                        snd_pcm_stream_t stream, int mode)
1277 {
1278         snd_config_t *sconf;
1279         struct slave_params params;
1280         struct snd_pcm_direct_open_conf dopen;
1281         int bsize, psize;
1282         int err;
1283
1284         err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen);
1285         if (err < 0)
1286                 return err;
1287
1288         /* the default settings, it might be invalid for some hardware */
1289         params.format = SND_PCM_FORMAT_S16;
1290         params.rate = 48000;
1291         params.channels = 2;
1292         params.period_time = -1;
1293         params.buffer_time = -1;
1294         bsize = psize = -1;
1295         params.periods = 3;
1296
1297         err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8,
1298                                  SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, &params.format,
1299                                  SND_PCM_HW_PARAM_RATE, 0, &params.rate,
1300                                  SND_PCM_HW_PARAM_CHANNELS, 0, &params.channels,
1301                                  SND_PCM_HW_PARAM_PERIOD_TIME, 0, &params.period_time,
1302                                  SND_PCM_HW_PARAM_BUFFER_TIME, 0, &params.buffer_time,
1303                                  SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
1304                                  SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
1305                                  SND_PCM_HW_PARAM_PERIODS, 0, &params.periods);
1306         if (err < 0)
1307                 return err;
1308
1309         /* set a reasonable default */  
1310         if (psize == -1 && params.period_time == -1)
1311                 params.period_time = 125000;    /* 0.125 seconds */
1312
1313         if (params.format == -2)
1314                 params.format = SND_PCM_FORMAT_UNKNOWN;
1315         else if (!(dmix_supported_format & (1ULL << params.format))) {
1316                 /* sorry, limited features */
1317                 SNDERR("Unsupported format");
1318                 snd_config_delete(sconf);
1319                 return -EINVAL;
1320         }
1321
1322         params.period_size = psize;
1323         params.buffer_size = bsize;
1324
1325         err = snd_pcm_dmix_open(pcmp, name, &dopen, &params,
1326                                 root, sconf, stream, mode);
1327         snd_config_delete(sconf);
1328         return err;
1329 }
1330 #ifndef DOC_HIDDEN
1331 SND_DLSYM_BUILD_VERSION(_snd_pcm_dmix_open, SND_PCM_DLSYM_VERSION);
1332 #endif