OSDN Git Service

pcm: dsnoop: Added "hw_ptr_alignment" option in configuration for slave pointer alignment
[android-x86/external-alsa-lib.git] / src / pcm / pcm_dshare.c
1 /**
2  * \file pcm/pcm_dshare.c
3  * \ingroup PCM_Plugins
4  * \brief PCM Direct Sharing of Channels Plugin Interface
5  * \author Jaroslav Kysela <perex@perex.cz>
6  * \date 2003
7  */
8 /*
9  *  PCM - Direct Sharing of Channels
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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_dshare = "";
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 static void do_silence(snd_pcm_t *pcm)
59 {
60         snd_pcm_direct_t *dshare = pcm->private_data;
61         const snd_pcm_channel_area_t *dst_areas;
62         unsigned int chn, dchn, channels;
63         snd_pcm_format_t format;
64
65         dst_areas = snd_pcm_mmap_areas(dshare->spcm);
66         channels = dshare->channels;
67         format = dshare->shmptr->s.format;
68         for (chn = 0; chn < channels; chn++) {
69                 dchn = dshare->bindings ? dshare->bindings[chn] : chn;
70                 if (dchn != UINT_MAX)
71                         snd_pcm_area_silence(&dst_areas[dchn], 0,
72                                              dshare->shmptr->s.buffer_size, format);
73         }
74 }
75
76 static void share_areas(snd_pcm_direct_t *dshare,
77                       const snd_pcm_channel_area_t *src_areas,
78                       const snd_pcm_channel_area_t *dst_areas,
79                       snd_pcm_uframes_t src_ofs,
80                       snd_pcm_uframes_t dst_ofs,
81                       snd_pcm_uframes_t size)
82 {
83         unsigned int chn, dchn, channels;
84         snd_pcm_format_t format;
85
86         channels = dshare->channels;
87         format = dshare->shmptr->s.format;
88         if (dshare->interleaved) {
89                 unsigned int fbytes = snd_pcm_format_physical_width(format) / 8;
90                 memcpy(((char *)dst_areas[0].addr) + (dst_ofs * channels * fbytes),
91                        ((char *)src_areas[0].addr) + (src_ofs * channels * fbytes),
92                        size * channels * fbytes);
93         } else {
94                 for (chn = 0; chn < channels; chn++) {
95                         dchn = dshare->bindings ? dshare->bindings[chn] : chn;
96                         if (dchn != UINT_MAX)
97                                 snd_pcm_area_copy(&dst_areas[dchn], dst_ofs,
98                                                   &src_areas[chn], src_ofs, size, format);
99
100                 }
101         }
102 }
103
104 /*
105  *  synchronize shm ring buffer with hardware
106  */
107 static void snd_pcm_dshare_sync_area(snd_pcm_t *pcm)
108 {
109         snd_pcm_direct_t *dshare = pcm->private_data;
110         snd_pcm_uframes_t slave_hw_ptr, slave_appl_ptr, slave_size;
111         snd_pcm_uframes_t appl_ptr, size;
112         const snd_pcm_channel_area_t *src_areas, *dst_areas;
113         
114         /* calculate the size to transfer */
115         size = dshare->appl_ptr - dshare->last_appl_ptr;
116         if (! size)
117                 return;
118         slave_hw_ptr = dshare->slave_hw_ptr;
119         /* don't write on the last active period - this area may be cleared
120          * by the driver during write operation...
121          */
122         slave_hw_ptr -= slave_hw_ptr % dshare->slave_period_size;
123         slave_hw_ptr += dshare->slave_buffer_size;
124         if (slave_hw_ptr >= dshare->slave_boundary)
125                 slave_hw_ptr -= dshare->slave_boundary;
126         if (slave_hw_ptr < dshare->slave_appl_ptr)
127                 slave_size = slave_hw_ptr + (dshare->slave_boundary - dshare->slave_appl_ptr);
128         else
129                 slave_size = slave_hw_ptr - dshare->slave_appl_ptr;
130         if (slave_size < size)
131                 size = slave_size;
132         if (! size)
133                 return;
134
135         /* add sample areas here */
136         src_areas = snd_pcm_mmap_areas(pcm);
137         dst_areas = snd_pcm_mmap_areas(dshare->spcm);
138         appl_ptr = dshare->last_appl_ptr % pcm->buffer_size;
139         dshare->last_appl_ptr += size;
140         dshare->last_appl_ptr %= pcm->boundary;
141         slave_appl_ptr = dshare->slave_appl_ptr % dshare->slave_buffer_size;
142         dshare->slave_appl_ptr += size;
143         dshare->slave_appl_ptr %= dshare->slave_boundary;
144         for (;;) {
145                 snd_pcm_uframes_t transfer = size;
146                 if (appl_ptr + transfer > pcm->buffer_size)
147                         transfer = pcm->buffer_size - appl_ptr;
148                 if (slave_appl_ptr + transfer > dshare->slave_buffer_size)
149                         transfer = dshare->slave_buffer_size - slave_appl_ptr;
150                 share_areas(dshare, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
151                 size -= transfer;
152                 if (! size)
153                         break;
154                 slave_appl_ptr += transfer;
155                 slave_appl_ptr %= dshare->slave_buffer_size;
156                 appl_ptr += transfer;
157                 appl_ptr %= pcm->buffer_size;
158         }
159 }
160
161 /*
162  *  synchronize hardware pointer (hw_ptr) with ours
163  */
164 static int snd_pcm_dshare_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr)
165 {
166         snd_pcm_direct_t *dshare = pcm->private_data;
167         snd_pcm_uframes_t old_slave_hw_ptr, avail;
168         snd_pcm_sframes_t diff;
169
170         old_slave_hw_ptr = dshare->slave_hw_ptr;
171         dshare->slave_hw_ptr = slave_hw_ptr;
172         diff = slave_hw_ptr - old_slave_hw_ptr;
173         if (diff == 0)          /* fast path */
174                 return 0;
175         if (dshare->state != SND_PCM_STATE_RUNNING &&
176             dshare->state != SND_PCM_STATE_DRAINING)
177                 /* not really started yet - don't update hw_ptr */
178                 return 0;
179         if (diff < 0) {
180                 slave_hw_ptr += dshare->slave_boundary;
181                 diff = slave_hw_ptr - old_slave_hw_ptr;
182         }
183         dshare->hw_ptr += diff;
184         dshare->hw_ptr %= pcm->boundary;
185         // printf("sync ptr diff = %li\n", diff);
186         if (pcm->stop_threshold >= pcm->boundary)       /* don't care */
187                 return 0;
188         avail = snd_pcm_mmap_playback_avail(pcm);
189         if (avail > dshare->avail_max)
190                 dshare->avail_max = avail;
191         if (avail >= pcm->stop_threshold) {
192                 snd_timer_stop(dshare->timer);
193                 do_silence(pcm);
194                 gettimestamp(&dshare->trigger_tstamp, pcm->tstamp_type);
195                 if (dshare->state == SND_PCM_STATE_RUNNING) {
196                         dshare->state = SND_PCM_STATE_XRUN;
197                         return -EPIPE;
198                 }
199                 dshare->state = SND_PCM_STATE_SETUP;
200                 /* clear queue to remove pending poll events */
201                 snd_pcm_direct_clear_timer_queue(dshare);
202         }
203         return 0;
204 }
205
206 static int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm)
207 {
208         snd_pcm_direct_t *dshare = pcm->private_data;
209         int err;
210
211         switch (snd_pcm_state(dshare->spcm)) {
212         case SND_PCM_STATE_DISCONNECTED:
213                 dshare->state = SNDRV_PCM_STATE_DISCONNECTED;
214                 return -ENODEV;
215         case SND_PCM_STATE_XRUN:
216                 if ((err = snd_pcm_direct_slave_recover(dshare)) < 0)
217                         return err;
218                 break;
219         default:
220                 break;
221         }
222         if (snd_pcm_direct_client_chk_xrun(dshare, pcm))
223                 return -EPIPE;
224         if (dshare->slowptr)
225                 snd_pcm_hwsync(dshare->spcm);
226
227         return snd_pcm_dshare_sync_ptr0(pcm, *dshare->spcm->hw.ptr);
228 }
229
230 /*
231  *  plugin implementation
232  */
233
234 static snd_pcm_state_t snd_pcm_dshare_state(snd_pcm_t *pcm);
235
236 static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
237 {
238         snd_pcm_direct_t *dshare = pcm->private_data;
239
240         memset(status, 0, sizeof(*status));
241         snd_pcm_status(dshare->spcm, status);
242
243         switch (dshare->state) {
244         case SNDRV_PCM_STATE_DRAINING:
245         case SNDRV_PCM_STATE_RUNNING:
246                 snd_pcm_dshare_sync_ptr0(pcm, status->hw_ptr);
247                 status->delay += snd_pcm_mmap_playback_delay(pcm)
248                                 + status->avail - dshare->spcm->buffer_size;
249                 break;
250         default:
251                 break;
252         }
253         status->state = snd_pcm_dshare_state(pcm);
254         status->trigger_tstamp = dshare->trigger_tstamp;
255         status->avail = snd_pcm_mmap_playback_avail(pcm);
256         status->avail_max = status->avail > dshare->avail_max ? status->avail : dshare->avail_max;
257         dshare->avail_max = 0;
258         return 0;
259 }
260
261 static snd_pcm_state_t snd_pcm_dshare_state(snd_pcm_t *pcm)
262 {
263         snd_pcm_direct_t *dshare = pcm->private_data;
264         int err;
265         snd_pcm_state_t state;
266         state = snd_pcm_state(dshare->spcm);
267         switch (state) {
268         case SND_PCM_STATE_SUSPENDED:
269         case SND_PCM_STATE_DISCONNECTED:
270                 dshare->state = state;
271                 return state;
272         case SND_PCM_STATE_XRUN:
273                 if ((err = snd_pcm_direct_slave_recover(dshare)) < 0)
274                         return err;
275                 break;
276         default:
277                 break;
278         }
279         snd_pcm_direct_client_chk_xrun(dshare, pcm);
280         if (dshare->state == STATE_RUN_PENDING)
281                 return SNDRV_PCM_STATE_RUNNING;
282         return dshare->state;
283 }
284
285 static int snd_pcm_dshare_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
286 {
287         snd_pcm_direct_t *dshare = pcm->private_data;
288         int err;
289         
290         switch (dshare->state) {
291         case SNDRV_PCM_STATE_DRAINING:
292         case SNDRV_PCM_STATE_RUNNING:
293                 err = snd_pcm_dshare_sync_ptr(pcm);
294                 if (err < 0)
295                         return err;
296                 /* fallthru */
297         case SNDRV_PCM_STATE_PREPARED:
298         case SNDRV_PCM_STATE_SUSPENDED:
299         case STATE_RUN_PENDING:
300                 *delayp = snd_pcm_mmap_playback_hw_avail(pcm);
301                 return 0;
302         case SNDRV_PCM_STATE_XRUN:
303                 return -EPIPE;
304         case SNDRV_PCM_STATE_DISCONNECTED:
305                 return -ENODEV;
306         default:
307                 return -EBADFD;
308         }
309 }
310
311 static int snd_pcm_dshare_hwsync(snd_pcm_t *pcm)
312 {
313         snd_pcm_direct_t *dshare = pcm->private_data;
314
315         switch(dshare->state) {
316         case SNDRV_PCM_STATE_DRAINING:
317         case SNDRV_PCM_STATE_RUNNING:
318                 return snd_pcm_dshare_sync_ptr(pcm);
319         case SNDRV_PCM_STATE_PREPARED:
320         case SNDRV_PCM_STATE_SUSPENDED:
321                 return 0;
322         case SNDRV_PCM_STATE_XRUN:
323                 return -EPIPE;
324         case SNDRV_PCM_STATE_DISCONNECTED:
325                 return -ENODEV;
326         default:
327                 return -EBADFD;
328         }
329 }
330
331 static int snd_pcm_dshare_reset(snd_pcm_t *pcm)
332 {
333         snd_pcm_direct_t *dshare = pcm->private_data;
334         dshare->hw_ptr %= pcm->period_size;
335         dshare->appl_ptr = dshare->last_appl_ptr = dshare->hw_ptr;
336         dshare->slave_appl_ptr = dshare->slave_hw_ptr = *dshare->spcm->hw.ptr;
337         snd_pcm_direct_reset_slave_ptr(pcm, dshare);
338         return 0;
339 }
340
341 static int snd_pcm_dshare_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dshare)
342 {
343         int err;
344
345         snd_pcm_hwsync(dshare->spcm);
346         dshare->slave_appl_ptr = dshare->slave_hw_ptr = *dshare->spcm->hw.ptr;
347         snd_pcm_direct_reset_slave_ptr(pcm, dshare);
348         err = snd_timer_start(dshare->timer);
349         if (err < 0)
350                 return err;
351         dshare->state = SND_PCM_STATE_RUNNING;
352         return 0;
353 }
354
355 static int snd_pcm_dshare_start(snd_pcm_t *pcm)
356 {
357         snd_pcm_direct_t *dshare = pcm->private_data;
358         snd_pcm_sframes_t avail;
359         int err;
360         
361         if (dshare->state != SND_PCM_STATE_PREPARED)
362                 return -EBADFD;
363         avail = snd_pcm_mmap_playback_hw_avail(pcm);
364         if (avail == 0)
365                 dshare->state = STATE_RUN_PENDING;
366         else if (avail < 0)
367                 return 0;
368         else {
369                 err = snd_pcm_dshare_start_timer(pcm, dshare);
370                 if (err < 0)
371                         return err;
372                 snd_pcm_dshare_sync_area(pcm);
373         }
374         gettimestamp(&dshare->trigger_tstamp, pcm->tstamp_type);
375         return 0;
376 }
377
378 static int snd_pcm_dshare_drop(snd_pcm_t *pcm)
379 {
380         snd_pcm_direct_t *dshare = pcm->private_data;
381         if (dshare->state == SND_PCM_STATE_OPEN)
382                 return -EBADFD;
383         dshare->state = SND_PCM_STATE_SETUP;
384         snd_pcm_direct_timer_stop(dshare);
385         do_silence(pcm);
386         return 0;
387 }
388
389 /* locked version */
390 static int __snd_pcm_dshare_drain(snd_pcm_t *pcm)
391 {
392         snd_pcm_direct_t *dshare = pcm->private_data;
393         snd_pcm_uframes_t stop_threshold;
394         int err;
395
396         switch (snd_pcm_state(dshare->spcm)) {
397         case SND_PCM_STATE_SUSPENDED:
398                 return -ESTRPIPE;
399         default:
400                 break;
401         }
402
403         if (dshare->state == SND_PCM_STATE_OPEN)
404                 return -EBADFD;
405         if (pcm->mode & SND_PCM_NONBLOCK)
406                 return -EAGAIN;
407         if (dshare->state == SND_PCM_STATE_PREPARED) {
408                 if (snd_pcm_mmap_playback_hw_avail(pcm) > 0)
409                         snd_pcm_dshare_start(pcm);
410                 else {
411                         snd_pcm_dshare_drop(pcm);
412                         return 0;
413                 }
414         }
415
416         if (dshare->state == SND_PCM_STATE_XRUN) {
417                 snd_pcm_dshare_drop(pcm);
418                 return 0;
419         }
420
421         stop_threshold = pcm->stop_threshold;
422         if (pcm->stop_threshold > pcm->buffer_size)
423                 pcm->stop_threshold = pcm->buffer_size;
424         dshare->state = SND_PCM_STATE_DRAINING;
425         do {
426                 err = snd_pcm_dshare_sync_ptr(pcm);
427                 if (err < 0) {
428                         snd_pcm_dshare_drop(pcm);
429                         break;
430                 }
431                 if (dshare->state == SND_PCM_STATE_DRAINING) {
432                         snd_pcm_dshare_sync_area(pcm);
433                         snd_pcm_wait_nocheck(pcm, -1);
434                         snd_pcm_direct_clear_timer_queue(dshare); /* force poll to wait */
435
436                         switch (snd_pcm_state(dshare->spcm)) {
437                         case SND_PCM_STATE_SUSPENDED:
438                                 return -ESTRPIPE;
439                         default:
440                                 break;
441                         }
442                 }
443         } while (dshare->state == SND_PCM_STATE_DRAINING);
444         pcm->stop_threshold = stop_threshold;
445         return 0;
446 }
447
448 static int snd_pcm_dshare_drain(snd_pcm_t *pcm)
449 {
450         int err;
451
452         snd_pcm_lock(pcm);
453         err = __snd_pcm_dshare_drain(pcm);
454         snd_pcm_unlock(pcm);
455         return err;
456 }
457
458 static int snd_pcm_dshare_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
459 {
460         return -EIO;
461 }
462
463 static snd_pcm_sframes_t snd_pcm_dshare_rewindable(snd_pcm_t *pcm)
464 {
465         return snd_pcm_mmap_playback_hw_rewindable(pcm);
466 }
467
468 static snd_pcm_sframes_t snd_pcm_dshare_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
469 {
470         snd_pcm_sframes_t avail;
471
472         avail = snd_pcm_dshare_rewindable(pcm);
473         if (frames > (snd_pcm_uframes_t)avail)
474                 frames = avail;
475         snd_pcm_mmap_appl_backward(pcm, frames);
476         return frames;
477 }
478
479 static snd_pcm_sframes_t snd_pcm_dshare_forwardable(snd_pcm_t *pcm)
480 {
481         return snd_pcm_mmap_playback_avail(pcm);
482 }
483
484 static snd_pcm_sframes_t snd_pcm_dshare_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
485 {
486         snd_pcm_sframes_t avail;
487
488         avail = snd_pcm_dshare_forwardable(pcm);
489         if (frames > (snd_pcm_uframes_t)avail)
490                 frames = avail;
491         snd_pcm_mmap_appl_forward(pcm, frames);
492         return frames;
493 }
494
495 static snd_pcm_sframes_t snd_pcm_dshare_readi(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
496 {
497         return -ENODEV;
498 }
499
500 static snd_pcm_sframes_t snd_pcm_dshare_readn(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
501 {
502         return -ENODEV;
503 }
504
505 static int snd_pcm_dshare_close(snd_pcm_t *pcm)
506 {
507         snd_pcm_direct_t *dshare = pcm->private_data;
508
509         if (dshare->timer)
510                 snd_timer_close(dshare->timer);
511         do_silence(pcm);
512         snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT);
513         dshare->shmptr->u.dshare.chn_mask &= ~dshare->u.dshare.chn_mask;
514         snd_pcm_close(dshare->spcm);
515         if (dshare->server)
516                 snd_pcm_direct_server_discard(dshare);
517         if (dshare->client)
518                 snd_pcm_direct_client_discard(dshare);
519         if (snd_pcm_direct_shm_discard(dshare)) {
520                 if (snd_pcm_direct_semaphore_discard(dshare))
521                         snd_pcm_direct_semaphore_final(dshare, DIRECT_IPC_SEM_CLIENT);
522         } else
523                 snd_pcm_direct_semaphore_final(dshare, DIRECT_IPC_SEM_CLIENT);
524         free(dshare->bindings);
525         pcm->private_data = NULL;
526         free(dshare);
527         return 0;
528 }
529
530 static snd_pcm_sframes_t snd_pcm_dshare_mmap_commit(snd_pcm_t *pcm,
531                                                   snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
532                                                   snd_pcm_uframes_t size)
533 {
534         snd_pcm_direct_t *dshare = pcm->private_data;
535         int err;
536
537         switch (snd_pcm_state(dshare->spcm)) {
538         case SND_PCM_STATE_XRUN:
539                 if ((err = snd_pcm_direct_slave_recover(dshare)) < 0)
540                         return err;
541                 break;
542         case SND_PCM_STATE_SUSPENDED:
543                 return -ESTRPIPE;
544         default:
545                 break;
546         }
547         if (snd_pcm_direct_client_chk_xrun(dshare, pcm))
548                 return -EPIPE;
549         if (! size)
550                 return 0;
551         snd_pcm_mmap_appl_forward(pcm, size);
552         if (dshare->state == STATE_RUN_PENDING) {
553                 err = snd_pcm_dshare_start_timer(pcm, dshare);
554                 if (err < 0)
555                         return err;
556         } else if (dshare->state == SND_PCM_STATE_RUNNING ||
557                    dshare->state == SND_PCM_STATE_DRAINING) {
558                 if ((err = snd_pcm_dshare_sync_ptr(pcm)) < 0)
559                         return err;
560         }
561         if (dshare->state == SND_PCM_STATE_RUNNING ||
562             dshare->state == SND_PCM_STATE_DRAINING) {
563                 /* ok, we commit the changes after the validation of area */
564                 /* it's intended, although the result might be crappy */
565                 snd_pcm_dshare_sync_area(pcm);
566                 /* clear timer queue to avoid a bogus return from poll */
567                 if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min)
568                         snd_pcm_direct_clear_timer_queue(dshare);
569         }
570         return size;
571 }
572
573 static snd_pcm_sframes_t snd_pcm_dshare_avail_update(snd_pcm_t *pcm)
574 {
575         snd_pcm_direct_t *dshare = pcm->private_data;
576         int err;
577         
578         if (dshare->state == SND_PCM_STATE_RUNNING ||
579             dshare->state == SND_PCM_STATE_DRAINING) {
580                 if ((err = snd_pcm_dshare_sync_ptr(pcm)) < 0)
581                         return err;
582         }
583         if (dshare->state == SND_PCM_STATE_XRUN)
584                 return -EPIPE;
585
586         return snd_pcm_mmap_playback_avail(pcm);
587 }
588
589 static int snd_pcm_dshare_htimestamp(snd_pcm_t *pcm,
590                                      snd_pcm_uframes_t *avail,
591                                      snd_htimestamp_t *tstamp)
592 {
593         snd_pcm_direct_t *dshare = pcm->private_data;
594         snd_pcm_uframes_t avail1;
595         int ok = 0;
596         
597         while (1) {
598                 if (dshare->state == SND_PCM_STATE_RUNNING ||
599                     dshare->state == SND_PCM_STATE_DRAINING)
600                         snd_pcm_dshare_sync_ptr(pcm);
601                 avail1 = snd_pcm_mmap_playback_avail(pcm);
602                 if (ok && *avail == avail1)
603                         break;
604                 *avail = avail1;
605                 *tstamp = snd_pcm_hw_fast_tstamp(dshare->spcm);
606                 ok = 1;
607         }
608         return 0;
609 }
610
611 static void snd_pcm_dshare_dump(snd_pcm_t *pcm, snd_output_t *out)
612 {
613         snd_pcm_direct_t *dshare = pcm->private_data;
614
615         snd_output_printf(out, "Direct Share PCM\n");
616         if (pcm->setup) {
617                 snd_output_printf(out, "Its setup is:\n");
618                 snd_pcm_dump_setup(pcm, out);
619         }
620         if (dshare->spcm)
621                 snd_pcm_dump(dshare->spcm, out);
622 }
623
624 static const snd_pcm_ops_t snd_pcm_dshare_ops = {
625         .close = snd_pcm_dshare_close,
626         .info = snd_pcm_direct_info,
627         .hw_refine = snd_pcm_direct_hw_refine,
628         .hw_params = snd_pcm_direct_hw_params,
629         .hw_free = snd_pcm_direct_hw_free,
630         .sw_params = snd_pcm_direct_sw_params,
631         .channel_info = snd_pcm_direct_channel_info,
632         .dump = snd_pcm_dshare_dump,
633         .nonblock = snd_pcm_direct_nonblock,
634         .async = snd_pcm_direct_async,
635         .mmap = snd_pcm_direct_mmap,
636         .munmap = snd_pcm_direct_munmap,
637         .get_chmap = snd_pcm_direct_get_chmap,
638         .set_chmap = snd_pcm_direct_set_chmap,
639 };
640
641 static const snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = {
642         .status = snd_pcm_dshare_status,
643         .state = snd_pcm_dshare_state,
644         .hwsync = snd_pcm_dshare_hwsync,
645         .delay = snd_pcm_dshare_delay,
646         .prepare = snd_pcm_direct_prepare,
647         .reset = snd_pcm_dshare_reset,
648         .start = snd_pcm_dshare_start,
649         .drop = snd_pcm_dshare_drop,
650         .drain = snd_pcm_dshare_drain,
651         .pause = snd_pcm_dshare_pause,
652         .rewindable = snd_pcm_dshare_rewindable,
653         .rewind = snd_pcm_dshare_rewind,
654         .forwardable = snd_pcm_dshare_forwardable,
655         .forward = snd_pcm_dshare_forward,
656         .resume = snd_pcm_direct_resume,
657         .link = NULL,
658         .link_slaves = NULL,
659         .unlink = NULL,
660         .writei = snd_pcm_mmap_writei,
661         .writen = snd_pcm_mmap_writen,
662         .readi = snd_pcm_dshare_readi,
663         .readn = snd_pcm_dshare_readn,
664         .avail_update = snd_pcm_dshare_avail_update,
665         .mmap_commit = snd_pcm_dshare_mmap_commit,
666         .htimestamp = snd_pcm_dshare_htimestamp,
667         .poll_descriptors = snd_pcm_direct_poll_descriptors,
668         .poll_descriptors_count = NULL,
669         .poll_revents = snd_pcm_direct_poll_revents,
670 };
671
672 /**
673  * \brief Creates a new dshare PCM
674  * \param pcmp Returns created PCM handle
675  * \param name Name of PCM
676  * \param opts Direct PCM configurations
677  * \param params Parameters for slave
678  * \param root Configuration root
679  * \param sconf Slave configuration
680  * \param stream PCM Direction (stream)
681  * \param mode PCM Mode
682  * \retval zero on success otherwise a negative error code
683  * \warning Using of this function might be dangerous in the sense
684  *          of compatibility reasons. The prototype might be freely
685  *          changed in future.
686  */
687 int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
688                         struct snd_pcm_direct_open_conf *opts,
689                         struct slave_params *params,
690                         snd_config_t *root, snd_config_t *sconf,
691                         snd_pcm_stream_t stream, int mode)
692 {
693         snd_pcm_t *pcm = NULL, *spcm = NULL;
694         snd_pcm_direct_t *dshare = NULL;
695         int ret, first_instance;
696         unsigned int chn;
697         int fail_sem_loop = 10;
698
699         assert(pcmp);
700
701         if (stream != SND_PCM_STREAM_PLAYBACK) {
702                 SNDERR("The dshare plugin supports only playback stream");
703                 return -EINVAL;
704         }
705
706         dshare = calloc(1, sizeof(snd_pcm_direct_t));
707         if (!dshare) {
708                 ret = -ENOMEM;
709                 goto _err_nosem;
710         }
711         
712         ret = snd_pcm_direct_parse_bindings(dshare, params, opts->bindings);
713         if (ret < 0)
714                 goto _err_nosem;
715                 
716         if (!dshare->bindings) {
717                 SNDERR("dshare: specify bindings!!!");
718                 ret = -EINVAL;
719                 goto _err_nosem;
720         }
721         
722         dshare->ipc_key = opts->ipc_key;
723         dshare->ipc_perm = opts->ipc_perm;
724         dshare->ipc_gid = opts->ipc_gid;
725         dshare->semid = -1;
726         dshare->shmid = -1;
727
728         ret = snd_pcm_new(&pcm, dshare->type = SND_PCM_TYPE_DSHARE, name, stream, mode);
729         if (ret < 0)
730                 goto _err_nosem;
731
732         while (1) {
733                 ret = snd_pcm_direct_semaphore_create_or_connect(dshare);
734                 if (ret < 0) {
735                         SNDERR("unable to create IPC semaphore");
736                         goto _err_nosem;
737                 }
738         
739                 ret = snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT);
740                 if (ret < 0) {
741                         snd_pcm_direct_semaphore_discard(dshare);
742                         if (--fail_sem_loop <= 0)
743                                 goto _err_nosem;
744                         continue;
745                 }
746                 break;
747         }
748
749         first_instance = ret = snd_pcm_direct_shm_create_or_connect(dshare);
750         if (ret < 0) {
751                 SNDERR("unable to create IPC shm instance");
752                 goto _err;
753         }
754                 
755         pcm->ops = &snd_pcm_dshare_ops;
756         pcm->fast_ops = &snd_pcm_dshare_fast_ops;
757         pcm->private_data = dshare;
758         dshare->state = SND_PCM_STATE_OPEN;
759         dshare->slowptr = opts->slowptr;
760         dshare->max_periods = opts->max_periods;
761         dshare->var_periodsize = opts->var_periodsize;
762         dshare->hw_ptr_alignment = opts->hw_ptr_alignment;
763         dshare->sync_ptr = snd_pcm_dshare_sync_ptr;
764
765  retry:
766         if (first_instance) {
767                 /* recursion is already checked in
768                    snd_pcm_direct_get_slave_ipc_offset() */
769                 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
770                                          mode | SND_PCM_NONBLOCK, NULL);
771                 if (ret < 0) {
772                         SNDERR("unable to open slave");
773                         goto _err;
774                 }
775         
776                 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
777                         SNDERR("dshare plugin can be only connected to hw plugin");
778                         goto _err;
779                 }
780                 
781                 ret = snd_pcm_direct_initialize_slave(dshare, spcm, params);
782                 if (ret < 0) {
783                         SNDERR("unable to initialize slave");
784                         goto _err;
785                 }
786
787                 dshare->spcm = spcm;
788                 
789                 if (dshare->shmptr->use_server) {
790                         ret = snd_pcm_direct_server_create(dshare);
791                         if (ret < 0) {
792                                 SNDERR("unable to create server");
793                                 goto _err;
794                         }
795                 }
796
797                 dshare->shmptr->type = spcm->type;
798         } else {
799                 if (dshare->shmptr->use_server) {
800                         /* up semaphore to avoid deadlock */
801                         snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT);
802                         ret = snd_pcm_direct_client_connect(dshare);
803                         if (ret < 0) {
804                                 SNDERR("unable to connect client");
805                                 goto _err_nosem;
806                         }
807                         
808                         snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT);
809                         ret = snd_pcm_direct_open_secondary_client(&spcm, dshare, "dshare_client");
810                         if (ret < 0)
811                                 goto _err;
812
813                 } else {
814
815                         ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
816                                                  mode | SND_PCM_NONBLOCK |
817                                                  SND_PCM_APPEND,
818                                                  NULL);
819                         if (ret < 0) {
820                                 /* all other streams have been closed;
821                                  * retry as the first instance
822                                  */
823                                 if (ret == -EBADFD) {
824                                         first_instance = 1;
825                                         goto retry;
826                                 }
827                                 SNDERR("unable to open slave");
828                                 goto _err;
829                         }
830                         if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
831                                 SNDERR("dshare plugin can be only connected to hw plugin");
832                                 ret = -EINVAL;
833                                 goto _err;
834                         }
835                 
836                         ret = snd_pcm_direct_initialize_secondary_slave(dshare, spcm, params);
837                         if (ret < 0) {
838                                 SNDERR("unable to initialize slave");
839                                 goto _err;
840                         }
841                 }
842
843                 dshare->spcm = spcm;
844         }
845
846         for (chn = 0; chn < dshare->channels; chn++) {
847                 unsigned int dchn = dshare->bindings ? dshare->bindings[chn] : chn;
848                 if (dchn != UINT_MAX)
849                         dshare->u.dshare.chn_mask |= (1ULL << dchn);
850         }
851         if (dshare->shmptr->u.dshare.chn_mask & dshare->u.dshare.chn_mask) {
852                 SNDERR("destination channel specified in bindings is already used");
853                 dshare->u.dshare.chn_mask = 0;
854                 ret = -EINVAL;
855                 goto _err;
856         }
857         dshare->shmptr->u.dshare.chn_mask |= dshare->u.dshare.chn_mask;
858                 
859         ret = snd_pcm_direct_initialize_poll_fd(dshare);
860         if (ret < 0) {
861                 SNDERR("unable to initialize poll_fd");
862                 goto _err;
863         }
864
865         pcm->poll_fd = dshare->poll_fd;
866         pcm->poll_events = POLLIN;      /* it's different than other plugins */
867         pcm->tstamp_type = spcm->tstamp_type;
868         pcm->mmap_rw = 1;
869         snd_pcm_set_hw_ptr(pcm, &dshare->hw_ptr, -1, 0);
870         snd_pcm_set_appl_ptr(pcm, &dshare->appl_ptr, -1, 0);
871         
872         snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT);
873
874         *pcmp = pcm;
875         return 0;
876         
877  _err:
878         if (dshare->shmptr)
879                 dshare->shmptr->u.dshare.chn_mask &= ~dshare->u.dshare.chn_mask;
880         if (dshare->timer)
881                 snd_timer_close(dshare->timer);
882         if (dshare->server)
883                 snd_pcm_direct_server_discard(dshare);
884         if (dshare->client)
885                 snd_pcm_direct_client_discard(dshare);
886         if (spcm)
887                 snd_pcm_close(spcm);
888         if ((dshare->shmid >= 0) && (snd_pcm_direct_shm_discard(dshare))) {
889                 if (snd_pcm_direct_semaphore_discard(dshare))
890                         snd_pcm_direct_semaphore_final(dshare, DIRECT_IPC_SEM_CLIENT);
891         } else
892                 snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT);
893  _err_nosem:
894         if (dshare) {
895                 free(dshare->bindings);
896                 free(dshare);
897         }
898         if (pcm)
899                 snd_pcm_free(pcm);
900         return ret;
901 }
902
903 /*! \page pcm_plugins
904
905 \section pcm_plugins_dshare Plugin: dshare
906
907 This plugin provides sharing channels.
908 Unlike \ref pcm_plugins_share "share plugin", this plugin doesn't need
909 the explicit server program but accesses the shared buffer concurrently
910 from each client as well as \ref pcm_plugins_dmix "dmix" and
911 \ref pcm_plugins_dsnoop "dsnoop" plugins do.
912 The parameters below are almost identical with these plugins.
913
914 \code
915 pcm.name {
916         type dshare             # Direct sharing
917         ipc_key INT             # unique IPC key
918         ipc_key_add_uid BOOL    # add current uid to unique IPC key
919         ipc_perm INT            # IPC permissions (octal, default 0600)
920         hw_ptr_alignment STR    # Slave application and hw pointer alignment type
921                 # STR can be one of the below strings :
922                 # no
923                 # roundup
924                 # rounddown
925                 # auto (default)
926         slave STR
927         # or
928         slave {                 # Slave definition
929                 pcm STR         # slave PCM name
930                 # or
931                 pcm { }         # slave PCM definition
932                 format STR      # format definition
933                 rate INT        # rate definition
934                 channels INT
935                 period_time INT # in usec
936                 # or
937                 period_size INT # in bytes
938                 buffer_time INT # in usec
939                 # or
940                 buffer_size INT # in bytes
941                 periods INT     # when buffer_size or buffer_time is not specified
942         }
943         bindings {              # note: this is client independent!!!
944                 N INT           # maps slave channel to client channel N
945         }
946         slowptr BOOL            # slow but more precise pointer updates
947 }
948 \endcode
949
950 <code>hw_ptr_alignment</code> specifies slave application and hw
951 pointer alignment type. By default hw_ptr_alignment is auto. Below are
952 the possible configurations:
953 - no: minimal latency with minimal frames dropped at startup. But
954   wakeup of application (return from snd_pcm_wait() or poll()) can
955   take up to 2 * period.
956 - roundup: It is guaranteed that all frames will be played at
957   startup. But the latency will increase upto period-1 frames.
958 - rounddown: It is guaranteed that a wakeup will happen for each
959   period and frames can be written from application. But on startup
960   upto period-1 frames will be dropped.
961 - auto: Selects the best approach depending on the used period and
962   buffer size.
963   If the application buffer size is < 2 * application period,
964   "roundup" will be selected to avoid under runs. If the slave_period
965   is < 10ms we could expect that there are low latency
966   requirements. Therefore "rounddown" will be chosen to avoid long
967   wakeup times. Such wakeup delay could otherwise end up with Xruns in
968   case of a dependency to another sound device (e.g. forwarding of
969   microphone to speaker). Else "no" will be chosen.
970
971 \subsection pcm_plugins_dshare_funcref Function reference
972
973 <UL>
974   <LI>snd_pcm_dshare_open()
975   <LI>_snd_pcm_dshare_open()
976 </UL>
977
978 */
979
980 /**
981  * \brief Creates a new dshare PCM
982  * \param pcmp Returns created PCM handle
983  * \param name Name of PCM
984  * \param root Root configuration node
985  * \param conf Configuration node with dshare PCM description
986  * \param stream PCM Stream
987  * \param mode PCM Mode
988  * \warning Using of this function might be dangerous in the sense
989  *          of compatibility reasons. The prototype might be freely
990  *          changed in future.
991  */
992 int _snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
993                        snd_config_t *root, snd_config_t *conf,
994                        snd_pcm_stream_t stream, int mode)
995 {
996         snd_config_t *sconf;
997         struct slave_params params;
998         struct snd_pcm_direct_open_conf dopen;
999         int bsize, psize;
1000         int err;
1001
1002         err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen);
1003         if (err < 0)
1004                 return err;
1005
1006         /* the default settings, it might be invalid for some hardware */
1007         params.format = SND_PCM_FORMAT_S16;
1008         params.rate = 48000;
1009         params.channels = 2;
1010         params.period_time = -1;
1011         params.buffer_time = -1;
1012         bsize = psize = -1;
1013         params.periods = 3;
1014         err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8,
1015                                  SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, &params.format,
1016                                  SND_PCM_HW_PARAM_RATE, 0, &params.rate,
1017                                  SND_PCM_HW_PARAM_CHANNELS, 0, &params.channels,
1018                                  SND_PCM_HW_PARAM_PERIOD_TIME, 0, &params.period_time,
1019                                  SND_PCM_HW_PARAM_BUFFER_TIME, 0, &params.buffer_time,
1020                                  SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
1021                                  SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
1022                                  SND_PCM_HW_PARAM_PERIODS, 0, &params.periods);
1023         if (err < 0)
1024                 return err;
1025
1026         /* set a reasonable default */
1027         if (psize == -1 && params.period_time == -1)
1028                 params.period_time = 125000;    /* 0.125 seconds */
1029
1030         if (params.format == -2)
1031                 params.format = SND_PCM_FORMAT_UNKNOWN;
1032
1033         params.period_size = psize;
1034         params.buffer_size = bsize;
1035
1036         err = snd_pcm_dshare_open(pcmp, name, &dopen, &params,
1037                                   root, sconf, stream, mode);
1038         snd_config_delete(sconf);
1039         return err;
1040 }
1041 #ifndef DOC_HIDDEN
1042 SND_DLSYM_BUILD_VERSION(_snd_pcm_dshare_open, SND_PCM_DLSYM_VERSION);
1043 #endif