OSDN Git Service

pcm: remove extra NULL checks in snd_pcm_dsnoop_open()
[android-x86/external-alsa-lib.git] / src / pcm / pcm_dsnoop.c
1 /**
2  * \file pcm/pcm_dsnoop.c
3  * \ingroup PCM_Plugins
4  * \brief PCM Capture Stream Snooping (dsnoop) Plugin Interface
5  * \author Jaroslav Kysela <perex@perex.cz>
6  * \date 2003
7  */
8 /*
9  *  PCM - Capture Stream Snooping
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_dsnoop = "";
51 #endif
52
53 /*
54  *
55  */
56
57 static int snoop_timestamp(snd_pcm_t *pcm)
58 {
59         snd_pcm_direct_t *dsnoop = pcm->private_data;
60         snd_pcm_uframes_t ptr1 = -2LL /* invalid value */, ptr2;
61
62         /* loop is required to sync hw.ptr with timestamp */
63         while (1) {
64                 ptr2 = *dsnoop->spcm->hw.ptr;
65                 if (ptr1 == ptr2)
66                         break;
67                 ptr1 = ptr2;
68                 dsnoop->update_tstamp = snd_pcm_hw_fast_tstamp(dsnoop->spcm);
69         }
70         dsnoop->slave_hw_ptr = ptr1;
71         return 0;
72 }
73
74 static void snoop_areas(snd_pcm_direct_t *dsnoop,
75                         const snd_pcm_channel_area_t *src_areas,
76                         const snd_pcm_channel_area_t *dst_areas,
77                         snd_pcm_uframes_t src_ofs,
78                         snd_pcm_uframes_t dst_ofs,
79                         snd_pcm_uframes_t size)
80 {
81         unsigned int chn, schn, channels;
82         snd_pcm_format_t format;
83
84         channels = dsnoop->channels;
85         format = dsnoop->shmptr->s.format;
86         if (dsnoop->interleaved) {
87                 unsigned int fbytes = snd_pcm_format_physical_width(format) / 8;
88                 memcpy(((char *)dst_areas[0].addr) + (dst_ofs * channels * fbytes),
89                        ((char *)src_areas[0].addr) + (src_ofs * channels * fbytes),
90                        size * channels * fbytes);
91         } else {
92                 for (chn = 0; chn < channels; chn++) {
93                         schn = dsnoop->bindings ? dsnoop->bindings[chn] : chn;
94                         snd_pcm_area_copy(&dst_areas[chn], dst_ofs, &src_areas[schn], src_ofs, size, format);
95                 }
96         }
97 }
98
99 /*
100  *  synchronize shm ring buffer with hardware
101  */
102 static void snd_pcm_dsnoop_sync_area(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr, snd_pcm_uframes_t size)
103 {
104         snd_pcm_direct_t *dsnoop = pcm->private_data;
105         snd_pcm_uframes_t hw_ptr = dsnoop->hw_ptr;
106         snd_pcm_uframes_t transfer;
107         const snd_pcm_channel_area_t *src_areas, *dst_areas;
108         
109         /* add sample areas here */
110         dst_areas = snd_pcm_mmap_areas(pcm);
111         src_areas = snd_pcm_mmap_areas(dsnoop->spcm);
112         hw_ptr %= pcm->buffer_size;
113         slave_hw_ptr %= dsnoop->slave_buffer_size;
114         while (size > 0) {
115                 transfer = hw_ptr + size > pcm->buffer_size ? pcm->buffer_size - hw_ptr : size;
116                 transfer = slave_hw_ptr + transfer > dsnoop->slave_buffer_size ?
117                         dsnoop->slave_buffer_size - slave_hw_ptr : transfer;
118                 size -= transfer;
119                 snoop_areas(dsnoop, src_areas, dst_areas, slave_hw_ptr, hw_ptr, transfer);
120                 slave_hw_ptr += transfer;
121                 slave_hw_ptr %= dsnoop->slave_buffer_size;
122                 hw_ptr += transfer;
123                 hw_ptr %= pcm->buffer_size;
124         }
125 }
126
127 /*
128  *  synchronize hardware pointer (hw_ptr) with ours
129  */
130 static int snd_pcm_dsnoop_sync_ptr(snd_pcm_t *pcm)
131 {
132         snd_pcm_direct_t *dsnoop = pcm->private_data;
133         snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail;
134         snd_pcm_sframes_t diff;
135         int err;
136
137         switch (snd_pcm_state(dsnoop->spcm)) {
138         case SND_PCM_STATE_DISCONNECTED:
139                 dsnoop->state = SNDRV_PCM_STATE_DISCONNECTED;
140                 return -ENODEV;
141         case SND_PCM_STATE_XRUN:
142                 if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0)
143                         return err;
144                 break;
145         default:
146                 break;
147         }
148         if (snd_pcm_direct_client_chk_xrun(dsnoop, pcm))
149                 return -EPIPE;
150         if (dsnoop->slowptr)
151                 snd_pcm_hwsync(dsnoop->spcm);
152         old_slave_hw_ptr = dsnoop->slave_hw_ptr;
153         snoop_timestamp(pcm);
154         slave_hw_ptr = dsnoop->slave_hw_ptr;
155         diff = pcm_frame_diff(slave_hw_ptr, old_slave_hw_ptr, dsnoop->slave_boundary);
156         if (diff == 0)          /* fast path */
157                 return 0;
158         snd_pcm_dsnoop_sync_area(pcm, old_slave_hw_ptr, diff);
159         dsnoop->hw_ptr += diff;
160         dsnoop->hw_ptr %= pcm->boundary;
161         // printf("sync ptr diff = %li\n", diff);
162         if (pcm->stop_threshold >= pcm->boundary)       /* don't care */
163                 return 0;
164         if ((avail = snd_pcm_mmap_capture_avail(pcm)) >= pcm->stop_threshold) {
165                 gettimestamp(&dsnoop->trigger_tstamp, pcm->tstamp_type);
166                 dsnoop->state = SND_PCM_STATE_XRUN;
167                 dsnoop->avail_max = avail;
168                 return -EPIPE;
169         }
170         if (avail > dsnoop->avail_max)
171                 dsnoop->avail_max = avail;
172         return 0;
173 }
174
175 /*
176  *  plugin implementation
177  */
178
179 static int snd_pcm_dsnoop_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
180 {
181         snd_pcm_direct_t *dsnoop = pcm->private_data;
182         snd_pcm_state_t state;
183
184         switch(dsnoop->state) {
185         case SNDRV_PCM_STATE_DRAINING:
186         case SNDRV_PCM_STATE_RUNNING:
187                 snd_pcm_dsnoop_sync_ptr(pcm);
188                 break;
189         default:
190                 break;
191         }
192         memset(status, 0, sizeof(*status));
193         snd_pcm_status(dsnoop->spcm, status);
194         state = snd_pcm_state(dsnoop->spcm);
195         status->state = state == SND_PCM_STATE_RUNNING ? dsnoop->state : state;
196         status->appl_ptr = *pcm->appl.ptr; /* slave PCM doesn't set appl_ptr */
197         status->trigger_tstamp = dsnoop->trigger_tstamp;
198         status->avail = snd_pcm_mmap_capture_avail(pcm);
199         status->avail_max = status->avail > dsnoop->avail_max ? status->avail : dsnoop->avail_max;
200         dsnoop->avail_max = 0;
201         status->delay = snd_pcm_mmap_capture_delay(pcm);
202         return 0;
203 }
204
205 static snd_pcm_state_t snd_pcm_dsnoop_state(snd_pcm_t *pcm)
206 {
207         snd_pcm_direct_t *dsnoop = pcm->private_data;
208         int err;
209         snd_pcm_state_t state;
210         state = snd_pcm_state(dsnoop->spcm);
211         switch (state) {
212         case SND_PCM_STATE_SUSPENDED:
213         case SND_PCM_STATE_DISCONNECTED:
214                 dsnoop->state = state;
215                 return state;
216         case SND_PCM_STATE_XRUN:
217                 if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0)
218                         return err;
219                 break;
220         default:
221                 break;
222         }
223         snd_pcm_direct_client_chk_xrun(dsnoop, pcm);
224         return dsnoop->state;
225 }
226
227 static int snd_pcm_dsnoop_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
228 {
229         snd_pcm_direct_t *dsnoop = pcm->private_data;
230         int err;
231         
232         switch(dsnoop->state) {
233         case SNDRV_PCM_STATE_DRAINING:
234         case SNDRV_PCM_STATE_RUNNING:
235                 err = snd_pcm_dsnoop_sync_ptr(pcm);
236                 if (err < 0)
237                         return err;
238                 /* Fall through */
239         case SNDRV_PCM_STATE_PREPARED:
240         case SNDRV_PCM_STATE_SUSPENDED:
241                 *delayp = snd_pcm_mmap_capture_avail(pcm);
242                 return 0;
243         case SNDRV_PCM_STATE_XRUN:
244                 return -EPIPE;
245         case SNDRV_PCM_STATE_DISCONNECTED:
246                 return -ENODEV;
247         default:
248                 return -EBADFD;
249         }
250 }
251
252 static int snd_pcm_dsnoop_hwsync(snd_pcm_t *pcm)
253 {
254         snd_pcm_direct_t *dsnoop = pcm->private_data;
255
256         switch(dsnoop->state) {
257         case SNDRV_PCM_STATE_DRAINING:
258         case SNDRV_PCM_STATE_RUNNING:
259                 return snd_pcm_dsnoop_sync_ptr(pcm);
260         case SNDRV_PCM_STATE_PREPARED:
261         case SNDRV_PCM_STATE_SUSPENDED:
262                 return 0;
263         case SNDRV_PCM_STATE_XRUN:
264                 return -EPIPE;
265         case SNDRV_PCM_STATE_DISCONNECTED:
266                 return -ENODEV;
267         default:
268                 return -EBADFD;
269         }
270 }
271
272 static int snd_pcm_dsnoop_reset(snd_pcm_t *pcm)
273 {
274         snd_pcm_direct_t *dsnoop = pcm->private_data;
275         dsnoop->hw_ptr %= pcm->period_size;
276         dsnoop->appl_ptr = dsnoop->hw_ptr;
277         dsnoop->slave_appl_ptr = dsnoop->slave_hw_ptr;
278         snd_pcm_direct_reset_slave_ptr(pcm, dsnoop);
279         return 0;
280 }
281
282 static int snd_pcm_dsnoop_start(snd_pcm_t *pcm)
283 {
284         snd_pcm_direct_t *dsnoop = pcm->private_data;
285         int err;
286
287         if (dsnoop->state != SND_PCM_STATE_PREPARED)
288                 return -EBADFD;
289         snd_pcm_hwsync(dsnoop->spcm);
290         snoop_timestamp(pcm);
291         dsnoop->slave_appl_ptr = dsnoop->slave_hw_ptr;
292         snd_pcm_direct_reset_slave_ptr(pcm, dsnoop);
293         err = snd_timer_start(dsnoop->timer);
294         if (err < 0)
295                 return err;
296         dsnoop->state = SND_PCM_STATE_RUNNING;
297         dsnoop->trigger_tstamp = dsnoop->update_tstamp;
298         return 0;
299 }
300
301 static int snd_pcm_dsnoop_drop(snd_pcm_t *pcm)
302 {
303         snd_pcm_direct_t *dsnoop = pcm->private_data;
304         if (dsnoop->state == SND_PCM_STATE_OPEN)
305                 return -EBADFD;
306         dsnoop->state = SND_PCM_STATE_SETUP;
307         snd_timer_stop(dsnoop->timer);
308         return 0;
309 }
310
311 /* locked version */
312 static int __snd_pcm_dsnoop_drain(snd_pcm_t *pcm)
313 {
314         snd_pcm_direct_t *dsnoop = pcm->private_data;
315         snd_pcm_uframes_t stop_threshold;
316         int err;
317
318         if (dsnoop->state == SND_PCM_STATE_OPEN)
319                 return -EBADFD;
320         stop_threshold = pcm->stop_threshold;
321         if (pcm->stop_threshold > pcm->buffer_size)
322                 pcm->stop_threshold = pcm->buffer_size;
323         while (dsnoop->state == SND_PCM_STATE_RUNNING) {
324                 err = snd_pcm_dsnoop_sync_ptr(pcm);
325                 if (err < 0)
326                         break;
327                 if (pcm->mode & SND_PCM_NONBLOCK)
328                         return -EAGAIN;
329                 __snd_pcm_wait_in_lock(pcm, -1);
330         }
331         pcm->stop_threshold = stop_threshold;
332         return snd_pcm_dsnoop_drop(pcm);
333 }
334
335 static int snd_pcm_dsnoop_drain(snd_pcm_t *pcm)
336 {
337         int err;
338
339         snd_pcm_lock(pcm);
340         err = __snd_pcm_dsnoop_drain(pcm);
341         snd_pcm_unlock(pcm);
342         return err;
343 }
344
345 static int snd_pcm_dsnoop_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
346 {
347         return -EIO;
348 }
349
350 static snd_pcm_sframes_t snd_pcm_dsnoop_rewindable(snd_pcm_t *pcm)
351 {
352         return snd_pcm_mmap_capture_hw_rewindable(pcm);
353 }
354
355 static snd_pcm_sframes_t snd_pcm_dsnoop_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
356 {
357         snd_pcm_sframes_t avail;
358
359         avail = snd_pcm_dsnoop_rewindable(pcm);
360         if (frames > (snd_pcm_uframes_t)avail)
361                 frames = avail;
362         snd_pcm_mmap_appl_backward(pcm, frames);
363         return frames;
364 }
365
366 static snd_pcm_sframes_t snd_pcm_dsnoop_forwardable(snd_pcm_t *pcm)
367 {
368         return snd_pcm_mmap_capture_avail(pcm);
369 }
370
371 static snd_pcm_sframes_t snd_pcm_dsnoop_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
372 {
373         snd_pcm_sframes_t avail;
374
375         avail = snd_pcm_dsnoop_forwardable(pcm);
376         if (frames > (snd_pcm_uframes_t)avail)
377                 frames = avail;
378         snd_pcm_mmap_appl_forward(pcm, frames);
379         return frames;
380 }
381
382 static snd_pcm_sframes_t snd_pcm_dsnoop_writei(snd_pcm_t *pcm ATTRIBUTE_UNUSED, const void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
383 {
384         return -ENODEV;
385 }
386
387 static snd_pcm_sframes_t snd_pcm_dsnoop_writen(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
388 {
389         return -ENODEV;
390 }
391
392 static int snd_pcm_dsnoop_close(snd_pcm_t *pcm)
393 {
394         snd_pcm_direct_t *dsnoop = pcm->private_data;
395
396         if (dsnoop->timer)
397                 snd_timer_close(dsnoop->timer);
398         snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT);
399         snd_pcm_close(dsnoop->spcm);
400         if (dsnoop->server)
401                 snd_pcm_direct_server_discard(dsnoop);
402         if (dsnoop->client)
403                 snd_pcm_direct_client_discard(dsnoop);
404         if (snd_pcm_direct_shm_discard(dsnoop)) {
405                 if (snd_pcm_direct_semaphore_discard(dsnoop))
406                         snd_pcm_direct_semaphore_final(dsnoop, DIRECT_IPC_SEM_CLIENT);
407         } else
408                 snd_pcm_direct_semaphore_final(dsnoop, DIRECT_IPC_SEM_CLIENT);
409         free(dsnoop->bindings);
410         pcm->private_data = NULL;
411         free(dsnoop);
412         return 0;
413 }
414
415 static snd_pcm_sframes_t snd_pcm_dsnoop_mmap_commit(snd_pcm_t *pcm,
416                                                     snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
417                                                     snd_pcm_uframes_t size)
418 {
419         snd_pcm_direct_t *dsnoop = pcm->private_data;
420         int err;
421
422         switch (snd_pcm_state(dsnoop->spcm)) {
423         case SND_PCM_STATE_XRUN:
424                 if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0)
425                         return err;
426                 break;
427         case SND_PCM_STATE_SUSPENDED:
428                 return -ESTRPIPE;
429         default:
430                 break;
431         }
432         if (snd_pcm_direct_client_chk_xrun(dsnoop, pcm))
433                 return -EPIPE;
434         if (dsnoop->state == SND_PCM_STATE_RUNNING) {
435                 err = snd_pcm_dsnoop_sync_ptr(pcm);
436                 if (err < 0)
437                         return err;
438         }
439         snd_pcm_mmap_appl_forward(pcm, size);
440         /* clear timer queue to avoid a bogus return from poll */
441         if (snd_pcm_mmap_capture_avail(pcm) < pcm->avail_min)
442                 snd_pcm_direct_clear_timer_queue(dsnoop);
443         return size;
444 }
445
446 static snd_pcm_sframes_t snd_pcm_dsnoop_avail_update(snd_pcm_t *pcm)
447 {
448         snd_pcm_direct_t *dsnoop = pcm->private_data;
449         int err;
450         
451         if (dsnoop->state == SND_PCM_STATE_RUNNING) {
452                 err = snd_pcm_dsnoop_sync_ptr(pcm);
453                 if (err < 0)
454                         return err;
455         }
456         if (dsnoop->state == SND_PCM_STATE_XRUN)
457                 return -EPIPE;
458
459         return snd_pcm_mmap_capture_avail(pcm);
460 }
461
462 static int snd_pcm_dsnoop_htimestamp(snd_pcm_t *pcm,
463                                      snd_pcm_uframes_t *avail,
464                                      snd_htimestamp_t *tstamp)
465 {
466         snd_pcm_direct_t *dsnoop = pcm->private_data;
467         snd_pcm_uframes_t avail1;
468         int ok = 0;
469         
470         while (1) {
471                 if (dsnoop->state == SND_PCM_STATE_RUNNING ||
472                     dsnoop->state == SND_PCM_STATE_DRAINING)
473                         snd_pcm_dsnoop_sync_ptr(pcm);
474                 avail1 = snd_pcm_mmap_capture_avail(pcm);
475                 if (ok && *avail == avail1)
476                         break;
477                 *avail = avail1;
478                 *tstamp = snd_pcm_hw_fast_tstamp(dsnoop->spcm);
479                 ok = 1;
480         }
481         return 0;
482 }
483
484 static void snd_pcm_dsnoop_dump(snd_pcm_t *pcm, snd_output_t *out)
485 {
486         snd_pcm_direct_t *dsnoop = pcm->private_data;
487
488         snd_output_printf(out, "Direct Snoop PCM\n");
489         if (pcm->setup) {
490                 snd_output_printf(out, "Its setup is:\n");
491                 snd_pcm_dump_setup(pcm, out);
492         }
493         if (dsnoop->spcm)
494                 snd_pcm_dump(dsnoop->spcm, out);
495 }
496
497 static const snd_pcm_ops_t snd_pcm_dsnoop_ops = {
498         .close = snd_pcm_dsnoop_close,
499         .info = snd_pcm_direct_info,
500         .hw_refine = snd_pcm_direct_hw_refine,
501         .hw_params = snd_pcm_direct_hw_params,
502         .hw_free = snd_pcm_direct_hw_free,
503         .sw_params = snd_pcm_direct_sw_params,
504         .channel_info = snd_pcm_direct_channel_info,
505         .dump = snd_pcm_dsnoop_dump,
506         .nonblock = snd_pcm_direct_nonblock,
507         .async = snd_pcm_direct_async,
508         .mmap = snd_pcm_direct_mmap,
509         .munmap = snd_pcm_direct_munmap,
510         .query_chmaps = snd_pcm_direct_query_chmaps,
511         .get_chmap = snd_pcm_direct_get_chmap,
512         .set_chmap = snd_pcm_direct_set_chmap,
513 };
514
515 static const snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = {
516         .status = snd_pcm_dsnoop_status,
517         .state = snd_pcm_dsnoop_state,
518         .hwsync = snd_pcm_dsnoop_hwsync,
519         .delay = snd_pcm_dsnoop_delay,
520         .prepare = snd_pcm_direct_prepare,
521         .reset = snd_pcm_dsnoop_reset,
522         .start = snd_pcm_dsnoop_start,
523         .drop = snd_pcm_dsnoop_drop,
524         .drain = snd_pcm_dsnoop_drain,
525         .pause = snd_pcm_dsnoop_pause,
526         .rewindable = snd_pcm_dsnoop_rewindable,
527         .rewind = snd_pcm_dsnoop_rewind,
528         .forwardable = snd_pcm_dsnoop_forwardable,
529         .forward = snd_pcm_dsnoop_forward,
530         .resume = snd_pcm_direct_resume,
531         .link = NULL,
532         .link_slaves = NULL,
533         .unlink = NULL,
534         .writei = snd_pcm_dsnoop_writei,
535         .writen = snd_pcm_dsnoop_writen,
536         .readi = snd_pcm_mmap_readi,
537         .readn = snd_pcm_mmap_readn,
538         .avail_update = snd_pcm_dsnoop_avail_update,
539         .mmap_commit = snd_pcm_dsnoop_mmap_commit,
540         .htimestamp = snd_pcm_dsnoop_htimestamp,
541         .poll_descriptors = snd_pcm_direct_poll_descriptors,
542         .poll_descriptors_count = NULL,
543         .poll_revents = snd_pcm_direct_poll_revents,
544 };
545
546 /**
547  * \brief Creates a new dsnoop PCM
548  * \param pcmp Returns created PCM handle
549  * \param name Name of PCM
550  * \param opts Direct PCM configurations
551  * \param params Parameters for slave
552  * \param root Configuration root
553  * \param sconf Slave configuration
554  * \param stream PCM Direction (stream)
555  * \param mode PCM Mode
556  * \retval zero on success otherwise a negative error code
557  * \warning Using of this function might be dangerous in the sense
558  *          of compatibility reasons. The prototype might be freely
559  *          changed in future.
560  */
561 int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
562                         struct snd_pcm_direct_open_conf *opts,
563                         struct slave_params *params,
564                         snd_config_t *root, snd_config_t *sconf,
565                         snd_pcm_stream_t stream, int mode)
566 {
567         snd_pcm_t *pcm, *spcm = NULL;
568         snd_pcm_direct_t *dsnoop;
569         int ret, first_instance;
570
571         assert(pcmp);
572
573         if (stream != SND_PCM_STREAM_CAPTURE) {
574                 SNDERR("The dsnoop plugin supports only capture stream");
575                 return -EINVAL;
576         }
577
578         ret = _snd_pcm_direct_new(&pcm, &dsnoop, SND_PCM_TYPE_DSNOOP, name, opts, params, stream, mode);
579         if (ret < 0)
580                 return ret;
581         first_instance = ret;
582
583         pcm->ops = &snd_pcm_dsnoop_ops;
584         pcm->fast_ops = &snd_pcm_dsnoop_fast_ops;
585         pcm->private_data = dsnoop;
586         dsnoop->state = SND_PCM_STATE_OPEN;
587         dsnoop->slowptr = opts->slowptr;
588         dsnoop->max_periods = opts->max_periods;
589         dsnoop->var_periodsize = opts->var_periodsize;
590         dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr;
591         dsnoop->hw_ptr_alignment = opts->hw_ptr_alignment;
592
593  retry:
594         if (first_instance) {
595                 /* recursion is already checked in
596                    snd_pcm_direct_get_slave_ipc_offset() */
597                 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
598                                          mode | SND_PCM_NONBLOCK, NULL);
599                 if (ret < 0) {
600                         SNDERR("unable to open slave");
601                         goto _err;
602                 }
603         
604                 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
605                         SNDERR("dsnoop plugin can be only connected to hw plugin");
606                         goto _err;
607                 }
608                 
609                 ret = snd_pcm_direct_initialize_slave(dsnoop, spcm, params);
610                 if (ret < 0) {
611                         SNDERR("unable to initialize slave");
612                         goto _err;
613                 }
614
615                 dsnoop->spcm = spcm;
616                 
617                 if (dsnoop->shmptr->use_server) {
618                         ret = snd_pcm_direct_server_create(dsnoop);
619                         if (ret < 0) {
620                                 SNDERR("unable to create server");
621                                 goto _err;
622                         }
623                 }
624
625                 dsnoop->shmptr->type = spcm->type;
626         } else {
627                 if (dsnoop->shmptr->use_server) {
628                         /* up semaphore to avoid deadlock */
629                         snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
630                         ret = snd_pcm_direct_client_connect(dsnoop);
631                         if (ret < 0) {
632                                 SNDERR("unable to connect client");
633                                 goto _err_nosem;
634                         }
635                         
636                         snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT);
637
638                         ret = snd_pcm_direct_open_secondary_client(&spcm, dsnoop, "dsnoop_client");
639                         if (ret < 0)
640                                 goto _err;
641                 } else {
642
643                         ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
644                                                  mode | SND_PCM_NONBLOCK |
645                                                  SND_PCM_APPEND,
646                                                  NULL);
647                         if (ret < 0) {
648                                 /* all other streams have been closed;
649                                  * retry as the first instance
650                                  */
651                                 if (ret == -EBADFD) {
652                                         first_instance = 1;
653                                         goto retry;
654                                 }
655                                 SNDERR("unable to open slave");
656                                 goto _err;
657                         }
658                         if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
659                                 SNDERR("dsnoop plugin can be only connected to hw plugin");
660                                 ret = -EINVAL;
661                                 goto _err;
662                         }
663                 
664                         ret = snd_pcm_direct_initialize_secondary_slave(dsnoop, spcm, params);
665                         if (ret < 0) {
666                                 SNDERR("unable to initialize slave");
667                                 goto _err;
668                         }
669                 }
670
671                 dsnoop->spcm = spcm;
672         }
673
674         ret = snd_pcm_direct_initialize_poll_fd(dsnoop);
675         if (ret < 0) {
676                 SNDERR("unable to initialize poll_fd");
677                 goto _err;
678         }
679
680         pcm->poll_fd = dsnoop->poll_fd;
681         pcm->poll_events = POLLIN;      /* it's different than other plugins */
682         pcm->tstamp_type = spcm->tstamp_type;
683         pcm->mmap_rw = 1;
684         snd_pcm_set_hw_ptr(pcm, &dsnoop->hw_ptr, -1, 0);
685         snd_pcm_set_appl_ptr(pcm, &dsnoop->appl_ptr, -1, 0);
686         
687         if (dsnoop->channels == UINT_MAX)
688                 dsnoop->channels = dsnoop->shmptr->s.channels;
689         
690         snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
691
692         *pcmp = pcm;
693         return 0;
694         
695  _err:
696         if (dsnoop->timer)
697                 snd_timer_close(dsnoop->timer);
698         if (dsnoop->server)
699                 snd_pcm_direct_server_discard(dsnoop);
700         if (dsnoop->client)
701                 snd_pcm_direct_client_discard(dsnoop);
702         if (spcm)
703                 snd_pcm_close(spcm);
704         if ((dsnoop->shmid >= 0) && (snd_pcm_direct_shm_discard(dsnoop))) {
705                 if (snd_pcm_direct_semaphore_discard(dsnoop))
706                         snd_pcm_direct_semaphore_final(dsnoop, DIRECT_IPC_SEM_CLIENT);
707         } else
708                 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
709
710  _err_nosem:
711         free(dsnoop->bindings);
712         free(dsnoop);
713         snd_pcm_free(pcm);
714         return ret;
715 }
716
717 /*! \page pcm_plugins
718
719 \section pcm_plugins_dsnoop Plugin: dsnoop
720
721 This plugin splits one capture stream to more.
722 It works the reverse way of \ref pcm_plugins_dmix "dmix plugin",
723 reading the shared capture buffer from many clients concurrently.
724 The meaning of parameters below are almost identical with
725 dmix plugin.
726
727 \code
728 pcm.name {
729         type dsnoop             # Direct snoop
730         ipc_key INT             # unique IPC key
731         ipc_key_add_uid BOOL    # add current uid to unique IPC key
732         ipc_perm INT            # IPC permissions (octal, default 0600)
733         hw_ptr_alignment STR    # Slave application and hw pointer alignment type
734                 # STR can be one of the below strings :
735                 # no
736                 # roundup
737                 # rounddown
738                 # auto (default)
739         tstamp_type STR         # timestamp type
740                                 # STR can be one of the below strings :
741                                 # default, gettimeofday, monotonic, monotonic_raw
742         slave STR
743         # or
744         slave {                 # Slave definition
745                 pcm STR         # slave PCM name
746                 # or
747                 pcm { }         # slave PCM definition
748                 format STR      # format definition
749                 rate INT        # rate definition
750                 channels INT
751                 period_time INT # in usec
752                 # or
753                 period_size INT # in frames
754                 buffer_time INT # in usec
755                 # or
756                 buffer_size INT # in frames
757                 periods INT     # when buffer_size or buffer_time is not specified
758         }
759         bindings {              # note: this is client independent!!!
760                 N INT           # maps slave channel to client channel N
761         }
762         slowptr BOOL            # slow but more precise pointer updates
763 }
764 \endcode
765
766 <code>hw_ptr_alignment</code> specifies slave application and hw
767 pointer alignment type. By default hw_ptr_alignment is auto. Below are
768 the possible configurations:
769 - no: minimal latency with minimal frames dropped at startup. But
770   wakeup of application (return from snd_pcm_wait() or poll()) can
771   take up to 2 * period.
772 - roundup: It is guaranteed that all frames will be played at
773   startup. But the latency will increase upto period-1 frames.
774 - rounddown: It is guaranteed that a wakeup will happen for each
775   period and frames can be written from application. But on startup
776   upto period-1 frames will be dropped.
777 - auto: Selects the best approach depending on the used period and
778   buffer size.
779   If the application buffer size is < 2 * application period,
780   "roundup" will be selected to avoid over runs. If the slave_period
781   is < 10ms we could expect that there are low latency
782   requirements. Therefore "rounddown" will be chosen to avoid long
783   wakeup times. Else "no" will be chosen.
784
785 \subsection pcm_plugins_dsnoop_funcref Function reference
786
787 <UL>
788   <LI>snd_pcm_dsnoop_open()
789   <LI>_snd_pcm_dsnoop_open()
790 </UL>
791
792 */
793
794 /**
795  * \brief Creates a new dsnoop PCM
796  * \param pcmp Returns created PCM handle
797  * \param name Name of PCM
798  * \param root Root configuration node
799  * \param conf Configuration node with dsnoop PCM description
800  * \param stream PCM Stream
801  * \param mode PCM Mode
802  * \warning Using of this function might be dangerous in the sense
803  *          of compatibility reasons. The prototype might be freely
804  *          changed in future.
805  */
806 int _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
807                        snd_config_t *root, snd_config_t *conf,
808                        snd_pcm_stream_t stream, int mode)
809 {
810         snd_config_t *sconf;
811         struct slave_params params;
812         struct snd_pcm_direct_open_conf dopen;
813         int bsize, psize;
814         int err;
815
816         err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen);
817         if (err < 0)
818                 return err;
819
820         /* the default settings, it might be invalid for some hardware */
821         params.format = SND_PCM_FORMAT_S16;
822         params.rate = 48000;
823         params.channels = 2;
824         params.period_time = -1;
825         params.buffer_time = -1;
826         bsize = psize = -1;
827         params.periods = 3;
828         err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8,
829                                  SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, &params.format,
830                                  SND_PCM_HW_PARAM_RATE, 0, &params.rate,
831                                  SND_PCM_HW_PARAM_CHANNELS, 0, &params.channels,
832                                  SND_PCM_HW_PARAM_PERIOD_TIME, 0, &params.period_time,
833                                  SND_PCM_HW_PARAM_BUFFER_TIME, 0, &params.buffer_time,
834                                  SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
835                                  SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
836                                  SND_PCM_HW_PARAM_PERIODS, 0, &params.periods);
837         if (err < 0)
838                 return err;
839
840         /* set a reasonable default */  
841         if (psize == -1 && params.period_time == -1)
842                 params.period_time = 125000;    /* 0.125 seconds */
843
844         if (params.format == -2)
845                 params.format = SND_PCM_FORMAT_UNKNOWN;
846
847         params.period_size = psize;
848         params.buffer_size = bsize;
849
850         err = snd_pcm_dsnoop_open(pcmp, name, &dopen, &params,
851                                   root, sconf, stream, mode);
852         snd_config_delete(sconf);
853         return err;
854 }
855 #ifndef DOC_HIDDEN
856 SND_DLSYM_BUILD_VERSION(_snd_pcm_dsnoop_open, SND_PCM_DLSYM_VERSION);
857 #endif