OSDN Git Service

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