• Home
  • History
  • Annotate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/ap/gpl/iserver/alsa-lib-1.0.26/src/pcm/

Lines Matching defs:*

2  * \file pcm/pcm_share.c
3 * \ingroup PCM_Plugins
4 * \brief PCM Share Plugin Interface
5 * \author Abramo Bagnara <abramo@alsa-project.org>
6 * \date 2000-2001
9 * PCM - Share
10 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
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.
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.
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
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <limits.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <signal.h>
35 #include <math.h>
36 #include <sys/socket.h>
37 #include <sys/poll.h>
38 #include <sys/shm.h>
39 #include <pthread.h>
40 #include "pcm_local.h"
42 #ifndef PIC
43 /* entry for static linking */
44 const char *_snd_module_pcm_share = "";
45 #endif
47 #ifndef DOC_HIDDEN
49 static LIST_HEAD(snd_pcm_share_slaves);
50 static pthread_mutex_t snd_pcm_share_slaves_mutex = PTHREAD_MUTEX_INITIALIZER;
52 #ifdef MUTEX_DEBUG
53 #define Pthread_mutex_lock(mutex) \
54 char *snd_pcm_share_slaves_mutex_holder;
55 do { \
56 int err = pthread_mutex_trylock(mutex); \
57 if (err < 0) { \
58 fprintf(stderr, "lock " #mutex " is busy (%s): waiting in " __FUNCTION__ "\n", *(mutex##_holder)); \
59 pthread_mutex_lock(mutex); \
60 fprintf(stderr, "... got\n"); \
62 *(mutex##_holder) = __FUNCTION__; \
63 } while (0)
65 #define Pthread_mutex_unlock(mutex) \
66 do { \
67 *(mutex##_holder) = 0; \
68 pthread_mutex_unlock(mutex); \
69 } while (0)
70 #else
71 #define Pthread_mutex_lock(mutex) pthread_mutex_lock(mutex)
72 #define Pthread_mutex_unlock(mutex) pthread_mutex_unlock(mutex)
73 #endif
75 typedef struct {
76 struct list_head clients;
77 struct list_head list;
78 snd_pcm_t *pcm;
79 snd_pcm_format_t format;
80 int rate;
81 unsigned int channels;
82 snd_pcm_sframes_t period_time;
83 snd_pcm_sframes_t buffer_time;
84 unsigned int open_count;
85 unsigned int setup_count;
86 unsigned int prepared_count;
87 unsigned int running_count;
88 snd_pcm_uframes_t safety_threshold;
89 snd_pcm_uframes_t silence_frames;
90 snd_pcm_sw_params_t sw_params;
91 snd_pcm_uframes_t hw_ptr;
92 int poll[2];
93 int polling;
94 pthread_t thread;
95 pthread_mutex_t mutex;
96 #ifdef MUTEX_DEBUG
97 char *mutex_holder;
98 #endif
99 pthread_cond_t poll_cond;
100 } snd_pcm_share_slave_t;
102 typedef struct {
103 struct list_head list;
104 snd_pcm_t *pcm;
105 snd_pcm_share_slave_t *slave;
106 unsigned int channels;
107 unsigned int *slave_channels;
108 int drain_silenced;
109 snd_htimestamp_t trigger_tstamp;
110 snd_pcm_state_t state;
111 snd_pcm_uframes_t hw_ptr;
112 snd_pcm_uframes_t appl_ptr;
113 int ready;
114 int client_socket;
115 int slave_socket;
116 } snd_pcm_share_t;
118 #endif /* DOC_HIDDEN */
120 static void _snd_pcm_share_stop(snd_pcm_t *pcm, snd_pcm_state_t state);
122 static snd_pcm_uframes_t snd_pcm_share_slave_avail(snd_pcm_share_slave_t *slave)
124 snd_pcm_sframes_t avail;
125 snd_pcm_t *pcm = slave->pcm;
126 avail = slave->hw_ptr - *pcm->appl.ptr;
127 if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
128 avail += pcm->buffer_size;
129 if (avail < 0)
130 avail += pcm->boundary;
131 return avail;
134 /* Warning: take the mutex before to call this */
135 /* Return number of frames to mmap_commit the slave */
136 static snd_pcm_uframes_t _snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave)
138 struct list_head *i;
139 snd_pcm_uframes_t buffer_size, boundary;
140 snd_pcm_uframes_t slave_appl_ptr;
141 snd_pcm_sframes_t frames, safety_frames;
142 snd_pcm_sframes_t min_frames, max_frames;
143 snd_pcm_uframes_t avail, slave_avail;
144 snd_pcm_uframes_t slave_hw_avail;
145 slave_avail = snd_pcm_share_slave_avail(slave);
146 boundary = slave->pcm->boundary;
147 buffer_size = slave->pcm->buffer_size;
148 min_frames = slave_avail;
149 max_frames = 0;
150 slave_appl_ptr = *slave->pcm->appl.ptr;
151 list_for_each(i, &slave->clients) {
152 snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
153 snd_pcm_t *pcm = share->pcm;
154 switch (share->state) {
155 case SND_PCM_STATE_RUNNING:
156 break;
157 case SND_PCM_STATE_DRAINING:
158 if (pcm->stream != SND_PCM_STREAM_PLAYBACK)
159 continue;
160 break;
161 default:
162 continue;
164 avail = snd_pcm_mmap_avail(pcm);
165 frames = slave_avail - avail;
166 if (frames > max_frames)
167 max_frames = frames;
168 if (share->state != SND_PCM_STATE_RUNNING)
169 continue;
170 if (frames < min_frames)
171 min_frames = frames;
173 if (max_frames == 0)
174 return 0;
175 frames = min_frames;
176 /* Slave xrun prevention */
177 slave_hw_avail = buffer_size - slave_avail;
178 safety_frames = slave->safety_threshold - slave_hw_avail;
179 if (safety_frames > 0 &&
180 frames < safety_frames) {
181 /* Avoid to pass over the last */
182 if (max_frames < safety_frames)
183 frames = max_frames;
184 else
185 frames = safety_frames;
187 if (frames < 0)
188 return 0;
189 return frames;
194 - stop PCM on xrun
195 - update poll status
196 - draining silencing
197 - return distance in frames to next event
199 static snd_pcm_uframes_t _snd_pcm_share_missing(snd_pcm_t *pcm)
201 snd_pcm_share_t *share = pcm->private_data;
202 snd_pcm_share_slave_t *slave = share->slave;
203 snd_pcm_t *spcm = slave->pcm;
204 snd_pcm_uframes_t buffer_size = spcm->buffer_size;
205 int ready = 1, running = 0;
206 snd_pcm_uframes_t avail = 0, slave_avail;
207 snd_pcm_sframes_t hw_avail;
208 snd_pcm_uframes_t missing = INT_MAX;
209 snd_pcm_sframes_t ready_missing;
210 // printf("state=%s hw_ptr=%ld appl_ptr=%ld slave appl_ptr=%ld safety=%ld silence=%ld\n", snd_pcm_state_name(share->state), slave->hw_ptr, share->appl_ptr, *slave->pcm->appl_ptr, slave->safety_threshold, slave->silence_frames);
211 switch (share->state) {
212 case SND_PCM_STATE_RUNNING:
213 break;
214 case SND_PCM_STATE_DRAINING:
215 if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
216 break;
217 /* Fall through */
218 default:
219 return INT_MAX;
221 share->hw_ptr = slave->hw_ptr;
222 avail = snd_pcm_mmap_avail(pcm);
223 if (avail >= pcm->stop_threshold) {
224 _snd_pcm_share_stop(pcm, share->state == SND_PCM_STATE_DRAINING ? SND_PCM_STATE_SETUP : SND_PCM_STATE_XRUN);
225 goto update_poll;
227 hw_avail = buffer_size - avail;
228 slave_avail = snd_pcm_share_slave_avail(slave);
229 if (avail < slave_avail) {
230 /* Some frames need still to be transferred */
231 snd_pcm_sframes_t slave_hw_avail = buffer_size - slave_avail;
232 snd_pcm_sframes_t safety_missing = slave_hw_avail - slave->safety_threshold;
233 if (safety_missing < 0) {
234 snd_pcm_sframes_t err;
235 snd_pcm_sframes_t frames = slave_avail - avail;
236 if (-safety_missing <= frames) {
237 frames = -safety_missing;
238 missing = 1;
240 err = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), frames);
241 if (err < 0) {
242 SYSMSG("snd_pcm_mmap_commit error");
243 return INT_MAX;
245 if (err != frames)
246 SYSMSG("commit returns %ld for size %ld", err, frames);
247 slave_avail -= err;
248 } else {
249 if (safety_missing == 0)
250 missing = 1;
251 else
252 missing = safety_missing;
255 switch (share->state) {
256 case SND_PCM_STATE_DRAINING:
257 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
258 if (hw_avail <= 0) {
259 _snd_pcm_share_stop(pcm, SND_PCM_STATE_SETUP);
260 break;
262 if ((snd_pcm_uframes_t)hw_avail < missing)
263 missing = hw_avail;
264 running = 1;
265 ready = 0;
267 break;
268 case SND_PCM_STATE_RUNNING:
269 if (avail >= pcm->stop_threshold) {
270 _snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
271 break;
272 } else {
273 snd_pcm_uframes_t xrun_missing = pcm->stop_threshold - avail;
274 if (missing > xrun_missing)
275 missing = xrun_missing;
277 ready_missing = pcm->avail_min - avail;
278 if (ready_missing > 0) {
279 ready = 0;
280 if (missing > (snd_pcm_uframes_t)ready_missing)
281 missing = ready_missing;
283 running = 1;
284 break;
285 default:
286 SNDERR("invalid shared PCM state %d", share->state);
287 return INT_MAX;
290 update_poll:
291 if (ready != share->ready) {
292 char buf[1];
293 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
294 if (ready)
295 read(share->slave_socket, buf, 1);
296 else
297 write(share->client_socket, buf, 1);
298 } else {
299 if (ready)
300 write(share->slave_socket, buf, 1);
301 else
302 read(share->client_socket, buf, 1);
304 share->ready = ready;
306 if (!running)
307 return INT_MAX;
308 if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
309 share->state == SND_PCM_STATE_DRAINING &&
310 !share->drain_silenced) {
311 /* drain silencing */
312 if (avail >= slave->silence_frames) {
313 snd_pcm_uframes_t offset = share->appl_ptr % buffer_size;
314 snd_pcm_uframes_t xfer = 0;
315 snd_pcm_uframes_t size = slave->silence_frames;
316 while (xfer < size) {
317 snd_pcm_uframes_t frames = size - xfer;
318 snd_pcm_uframes_t cont = buffer_size - offset;
319 if (cont < frames)
320 frames = cont;
321 snd_pcm_areas_silence(pcm->running_areas, offset, pcm->channels, frames, pcm->format);
322 offset += frames;
323 if (offset >= buffer_size)
324 offset = 0;
325 xfer += frames;
327 share->drain_silenced = 1;
328 } else {
329 snd_pcm_uframes_t silence_missing;
330 silence_missing = slave->silence_frames - avail;
331 if (silence_missing < missing)
332 missing = silence_missing;
335 // printf("missing=%d\n", missing);
336 return missing;
339 static snd_pcm_uframes_t _snd_pcm_share_slave_missing(snd_pcm_share_slave_t *slave)
341 snd_pcm_uframes_t missing = INT_MAX;
342 struct list_head *i;
343 /* snd_pcm_sframes_t avail = */ snd_pcm_avail_update(slave->pcm);
344 slave->hw_ptr = *slave->pcm->hw.ptr;
345 list_for_each(i, &slave->clients) {
346 snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
347 snd_pcm_t *pcm = share->pcm;
348 snd_pcm_uframes_t m = _snd_pcm_share_missing(pcm);
349 if (m < missing)
350 missing = m;
352 return missing;
355 static void *snd_pcm_share_thread(void *data)
357 snd_pcm_share_slave_t *slave = data;
358 snd_pcm_t *spcm = slave->pcm;
359 struct pollfd pfd[2];
360 int err;
362 pfd[0].fd = slave->poll[0];
363 pfd[0].events = POLLIN;
364 err = snd_pcm_poll_descriptors(spcm, &pfd[1], 1);
365 if (err != 1) {
366 SNDERR("invalid poll descriptors %d", err);
367 return NULL;
369 Pthread_mutex_lock(&slave->mutex);
370 err = pipe(slave->poll);
371 if (err < 0) {
372 SYSERR("can't create a pipe");
373 return NULL;
375 while (slave->open_count > 0) {
376 snd_pcm_uframes_t missing;
377 // printf("begin min_missing\n");
378 missing = _snd_pcm_share_slave_missing(slave);
379 // printf("min_missing=%ld\n", missing);
380 if (missing < INT_MAX) {
381 snd_pcm_uframes_t hw_ptr;
382 snd_pcm_sframes_t avail_min;
383 hw_ptr = slave->hw_ptr + missing;
384 hw_ptr += spcm->period_size - 1;
385 if (hw_ptr >= spcm->boundary)
386 hw_ptr -= spcm->boundary;
387 hw_ptr -= hw_ptr % spcm->period_size;
388 avail_min = hw_ptr - *spcm->appl.ptr;
389 if (spcm->stream == SND_PCM_STREAM_PLAYBACK)
390 avail_min += spcm->buffer_size;
391 if (avail_min < 0)
392 avail_min += spcm->boundary;
393 // printf("avail_min=%d\n", avail_min);
394 if ((snd_pcm_uframes_t)avail_min != spcm->avail_min) {
395 snd_pcm_sw_params_set_avail_min(spcm, &slave->sw_params, avail_min);
396 err = snd_pcm_sw_params(spcm, &slave->sw_params);
397 if (err < 0) {
398 SYSERR("snd_pcm_sw_params error");
399 return NULL;
402 slave->polling = 1;
403 Pthread_mutex_unlock(&slave->mutex);
404 err = poll(pfd, 2, -1);
405 Pthread_mutex_lock(&slave->mutex);
406 if (pfd[0].revents & POLLIN) {
407 char buf[1];
408 read(pfd[0].fd, buf, 1);
410 } else {
411 slave->polling = 0;
412 pthread_cond_wait(&slave->poll_cond, &slave->mutex);
415 Pthread_mutex_unlock(&slave->mutex);
416 return NULL;
419 static void _snd_pcm_share_update(snd_pcm_t *pcm)
421 snd_pcm_share_t *share = pcm->private_data;
422 snd_pcm_share_slave_t *slave = share->slave;
423 snd_pcm_t *spcm = slave->pcm;
424 snd_pcm_uframes_t missing;
425 /* snd_pcm_sframes_t avail = */ snd_pcm_avail_update(spcm);
426 slave->hw_ptr = *slave->pcm->hw.ptr;
427 missing = _snd_pcm_share_missing(pcm);
428 // printf("missing %ld\n", missing);
429 if (!slave->polling) {
430 pthread_cond_signal(&slave->poll_cond);
431 return;
433 if (missing < INT_MAX) {
434 snd_pcm_uframes_t hw_ptr;
435 snd_pcm_sframes_t avail_min;
436 hw_ptr = slave->hw_ptr + missing;
437 hw_ptr += spcm->period_size - 1;
438 if (hw_ptr >= spcm->boundary)
439 hw_ptr -= spcm->boundary;
440 hw_ptr -= hw_ptr % spcm->period_size;
441 avail_min = hw_ptr - *spcm->appl.ptr;
442 if (spcm->stream == SND_PCM_STREAM_PLAYBACK)
443 avail_min += spcm->buffer_size;
444 if (avail_min < 0)
445 avail_min += spcm->boundary;
446 if ((snd_pcm_uframes_t)avail_min < spcm->avail_min) {
447 int err;
448 snd_pcm_sw_params_set_avail_min(spcm, &slave->sw_params, avail_min);
449 err = snd_pcm_sw_params(spcm, &slave->sw_params);
450 if (err < 0) {
451 SYSERR("snd_pcm_sw_params error");
452 return;
458 static int snd_pcm_share_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
460 return 0;
463 static int snd_pcm_share_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int sig ATTRIBUTE_UNUSED, pid_t pid ATTRIBUTE_UNUSED)
465 return -ENOSYS;
468 static int snd_pcm_share_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
470 snd_pcm_share_t *share = pcm->private_data;
471 return snd_pcm_info(share->slave->pcm, info);
474 static int snd_pcm_share_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
476 snd_pcm_share_t *share = pcm->private_data;
477 snd_pcm_share_slave_t *slave = share->slave;
478 snd_pcm_access_mask_t access_mask;
479 int err;
480 snd_pcm_access_mask_any(&access_mask);
481 snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
482 err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
483 &access_mask);
484 if (err < 0)
485 return err;
486 err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS,
487 share->channels, 0);
488 if (err < 0)
489 return err;
490 if (slave->format != SND_PCM_FORMAT_UNKNOWN) {
491 err = _snd_pcm_hw_params_set_format(params, slave->format);
492 if (err < 0)
493 return err;
496 if (slave->rate >= 0) {
497 err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_RATE,
498 slave->rate, 0);
499 if (err < 0)
500 return err;
502 if (slave->period_time >= 0) {
503 err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_PERIOD_TIME,
504 slave->period_time, 0);
505 if (err < 0)
506 return err;
508 if (slave->buffer_time >= 0) {
509 err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_BUFFER_TIME,
510 slave->buffer_time, 0);
511 if (err < 0)
512 return err;
514 params->info |= SND_PCM_INFO_DOUBLE;
515 return 0;
518 static int snd_pcm_share_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
520 snd_pcm_share_t *share = pcm->private_data;
521 snd_pcm_share_slave_t *slave = share->slave;
522 snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP };
523 _snd_pcm_hw_params_any(sparams);
524 _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
525 &saccess_mask);
526 _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS,
527 slave->channels, 0);
528 return 0;
531 static int snd_pcm_share_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
532 snd_pcm_hw_params_t *sparams)
534 int err;
535 unsigned int links = (SND_PCM_HW_PARBIT_FORMAT |
536 SND_PCM_HW_PARBIT_SUBFORMAT |
537 SND_PCM_HW_PARBIT_RATE |
538 SND_PCM_HW_PARBIT_PERIOD_SIZE |
539 SND_PCM_HW_PARBIT_PERIOD_TIME |
540 SND_PCM_HW_PARBIT_BUFFER_SIZE |
541 SND_PCM_HW_PARBIT_BUFFER_TIME |
542 SND_PCM_HW_PARBIT_PERIODS);
543 const snd_pcm_access_mask_t *access_mask = snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS);
544 if (!snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) &&
545 !snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED) &&
546 !snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) {
547 snd_pcm_access_mask_t saccess_mask;
548 snd_pcm_access_mask_any(&saccess_mask);
549 snd_pcm_access_mask_reset(&saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
550 err = _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
551 &saccess_mask);
552 if (err < 0)
553 return err;
555 err = _snd_pcm_hw_params_refine(sparams, links, params);
556 if (err < 0)
557 return err;
558 return 0;
561 static int snd_pcm_share_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
562 snd_pcm_hw_params_t *sparams)
564 int err;
565 unsigned int links = (SND_PCM_HW_PARBIT_FORMAT |
566 SND_PCM_HW_PARBIT_SUBFORMAT |
567 SND_PCM_HW_PARBIT_RATE |
568 SND_PCM_HW_PARBIT_PERIOD_SIZE |
569 SND_PCM_HW_PARBIT_PERIOD_TIME |
570 SND_PCM_HW_PARBIT_BUFFER_SIZE |
571 SND_PCM_HW_PARBIT_BUFFER_TIME |
572 SND_PCM_HW_PARBIT_PERIODS);
573 snd_pcm_access_mask_t access_mask;
574 const snd_pcm_access_mask_t *saccess_mask = snd_pcm_hw_param_get_mask(sparams, SND_PCM_HW_PARAM_ACCESS);
575 snd_pcm_access_mask_any(&access_mask);
576 snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
577 if (!snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
578 snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
579 if (!snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX) &&
580 !snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED))
581 snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
582 err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
583 &access_mask);
584 if (err < 0)
585 return err;
586 err = _snd_pcm_hw_params_refine(params, links, sparams);
587 if (err < 0)
588 return err;
589 return 0;
592 static int snd_pcm_share_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
594 snd_pcm_share_t *share = pcm->private_data;
595 return snd_pcm_hw_refine(share->slave->pcm, params);
598 static int snd_pcm_share_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
600 snd_pcm_share_t *share = pcm->private_data;
601 return _snd_pcm_hw_params(share->slave->pcm, params);
604 static int snd_pcm_share_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
606 return snd_pcm_hw_refine_slave(pcm, params,
607 snd_pcm_share_hw_refine_cprepare,
608 snd_pcm_share_hw_refine_cchange,
609 snd_pcm_share_hw_refine_sprepare,
610 snd_pcm_share_hw_refine_schange,
611 snd_pcm_share_hw_refine_slave);
614 static int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
616 snd_pcm_share_t *share = pcm->private_data;
617 snd_pcm_share_slave_t *slave = share->slave;
618 snd_pcm_t *spcm = slave->pcm;
619 int err = 0;
620 Pthread_mutex_lock(&slave->mutex);
621 if (slave->setup_count) {
622 err = _snd_pcm_hw_params_set_format(params, spcm->format);
623 if (err < 0)
624 goto _err;
625 err = _snd_pcm_hw_params_set_subformat(params, spcm->subformat);
626 if (err < 0)
627 goto _err;
628 err = _snd_pcm_hw_param_set_minmax(params, SND_PCM_HW_PARAM_RATE,
629 spcm->rate, 0,
630 spcm->rate, 1);
631 if (err < 0)
632 goto _err;
633 err = _snd_pcm_hw_param_set_minmax(params, SND_PCM_HW_PARAM_PERIOD_TIME,
634 spcm->period_time, 0,
635 spcm->period_time, 1);
636 if (err < 0)
637 goto _err;
638 err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_BUFFER_SIZE,
639 spcm->buffer_size, 0);
640 _err:
641 if (err < 0) {
642 SNDERR("slave is already running with incompatible setup");
643 err = -EBUSY;
644 goto _end;
646 } else {
647 err = snd_pcm_hw_params_slave(pcm, params,
648 snd_pcm_share_hw_refine_cchange,
649 snd_pcm_share_hw_refine_sprepare,
650 snd_pcm_share_hw_refine_schange,
651 snd_pcm_share_hw_params_slave);
652 if (err < 0)
653 goto _end;
654 snd_pcm_sw_params_current(slave->pcm, &slave->sw_params);
655 /* >= 30 ms */
656 slave->safety_threshold = slave->pcm->rate * 30 / 1000;
657 slave->safety_threshold += slave->pcm->period_size - 1;
658 slave->safety_threshold -= slave->safety_threshold % slave->pcm->period_size;
659 slave->silence_frames = slave->safety_threshold;
660 if (slave->pcm->stream == SND_PCM_STREAM_PLAYBACK)
661 snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->channels, slave->pcm->buffer_size, slave->pcm->format);
663 share->state = SND_PCM_STATE_SETUP;
664 slave->setup_count++;
665 _end:
666 Pthread_mutex_unlock(&slave->mutex);
667 return err;
670 static int snd_pcm_share_hw_free(snd_pcm_t *pcm)
672 snd_pcm_share_t *share = pcm->private_data;
673 snd_pcm_share_slave_t *slave = share->slave;
674 int err = 0;
675 Pthread_mutex_lock(&slave->mutex);
676 slave->setup_count--;
677 if (slave->setup_count == 0)
678 err = snd_pcm_hw_free(slave->pcm);
679 share->state = SND_PCM_STATE_OPEN;
680 Pthread_mutex_unlock(&slave->mutex);
681 return err;
684 static int snd_pcm_share_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params ATTRIBUTE_UNUSED)
686 return 0;
689 static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
691 snd_pcm_share_t *share = pcm->private_data;
692 snd_pcm_share_slave_t *slave = share->slave;
693 int err = 0;
694 snd_pcm_sframes_t sd = 0, d = 0;
695 Pthread_mutex_lock(&slave->mutex);
696 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
697 status->avail = snd_pcm_mmap_playback_avail(pcm);
698 if (share->state != SND_PCM_STATE_RUNNING &&
699 share->state != SND_PCM_STATE_DRAINING)
700 goto _notrunning;
701 d = pcm->buffer_size - status->avail;
702 } else {
703 status->avail = snd_pcm_mmap_capture_avail(pcm);
704 if (share->state != SND_PCM_STATE_RUNNING)
705 goto _notrunning;
706 d = status->avail;
708 err = snd_pcm_delay(slave->pcm, &sd);
709 if (err < 0)
710 goto _end;
711 _notrunning:
712 status->delay = sd + d;
713 status->state = share->state;
714 status->trigger_tstamp = share->trigger_tstamp;
715 _end:
716 Pthread_mutex_unlock(&slave->mutex);
717 return err;
720 static snd_pcm_state_t snd_pcm_share_state(snd_pcm_t *pcm)
722 snd_pcm_share_t *share = pcm->private_data;
723 return share->state;
726 static int _snd_pcm_share_hwsync(snd_pcm_t *pcm)
728 snd_pcm_share_t *share = pcm->private_data;
729 snd_pcm_share_slave_t *slave = share->slave;
730 switch (share->state) {
731 case SND_PCM_STATE_XRUN:
732 return -EPIPE;
733 default:
734 break;
736 return snd_pcm_hwsync(slave->pcm);
739 static int snd_pcm_share_hwsync(snd_pcm_t *pcm)
741 snd_pcm_share_t *share = pcm->private_data;
742 snd_pcm_share_slave_t *slave = share->slave;
743 int err;
744 Pthread_mutex_lock(&slave->mutex);
745 err = _snd_pcm_share_hwsync(pcm);
746 Pthread_mutex_unlock(&slave->mutex);
747 return err;
750 static int _snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
752 snd_pcm_share_t *share = pcm->private_data;
753 snd_pcm_share_slave_t *slave = share->slave;
754 switch (share->state) {
755 case SND_PCM_STATE_XRUN:
756 return -EPIPE;
757 case SND_PCM_STATE_RUNNING:
758 break;
759 case SND_PCM_STATE_DRAINING:
760 if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
761 break;
762 /* Fall through */
763 default:
764 return -EBADFD;
766 return snd_pcm_delay(slave->pcm, delayp);
769 static int snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
771 snd_pcm_share_t *share = pcm->private_data;
772 snd_pcm_share_slave_t *slave = share->slave;
773 int err;
774 Pthread_mutex_lock(&slave->mutex);
775 err = _snd_pcm_share_delay(pcm, delayp);
776 Pthread_mutex_unlock(&slave->mutex);
777 return err;
780 static snd_pcm_sframes_t snd_pcm_share_avail_update(snd_pcm_t *pcm)
782 snd_pcm_share_t *share = pcm->private_data;
783 snd_pcm_share_slave_t *slave = share->slave;
784 snd_pcm_sframes_t avail;
785 Pthread_mutex_lock(&slave->mutex);
786 if (share->state == SND_PCM_STATE_RUNNING) {
787 avail = snd_pcm_avail_update(slave->pcm);
788 if (avail < 0) {
789 Pthread_mutex_unlock(&slave->mutex);
790 return avail;
792 share->hw_ptr = *slave->pcm->hw.ptr;
794 Pthread_mutex_unlock(&slave->mutex);
795 avail = snd_pcm_mmap_avail(pcm);
796 if ((snd_pcm_uframes_t)avail > pcm->buffer_size)
797 return -EPIPE;
798 return avail;
801 static int snd_pcm_share_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
802 snd_htimestamp_t *tstamp)
804 snd_pcm_share_t *share = pcm->private_data;
805 snd_pcm_share_slave_t *slave = share->slave;
806 int err;
807 Pthread_mutex_lock(&slave->mutex);
808 err = snd_pcm_htimestamp(slave->pcm, avail, tstamp);
809 Pthread_mutex_unlock(&slave->mutex);
810 return err;
813 /* Call it with mutex held */
814 static snd_pcm_sframes_t _snd_pcm_share_mmap_commit(snd_pcm_t *pcm,
815 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
816 snd_pcm_uframes_t size)
818 snd_pcm_share_t *share = pcm->private_data;
819 snd_pcm_share_slave_t *slave = share->slave;
820 snd_pcm_t *spcm = slave->pcm;
821 snd_pcm_sframes_t ret;
822 snd_pcm_sframes_t frames;
823 if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
824 share->state == SND_PCM_STATE_RUNNING) {
825 frames = *spcm->appl.ptr - share->appl_ptr;
826 if (frames > (snd_pcm_sframes_t)pcm->buffer_size)
827 frames -= pcm->boundary;
828 else if (frames < -(snd_pcm_sframes_t)pcm->buffer_size)
829 frames += pcm->boundary;
830 if (frames > 0) {
831 /* Latecomer PCM */
832 ret = snd_pcm_rewind(spcm, frames);
833 if (ret < 0)
834 return ret;
837 snd_pcm_mmap_appl_forward(pcm, size);
838 if (share->state == SND_PCM_STATE_RUNNING) {
839 frames = _snd_pcm_share_slave_forward(slave);
840 if (frames > 0) {
841 snd_pcm_sframes_t err;
842 err = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), frames);
843 if (err < 0) {
844 SYSMSG("snd_pcm_mmap_commit error");
845 return err;
847 if (err != frames) {
848 SYSMSG("commit returns %ld for size %ld", err, frames);
849 return err;
852 _snd_pcm_share_update(pcm);
854 return size;
857 static snd_pcm_sframes_t snd_pcm_share_mmap_commit(snd_pcm_t *pcm,
858 snd_pcm_uframes_t offset,
859 snd_pcm_uframes_t size)
861 snd_pcm_share_t *share = pcm->private_data;
862 snd_pcm_share_slave_t *slave = share->slave;
863 snd_pcm_sframes_t ret;
864 Pthread_mutex_lock(&slave->mutex);
865 ret = _snd_pcm_share_mmap_commit(pcm, offset, size);
866 Pthread_mutex_unlock(&slave->mutex);
867 return ret;
870 static int snd_pcm_share_prepare(snd_pcm_t *pcm)
872 snd_pcm_share_t *share = pcm->private_data;
873 snd_pcm_share_slave_t *slave = share->slave;
874 int err = 0;
875 Pthread_mutex_lock(&slave->mutex);
876 switch (share->state) {
877 case SND_PCM_STATE_OPEN:
878 err = -EBADFD;
879 goto _end;
880 case SND_PCM_STATE_RUNNING:
881 err = -EBUSY;
882 goto _end;
883 case SND_PCM_STATE_PREPARED:
884 err = 0;
885 goto _end;
886 default: /* nothing todo */
887 break;
889 if (slave->prepared_count == 0) {
890 err = snd_pcm_prepare(slave->pcm);
891 if (err < 0)
892 goto _end;
894 slave->prepared_count++;
895 share->hw_ptr = 0;
896 share->appl_ptr = 0;
897 share->state = SND_PCM_STATE_PREPARED;
898 _end:
899 Pthread_mutex_unlock(&slave->mutex);
900 return err;
903 static int snd_pcm_share_reset(snd_pcm_t *pcm)
905 snd_pcm_share_t *share = pcm->private_data;
906 snd_pcm_share_slave_t *slave = share->slave;
907 int err = 0;
908 /* FIXME? */
909 Pthread_mutex_lock(&slave->mutex);
910 snd_pcm_areas_silence(pcm->running_areas, 0, pcm->channels, pcm->buffer_size, pcm->format);
911 share->hw_ptr = *slave->pcm->hw.ptr;
912 share->appl_ptr = share->hw_ptr;
913 Pthread_mutex_unlock(&slave->mutex);
914 return err;
917 static int snd_pcm_share_start(snd_pcm_t *pcm)
919 snd_pcm_share_t *share = pcm->private_data;
920 snd_pcm_share_slave_t *slave = share->slave;
921 snd_pcm_t *spcm = slave->pcm;
922 int err = 0;
923 if (share->state != SND_PCM_STATE_PREPARED)
924 return -EBADFD;
925 Pthread_mutex_lock(&slave->mutex);
926 share->state = SND_PCM_STATE_RUNNING;
927 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
928 snd_pcm_uframes_t hw_avail = snd_pcm_mmap_playback_hw_avail(pcm);
929 snd_pcm_uframes_t xfer = 0;
930 if (hw_avail == 0) {
931 err = -EPIPE;
932 goto _end;
934 if (slave->running_count) {
935 snd_pcm_sframes_t sd;
936 err = snd_pcm_delay(spcm, &sd);
937 if (err < 0)
938 goto _end;
939 err = snd_pcm_rewind(spcm, sd);
940 if (err < 0)
941 goto _end;
943 assert(share->hw_ptr == 0);
944 share->hw_ptr = *spcm->hw.ptr;
945 share->appl_ptr = *spcm->appl.ptr;
946 while (xfer < hw_avail) {
947 snd_pcm_uframes_t frames = hw_avail - xfer;
948 snd_pcm_uframes_t offset = snd_pcm_mmap_offset(pcm);
949 snd_pcm_uframes_t cont = pcm->buffer_size - offset;
950 if (cont < frames)
951 frames = cont;
952 if (pcm->stopped_areas != NULL)
953 snd_pcm_areas_copy(pcm->running_areas, offset,
954 pcm->stopped_areas, xfer,
955 pcm->channels, frames,
956 pcm->format);
957 xfer += frames;
959 snd_pcm_mmap_appl_forward(pcm, hw_avail);
960 if (slave->running_count == 0) {
961 snd_pcm_sframes_t res;
962 res = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), hw_avail);
963 if (res < 0) {
964 err = res;
965 goto _end;
967 assert((snd_pcm_uframes_t)res == hw_avail);
970 if (slave->running_count == 0) {
971 err = snd_pcm_start(spcm);
972 if (err < 0)
973 goto _end;
975 slave->running_count++;
976 _snd_pcm_share_update(pcm);
977 gettimestamp(&share->trigger_tstamp, pcm->monotonic);
978 _end:
979 Pthread_mutex_unlock(&slave->mutex);
980 return err;
983 static int snd_pcm_share_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
985 return -ENOSYS;
988 static int snd_pcm_share_resume(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
990 return -ENXIO;
993 static int snd_pcm_share_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
995 snd_pcm_share_t *share = pcm->private_data;
996 snd_pcm_share_slave_t *slave = share->slave;
997 unsigned int channel = info->channel;
998 int c = share->slave_channels[channel];
999 int err;
1000 info->channel = c;
1001 err = snd_pcm_channel_info(slave->pcm, info);
1002 info->channel = channel;
1003 return err;
1006 static snd_pcm_sframes_t _snd_pcm_share_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
1008 snd_pcm_share_t *share = pcm->private_data;
1009 snd_pcm_share_slave_t *slave = share->slave;
1010 snd_pcm_sframes_t n;
1011 switch (share->state) {
1012 case SND_PCM_STATE_RUNNING:
1013 break;
1014 case SND_PCM_STATE_PREPARED:
1015 if (pcm->stream != SND_PCM_STREAM_PLAYBACK)
1016 return -EBADFD;
1017 break;
1018 case SND_PCM_STATE_DRAINING:
1019 if (pcm->stream != SND_PCM_STREAM_CAPTURE)
1020 return -EBADFD;
1021 break;
1022 case SND_PCM_STATE_XRUN:
1023 return -EPIPE;
1024 default:
1025 return -EBADFD;
1027 n = snd_pcm_mmap_hw_avail(pcm);
1028 assert(n >= 0);
1029 if ((snd_pcm_uframes_t)n > frames)
1030 frames = n;
1031 if (share->state == SND_PCM_STATE_RUNNING && frames > 0) {
1032 snd_pcm_sframes_t ret = snd_pcm_rewind(slave->pcm, frames);
1033 if (ret < 0)
1034 return ret;
1035 frames = ret;
1037 snd_pcm_mmap_appl_backward(pcm, frames);
1038 _snd_pcm_share_update(pcm);
1039 return n;
1042 static snd_pcm_sframes_t snd_pcm_share_rewindable(snd_pcm_t *pcm)
1044 snd_pcm_share_t *share = pcm->private_data;
1045 snd_pcm_share_slave_t *slave = share->slave;
1046 snd_pcm_sframes_t ret;
1047 Pthread_mutex_lock(&slave->mutex);
1048 ret = snd_pcm_rewindable(slave->pcm);
1049 Pthread_mutex_unlock(&slave->mutex);
1050 return ret;
1053 static snd_pcm_sframes_t snd_pcm_share_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
1055 snd_pcm_share_t *share = pcm->private_data;
1056 snd_pcm_share_slave_t *slave = share->slave;
1057 snd_pcm_sframes_t ret;
1058 Pthread_mutex_lock(&slave->mutex);
1059 ret = _snd_pcm_share_rewind(pcm, frames);
1060 Pthread_mutex_unlock(&slave->mutex);
1061 return ret;
1064 static snd_pcm_sframes_t _snd_pcm_share_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
1066 snd_pcm_share_t *share = pcm->private_data;
1067 snd_pcm_share_slave_t *slave = share->slave;
1068 snd_pcm_sframes_t n;
1069 switch (share->state) {
1070 case SND_PCM_STATE_RUNNING:
1071 break;
1072 case SND_PCM_STATE_PREPARED:
1073 if (pcm->stream != SND_PCM_STREAM_PLAYBACK)
1074 return -EBADFD;
1075 break;
1076 case SND_PCM_STATE_DRAINING:
1077 if (pcm->stream != SND_PCM_STREAM_CAPTURE)
1078 return -EBADFD;
1079 break;
1080 case SND_PCM_STATE_XRUN:
1081 return -EPIPE;
1082 default:
1083 return -EBADFD;
1085 n = snd_pcm_mmap_avail(pcm);
1086 if ((snd_pcm_uframes_t)n > frames)
1087 frames = n;
1088 if (share->state == SND_PCM_STATE_RUNNING && frames > 0) {
1089 snd_pcm_sframes_t ret = INTERNAL(snd_pcm_forward)(slave->pcm, frames);
1090 if (ret < 0)
1091 return ret;
1092 frames = ret;
1094 snd_pcm_mmap_appl_forward(pcm, frames);
1095 _snd_pcm_share_update(pcm);
1096 return n;
1099 static snd_pcm_sframes_t snd_pcm_share_forwardable(snd_pcm_t *pcm)
1101 snd_pcm_share_t *share = pcm->private_data;
1102 snd_pcm_share_slave_t *slave = share->slave;
1103 snd_pcm_sframes_t ret;
1104 Pthread_mutex_lock(&slave->mutex);
1105 ret = snd_pcm_forwardable(slave->pcm);
1106 Pthread_mutex_unlock(&slave->mutex);
1107 return ret;
1110 static snd_pcm_sframes_t snd_pcm_share_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
1112 snd_pcm_share_t *share = pcm->private_data;
1113 snd_pcm_share_slave_t *slave = share->slave;
1114 snd_pcm_sframes_t ret;
1115 Pthread_mutex_lock(&slave->mutex);
1116 ret = _snd_pcm_share_forward(pcm, frames);
1117 Pthread_mutex_unlock(&slave->mutex);
1118 return ret;
1121 /* Warning: take the mutex before to call this */
1122 static void _snd_pcm_share_stop(snd_pcm_t *pcm, snd_pcm_state_t state)
1124 snd_pcm_share_t *share = pcm->private_data;
1125 snd_pcm_share_slave_t *slave = share->slave;
1126 #if 0
1127 if (!pcm->mmap_channels) {
1128 /* PCM closing already begun in the main thread */
1129 return;
1131 #endif
1132 gettimestamp(&share->trigger_tstamp, pcm->monotonic);
1133 if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
1134 snd_pcm_areas_copy(pcm->stopped_areas, 0,
1135 pcm->running_areas, 0,
1136 pcm->channels, pcm->buffer_size,
1137 pcm->format);
1138 } else if (slave->running_count > 1) {
1139 int err;
1140 snd_pcm_sframes_t delay;
1141 snd_pcm_areas_silence(pcm->running_areas, 0, pcm->channels,
1142 pcm->buffer_size, pcm->format);
1143 err = snd_pcm_delay(slave->pcm, &delay);
1144 if (err >= 0 && delay > 0)
1145 snd_pcm_rewind(slave->pcm, delay);
1146 share->drain_silenced = 0;
1148 share->state = state;
1149 slave->prepared_count--;
1150 slave->running_count--;
1151 if (slave->running_count == 0) {
1152 int err = snd_pcm_drop(slave->pcm);
1153 assert(err >= 0);
1157 static int snd_pcm_share_drain(snd_pcm_t *pcm)
1159 snd_pcm_share_t *share = pcm->private_data;
1160 snd_pcm_share_slave_t *slave = share->slave;
1161 int err = 0;
1162 Pthread_mutex_lock(&slave->mutex);
1163 switch (share->state) {
1164 case SND_PCM_STATE_OPEN:
1165 err = -EBADFD;
1166 goto _end;
1167 case SND_PCM_STATE_PREPARED:
1168 share->state = SND_PCM_STATE_SETUP;
1169 goto _end;
1170 case SND_PCM_STATE_SETUP:
1171 goto _end;
1172 default:
1173 break;
1175 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
1176 switch (share->state) {
1177 case SND_PCM_STATE_XRUN:
1178 share->state = SND_PCM_STATE_SETUP;
1179 goto _end;
1180 case SND_PCM_STATE_DRAINING:
1181 case SND_PCM_STATE_RUNNING:
1182 share->state = SND_PCM_STATE_DRAINING;
1183 _snd_pcm_share_update(pcm);
1184 Pthread_mutex_unlock(&slave->mutex);
1185 if (!(pcm->mode & SND_PCM_NONBLOCK))
1186 snd_pcm_wait(pcm, -1);
1187 return 0;
1188 default:
1189 assert(0);
1190 break;
1192 } else {
1193 switch (share->state) {
1194 case SND_PCM_STATE_RUNNING:
1195 _snd_pcm_share_stop(pcm, SND_PCM_STATE_DRAINING);
1196 _snd_pcm_share_update(pcm);
1197 /* Fall through */
1198 case SND_PCM_STATE_XRUN:
1199 case SND_PCM_STATE_DRAINING:
1200 if (snd_pcm_mmap_capture_avail(pcm) <= 0)
1201 share->state = SND_PCM_STATE_SETUP;
1202 else
1203 share->state = SND_PCM_STATE_DRAINING;
1204 break;
1205 default:
1206 assert(0);
1207 break;
1210 _end:
1211 Pthread_mutex_unlock(&slave->mutex);
1212 return err;
1215 static int snd_pcm_share_drop(snd_pcm_t *pcm)
1217 snd_pcm_share_t *share = pcm->private_data;
1218 snd_pcm_share_slave_t *slave = share->slave;
1219 int err = 0;
1220 Pthread_mutex_lock(&slave->mutex);
1221 switch (share->state) {
1222 case SND_PCM_STATE_OPEN:
1223 err = -EBADFD;
1224 goto _end;
1225 case SND_PCM_STATE_SETUP:
1226 break;
1227 case SND_PCM_STATE_DRAINING:
1228 if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
1229 share->state = SND_PCM_STATE_SETUP;
1230 break;
1232 /* Fall through */
1233 case SND_PCM_STATE_RUNNING:
1234 _snd_pcm_share_stop(pcm, SND_PCM_STATE_SETUP);
1235 _snd_pcm_share_update(pcm);
1236 break;
1237 case SND_PCM_STATE_PREPARED:
1238 case SND_PCM_STATE_XRUN:
1239 share->state = SND_PCM_STATE_SETUP;
1240 break;
1241 default:
1242 assert(0);
1243 break;
1246 share->appl_ptr = share->hw_ptr = 0;
1247 _end:
1248 Pthread_mutex_unlock(&slave->mutex);
1249 return err;
1252 static int snd_pcm_share_close(snd_pcm_t *pcm)
1254 snd_pcm_share_t *share = pcm->private_data;
1255 snd_pcm_share_slave_t *slave = share->slave;
1256 int err = 0;
1258 Pthread_mutex_lock(&snd_pcm_share_slaves_mutex);
1259 Pthread_mutex_lock(&slave->mutex);
1260 slave->open_count--;
1261 if (slave->open_count == 0) {
1262 pthread_cond_signal(&slave->poll_cond);
1263 Pthread_mutex_unlock(&slave->mutex);
1264 err = pthread_join(slave->thread, 0);
1265 assert(err == 0);
1266 err = snd_pcm_close(slave->pcm);
1267 pthread_mutex_destroy(&slave->mutex);
1268 pthread_cond_destroy(&slave->poll_cond);
1269 list_del(&slave->list);
1270 free(slave);
1271 list_del(&share->list);
1272 } else {
1273 list_del(&share->list);
1274 Pthread_mutex_unlock(&slave->mutex);
1276 Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex);
1277 close(share->client_socket);
1278 close(share->slave_socket);
1279 free(share->slave_channels);
1280 free(share);
1281 return err;
1284 static int snd_pcm_share_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
1286 return 0;
1289 static int snd_pcm_share_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
1291 return 0;
1294 static void snd_pcm_share_dump(snd_pcm_t *pcm, snd_output_t *out)
1296 snd_pcm_share_t *share = pcm->private_data;
1297 snd_pcm_share_slave_t *slave = share->slave;
1298 unsigned int k;
1299 snd_output_printf(out, "Share PCM\n");
1300 snd_output_printf(out, " Channel bindings:\n");
1301 for (k = 0; k < share->channels; ++k)
1302 snd_output_printf(out, " %d: %d\n", k, share->slave_channels[k]);
1303 if (pcm->setup) {
1304 snd_output_printf(out, "Its setup is:\n");
1305 snd_pcm_dump_setup(pcm, out);
1307 snd_output_printf(out, "Slave: ");
1308 snd_pcm_dump(slave->pcm, out);
1311 static const snd_pcm_ops_t snd_pcm_share_ops = {
1312 .close = snd_pcm_share_close,
1313 .info = snd_pcm_share_info,
1314 .hw_refine = snd_pcm_share_hw_refine,
1315 .hw_params = snd_pcm_share_hw_params,
1316 .hw_free = snd_pcm_share_hw_free,
1317 .sw_params = snd_pcm_share_sw_params,
1318 .channel_info = snd_pcm_share_channel_info,
1319 .dump = snd_pcm_share_dump,
1320 .nonblock = snd_pcm_share_nonblock,
1321 .async = snd_pcm_share_async,
1322 .mmap = snd_pcm_share_mmap,
1323 .munmap = snd_pcm_share_munmap,
1326 static const snd_pcm_fast_ops_t snd_pcm_share_fast_ops = {
1327 .status = snd_pcm_share_status,
1328 .state = snd_pcm_share_state,
1329 .hwsync = snd_pcm_share_hwsync,
1330 .delay = snd_pcm_share_delay,
1331 .prepare = snd_pcm_share_prepare,
1332 .reset = snd_pcm_share_reset,
1333 .start = snd_pcm_share_start,
1334 .drop = snd_pcm_share_drop,
1335 .drain = snd_pcm_share_drain,
1336 .pause = snd_pcm_share_pause,
1337 .writei = snd_pcm_mmap_writei,
1338 .writen = snd_pcm_mmap_writen,
1339 .readi = snd_pcm_mmap_readi,
1340 .readn = snd_pcm_mmap_readn,
1341 .rewindable = snd_pcm_share_rewindable,
1342 .rewind = snd_pcm_share_rewind,
1343 .forwardable = snd_pcm_share_forwardable,
1344 .forward = snd_pcm_share_forward,
1345 .resume = snd_pcm_share_resume,
1346 .avail_update = snd_pcm_share_avail_update,
1347 .htimestamp = snd_pcm_share_htimestamp,
1348 .mmap_commit = snd_pcm_share_mmap_commit,
1352 * \brief Creates a new Share PCM
1353 * \param pcmp Returns created PCM handle
1354 * \param name Name of PCM
1355 * \param sname Slave name
1356 * \param sformat Slave format
1357 * \param srate Slave rate
1358 * \param schannels Slave channels
1359 * \param speriod_time Slave period time
1360 * \param sbuffer_time Slave buffer time
1361 * \param channels Count of channels
1362 * \param channels_map Map of channels
1363 * \param stream Direction
1364 * \param mode PCM mode
1365 * \retval zero on success otherwise a negative error code
1366 * \warning Using of this function might be dangerous in the sense
1367 * of compatibility reasons. The prototype might be freely
1368 * changed in future.
1370 int snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname,
1371 snd_pcm_format_t sformat, int srate,
1372 unsigned int schannels,
1373 int speriod_time, int sbuffer_time,
1374 unsigned int channels, unsigned int *channels_map,
1375 snd_pcm_stream_t stream, int mode)
1377 snd_pcm_t *pcm;
1378 snd_pcm_share_t *share;
1379 int err;
1380 struct list_head *i;
1381 char slave_map[32] = { 0 };
1382 unsigned int k;
1383 snd_pcm_share_slave_t *slave = NULL;
1384 int sd[2];
1386 assert(pcmp);
1387 assert(channels > 0 && sname && channels_map);
1389 for (k = 0; k < channels; ++k) {
1390 if (channels_map[k] >= sizeof(slave_map) / sizeof(slave_map[0])) {
1391 SNDERR("Invalid slave channel (%d) in binding", channels_map[k]);
1392 return -EINVAL;
1394 if (slave_map[channels_map[k]]) {
1395 SNDERR("Repeated slave channel (%d) in binding", channels_map[k]);
1396 return -EINVAL;
1398 slave_map[channels_map[k]] = 1;
1399 assert((unsigned)channels_map[k] < schannels);
1402 share = calloc(1, sizeof(snd_pcm_share_t));
1403 if (!share)
1404 return -ENOMEM;
1406 share->channels = channels;
1407 share->slave_channels = calloc(channels, sizeof(*share->slave_channels));
1408 if (!share->slave_channels) {
1409 free(share);
1410 return -ENOMEM;
1412 memcpy(share->slave_channels, channels_map, channels * sizeof(*share->slave_channels));
1414 err = snd_pcm_new(&pcm, SND_PCM_TYPE_SHARE, name, stream, mode);
1415 if (err < 0) {
1416 free(share->slave_channels);
1417 free(share);
1418 return err;
1420 err = socketpair(AF_LOCAL, SOCK_STREAM, 0, sd);
1421 if (err < 0) {
1422 snd_pcm_free(pcm);
1423 free(share->slave_channels);
1424 free(share);
1425 return -errno;
1428 if (stream == SND_PCM_STREAM_PLAYBACK) {
1429 int bufsize = 1;
1430 err = setsockopt(sd[0], SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
1431 if (err >= 0) {
1432 struct pollfd pfd;
1433 pfd.fd = sd[0];
1434 pfd.events = POLLOUT;
1435 while ((err = poll(&pfd, 1, 0)) == 1) {
1436 char buf[1];
1437 err = write(sd[0], buf, 1);
1438 assert(err != 0);
1439 if (err != 1)
1440 break;
1444 if (err < 0) {
1445 err = -errno;
1446 close(sd[0]);
1447 close(sd[1]);
1448 snd_pcm_free(pcm);
1449 free(share->slave_channels);
1450 free(share);
1451 return err;
1454 Pthread_mutex_lock(&snd_pcm_share_slaves_mutex);
1455 list_for_each(i, &snd_pcm_share_slaves) {
1456 snd_pcm_share_slave_t *s = list_entry(i, snd_pcm_share_slave_t, list);
1457 if (s->pcm->name && strcmp(s->pcm->name, sname) == 0) {
1458 slave = s;
1459 break;
1462 if (!slave) {
1463 snd_pcm_t *spcm;
1464 err = snd_pcm_open(&spcm, sname, stream, mode);
1465 if (err < 0) {
1466 Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex);
1467 close(sd[0]);
1468 close(sd[1]);
1469 snd_pcm_free(pcm);
1470 free(share->slave_channels);
1471 free(share);
1472 return err;
1474 /* FIXME: bellow is a real ugly hack to get things working */
1475 /* there is a memory leak somewhere, but I'm unable to trace it --jk */
1476 slave = calloc(1, sizeof(snd_pcm_share_slave_t) * 8);
1477 if (!slave) {
1478 Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex);
1479 snd_pcm_close(spcm);
1480 close(sd[0]);
1481 close(sd[1]);
1482 snd_pcm_free(pcm);
1483 free(share->slave_channels);
1484 free(share);
1485 return err;
1487 INIT_LIST_HEAD(&slave->clients);
1488 slave->pcm = spcm;
1489 slave->channels = schannels;
1490 slave->format = sformat;
1491 slave->rate = srate;
1492 slave->period_time = speriod_time;
1493 slave->buffer_time = sbuffer_time;
1494 pthread_mutex_init(&slave->mutex, NULL);
1495 pthread_cond_init(&slave->poll_cond, NULL);
1496 list_add_tail(&slave->list, &snd_pcm_share_slaves);
1497 Pthread_mutex_lock(&slave->mutex);
1498 err = pthread_create(&slave->thread, NULL, snd_pcm_share_thread, slave);
1499 assert(err == 0);
1500 Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex);
1501 } else {
1502 Pthread_mutex_lock(&slave->mutex);
1503 Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex);
1504 list_for_each(i, &slave->clients) {
1505 snd_pcm_share_t *sh = list_entry(i, snd_pcm_share_t, list);
1506 for (k = 0; k < sh->channels; ++k) {
1507 if (slave_map[sh->slave_channels[k]]) {
1508 SNDERR("Slave channel %d is already in use", sh->slave_channels[k]);
1509 Pthread_mutex_unlock(&slave->mutex);
1510 close(sd[0]);
1511 close(sd[1]);
1512 snd_pcm_free(pcm);
1513 free(share->slave_channels);
1514 free(share);
1515 return -EBUSY;
1521 share->slave = slave;
1522 share->pcm = pcm;
1523 share->client_socket = sd[0];
1524 share->slave_socket = sd[1];
1526 pcm->mmap_rw = 1;
1527 pcm->ops = &snd_pcm_share_ops;
1528 pcm->fast_ops = &snd_pcm_share_fast_ops;
1529 pcm->private_data = share;
1530 pcm->poll_fd = share->client_socket;
1531 pcm->poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
1532 pcm->monotonic = slave->pcm->monotonic;
1533 snd_pcm_set_hw_ptr(pcm, &share->hw_ptr, -1, 0);
1534 snd_pcm_set_appl_ptr(pcm, &share->appl_ptr, -1, 0);
1536 slave->open_count++;
1537 list_add_tail(&share->list, &slave->clients);
1539 Pthread_mutex_unlock(&slave->mutex);
1541 *pcmp = pcm;
1542 return 0;
1545 /*! \page pcm_plugins
1547 \section pcm_plugins_share Plugin: Share
1549 This plugin allows sharing of multiple channels with more clients. The access
1550 to each channel is exlusive (samples are not mixed together). It means, if
1551 the channel zero is used with first client, the channel cannot be used with
1552 second one. If you are looking for a mixing plugin, use the
1553 \ref pcm_plugins_dmix "dmix plugin".
1555 The difference from \ref pcm_plugins_dshare "dshare plugin" is that
1556 share plugin requires the server program "aserver", while dshare plugin
1557 doesn't need the explicit server but access to the shared buffer.
1559 \code
1560 pcm.name {
1561 type share # Share PCM
1562 slave STR # Slave name
1563 # or
1564 slave { # Slave definition
1565 pcm STR # Slave PCM name
1566 [format STR] # Slave format
1567 [channels INT] # Slave channels
1568 [rate INT] # Slave rate
1569 [period_time INT] # Slave period time in us
1570 [buffer_time INT] # Slave buffer time in us
1572 bindings {
1573 N INT # Slave channel INT for client channel N
1576 \endcode
1578 \subsection pcm_plugins_share_funcref Function reference
1580 <UL>
1581 <LI>snd_pcm_share_open()
1582 <LI>_snd_pcm_share_open()
1583 </UL>
1588 * \brief Creates a new Share PCM
1589 * \param pcmp Returns created PCM handle
1590 * \param name Name of PCM
1591 * \param root Root configuration node
1592 * \param conf Configuration node with Share PCM description
1593 * \param stream Stream type
1594 * \param mode Stream mode
1595 * \retval zero on success otherwise a negative error code
1596 * \warning Using of this function might be dangerous in the sense
1597 * of compatibility reasons. The prototype might be freely
1598 * changed in future.
1600 int _snd_pcm_share_open(snd_pcm_t **pcmp, const char *name,
1601 snd_config_t *root, snd_config_t *conf,
1602 snd_pcm_stream_t stream, int mode)
1604 snd_config_iterator_t i, next;
1605 const char *sname = NULL;
1606 snd_config_t *bindings = NULL;
1607 int err;
1608 snd_config_t *slave = NULL, *sconf;
1609 unsigned int *channels_map = NULL;
1610 unsigned int channels = 0;
1611 snd_pcm_format_t sformat = SND_PCM_FORMAT_UNKNOWN;
1612 int schannels = -1;
1613 int srate = -1;
1614 int speriod_time= -1, sbuffer_time = -1;
1615 unsigned int schannel_max = 0;
1617 snd_config_for_each(i, next, conf) {
1618 snd_config_t *n = snd_config_iterator_entry(i);
1619 const char *id;
1620 if (snd_config_get_id(n, &id) < 0)
1621 continue;
1622 if (snd_pcm_conf_generic_id(id))
1623 continue;
1624 if (strcmp(id, "slave") == 0) {
1625 slave = n;
1626 continue;
1628 if (strcmp(id, "bindings") == 0) {
1629 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
1630 SNDERR("Invalid type for %s", id);
1631 return -EINVAL;
1633 bindings = n;
1634 continue;
1636 SNDERR("Unknown field %s", id);
1637 return -EINVAL;
1639 if (!slave) {
1640 SNDERR("slave is not defined");
1641 return -EINVAL;
1643 err = snd_pcm_slave_conf(root, slave, &sconf, 5,
1644 SND_PCM_HW_PARAM_FORMAT, 0, &sformat,
1645 SND_PCM_HW_PARAM_CHANNELS, 0, &schannels,
1646 SND_PCM_HW_PARAM_RATE, 0, &srate,
1647 SND_PCM_HW_PARAM_PERIOD_TIME, 0, &speriod_time,
1648 SND_PCM_HW_PARAM_BUFFER_TIME, 0, &sbuffer_time);
1649 if (err < 0)
1650 return err;
1652 /* FIXME: nothing strictly forces to have named definition */
1653 err = snd_config_get_string(sconf, &sname);
1654 sname = err >= 0 && sname ? strdup(sname) : NULL;
1655 snd_config_delete(sconf);
1656 if (sname == NULL) {
1657 SNDERR("slave.pcm is not a string");
1658 return err;
1661 if (!bindings) {
1662 SNDERR("bindings is not defined");
1663 err = -EINVAL;
1664 goto _free;
1666 snd_config_for_each(i, next, bindings) {
1667 long cchannel = -1;
1668 snd_config_t *n = snd_config_iterator_entry(i);
1669 const char *id;
1670 if (snd_config_get_id(n, &id) < 0)
1671 continue;
1672 err = safe_strtol(id, &cchannel);
1673 if (err < 0 || cchannel < 0) {
1674 SNDERR("Invalid client channel in binding: %s", id);
1675 err = -EINVAL;
1676 goto _free;
1678 if ((unsigned)cchannel >= channels)
1679 channels = cchannel + 1;
1681 if (channels == 0) {
1682 SNDERR("No bindings defined");
1683 err = -EINVAL;
1684 goto _free;
1686 channels_map = calloc(channels, sizeof(*channels_map));
1687 if (! channels_map) {
1688 err = -ENOMEM;
1689 goto _free;
1692 snd_config_for_each(i, next, bindings) {
1693 snd_config_t *n = snd_config_iterator_entry(i);
1694 const char *id;
1695 long cchannel;
1696 long schannel = -1;
1697 if (snd_config_get_id(n, &id) < 0)
1698 continue;
1699 cchannel = atoi(id);
1700 err = snd_config_get_integer(n, &schannel);
1701 if (err < 0) {
1702 goto _free;
1704 assert(schannel >= 0);
1705 assert(schannels <= 0 || schannel < schannels);
1706 channels_map[cchannel] = schannel;
1707 if ((unsigned)schannel > schannel_max)
1708 schannel_max = schannel;
1710 if (schannels <= 0)
1711 schannels = schannel_max + 1;
1712 err = snd_pcm_share_open(pcmp, name, sname, sformat, srate,
1713 (unsigned int) schannels,
1714 speriod_time, sbuffer_time,
1715 channels, channels_map, stream, mode);
1716 _free:
1717 free(channels_map);
1718 free((char *)sname);
1719 return err;
1721 #ifndef DOC_HIDDEN
1722 SND_DLSYM_BUILD_VERSION(_snd_pcm_share_open, SND_PCM_DLSYM_VERSION);
1723 #endif