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