OSDN Git Service

Remove pause and fix timer initialization in prepare
[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@suse.cz>
6  * \date 2003
7  */
8 /*
9  *  PCM - Direct Stream Mixing
10  *  Copyright (c) 2003 by Jaroslav Kysela <perex@suse.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 <sys/ioctl.h>
38 #include <sys/mman.h>
39 #include <sys/shm.h>
40 #include <sys/sem.h>
41 #include <sys/wait.h>
42 #include <sys/socket.h>
43 #include <sys/un.h>
44 #include <sys/mman.h>
45 #include "pcm_direct.h"
46
47 #ifndef PIC
48 /* entry for static linking */
49 const char *_snd_module_pcm_dmix = "";
50 #endif
51
52 /* start is pending - this state happens when rate plugin does a delayed commit */
53 #define STATE_RUN_PENDING       1024
54
55 /*
56  *
57  */
58
59 static int shm_sum_discard(snd_pcm_direct_t *dmix);
60
61 /*
62  *  sum ring buffer shared memory area 
63  */
64 static int shm_sum_create_or_connect(snd_pcm_direct_t *dmix)
65 {
66         struct shmid_ds buf;
67         int tmpid, err;
68         size_t size;
69
70         size = dmix->shmptr->s.channels *
71                dmix->shmptr->s.buffer_size *
72                sizeof(signed int);      
73 retryshm:
74         dmix->u.dmix.shmid_sum = shmget(dmix->ipc_key + 1, size, IPC_CREAT | 0666);
75         err = -errno;
76         if (dmix->u.dmix.shmid_sum < 0){
77                 if (errno == EINVAL)
78                 if ((tmpid = shmget(dmix->ipc_key + 1, 0, 0666)) != -1)
79                 if (!shmctl(tmpid, IPC_STAT, &buf))
80                 if (!buf.shm_nattch) 
81                 /* no users so destroy the segment */
82                 if (!shmctl(tmpid, IPC_RMID, NULL))
83                     goto retryshm;
84                 return err;
85         }
86         dmix->u.dmix.sum_buffer = shmat(dmix->u.dmix.shmid_sum, 0, 0);
87         if (dmix->u.dmix.sum_buffer == (void *) -1) {
88                 shm_sum_discard(dmix);
89                 return -errno;
90         }
91         mlock(dmix->u.dmix.sum_buffer, size);
92         return 0;
93 }
94
95 static int shm_sum_discard(snd_pcm_direct_t *dmix)
96 {
97         struct shmid_ds buf;
98         int ret = 0;
99
100         if (dmix->u.dmix.shmid_sum < 0)
101                 return -EINVAL;
102         if (dmix->u.dmix.sum_buffer != (void *) -1 && shmdt(dmix->u.dmix.sum_buffer) < 0)
103                 return -errno;
104         dmix->u.dmix.sum_buffer = (void *) -1;
105         if (shmctl(dmix->u.dmix.shmid_sum, IPC_STAT, &buf) < 0)
106                 return -errno;
107         if (buf.shm_nattch == 0) {      /* we're the last user, destroy the segment */
108                 if (shmctl(dmix->u.dmix.shmid_sum, IPC_RMID, NULL) < 0)
109                         return -errno;
110                 ret = 1;
111         }
112         dmix->u.dmix.shmid_sum = -1;
113         return ret;
114 }
115
116 static void dmix_server_free(snd_pcm_direct_t *dmix)
117 {
118         /* remove the memory region */
119         shm_sum_create_or_connect(dmix);
120         shm_sum_discard(dmix);
121 }
122
123 /*
124  *  the main function of this plugin: mixing
125  *  FIXME: optimize it for different architectures
126  */
127
128 #if defined(__i386__)
129 #include "pcm_dmix_i386.c"
130 #elif defined(__x86_64__)
131 #include "pcm_dmix_x86_64.c"
132 #else
133 #include "pcm_dmix_generic.c"
134 #endif
135
136 static void mix_areas(snd_pcm_direct_t *dmix,
137                       const snd_pcm_channel_area_t *src_areas,
138                       const snd_pcm_channel_area_t *dst_areas,
139                       snd_pcm_uframes_t src_ofs,
140                       snd_pcm_uframes_t dst_ofs,
141                       snd_pcm_uframes_t size)
142 {
143         volatile signed int *sum;
144         unsigned int src_step, dst_step;
145         unsigned int chn, dchn, channels;
146         
147         channels = dmix->channels;
148         if (dmix->shmptr->s.format == SND_PCM_FORMAT_S16) {
149                 signed short *src;
150                 volatile signed short *dst;
151                 if (dmix->interleaved) {
152                         /*
153                          * process all areas in one loop
154                          * it optimizes the memory accesses for this case
155                          */
156                         dmix->u.dmix.mix_areas1(size * channels,
157                                          ((signed short *)dst_areas[0].addr) + (dst_ofs * channels),
158                                          ((signed short *)src_areas[0].addr) + (src_ofs * channels),
159                                          dmix->u.dmix.sum_buffer + (dst_ofs * channels),
160                                          sizeof(signed short),
161                                          sizeof(signed short),
162                                          sizeof(signed int));
163                         return;
164                 }
165                 for (chn = 0; chn < channels; chn++) {
166                         dchn = dmix->bindings ? dmix->bindings[chn] : chn;
167                         if (dchn >= dmix->shmptr->s.channels)
168                                 continue;
169                         src_step = src_areas[chn].step / 8;
170                         dst_step = dst_areas[dchn].step / 8;
171                         src = (signed short *)(((char *)src_areas[chn].addr + src_areas[chn].first / 8) + (src_ofs * src_step));
172                         dst = (signed short *)(((char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + (dst_ofs * dst_step));
173                         sum = dmix->u.dmix.sum_buffer + channels * dst_ofs + chn;
174                         dmix->u.dmix.mix_areas1(size, dst, src, sum, dst_step, src_step, channels * sizeof(signed int));
175                 }
176         } else {
177                 signed int *src;
178                 volatile signed int *dst;
179                 if (dmix->interleaved) {
180                         /*
181                          * process all areas in one loop
182                          * it optimizes the memory accesses for this case
183                          */
184                         dmix->u.dmix.mix_areas2(size * channels,
185                                          ((signed int *)dst_areas[0].addr) + (dst_ofs * channels),
186                                          ((signed int *)src_areas[0].addr) + (src_ofs * channels),
187                                          dmix->u.dmix.sum_buffer + (dst_ofs * channels),
188                                          sizeof(signed int),
189                                          sizeof(signed int),
190                                          sizeof(signed int));
191                         return;
192                 }
193                 for (chn = 0; chn < channels; chn++) {
194                         dchn = dmix->bindings ? dmix->bindings[chn] : chn;
195                         if (dchn >= dmix->shmptr->s.channels)
196                                 continue;
197                         src_step = src_areas[chn].step / 8;
198                         dst_step = dst_areas[dchn].step / 8;
199                         src = (signed int *)(((char *)src_areas[chn].addr + src_areas[chn].first / 8) + (src_ofs * src_step));
200                         dst = (signed int *)(((char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + (dst_ofs * dst_step));
201                         sum = dmix->u.dmix.sum_buffer + channels * dst_ofs + chn;
202                         dmix->u.dmix.mix_areas2(size, dst, src, sum, dst_step, src_step, channels * sizeof(signed int));
203                 }
204         }
205 }
206
207 /*
208  * if no concurrent access is allowed in the mixing routines, we need to protect
209  * the area via semaphore
210  */
211 #ifdef NO_CONCURRENT_ACCESS
212 #define dmix_down_sem(dmix) snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT)
213 #define dmix_up_sem(dmix) snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT)
214 #else
215 #define dmix_down_sem(dmix)
216 #define dmix_up_sem(dmix)
217 #endif
218
219 /*
220  *  synchronize shm ring buffer with hardware
221  */
222 static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm, snd_pcm_uframes_t size)
223 {
224         snd_pcm_direct_t *dmix = pcm->private_data;
225         snd_pcm_uframes_t appl_ptr, slave_appl_ptr, transfer;
226         const snd_pcm_channel_area_t *src_areas, *dst_areas;
227         
228         /* get the start of update area */
229         appl_ptr = dmix->appl_ptr - size;
230         if (appl_ptr > pcm->boundary)
231                 appl_ptr += pcm->boundary;
232         appl_ptr %= pcm->buffer_size;
233         /* add sample areas here */
234         src_areas = snd_pcm_mmap_areas(pcm);
235         dst_areas = snd_pcm_mmap_areas(dmix->spcm);
236         slave_appl_ptr = dmix->slave_appl_ptr % dmix->shmptr->s.buffer_size;
237         dmix->slave_appl_ptr += size;
238         dmix->slave_appl_ptr %= dmix->shmptr->s.boundary;
239         dmix_down_sem(dmix);
240         for (;;) {
241                 transfer = appl_ptr + size > pcm->buffer_size ? pcm->buffer_size - appl_ptr : size;
242                 if (slave_appl_ptr + transfer > dmix->shmptr->s.buffer_size)
243                         transfer = dmix->shmptr->s.buffer_size - slave_appl_ptr;
244                 if (! transfer)
245                         break;
246                 mix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
247                 if (transfer >= size)
248                         break;
249                 size -= transfer;
250                 slave_appl_ptr += transfer;
251                 slave_appl_ptr %= dmix->shmptr->s.buffer_size;
252                 appl_ptr += transfer;
253                 appl_ptr %= pcm->buffer_size;
254         }
255         dmix_up_sem(dmix);
256 }
257
258 /*
259  *  synchronize hardware pointer (hw_ptr) with ours
260  */
261 static int _snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm, int do_slave_sync)
262 {
263         snd_pcm_direct_t *dmix = pcm->private_data;
264         snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail;
265         snd_pcm_sframes_t diff;
266         
267         switch (snd_pcm_state(dmix->spcm)) {
268         case SND_PCM_STATE_DISCONNECTED:
269                 dmix->state = SND_PCM_STATE_DISCONNECTED;
270                 return -ENOTTY;
271         default:
272                 break;
273         }
274         if (do_slave_sync)
275                 snd_pcm_hwsync(dmix->spcm);
276         old_slave_hw_ptr = dmix->slave_hw_ptr;
277         slave_hw_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
278         diff = slave_hw_ptr - old_slave_hw_ptr;
279         if (diff == 0)          /* fast path */
280                 return 0;
281         if (dmix->state != SND_PCM_STATE_RUNNING &&
282             dmix->state != SND_PCM_STATE_DRAINING)
283                 /* not really started yet - don't update hw_ptr */
284                 return 0;
285         if (diff < 0) {
286                 slave_hw_ptr += dmix->shmptr->s.boundary;
287                 diff = slave_hw_ptr - old_slave_hw_ptr;
288         }
289         dmix->hw_ptr += diff;
290         dmix->hw_ptr %= pcm->boundary;
291         if (pcm->stop_threshold >= pcm->boundary)       /* don't care */
292                 return 0;
293         avail = snd_pcm_mmap_playback_avail(pcm);
294         if (avail > dmix->avail_max)
295                 dmix->avail_max = avail;
296         if (avail >= pcm->stop_threshold) {
297                 struct timeval tv;
298                 snd_pcm_direct_timer_stop(dmix);
299                 gettimeofday(&tv, 0);
300                 dmix->trigger_tstamp.tv_sec = tv.tv_sec;
301                 dmix->trigger_tstamp.tv_nsec = tv.tv_usec * 1000L;
302                 if (dmix->state == SND_PCM_STATE_RUNNING) {
303                         dmix->state = SND_PCM_STATE_XRUN;
304                         return -EPIPE;
305                 }
306                 dmix->state = SND_PCM_STATE_SETUP;
307         }
308         return 0;
309 }
310
311 static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm)
312 {
313         snd_pcm_direct_t *dmix = pcm->private_data;
314         return _snd_pcm_dmix_sync_ptr(pcm, dmix->slowptr);
315 }
316
317 /*
318  *  plugin implementation
319  */
320
321 static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm)
322 {
323         snd_pcm_direct_t *dmix = pcm->private_data;
324         snd_pcm_state_t state;
325         state = snd_pcm_state(dmix->spcm);
326         switch (state) {
327         case SND_PCM_STATE_SUSPENDED:
328                 return state;
329         case SND_PCM_STATE_DISCONNECTED:
330                 return state;
331         default:
332                 break;
333         }
334         if (dmix->state == STATE_RUN_PENDING)
335                 return SNDRV_PCM_STATE_RUNNING;
336         return dmix->state;
337 }
338
339 static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
340 {
341         snd_pcm_direct_t *dmix = pcm->private_data;
342
343         switch (dmix->state) {
344         case SNDRV_PCM_STATE_DRAINING:
345         case SNDRV_PCM_STATE_RUNNING:
346                 snd_pcm_dmix_sync_ptr(pcm);
347                 break;
348         default:
349                 break;
350         }
351         memset(status, 0, sizeof(*status));
352         status->state = snd_pcm_dmix_state(pcm);
353         status->trigger_tstamp = dmix->trigger_tstamp;
354         status->tstamp = snd_pcm_hw_fast_tstamp(dmix->spcm);
355         status->avail = snd_pcm_mmap_playback_avail(pcm);
356         status->avail_max = status->avail > dmix->avail_max ? status->avail : dmix->avail_max;
357         dmix->avail_max = 0;
358         return 0;
359 }
360
361 static int snd_pcm_dmix_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
362 {
363         snd_pcm_direct_t *dmix = pcm->private_data;
364         int err;
365         
366         switch(dmix->state) {
367         case SNDRV_PCM_STATE_DRAINING:
368         case SNDRV_PCM_STATE_RUNNING:
369                 err = snd_pcm_dmix_sync_ptr(pcm);
370                 if (err < 0)
371                         return err;
372                 /* fallthru */
373         case SNDRV_PCM_STATE_PREPARED:
374         case SNDRV_PCM_STATE_SUSPENDED:
375         case STATE_RUN_PENDING:
376                 *delayp = snd_pcm_mmap_playback_hw_avail(pcm);
377                 return 0;
378         case SNDRV_PCM_STATE_XRUN:
379                 return -EPIPE;
380         case SNDRV_PCM_STATE_DISCONNECTED:
381                 return -ENOTTY;
382         default:
383                 return -EBADFD;
384         }
385 }
386
387 static int snd_pcm_dmix_hwsync(snd_pcm_t *pcm)
388 {
389         snd_pcm_direct_t *dmix = pcm->private_data;
390
391         switch(dmix->state) {
392         case SNDRV_PCM_STATE_DRAINING:
393         case SNDRV_PCM_STATE_RUNNING:
394                 /* sync slave PCM */
395                 return _snd_pcm_dmix_sync_ptr(pcm, 1);
396         case SNDRV_PCM_STATE_PREPARED:
397         case SNDRV_PCM_STATE_SUSPENDED:
398         case STATE_RUN_PENDING:
399                 return 0;
400         case SNDRV_PCM_STATE_XRUN:
401                 return -EPIPE;
402         case SNDRV_PCM_STATE_DISCONNECTED:
403                 return -ENOTTY;
404         default:
405                 return -EBADFD;
406         }
407 }
408
409 static int snd_pcm_dmix_prepare(snd_pcm_t *pcm)
410 {
411         snd_pcm_direct_t *dmix = pcm->private_data;
412
413         snd_pcm_direct_check_interleave(dmix, pcm);
414         // assert(pcm->boundary == dmix->shmptr->s.boundary);   /* for sure */
415         dmix->state = SND_PCM_STATE_PREPARED;
416         dmix->appl_ptr = 0;
417         dmix->hw_ptr = 0;
418         return snd_pcm_direct_set_timer_params(dmix);
419 }
420
421 static int snd_pcm_dmix_reset(snd_pcm_t *pcm)
422 {
423         snd_pcm_direct_t *dmix = pcm->private_data;
424         dmix->hw_ptr %= pcm->period_size;
425         dmix->appl_ptr = dmix->hw_ptr;
426         dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
427         return 0;
428 }
429
430 static int snd_pcm_dmix_start_timer(snd_pcm_direct_t *dmix)
431 {
432         int err;
433
434         snd_pcm_hwsync(dmix->spcm);
435         dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
436         err = snd_timer_start(dmix->timer);
437         if (err < 0)
438                 return err;
439         dmix->state = SND_PCM_STATE_RUNNING;
440         return 0;
441 }
442
443 static int snd_pcm_dmix_start(snd_pcm_t *pcm)
444 {
445         snd_pcm_direct_t *dmix = pcm->private_data;
446         snd_pcm_sframes_t avail;
447         struct timeval tv;
448         int err;
449         
450         if (dmix->state != SND_PCM_STATE_PREPARED)
451                 return -EBADFD;
452         avail = snd_pcm_mmap_playback_hw_avail(pcm);
453         if (avail == 0)
454                 dmix->state = STATE_RUN_PENDING;
455         else if (avail < 0)
456                 return 0;
457         else {
458                 if (avail > (snd_pcm_sframes_t)pcm->buffer_size)
459                         avail = pcm->buffer_size;
460                 if ((err = snd_pcm_dmix_start_timer(dmix)) < 0)
461                         return err;
462                 snd_pcm_dmix_sync_area(pcm, avail);
463         }
464         gettimeofday(&tv, 0);
465         dmix->trigger_tstamp.tv_sec = tv.tv_sec;
466         dmix->trigger_tstamp.tv_nsec = tv.tv_usec * 1000L;
467         return 0;
468 }
469
470 static int snd_pcm_dmix_drop(snd_pcm_t *pcm)
471 {
472         snd_pcm_direct_t *dmix = pcm->private_data;
473         if (dmix->state == SND_PCM_STATE_OPEN)
474                 return -EBADFD;
475         snd_pcm_direct_timer_stop(dmix);
476         dmix->state = SND_PCM_STATE_SETUP;
477         return 0;
478 }
479
480 static int snd_pcm_dmix_drain(snd_pcm_t *pcm)
481 {
482         snd_pcm_direct_t *dmix = pcm->private_data;
483         snd_pcm_uframes_t stop_threshold;
484         int err;
485
486         if (dmix->state == SND_PCM_STATE_OPEN)
487                 return -EBADFD;
488         if (pcm->mode & SND_PCM_NONBLOCK)
489                 return -EAGAIN;
490         if (dmix->state == SND_PCM_STATE_PREPARED &&
491             snd_pcm_mmap_playback_hw_avail(pcm) > 0)
492                 snd_pcm_dmix_start(pcm);
493         stop_threshold = pcm->stop_threshold;
494         if (pcm->stop_threshold > pcm->buffer_size)
495                 pcm->stop_threshold = pcm->buffer_size;
496         dmix->state = SND_PCM_STATE_DRAINING;
497         do {
498                 err = snd_pcm_dmix_sync_ptr(pcm);
499                 if (err < 0) {
500                         snd_pcm_dmix_drop(pcm);
501                         return err;
502                 }
503                 if (dmix->state == SND_PCM_STATE_DRAINING) {
504                         snd_pcm_wait_nocheck(pcm, -1);
505                         snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */
506                 }
507         } while (dmix->state == SND_PCM_STATE_DRAINING);
508         pcm->stop_threshold = stop_threshold;
509         return 0;
510 }
511
512 static int snd_pcm_dmix_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
513 {
514         return -EIO;
515 }
516
517 static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_uframes_t frames ATTRIBUTE_UNUSED)
518 {
519 #if 0
520         /* FIXME: substract samples from the mix ring buffer, too? */
521         snd_pcm_mmap_appl_backward(pcm, frames);
522         return frames;
523 #else
524         return -EIO;
525 #endif
526 }
527
528 static snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
529 {
530         snd_pcm_sframes_t avail;
531
532         avail = snd_pcm_mmap_playback_avail(pcm);
533         if (avail < 0)
534                 return 0;
535         if (frames > (snd_pcm_uframes_t)avail)
536                 frames = avail;
537         snd_pcm_mmap_appl_forward(pcm, frames);
538         return frames;
539 }
540
541 static int snd_pcm_dmix_resume(snd_pcm_t *pcm)
542 {
543         snd_pcm_direct_t *dmix = pcm->private_data;
544         snd_pcm_resume(dmix->spcm);
545         return 0;
546 }
547
548 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)
549 {
550         return -ENODEV;
551 }
552
553 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)
554 {
555         return -ENODEV;
556 }
557
558 static int snd_pcm_dmix_close(snd_pcm_t *pcm)
559 {
560         snd_pcm_direct_t *dmix = pcm->private_data;
561
562         if (dmix->timer)
563                 snd_timer_close(dmix->timer);
564         snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
565         snd_pcm_close(dmix->spcm);
566         if (dmix->server)
567                 snd_pcm_direct_server_discard(dmix);
568         if (dmix->client)
569                 snd_pcm_direct_client_discard(dmix);
570         shm_sum_discard(dmix);
571         if (snd_pcm_direct_shm_discard(dmix) > 0) {
572                 if (snd_pcm_direct_semaphore_discard(dmix) < 0)
573                         snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
574         } else {
575                 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
576         }
577         if (dmix->bindings)
578                 free(dmix->bindings);
579         pcm->private_data = NULL;
580         free(dmix);
581         return 0;
582 }
583
584 static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm,
585                                                   snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
586                                                   snd_pcm_uframes_t size)
587 {
588         snd_pcm_direct_t *dmix = pcm->private_data;
589         int err;
590
591         switch (snd_pcm_state(dmix->spcm)) {
592         case SND_PCM_STATE_XRUN:
593                 return -EPIPE;
594         case SND_PCM_STATE_SUSPENDED:
595                 return -ESTRPIPE;
596         default:
597                 break;
598         }
599         if (! size)
600                 return 0;
601         snd_pcm_mmap_appl_forward(pcm, size);
602         if (dmix->state == STATE_RUN_PENDING) {
603                 if ((err = snd_pcm_dmix_start_timer(dmix)) < 0)
604                         return err;
605         } else if (dmix->state == SND_PCM_STATE_RUNNING ||
606                    dmix->state == SND_PCM_STATE_DRAINING)
607                 _snd_pcm_dmix_sync_ptr(pcm, 1);
608         if (dmix->state == SND_PCM_STATE_RUNNING ||
609             dmix->state == SND_PCM_STATE_DRAINING) {
610                 /* ok, we commit the changes after the validation of area */
611                 /* it's intended, although the result might be crappy */
612                 snd_pcm_dmix_sync_area(pcm, size);
613                 /* clear timer queue to avoid a bogus return from poll */
614                 if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min)
615                         snd_pcm_direct_clear_timer_queue(dmix);
616         }
617         return size;
618 }
619
620 static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm)
621 {
622         snd_pcm_direct_t *dmix = pcm->private_data;
623         
624         if (dmix->state == SND_PCM_STATE_RUNNING ||
625             dmix->state == SND_PCM_STATE_DRAINING)
626                 snd_pcm_dmix_sync_ptr(pcm);
627         return snd_pcm_mmap_playback_avail(pcm);
628 }
629
630 static void snd_pcm_dmix_dump(snd_pcm_t *pcm, snd_output_t *out)
631 {
632         snd_pcm_direct_t *dmix = pcm->private_data;
633
634         snd_output_printf(out, "Direct Stream Mixing PCM\n");
635         if (pcm->setup) {
636                 snd_output_printf(out, "\nIts setup is:\n");
637                 snd_pcm_dump_setup(pcm, out);
638         }
639         if (dmix->spcm)
640                 snd_pcm_dump(dmix->spcm, out);
641 }
642
643 static snd_pcm_ops_t snd_pcm_dmix_ops = {
644         .close = snd_pcm_dmix_close,
645         .info = snd_pcm_direct_info,
646         .hw_refine = snd_pcm_direct_hw_refine,
647         .hw_params = snd_pcm_direct_hw_params,
648         .hw_free = snd_pcm_direct_hw_free,
649         .sw_params = snd_pcm_direct_sw_params,
650         .channel_info = snd_pcm_direct_channel_info,
651         .dump = snd_pcm_dmix_dump,
652         .nonblock = snd_pcm_direct_nonblock,
653         .async = snd_pcm_direct_async,
654         .poll_revents = snd_pcm_direct_poll_revents,
655         .mmap = snd_pcm_direct_mmap,
656         .munmap = snd_pcm_direct_munmap,
657 };
658
659 static snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
660         .status = snd_pcm_dmix_status,
661         .state = snd_pcm_dmix_state,
662         .hwsync = snd_pcm_dmix_hwsync,
663         .delay = snd_pcm_dmix_delay,
664         .prepare = snd_pcm_dmix_prepare,
665         .reset = snd_pcm_dmix_reset,
666         .start = snd_pcm_dmix_start,
667         .drop = snd_pcm_dmix_drop,
668         .drain = snd_pcm_dmix_drain,
669         .pause = snd_pcm_dmix_pause,
670         .rewind = snd_pcm_dmix_rewind,
671         .forward = snd_pcm_dmix_forward,
672         .resume = snd_pcm_dmix_resume,
673         .poll_ask = NULL,
674         .link_fd = NULL,
675         .link = NULL,
676         .unlink = NULL,
677         .writei = snd_pcm_mmap_writei,
678         .writen = snd_pcm_mmap_writen,
679         .readi = snd_pcm_dmix_readi,
680         .readn = snd_pcm_dmix_readn,
681         .avail_update = snd_pcm_dmix_avail_update,
682         .mmap_commit = snd_pcm_dmix_mmap_commit,
683 };
684
685 /**
686  * \brief Creates a new dmix PCM
687  * \param pcmp Returns created PCM handle
688  * \param name Name of PCM
689  * \param ipc_key IPC key for semaphore and shared memory
690  * \param ipc_perm IPC permissions for semaphore and shared memory
691  * \param params Parameters for slave
692  * \param bindings Channel bindings
693  * \param slowptr Slow but more precise pointer updates
694  * \param root Configuration root
695  * \param sconf Slave configuration
696  * \param stream PCM Direction (stream)
697  * \param mode PCM Mode
698  * \retval zero on success otherwise a negative error code
699  * \warning Using of this function might be dangerous in the sense
700  *          of compatibility reasons. The prototype might be freely
701  *          changed in future.
702  */
703 int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
704                       key_t ipc_key, mode_t ipc_perm,
705                       struct slave_params *params,
706                       snd_config_t *bindings,
707                       int slowptr,
708                       snd_config_t *root, snd_config_t *sconf,
709                       snd_pcm_stream_t stream, int mode)
710 {
711         snd_pcm_t *pcm = NULL, *spcm = NULL;
712         snd_pcm_direct_t *dmix = NULL;
713         int ret, first_instance;
714         int fail_sem_loop = 10;
715
716         assert(pcmp);
717
718         if (stream != SND_PCM_STREAM_PLAYBACK) {
719                 SNDERR("The dmix plugin supports only playback stream");
720                 return -EINVAL;
721         }
722
723         dmix = calloc(1, sizeof(snd_pcm_direct_t));
724         if (!dmix) {
725                 ret = -ENOMEM;
726                 goto _err;
727         }
728         
729         ret = snd_pcm_direct_parse_bindings(dmix, bindings);
730         if (ret < 0)
731                 goto _err;
732         
733         dmix->ipc_key = ipc_key;
734         dmix->ipc_perm = ipc_perm;
735         dmix->semid = -1;
736         dmix->shmid = -1;
737
738         ret = snd_pcm_new(&pcm, dmix->type = SND_PCM_TYPE_DMIX, name, stream, mode);
739         if (ret < 0)
740                 goto _err;
741
742         
743         while (1) {
744                 ret = snd_pcm_direct_semaphore_create_or_connect(dmix);
745                 if (ret < 0) {
746                         SNDERR("unable to create IPC semaphore");
747                         goto _err;
748                 }
749                 ret = snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
750                 if (ret < 0) {
751                         snd_pcm_direct_semaphore_discard(dmix);
752                         if (--fail_sem_loop <= 0)
753                                 goto _err;
754                         continue;
755                 }
756                 break;
757         }
758                 
759         first_instance = ret = snd_pcm_direct_shm_create_or_connect(dmix);
760         if (ret < 0) {
761                 SNDERR("unable to create IPC shm instance");
762                 goto _err;
763         }
764                 
765         pcm->ops = &snd_pcm_dmix_ops;
766         pcm->fast_ops = &snd_pcm_dmix_fast_ops;
767         pcm->private_data = dmix;
768         dmix->state = SND_PCM_STATE_OPEN;
769         dmix->slowptr = slowptr;
770         dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
771
772         if (first_instance) {
773                 ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
774                 if (ret < 0) {
775                         SNDERR("unable to open slave");
776                         goto _err;
777                 }
778         
779                 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
780                         SNDERR("dmix plugin can be only connected to hw plugin");
781                         ret = -EINVAL;
782                         goto _err;
783                 }
784                 
785                 ret = snd_pcm_direct_initialize_slave(dmix, spcm, params);
786                 if (ret < 0) {
787                         SNDERR("unable to initialize slave");
788                         goto _err;
789                 }
790
791                 dmix->spcm = spcm;
792
793                 dmix->server_free = dmix_server_free;
794                 
795                 ret = snd_pcm_direct_server_create(dmix);
796                 if (ret < 0) {
797                         SNDERR("unable to create server");
798                         goto _err;
799                 }
800
801                 dmix->shmptr->type = spcm->type;
802         } else {
803                 ret = snd_pcm_direct_client_connect(dmix);
804                 if (ret < 0) {
805                         SNDERR("unable to connect client");
806                         return ret;
807                 }
808                         
809                 ret = snd_pcm_hw_open_fd(&spcm, "dmix_client", dmix->hw_fd, 0, 0);
810                 if (ret < 0) {
811                         SNDERR("unable to open hardware");
812                         goto _err;
813                 }
814                 
815                 spcm->donot_close = 1;
816                 spcm->setup = 1;
817                 spcm->buffer_size = dmix->shmptr->s.buffer_size;
818                 spcm->sample_bits = dmix->shmptr->s.sample_bits;
819                 spcm->channels = dmix->shmptr->s.channels;
820                 spcm->format = dmix->shmptr->s.format;
821                 spcm->boundary = dmix->shmptr->s.boundary;
822                 spcm->info = dmix->shmptr->s.info;
823                 ret = snd_pcm_mmap(spcm);
824                 if (ret < 0) {
825                         SNDERR("unable to mmap channels");
826                         goto _err;
827                 }
828                 dmix->spcm = spcm;
829         }
830
831         ret = shm_sum_create_or_connect(dmix);
832         if (ret < 0) {
833                 SNDERR("unable to initialize sum ring buffer");
834                 goto _err;
835         }
836
837         ret = snd_pcm_direct_initialize_poll_fd(dmix);
838         if (ret < 0) {
839                 SNDERR("unable to initialize poll_fd");
840                 goto _err;
841         }
842
843         mix_select_callbacks(dmix);
844                 
845         pcm->poll_fd = dmix->poll_fd;
846         pcm->poll_events = POLLIN;      /* it's different than other plugins */
847                 
848         pcm->mmap_rw = 1;
849         snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0);
850         snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0);
851         
852         if (dmix->channels == UINT_MAX)
853                 dmix->channels = dmix->shmptr->s.channels;
854
855         snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
856
857         *pcmp = pcm;
858         return 0;
859         
860  _err:
861         if (dmix) {
862                 if (dmix->timer)
863                         snd_timer_close(dmix->timer);
864                 if (dmix->server)
865                         snd_pcm_direct_server_discard(dmix);
866                 if (dmix->client)
867                         snd_pcm_direct_client_discard(dmix);
868                 if (spcm)
869                         snd_pcm_close(spcm);
870                 if (dmix->u.dmix.shmid_sum >= 0)
871                         shm_sum_discard(dmix);
872                 if (dmix->shmid >= 0) {
873                         if (snd_pcm_direct_shm_discard(dmix) > 0) {
874                                 if (dmix->semid >= 0) {
875                                         if (snd_pcm_direct_semaphore_discard(dmix) < 0)
876                                                 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
877                                 }
878                         }
879                 }
880                 if (dmix->bindings)
881                         free(dmix->bindings);
882                 free(dmix);
883         }
884         if (pcm)
885                 snd_pcm_free(pcm);
886         return ret;
887 }
888
889 /*! \page pcm_plugins
890
891 \section pcm_plugins_dmix Plugin: dmix
892
893 This plugin provides direct mixing of multiple streams. The resolution
894 for 32-bit mixing is only 24-bit. The low significant byte is filled with
895 zeros. The extra 8 bits are used for the saturation.
896
897 \code
898 pcm.name {
899         type dmix               # Direct mix
900         ipc_key INT             # unique IPC key
901         ipc_key_add_uid BOOL    # add current uid to unique IPC key
902         ipc_perm INT            # IPC permissions (octal, default 0600)
903         slave STR
904         # or
905         slave {                 # Slave definition
906                 pcm STR         # slave PCM name
907                 # or
908                 pcm { }         # slave PCM definition
909                 format STR      # format definition
910                 rate INT        # rate definition
911                 channels INT
912                 period_time INT # in usec
913                 # or
914                 period_size INT # in bytes
915                 buffer_time INT # in usec
916                 # or
917                 buffer_size INT # in bytes
918                 periods INT     # when buffer_size or buffer_time is not specified
919         }
920         bindings {              # note: this is client independent!!!
921                 N INT           # maps slave channel to client channel N
922         }
923         slowptr BOOL            # slow but more precise pointer updates
924 }
925 \endcode
926
927 <code>ipc_key</code> specfies the unique IPC key in integer.
928 This number must be unique for each different dmix definition,
929 since the shared memory is created with this key number.
930 When <code>ipc_key_add_uid</code> is set true, the uid value is
931 added to the value set in <code>ipc_key</code>.  This will
932 avoid the confliction of the same IPC key with different users
933 concurrently.
934
935 Note that the dmix plugin itself supports only a single configuration.
936 That is, it supports only the fixed rate (default 48000), format
937 (\c S16), channels (2), and period_time (125000).
938 For using other configuration, you have to set the value explicitly
939 in the slave PCM definition.  The rate, format and channels can be
940 covered by an additional \ref pcm_plugins_dmix "plug plugin",
941 but there is only one base configuration, anyway.
942
943 An example configuration for setting 44100 Hz, \c S32_LE format
944 as the slave PCM of "hw:0" is like below:
945 \code
946 pcm.dmix_44 {
947         type dmix
948         ipc_key 321456  # any unique value
949         ipc_key_add_uid true
950         slave {
951                 pcm "hw:0"
952                 format S32_LE
953                 rate 44100
954         }
955 }
956 \endcode
957 You can hear 48000 Hz samples still using this dmix pcm via plug plugin
958 like:
959 \code
960 % aplay -Dplug:dmix_44 foo_48k.wav
961 \endcode
962
963 For using the dmix plugin for OSS emulation device, you have to set
964 the period and the buffer sizes in power of two.  For example,
965 \code
966 pcm.dmixoss {
967         type dmix
968         ipc_key 321456  # any unique value
969         ipc_key_add_uid true
970         slave {
971                 pcm "hw:0"
972                 period_time 0
973                 period_size 1024  # must be power of 2
974                 buffer_size 8192  # ditto
975         }
976 }
977 \endcode
978 <code>period_time 0</code> must be set, too, for resetting the
979 default value.  In the case of soundcards with multi-channel IO,
980 adding the bindings would help
981 \code
982 pcm.dmixoss {
983         ...
984         bindings {
985                 0 0   # map from 0 to 0
986                 1 1   # map from 1 to 1
987         }
988 }
989 \endcode
990 so that only the first two channels are used by dmix.
991 Also, note that ICE1712 have the limited buffer size, 5513 frames
992 (corresponding to 640 kB).  In this case, reduce the buffer_size
993 to 4096.
994
995 \subsection pcm_plugins_dmix_funcref Function reference
996
997 <UL>
998   <LI>snd_pcm_dmix_open()
999   <LI>_snd_pcm_dmix_open()
1000 </UL>
1001
1002 */
1003
1004 /**
1005  * \brief Creates a new dmix PCM
1006  * \param pcmp Returns created PCM handle
1007  * \param name Name of PCM
1008  * \param root Root configuration node
1009  * \param conf Configuration node with dmix PCM description
1010  * \param stream PCM Stream
1011  * \param mode PCM Mode
1012  * \warning Using of this function might be dangerous in the sense
1013  *          of compatibility reasons. The prototype might be freely
1014  *          changed in future.
1015  */
1016 int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
1017                        snd_config_t *root, snd_config_t *conf,
1018                        snd_pcm_stream_t stream, int mode)
1019 {
1020         snd_config_iterator_t i, next;
1021         snd_config_t *slave = NULL, *bindings = NULL, *sconf;
1022         struct slave_params params;
1023         int bsize, psize, ipc_key_add_uid = 0, slowptr = 0;
1024         key_t ipc_key = 0;
1025         mode_t ipc_perm = 0600;
1026         int err;
1027         snd_config_for_each(i, next, conf) {
1028                 snd_config_t *n = snd_config_iterator_entry(i);
1029                 const char *id;
1030                 if (snd_config_get_id(n, &id) < 0)
1031                         continue;
1032                 if (snd_pcm_conf_generic_id(id))
1033                         continue;
1034                 if (strcmp(id, "ipc_key") == 0) {
1035                         long key;
1036                         err = snd_config_get_integer(n, &key);
1037                         if (err < 0) {
1038                                 SNDERR("The field ipc_key must be an integer type");
1039                                 return err;
1040                         }
1041                         ipc_key = key;
1042                         continue;
1043                 }
1044                 if (strcmp(id, "ipc_perm") == 0) {
1045                         char *perm;
1046                         char *endp;
1047                         err = snd_config_get_ascii(n, &perm);
1048                         if (err < 0) {
1049                                 SNDERR("The field ipc_perm must be a valid file permission");
1050                                 return err;
1051                         }
1052                         if (isdigit(*perm) == 0) {
1053                                 SNDERR("The field ipc_perm must be a valid file permission");
1054                                 return -EINVAL;
1055                         }
1056                         ipc_perm = strtol(perm, &endp, 8);
1057                         continue;
1058                 }
1059                 if (strcmp(id, "ipc_key_add_uid") == 0) {
1060                         if ((err = snd_config_get_bool(n)) < 0) {
1061                                 SNDERR("The field ipc_key_add_uid must be a boolean type");
1062                                 return err;
1063                         }
1064                         ipc_key_add_uid = err;
1065                         continue;
1066                 }
1067                 if (strcmp(id, "slave") == 0) {
1068                         slave = n;
1069                         continue;
1070                 }
1071                 if (strcmp(id, "bindings") == 0) {
1072                         bindings = n;
1073                         continue;
1074                 }
1075                 if (strcmp(id, "slowptr") == 0) {
1076                         err = snd_config_get_bool(n);
1077                         if (err < 0)
1078                                 return err;
1079                         slowptr = err;
1080                         continue;
1081                 }
1082                 SNDERR("Unknown field %s", id);
1083                 return -EINVAL;
1084         }
1085         if (!slave) {
1086                 SNDERR("slave is not defined");
1087                 return -EINVAL;
1088         }
1089         if (ipc_key_add_uid)
1090                 ipc_key += getuid();
1091         if (!ipc_key) {
1092                 SNDERR("Unique IPC key is not defined");
1093                 return -EINVAL;
1094         }
1095         /* the default settings, it might be invalid for some hardware */
1096         params.format = SND_PCM_FORMAT_S16;
1097         params.rate = 48000;
1098         params.channels = 2;
1099         params.period_time = -1;
1100         params.buffer_time = -1;
1101         bsize = psize = -1;
1102         params.periods = 3;
1103
1104         err = snd_pcm_slave_conf(root, slave, &sconf, 8,
1105                                  SND_PCM_HW_PARAM_FORMAT, 0, &params.format,
1106                                  SND_PCM_HW_PARAM_RATE, 0, &params.rate,
1107                                  SND_PCM_HW_PARAM_CHANNELS, 0, &params.channels,
1108                                  SND_PCM_HW_PARAM_PERIOD_TIME, 0, &params.period_time,
1109                                  SND_PCM_HW_PARAM_BUFFER_TIME, 0, &params.buffer_time,
1110                                  SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
1111                                  SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
1112                                  SND_PCM_HW_PARAM_PERIODS, 0, &params.periods);
1113         if (err < 0)
1114                 return err;
1115
1116         /* set a reasonable default */  
1117         if (psize == -1 && params.period_time == -1)
1118                 params.period_time = 125000;    /* 0.125 seconds */
1119
1120         /* sorry, limited features */
1121         if (params.format != SND_PCM_FORMAT_S16 &&
1122             params.format != SND_PCM_FORMAT_S32) {
1123                 SNDERR("invalid format, specify s16 or s32");
1124                 snd_config_delete(sconf);
1125                 return -EINVAL;
1126         }
1127
1128         params.period_size = psize;
1129         params.buffer_size = bsize;
1130
1131         err = snd_pcm_dmix_open(pcmp, name, ipc_key, ipc_perm, &params, bindings, slowptr, root, sconf, stream, mode);
1132         if (err < 0)
1133                 snd_config_delete(sconf);
1134         return err;
1135 }
1136 #ifndef DOC_HIDDEN
1137 SND_DLSYM_BUILD_VERSION(_snd_pcm_dmix_open, SND_PCM_DLSYM_VERSION);
1138 #endif