OSDN Git Service

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