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 <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 <poll.h>
38 #include <pthread.h>
39 #include "pcm_local.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 // 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);
209 switch (share->state) {
210 case SND_PCM_STATE_RUNNING:
211 break;
212 case SND_PCM_STATE_DRAINING:
213 if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
214 break;
215 /* Fall through */
216 default:
217 return INT_MAX;
218 }
219 share->hw_ptr = slave->hw_ptr;
220 avail = snd_pcm_mmap_avail(pcm);
221 if (avail >= pcm->stop_threshold) {
222 _snd_pcm_share_stop(pcm, share->state == SND_PCM_STATE_DRAINING ? SND_PCM_STATE_SETUP : SND_PCM_STATE_XRUN);
223 goto update_poll;
224 }
225 hw_avail = buffer_size - avail;
226 slave_avail = snd_pcm_share_slave_avail(slave);
227 if (avail < slave_avail) {
228 /* Some frames need still to be transferred */
229 snd_pcm_sframes_t slave_hw_avail = buffer_size - slave_avail;
230 snd_pcm_sframes_t safety_missing = slave_hw_avail - slave->safety_threshold;
231 if (safety_missing < 0) {
232 snd_pcm_sframes_t err;
233 snd_pcm_sframes_t frames = slave_avail - avail;
234 if (-safety_missing <= frames) {
235 frames = -safety_missing;
236 missing = 1;
237 }
238 err = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), frames);
239 if (err < 0) {
240 SYSMSG("snd_pcm_mmap_commit error");
241 return INT_MAX;
242 }
243 if (err != frames)
244 SYSMSG("commit returns %ld for size %ld", err, frames);
245 slave_avail -= err;
246 } else {
247 if (safety_missing == 0)
248 missing = 1;
249 else
250 missing = safety_missing;
251 }
252 }
253 switch (share->state) {
254 case SND_PCM_STATE_DRAINING:
255 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
256 if (hw_avail <= 0) {
257 _snd_pcm_share_stop(pcm, SND_PCM_STATE_SETUP);
258 break;
259 }
260 if ((snd_pcm_uframes_t)hw_avail < missing)
261 missing = hw_avail;
262 running = 1;
263 ready = 0;
264 }
265 break;
266 case SND_PCM_STATE_RUNNING:
267 if (avail >= pcm->stop_threshold) {
268 _snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
269 break;
270 } else {
271 snd_pcm_uframes_t xrun_missing = pcm->stop_threshold - avail;
272 if (missing > xrun_missing)
273 missing = xrun_missing;
274 }
275 ready_missing = pcm->avail_min - avail;
276 if (ready_missing > 0) {
277 ready = 0;
278 if (missing > (snd_pcm_uframes_t)ready_missing)
279 missing = ready_missing;
280 }
281 running = 1;
282 break;
283 default:
284 SNDERR("invalid shared PCM state %d", share->state);
285 return INT_MAX;
286 }
287
288 update_poll:
289 if (ready != share->ready) {
290 char buf[1];
291 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
292 if (ready)
293 read(share->slave_socket, buf, 1);
294 else
295 write(share->client_socket, buf, 1);
296 } else {
297 if (ready)
298 write(share->slave_socket, buf, 1);
299 else
300 read(share->client_socket, buf, 1);
301 }
302 share->ready = ready;
303 }
304 if (!running)
305 return INT_MAX;
306 if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
307 share->state == SND_PCM_STATE_DRAINING &&
308 !share->drain_silenced) {
309 /* drain silencing */
310 if (avail >= slave->silence_frames) {
311 snd_pcm_uframes_t offset = share->appl_ptr % buffer_size;
312 snd_pcm_uframes_t xfer = 0;
313 snd_pcm_uframes_t size = slave->silence_frames;
314 while (xfer < size) {
315 snd_pcm_uframes_t frames = size - xfer;
316 snd_pcm_uframes_t cont = buffer_size - offset;
317 if (cont < frames)
318 frames = cont;
319 snd_pcm_areas_silence(pcm->running_areas, offset, pcm->channels, frames, pcm->format);
320 offset += frames;
321 if (offset >= buffer_size)
322 offset = 0;
323 xfer += frames;
324 }
325 share->drain_silenced = 1;
326 } else {
327 snd_pcm_uframes_t silence_missing;
328 silence_missing = slave->silence_frames - avail;
329 if (silence_missing < missing)
330 missing = silence_missing;
331 }
332 }
333 // printf("missing=%d\n", missing);
334 return missing;
335 }
336
_snd_pcm_share_slave_missing(snd_pcm_share_slave_t * slave)337 static snd_pcm_uframes_t _snd_pcm_share_slave_missing(snd_pcm_share_slave_t *slave)
338 {
339 snd_pcm_uframes_t missing = INT_MAX;
340 struct list_head *i;
341 /* snd_pcm_sframes_t avail = */ snd_pcm_avail_update(slave->pcm);
342 slave->hw_ptr = *slave->pcm->hw.ptr;
343 list_for_each(i, &slave->clients) {
344 snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
345 snd_pcm_t *pcm = share->pcm;
346 snd_pcm_uframes_t m = _snd_pcm_share_missing(pcm);
347 if (m < missing)
348 missing = m;
349 }
350 return missing;
351 }
352
snd_pcm_share_thread(void * data)353 static void *snd_pcm_share_thread(void *data)
354 {
355 snd_pcm_share_slave_t *slave = data;
356 snd_pcm_t *spcm = slave->pcm;
357 struct pollfd pfd[2];
358 int err;
359
360 pfd[0].fd = slave->poll[0];
361 pfd[0].events = POLLIN;
362 err = snd_pcm_poll_descriptors(spcm, &pfd[1], 1);
363 if (err != 1) {
364 SNDERR("invalid poll descriptors %d", err);
365 return NULL;
366 }
367 Pthread_mutex_lock(&slave->mutex);
368 err = pipe(slave->poll);
369 if (err < 0) {
370 SYSERR("can't create a pipe");
371 Pthread_mutex_unlock(&slave->mutex);
372 return NULL;
373 }
374 while (slave->open_count > 0) {
375 snd_pcm_uframes_t missing;
376 // printf("begin min_missing\n");
377 missing = _snd_pcm_share_slave_missing(slave);
378 // printf("min_missing=%ld\n", missing);
379 if (missing < INT_MAX) {
380 snd_pcm_uframes_t hw_ptr;
381 snd_pcm_sframes_t avail_min;
382 hw_ptr = slave->hw_ptr + missing;
383 hw_ptr += spcm->period_size - 1;
384 if (hw_ptr >= spcm->boundary)
385 hw_ptr -= spcm->boundary;
386 hw_ptr -= hw_ptr % spcm->period_size;
387 avail_min = hw_ptr - *spcm->appl.ptr;
388 if (spcm->stream == SND_PCM_STREAM_PLAYBACK)
389 avail_min += spcm->buffer_size;
390 if (avail_min < 0)
391 avail_min += spcm->boundary;
392 // printf("avail_min=%d\n", avail_min);
393 if ((snd_pcm_uframes_t)avail_min != spcm->avail_min) {
394 snd_pcm_sw_params_set_avail_min(spcm, &slave->sw_params, avail_min);
395 err = snd_pcm_sw_params(spcm, &slave->sw_params);
396 if (err < 0) {
397 SYSERR("snd_pcm_sw_params error");
398 Pthread_mutex_unlock(&slave->mutex);
399 return NULL;
400 }
401 }
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);
409 }
410 } else {
411 slave->polling = 0;
412 pthread_cond_wait(&slave->poll_cond, &slave->mutex);
413 }
414 }
415 Pthread_mutex_unlock(&slave->mutex);
416 return NULL;
417 }
418
_snd_pcm_share_update(snd_pcm_t * pcm)419 static void _snd_pcm_share_update(snd_pcm_t *pcm)
420 {
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;
432 }
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;
453 }
454 }
455 }
456 }
457
snd_pcm_share_nonblock(snd_pcm_t * pcm ATTRIBUTE_UNUSED,int nonblock ATTRIBUTE_UNUSED)458 static int snd_pcm_share_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
459 {
460 return 0;
461 }
462
snd_pcm_share_async(snd_pcm_t * pcm ATTRIBUTE_UNUSED,int sig ATTRIBUTE_UNUSED,pid_t pid ATTRIBUTE_UNUSED)463 static int snd_pcm_share_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int sig ATTRIBUTE_UNUSED, pid_t pid ATTRIBUTE_UNUSED)
464 {
465 return -ENOSYS;
466 }
467
snd_pcm_share_info(snd_pcm_t * pcm,snd_pcm_info_t * info)468 static int snd_pcm_share_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
469 {
470 snd_pcm_share_t *share = pcm->private_data;
471 return snd_pcm_info(share->slave->pcm, info);
472 }
473
snd_pcm_share_hw_refine_cprepare(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)474 static int snd_pcm_share_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
475 {
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;
494 }
495
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;
501 }
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;
507 }
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;
513 }
514 params->info |= SND_PCM_INFO_DOUBLE;
515 return 0;
516 }
517
snd_pcm_share_hw_refine_sprepare(snd_pcm_t * pcm,snd_pcm_hw_params_t * sparams)518 static int snd_pcm_share_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
519 {
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;
529 }
530
snd_pcm_share_hw_refine_schange(snd_pcm_t * pcm ATTRIBUTE_UNUSED,snd_pcm_hw_params_t * params,snd_pcm_hw_params_t * sparams)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)
533 {
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;
554 }
555 err = _snd_pcm_hw_params_refine(sparams, links, params);
556 if (err < 0)
557 return err;
558 return 0;
559 }
560
snd_pcm_share_hw_refine_cchange(snd_pcm_t * pcm ATTRIBUTE_UNUSED,snd_pcm_hw_params_t * params,snd_pcm_hw_params_t * sparams)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)
563 {
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;
590 }
591
snd_pcm_share_hw_refine_slave(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)592 static int snd_pcm_share_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
593 {
594 snd_pcm_share_t *share = pcm->private_data;
595 return snd_pcm_hw_refine(share->slave->pcm, params);
596 }
597
snd_pcm_share_hw_params_slave(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)598 static int snd_pcm_share_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
599 {
600 snd_pcm_share_t *share = pcm->private_data;
601 return _snd_pcm_hw_params_internal(share->slave->pcm, params);
602 }
603
snd_pcm_share_hw_refine(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)604 static int snd_pcm_share_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
605 {
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);
612 }
613
snd_pcm_share_hw_params(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)614 static int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
615 {
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;
645 }
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);
662 }
663 share->state = SND_PCM_STATE_SETUP;
664 slave->setup_count++;
665 _end:
666 Pthread_mutex_unlock(&slave->mutex);
667 return err;
668 }
669
snd_pcm_share_hw_free(snd_pcm_t * pcm)670 static int snd_pcm_share_hw_free(snd_pcm_t *pcm)
671 {
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;
682 }
683
snd_pcm_share_sw_params(snd_pcm_t * pcm ATTRIBUTE_UNUSED,snd_pcm_sw_params_t * params ATTRIBUTE_UNUSED)684 static int snd_pcm_share_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params ATTRIBUTE_UNUSED)
685 {
686 return 0;
687 }
688
snd_pcm_share_status(snd_pcm_t * pcm,snd_pcm_status_t * status)689 static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
690 {
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;
707 }
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;
718 }
719
snd_pcm_share_state(snd_pcm_t * pcm)720 static snd_pcm_state_t snd_pcm_share_state(snd_pcm_t *pcm)
721 {
722 snd_pcm_share_t *share = pcm->private_data;
723 return share->state;
724 }
725
_snd_pcm_share_hwsync(snd_pcm_t * pcm)726 static int _snd_pcm_share_hwsync(snd_pcm_t *pcm)
727 {
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;
735 }
736 return snd_pcm_hwsync(slave->pcm);
737 }
738
snd_pcm_share_hwsync(snd_pcm_t * pcm)739 static int snd_pcm_share_hwsync(snd_pcm_t *pcm)
740 {
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;
748 }
749
_snd_pcm_share_delay(snd_pcm_t * pcm,snd_pcm_sframes_t * delayp)750 static int _snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
751 {
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;
765 }
766 return snd_pcm_delay(slave->pcm, delayp);
767 }
768
snd_pcm_share_delay(snd_pcm_t * pcm,snd_pcm_sframes_t * delayp)769 static int snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
770 {
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;
778 }
779
snd_pcm_share_avail_update(snd_pcm_t * pcm)780 static snd_pcm_sframes_t snd_pcm_share_avail_update(snd_pcm_t *pcm)
781 {
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;
791 }
792 share->hw_ptr = *slave->pcm->hw.ptr;
793 }
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;
799 }
800
snd_pcm_share_htimestamp(snd_pcm_t * pcm,snd_pcm_uframes_t * avail,snd_htimestamp_t * tstamp)801 static int snd_pcm_share_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
802 snd_htimestamp_t *tstamp)
803 {
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;
811 }
812
813 /* 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)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)
817 {
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;
835 }
836 }
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;
846 }
847 if (err != frames) {
848 SYSMSG("commit returns %ld for size %ld", err, frames);
849 return err;
850 }
851 }
852 _snd_pcm_share_update(pcm);
853 }
854 return size;
855 }
856
snd_pcm_share_mmap_commit(snd_pcm_t * pcm,snd_pcm_uframes_t offset,snd_pcm_uframes_t 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)
860 {
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;
868 }
869
snd_pcm_share_prepare(snd_pcm_t * pcm)870 static int snd_pcm_share_prepare(snd_pcm_t *pcm)
871 {
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;
888 }
889 if (slave->prepared_count == 0) {
890 err = snd_pcm_prepare(slave->pcm);
891 if (err < 0)
892 goto _end;
893 }
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;
901 }
902
snd_pcm_share_reset(snd_pcm_t * pcm)903 static int snd_pcm_share_reset(snd_pcm_t *pcm)
904 {
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;
915 }
916
snd_pcm_share_start(snd_pcm_t * pcm)917 static int snd_pcm_share_start(snd_pcm_t *pcm)
918 {
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;
933 }
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;
942 }
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;
958 }
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;
966 }
967 assert((snd_pcm_uframes_t)res == hw_avail);
968 }
969 }
970 if (slave->running_count == 0) {
971 err = snd_pcm_start(spcm);
972 if (err < 0)
973 goto _end;
974 }
975 slave->running_count++;
976 _snd_pcm_share_update(pcm);
977 gettimestamp(&share->trigger_tstamp, pcm->tstamp_type);
978 _end:
979 Pthread_mutex_unlock(&slave->mutex);
980 return err;
981 }
982
snd_pcm_share_pause(snd_pcm_t * pcm ATTRIBUTE_UNUSED,int enable ATTRIBUTE_UNUSED)983 static int snd_pcm_share_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
984 {
985 return -ENOSYS;
986 }
987
snd_pcm_share_resume(snd_pcm_t * pcm ATTRIBUTE_UNUSED)988 static int snd_pcm_share_resume(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
989 {
990 return -ENXIO;
991 }
992
snd_pcm_share_channel_info(snd_pcm_t * pcm,snd_pcm_channel_info_t * info)993 static int snd_pcm_share_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
994 {
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;
1004 }
1005
_snd_pcm_share_rewind(snd_pcm_t * pcm,snd_pcm_uframes_t frames)1006 static snd_pcm_sframes_t _snd_pcm_share_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
1007 {
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;
1026 }
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;
1036 }
1037 snd_pcm_mmap_appl_backward(pcm, frames);
1038 _snd_pcm_share_update(pcm);
1039 return n;
1040 }
1041
snd_pcm_share_rewindable(snd_pcm_t * pcm)1042 static snd_pcm_sframes_t snd_pcm_share_rewindable(snd_pcm_t *pcm)
1043 {
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;
1051 }
1052
snd_pcm_share_rewind(snd_pcm_t * pcm,snd_pcm_uframes_t frames)1053 static snd_pcm_sframes_t snd_pcm_share_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
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_share_rewind(pcm, frames);
1060 Pthread_mutex_unlock(&slave->mutex);
1061 return ret;
1062 }
1063
_snd_pcm_share_forward(snd_pcm_t * pcm,snd_pcm_uframes_t frames)1064 static snd_pcm_sframes_t _snd_pcm_share_forward(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 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;
1084 }
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;
1093 }
1094 snd_pcm_mmap_appl_forward(pcm, frames);
1095 _snd_pcm_share_update(pcm);
1096 return n;
1097 }
1098
snd_pcm_share_forwardable(snd_pcm_t * pcm)1099 static snd_pcm_sframes_t snd_pcm_share_forwardable(snd_pcm_t *pcm)
1100 {
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;
1108 }
1109
snd_pcm_share_forward(snd_pcm_t * pcm,snd_pcm_uframes_t frames)1110 static snd_pcm_sframes_t snd_pcm_share_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
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_share_forward(pcm, frames);
1117 Pthread_mutex_unlock(&slave->mutex);
1118 return ret;
1119 }
1120
1121 /* Warning: take the mutex before to call this */
_snd_pcm_share_stop(snd_pcm_t * pcm,snd_pcm_state_t state)1122 static void _snd_pcm_share_stop(snd_pcm_t *pcm, snd_pcm_state_t state)
1123 {
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;
1130 }
1131 #endif
1132 gettimestamp(&share->trigger_tstamp, pcm->tstamp_type);
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;
1147 }
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);
1154 }
1155 }
1156
snd_pcm_share_drain(snd_pcm_t * pcm)1157 static int snd_pcm_share_drain(snd_pcm_t *pcm)
1158 {
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;
1174 }
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;
1191 }
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;
1208 }
1209 }
1210 _end:
1211 Pthread_mutex_unlock(&slave->mutex);
1212 return err;
1213 }
1214
snd_pcm_share_drop(snd_pcm_t * pcm)1215 static int snd_pcm_share_drop(snd_pcm_t *pcm)
1216 {
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;
1231 }
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;
1244 }
1245
1246 share->appl_ptr = share->hw_ptr = 0;
1247 _end:
1248 Pthread_mutex_unlock(&slave->mutex);
1249 return err;
1250 }
1251
snd_pcm_share_close(snd_pcm_t * pcm)1252 static int snd_pcm_share_close(snd_pcm_t *pcm)
1253 {
1254 snd_pcm_share_t *share = pcm->private_data;
1255 snd_pcm_share_slave_t *slave = share->slave;
1256 int err = 0;
1257
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);
1275 }
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;
1282 }
1283
snd_pcm_share_mmap(snd_pcm_t * pcm ATTRIBUTE_UNUSED)1284 static int snd_pcm_share_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
1285 {
1286 return 0;
1287 }
1288
snd_pcm_share_munmap(snd_pcm_t * pcm ATTRIBUTE_UNUSED)1289 static int snd_pcm_share_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
1290 {
1291 return 0;
1292 }
1293
snd_pcm_share_dump(snd_pcm_t * pcm,snd_output_t * out)1294 static void snd_pcm_share_dump(snd_pcm_t *pcm, snd_output_t *out)
1295 {
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);
1306 }
1307 snd_output_printf(out, "Slave: ");
1308 snd_pcm_dump(slave->pcm, out);
1309 }
1310
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,
1324 };
1325
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,
1349 };
1350
1351 /**
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.
1369 */
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)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)
1376 {
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];
1385
1386 assert(pcmp);
1387 assert(channels > 0 && sname && channels_map);
1388
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;
1393 }
1394 if (slave_map[channels_map[k]]) {
1395 SNDERR("Repeated slave channel (%d) in binding", channels_map[k]);
1396 return -EINVAL;
1397 }
1398 slave_map[channels_map[k]] = 1;
1399 assert((unsigned)channels_map[k] < schannels);
1400 }
1401
1402 share = calloc(1, sizeof(snd_pcm_share_t));
1403 if (!share)
1404 return -ENOMEM;
1405
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;
1411 }
1412 memcpy(share->slave_channels, channels_map, channels * sizeof(*share->slave_channels));
1413
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;
1419 }
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;
1426 }
1427
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;
1441 }
1442 }
1443 }
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;
1452 }
1453
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;
1460 }
1461 }
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;
1473 }
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;
1486 }
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;
1516 }
1517 }
1518 }
1519 }
1520
1521 share->slave = slave;
1522 share->pcm = pcm;
1523 share->client_socket = sd[0];
1524 share->slave_socket = sd[1];
1525
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->tstamp_type = slave->pcm->tstamp_type;
1533 snd_pcm_set_hw_ptr(pcm, &share->hw_ptr, -1, 0);
1534 snd_pcm_set_appl_ptr(pcm, &share->appl_ptr, -1, 0);
1535
1536 slave->open_count++;
1537 list_add_tail(&share->list, &slave->clients);
1538
1539 Pthread_mutex_unlock(&slave->mutex);
1540
1541 *pcmp = pcm;
1542 return 0;
1543 }
1544
1545 /*! \page pcm_plugins
1546
1547 \section pcm_plugins_share Plugin: Share
1548
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".
1554
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.
1558
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
1571 }
1572 bindings {
1573 N INT # Slave channel INT for client channel N
1574 }
1575 }
1576 \endcode
1577
1578 \subsection pcm_plugins_share_funcref Function reference
1579
1580 <UL>
1581 <LI>snd_pcm_share_open()
1582 <LI>_snd_pcm_share_open()
1583 </UL>
1584
1585 */
1586
1587 /**
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.
1599 */
_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)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)
1603 {
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;
1616
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;
1627 }
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;
1632 }
1633 bindings = n;
1634 continue;
1635 }
1636 SNDERR("Unknown field %s", id);
1637 return -EINVAL;
1638 }
1639 if (!slave) {
1640 SNDERR("slave is not defined");
1641 return -EINVAL;
1642 }
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;
1651
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;
1659 }
1660
1661 if (!bindings) {
1662 SNDERR("bindings is not defined");
1663 err = -EINVAL;
1664 goto _free;
1665 }
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;
1677 }
1678 if ((unsigned)cchannel >= channels)
1679 channels = cchannel + 1;
1680 }
1681 if (channels == 0) {
1682 SNDERR("No bindings defined");
1683 err = -EINVAL;
1684 goto _free;
1685 }
1686 channels_map = calloc(channels, sizeof(*channels_map));
1687 if (! channels_map) {
1688 err = -ENOMEM;
1689 goto _free;
1690 }
1691
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;
1703 }
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;
1709 }
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;
1720 }
1721 #ifndef DOC_HIDDEN
1722 SND_DLSYM_BUILD_VERSION(_snd_pcm_share_open, SND_PCM_DLSYM_VERSION);
1723 #endif
1724