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->appl_ptr = *pcm->appl.ptr;
715 status->hw_ptr = *pcm->hw.ptr;
716 status->trigger_tstamp = share->trigger_tstamp;
717 _end:
718 Pthread_mutex_unlock(&slave->mutex);
719 return err;
720 }
721
snd_pcm_share_state(snd_pcm_t * pcm)722 static snd_pcm_state_t snd_pcm_share_state(snd_pcm_t *pcm)
723 {
724 snd_pcm_share_t *share = pcm->private_data;
725 return share->state;
726 }
727
_snd_pcm_share_hwsync(snd_pcm_t * pcm)728 static int _snd_pcm_share_hwsync(snd_pcm_t *pcm)
729 {
730 snd_pcm_share_t *share = pcm->private_data;
731 snd_pcm_share_slave_t *slave = share->slave;
732 switch (share->state) {
733 case SND_PCM_STATE_XRUN:
734 return -EPIPE;
735 default:
736 break;
737 }
738 return snd_pcm_hwsync(slave->pcm);
739 }
740
snd_pcm_share_hwsync(snd_pcm_t * pcm)741 static int snd_pcm_share_hwsync(snd_pcm_t *pcm)
742 {
743 snd_pcm_share_t *share = pcm->private_data;
744 snd_pcm_share_slave_t *slave = share->slave;
745 int err;
746 Pthread_mutex_lock(&slave->mutex);
747 err = _snd_pcm_share_hwsync(pcm);
748 Pthread_mutex_unlock(&slave->mutex);
749 return err;
750 }
751
_snd_pcm_share_delay(snd_pcm_t * pcm,snd_pcm_sframes_t * delayp)752 static int _snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
753 {
754 snd_pcm_share_t *share = pcm->private_data;
755 snd_pcm_share_slave_t *slave = share->slave;
756 switch (share->state) {
757 case SND_PCM_STATE_XRUN:
758 return -EPIPE;
759 case SND_PCM_STATE_RUNNING:
760 break;
761 case SND_PCM_STATE_DRAINING:
762 if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
763 break;
764 /* Fall through */
765 default:
766 return -EBADFD;
767 }
768 return snd_pcm_delay(slave->pcm, delayp);
769 }
770
snd_pcm_share_delay(snd_pcm_t * pcm,snd_pcm_sframes_t * delayp)771 static int snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
772 {
773 snd_pcm_share_t *share = pcm->private_data;
774 snd_pcm_share_slave_t *slave = share->slave;
775 int err;
776 Pthread_mutex_lock(&slave->mutex);
777 err = _snd_pcm_share_delay(pcm, delayp);
778 Pthread_mutex_unlock(&slave->mutex);
779 return err;
780 }
781
snd_pcm_share_avail_update(snd_pcm_t * pcm)782 static snd_pcm_sframes_t snd_pcm_share_avail_update(snd_pcm_t *pcm)
783 {
784 snd_pcm_share_t *share = pcm->private_data;
785 snd_pcm_share_slave_t *slave = share->slave;
786 snd_pcm_sframes_t avail;
787 Pthread_mutex_lock(&slave->mutex);
788 if (share->state == SND_PCM_STATE_RUNNING) {
789 avail = snd_pcm_avail_update(slave->pcm);
790 if (avail < 0) {
791 Pthread_mutex_unlock(&slave->mutex);
792 return avail;
793 }
794 share->hw_ptr = *slave->pcm->hw.ptr;
795 }
796 Pthread_mutex_unlock(&slave->mutex);
797 avail = snd_pcm_mmap_avail(pcm);
798 if ((snd_pcm_uframes_t)avail > pcm->buffer_size)
799 return -EPIPE;
800 return avail;
801 }
802
snd_pcm_share_htimestamp(snd_pcm_t * pcm,snd_pcm_uframes_t * avail,snd_htimestamp_t * tstamp)803 static int snd_pcm_share_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
804 snd_htimestamp_t *tstamp)
805 {
806 snd_pcm_share_t *share = pcm->private_data;
807 snd_pcm_share_slave_t *slave = share->slave;
808 int err;
809 Pthread_mutex_lock(&slave->mutex);
810 err = snd_pcm_htimestamp(slave->pcm, avail, tstamp);
811 Pthread_mutex_unlock(&slave->mutex);
812 return err;
813 }
814
815 /* 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)816 static snd_pcm_sframes_t _snd_pcm_share_mmap_commit(snd_pcm_t *pcm,
817 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
818 snd_pcm_uframes_t size)
819 {
820 snd_pcm_share_t *share = pcm->private_data;
821 snd_pcm_share_slave_t *slave = share->slave;
822 snd_pcm_t *spcm = slave->pcm;
823 snd_pcm_sframes_t ret;
824 snd_pcm_sframes_t frames;
825 if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
826 share->state == SND_PCM_STATE_RUNNING) {
827 frames = *spcm->appl.ptr - share->appl_ptr;
828 if (frames > (snd_pcm_sframes_t)pcm->buffer_size)
829 frames -= pcm->boundary;
830 else if (frames < -(snd_pcm_sframes_t)pcm->buffer_size)
831 frames += pcm->boundary;
832 if (frames > 0) {
833 /* Latecomer PCM */
834 ret = snd_pcm_rewind(spcm, frames);
835 if (ret < 0)
836 return ret;
837 }
838 }
839 snd_pcm_mmap_appl_forward(pcm, size);
840 if (share->state == SND_PCM_STATE_RUNNING) {
841 frames = _snd_pcm_share_slave_forward(slave);
842 if (frames > 0) {
843 snd_pcm_sframes_t err;
844 err = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), frames);
845 if (err < 0) {
846 SYSMSG("snd_pcm_mmap_commit error");
847 return err;
848 }
849 if (err != frames) {
850 SYSMSG("commit returns %ld for size %ld", err, frames);
851 return err;
852 }
853 }
854 _snd_pcm_share_update(pcm);
855 }
856 return size;
857 }
858
snd_pcm_share_mmap_commit(snd_pcm_t * pcm,snd_pcm_uframes_t offset,snd_pcm_uframes_t size)859 static snd_pcm_sframes_t snd_pcm_share_mmap_commit(snd_pcm_t *pcm,
860 snd_pcm_uframes_t offset,
861 snd_pcm_uframes_t size)
862 {
863 snd_pcm_share_t *share = pcm->private_data;
864 snd_pcm_share_slave_t *slave = share->slave;
865 snd_pcm_sframes_t ret;
866 Pthread_mutex_lock(&slave->mutex);
867 ret = _snd_pcm_share_mmap_commit(pcm, offset, size);
868 Pthread_mutex_unlock(&slave->mutex);
869 return ret;
870 }
871
snd_pcm_share_prepare(snd_pcm_t * pcm)872 static int snd_pcm_share_prepare(snd_pcm_t *pcm)
873 {
874 snd_pcm_share_t *share = pcm->private_data;
875 snd_pcm_share_slave_t *slave = share->slave;
876 int err = 0;
877 Pthread_mutex_lock(&slave->mutex);
878 switch (share->state) {
879 case SND_PCM_STATE_OPEN:
880 err = -EBADFD;
881 goto _end;
882 case SND_PCM_STATE_RUNNING:
883 err = -EBUSY;
884 goto _end;
885 case SND_PCM_STATE_PREPARED:
886 err = 0;
887 goto _end;
888 default: /* nothing todo */
889 break;
890 }
891 if (slave->prepared_count == 0) {
892 err = snd_pcm_prepare(slave->pcm);
893 if (err < 0)
894 goto _end;
895 }
896 slave->prepared_count++;
897 share->hw_ptr = 0;
898 share->appl_ptr = 0;
899 share->state = SND_PCM_STATE_PREPARED;
900 _end:
901 Pthread_mutex_unlock(&slave->mutex);
902 return err;
903 }
904
snd_pcm_share_reset(snd_pcm_t * pcm)905 static int snd_pcm_share_reset(snd_pcm_t *pcm)
906 {
907 snd_pcm_share_t *share = pcm->private_data;
908 snd_pcm_share_slave_t *slave = share->slave;
909 int err = 0;
910 /* FIXME? */
911 Pthread_mutex_lock(&slave->mutex);
912 snd_pcm_areas_silence(pcm->running_areas, 0, pcm->channels, pcm->buffer_size, pcm->format);
913 share->hw_ptr = *slave->pcm->hw.ptr;
914 share->appl_ptr = share->hw_ptr;
915 Pthread_mutex_unlock(&slave->mutex);
916 return err;
917 }
918
snd_pcm_share_start(snd_pcm_t * pcm)919 static int snd_pcm_share_start(snd_pcm_t *pcm)
920 {
921 snd_pcm_share_t *share = pcm->private_data;
922 snd_pcm_share_slave_t *slave = share->slave;
923 snd_pcm_t *spcm = slave->pcm;
924 int err = 0;
925 if (share->state != SND_PCM_STATE_PREPARED)
926 return -EBADFD;
927 Pthread_mutex_lock(&slave->mutex);
928 share->state = SND_PCM_STATE_RUNNING;
929 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
930 snd_pcm_uframes_t hw_avail = snd_pcm_mmap_playback_hw_avail(pcm);
931 snd_pcm_uframes_t xfer = 0;
932 if (hw_avail == 0) {
933 err = -EPIPE;
934 goto _end;
935 }
936 if (slave->running_count) {
937 snd_pcm_sframes_t sd;
938 err = snd_pcm_delay(spcm, &sd);
939 if (err < 0)
940 goto _end;
941 err = snd_pcm_rewind(spcm, sd);
942 if (err < 0)
943 goto _end;
944 }
945 assert(share->hw_ptr == 0);
946 share->hw_ptr = *spcm->hw.ptr;
947 share->appl_ptr = *spcm->appl.ptr;
948 while (xfer < hw_avail) {
949 snd_pcm_uframes_t frames = hw_avail - xfer;
950 snd_pcm_uframes_t offset = snd_pcm_mmap_offset(pcm);
951 snd_pcm_uframes_t cont = pcm->buffer_size - offset;
952 if (cont < frames)
953 frames = cont;
954 if (pcm->stopped_areas != NULL)
955 snd_pcm_areas_copy(pcm->running_areas, offset,
956 pcm->stopped_areas, xfer,
957 pcm->channels, frames,
958 pcm->format);
959 xfer += frames;
960 }
961 snd_pcm_mmap_appl_forward(pcm, hw_avail);
962 if (slave->running_count == 0) {
963 snd_pcm_sframes_t res;
964 res = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), hw_avail);
965 if (res < 0) {
966 err = res;
967 goto _end;
968 }
969 assert((snd_pcm_uframes_t)res == hw_avail);
970 }
971 }
972 if (slave->running_count == 0) {
973 err = snd_pcm_start(spcm);
974 if (err < 0)
975 goto _end;
976 }
977 slave->running_count++;
978 _snd_pcm_share_update(pcm);
979 gettimestamp(&share->trigger_tstamp, pcm->tstamp_type);
980 _end:
981 Pthread_mutex_unlock(&slave->mutex);
982 return err;
983 }
984
snd_pcm_share_pause(snd_pcm_t * pcm ATTRIBUTE_UNUSED,int enable ATTRIBUTE_UNUSED)985 static int snd_pcm_share_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
986 {
987 return -ENOSYS;
988 }
989
snd_pcm_share_resume(snd_pcm_t * pcm ATTRIBUTE_UNUSED)990 static int snd_pcm_share_resume(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
991 {
992 return -ENXIO;
993 }
994
snd_pcm_share_channel_info(snd_pcm_t * pcm,snd_pcm_channel_info_t * info)995 static int snd_pcm_share_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
996 {
997 snd_pcm_share_t *share = pcm->private_data;
998 snd_pcm_share_slave_t *slave = share->slave;
999 unsigned int channel = info->channel;
1000 int c = share->slave_channels[channel];
1001 int err;
1002 info->channel = c;
1003 err = snd_pcm_channel_info(slave->pcm, info);
1004 info->channel = channel;
1005 return err;
1006 }
1007
_snd_pcm_share_rewind(snd_pcm_t * pcm,snd_pcm_uframes_t frames)1008 static snd_pcm_sframes_t _snd_pcm_share_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
1009 {
1010 snd_pcm_share_t *share = pcm->private_data;
1011 snd_pcm_share_slave_t *slave = share->slave;
1012 snd_pcm_sframes_t n;
1013 switch (share->state) {
1014 case SND_PCM_STATE_RUNNING:
1015 break;
1016 case SND_PCM_STATE_PREPARED:
1017 if (pcm->stream != SND_PCM_STREAM_PLAYBACK)
1018 return -EBADFD;
1019 break;
1020 case SND_PCM_STATE_DRAINING:
1021 if (pcm->stream != SND_PCM_STREAM_CAPTURE)
1022 return -EBADFD;
1023 break;
1024 case SND_PCM_STATE_XRUN:
1025 return -EPIPE;
1026 default:
1027 return -EBADFD;
1028 }
1029 n = snd_pcm_mmap_hw_avail(pcm);
1030 assert(n >= 0);
1031 if ((snd_pcm_uframes_t)n > frames)
1032 frames = n;
1033 if (share->state == SND_PCM_STATE_RUNNING && frames > 0) {
1034 snd_pcm_sframes_t ret = snd_pcm_rewind(slave->pcm, frames);
1035 if (ret < 0)
1036 return ret;
1037 frames = ret;
1038 }
1039 snd_pcm_mmap_appl_backward(pcm, frames);
1040 _snd_pcm_share_update(pcm);
1041 return n;
1042 }
1043
snd_pcm_share_rewindable(snd_pcm_t * pcm)1044 static snd_pcm_sframes_t snd_pcm_share_rewindable(snd_pcm_t *pcm)
1045 {
1046 snd_pcm_share_t *share = pcm->private_data;
1047 snd_pcm_share_slave_t *slave = share->slave;
1048 snd_pcm_sframes_t ret;
1049 Pthread_mutex_lock(&slave->mutex);
1050 ret = snd_pcm_rewindable(slave->pcm);
1051 Pthread_mutex_unlock(&slave->mutex);
1052 return ret;
1053 }
1054
snd_pcm_share_rewind(snd_pcm_t * pcm,snd_pcm_uframes_t frames)1055 static snd_pcm_sframes_t snd_pcm_share_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
1056 {
1057 snd_pcm_share_t *share = pcm->private_data;
1058 snd_pcm_share_slave_t *slave = share->slave;
1059 snd_pcm_sframes_t ret;
1060 Pthread_mutex_lock(&slave->mutex);
1061 ret = _snd_pcm_share_rewind(pcm, frames);
1062 Pthread_mutex_unlock(&slave->mutex);
1063 return ret;
1064 }
1065
_snd_pcm_share_forward(snd_pcm_t * pcm,snd_pcm_uframes_t frames)1066 static snd_pcm_sframes_t _snd_pcm_share_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
1067 {
1068 snd_pcm_share_t *share = pcm->private_data;
1069 snd_pcm_share_slave_t *slave = share->slave;
1070 snd_pcm_sframes_t n;
1071 switch (share->state) {
1072 case SND_PCM_STATE_RUNNING:
1073 break;
1074 case SND_PCM_STATE_PREPARED:
1075 if (pcm->stream != SND_PCM_STREAM_PLAYBACK)
1076 return -EBADFD;
1077 break;
1078 case SND_PCM_STATE_DRAINING:
1079 if (pcm->stream != SND_PCM_STREAM_CAPTURE)
1080 return -EBADFD;
1081 break;
1082 case SND_PCM_STATE_XRUN:
1083 return -EPIPE;
1084 default:
1085 return -EBADFD;
1086 }
1087 n = snd_pcm_mmap_avail(pcm);
1088 if ((snd_pcm_uframes_t)n > frames)
1089 frames = n;
1090 if (share->state == SND_PCM_STATE_RUNNING && frames > 0) {
1091 snd_pcm_sframes_t ret = INTERNAL(snd_pcm_forward)(slave->pcm, frames);
1092 if (ret < 0)
1093 return ret;
1094 frames = ret;
1095 }
1096 snd_pcm_mmap_appl_forward(pcm, frames);
1097 _snd_pcm_share_update(pcm);
1098 return n;
1099 }
1100
snd_pcm_share_forwardable(snd_pcm_t * pcm)1101 static snd_pcm_sframes_t snd_pcm_share_forwardable(snd_pcm_t *pcm)
1102 {
1103 snd_pcm_share_t *share = pcm->private_data;
1104 snd_pcm_share_slave_t *slave = share->slave;
1105 snd_pcm_sframes_t ret;
1106 Pthread_mutex_lock(&slave->mutex);
1107 ret = snd_pcm_forwardable(slave->pcm);
1108 Pthread_mutex_unlock(&slave->mutex);
1109 return ret;
1110 }
1111
snd_pcm_share_forward(snd_pcm_t * pcm,snd_pcm_uframes_t frames)1112 static snd_pcm_sframes_t snd_pcm_share_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
1113 {
1114 snd_pcm_share_t *share = pcm->private_data;
1115 snd_pcm_share_slave_t *slave = share->slave;
1116 snd_pcm_sframes_t ret;
1117 Pthread_mutex_lock(&slave->mutex);
1118 ret = _snd_pcm_share_forward(pcm, frames);
1119 Pthread_mutex_unlock(&slave->mutex);
1120 return ret;
1121 }
1122
1123 /* Warning: take the mutex before to call this */
_snd_pcm_share_stop(snd_pcm_t * pcm,snd_pcm_state_t state)1124 static void _snd_pcm_share_stop(snd_pcm_t *pcm, snd_pcm_state_t state)
1125 {
1126 snd_pcm_share_t *share = pcm->private_data;
1127 snd_pcm_share_slave_t *slave = share->slave;
1128 #if 0
1129 if (!pcm->mmap_channels) {
1130 /* PCM closing already begun in the main thread */
1131 return;
1132 }
1133 #endif
1134 gettimestamp(&share->trigger_tstamp, pcm->tstamp_type);
1135 if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
1136 snd_pcm_areas_copy(pcm->stopped_areas, 0,
1137 pcm->running_areas, 0,
1138 pcm->channels, pcm->buffer_size,
1139 pcm->format);
1140 } else if (slave->running_count > 1) {
1141 int err;
1142 snd_pcm_sframes_t delay;
1143 snd_pcm_areas_silence(pcm->running_areas, 0, pcm->channels,
1144 pcm->buffer_size, pcm->format);
1145 err = snd_pcm_delay(slave->pcm, &delay);
1146 if (err >= 0 && delay > 0)
1147 snd_pcm_rewind(slave->pcm, delay);
1148 share->drain_silenced = 0;
1149 }
1150 share->state = state;
1151 slave->prepared_count--;
1152 slave->running_count--;
1153 if (slave->running_count == 0) {
1154 int err = snd_pcm_drop(slave->pcm);
1155 assert(err >= 0);
1156 }
1157 }
1158
snd_pcm_share_drain(snd_pcm_t * pcm)1159 static int snd_pcm_share_drain(snd_pcm_t *pcm)
1160 {
1161 snd_pcm_share_t *share = pcm->private_data;
1162 snd_pcm_share_slave_t *slave = share->slave;
1163 int err = 0;
1164 Pthread_mutex_lock(&slave->mutex);
1165 switch (share->state) {
1166 case SND_PCM_STATE_OPEN:
1167 err = -EBADFD;
1168 goto _end;
1169 case SND_PCM_STATE_PREPARED:
1170 share->state = SND_PCM_STATE_SETUP;
1171 goto _end;
1172 case SND_PCM_STATE_SETUP:
1173 goto _end;
1174 default:
1175 break;
1176 }
1177 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
1178 switch (share->state) {
1179 case SND_PCM_STATE_XRUN:
1180 share->state = SND_PCM_STATE_SETUP;
1181 goto _end;
1182 case SND_PCM_STATE_DRAINING:
1183 case SND_PCM_STATE_RUNNING:
1184 share->state = SND_PCM_STATE_DRAINING;
1185 _snd_pcm_share_update(pcm);
1186 Pthread_mutex_unlock(&slave->mutex);
1187 if (!(pcm->mode & SND_PCM_NONBLOCK))
1188 snd_pcm_wait(pcm, -1);
1189 return 0;
1190 default:
1191 assert(0);
1192 break;
1193 }
1194 } else {
1195 switch (share->state) {
1196 case SND_PCM_STATE_RUNNING:
1197 _snd_pcm_share_stop(pcm, SND_PCM_STATE_DRAINING);
1198 _snd_pcm_share_update(pcm);
1199 /* Fall through */
1200 case SND_PCM_STATE_XRUN:
1201 case SND_PCM_STATE_DRAINING:
1202 if (snd_pcm_mmap_capture_avail(pcm) <= 0)
1203 share->state = SND_PCM_STATE_SETUP;
1204 else
1205 share->state = SND_PCM_STATE_DRAINING;
1206 break;
1207 default:
1208 assert(0);
1209 break;
1210 }
1211 }
1212 _end:
1213 Pthread_mutex_unlock(&slave->mutex);
1214 return err;
1215 }
1216
snd_pcm_share_drop(snd_pcm_t * pcm)1217 static int snd_pcm_share_drop(snd_pcm_t *pcm)
1218 {
1219 snd_pcm_share_t *share = pcm->private_data;
1220 snd_pcm_share_slave_t *slave = share->slave;
1221 int err = 0;
1222 Pthread_mutex_lock(&slave->mutex);
1223 switch (share->state) {
1224 case SND_PCM_STATE_OPEN:
1225 err = -EBADFD;
1226 goto _end;
1227 case SND_PCM_STATE_SETUP:
1228 break;
1229 case SND_PCM_STATE_DRAINING:
1230 if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
1231 share->state = SND_PCM_STATE_SETUP;
1232 break;
1233 }
1234 /* Fall through */
1235 case SND_PCM_STATE_RUNNING:
1236 _snd_pcm_share_stop(pcm, SND_PCM_STATE_SETUP);
1237 _snd_pcm_share_update(pcm);
1238 break;
1239 case SND_PCM_STATE_PREPARED:
1240 case SND_PCM_STATE_XRUN:
1241 share->state = SND_PCM_STATE_SETUP;
1242 break;
1243 default:
1244 assert(0);
1245 break;
1246 }
1247
1248 share->appl_ptr = share->hw_ptr = 0;
1249 _end:
1250 Pthread_mutex_unlock(&slave->mutex);
1251 return err;
1252 }
1253
snd_pcm_share_close(snd_pcm_t * pcm)1254 static int snd_pcm_share_close(snd_pcm_t *pcm)
1255 {
1256 snd_pcm_share_t *share = pcm->private_data;
1257 snd_pcm_share_slave_t *slave = share->slave;
1258 int err = 0;
1259
1260 Pthread_mutex_lock(&snd_pcm_share_slaves_mutex);
1261 Pthread_mutex_lock(&slave->mutex);
1262 slave->open_count--;
1263 if (slave->open_count == 0) {
1264 pthread_cond_signal(&slave->poll_cond);
1265 Pthread_mutex_unlock(&slave->mutex);
1266 err = pthread_join(slave->thread, 0);
1267 assert(err == 0);
1268 err = snd_pcm_close(slave->pcm);
1269 pthread_mutex_destroy(&slave->mutex);
1270 pthread_cond_destroy(&slave->poll_cond);
1271 list_del(&slave->list);
1272 free(slave);
1273 list_del(&share->list);
1274 } else {
1275 list_del(&share->list);
1276 Pthread_mutex_unlock(&slave->mutex);
1277 }
1278 Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex);
1279 close(share->client_socket);
1280 close(share->slave_socket);
1281 free(share->slave_channels);
1282 free(share);
1283 return err;
1284 }
1285
snd_pcm_share_mmap(snd_pcm_t * pcm ATTRIBUTE_UNUSED)1286 static int snd_pcm_share_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
1287 {
1288 return 0;
1289 }
1290
snd_pcm_share_munmap(snd_pcm_t * pcm ATTRIBUTE_UNUSED)1291 static int snd_pcm_share_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
1292 {
1293 return 0;
1294 }
1295
snd_pcm_share_dump(snd_pcm_t * pcm,snd_output_t * out)1296 static void snd_pcm_share_dump(snd_pcm_t *pcm, snd_output_t *out)
1297 {
1298 snd_pcm_share_t *share = pcm->private_data;
1299 snd_pcm_share_slave_t *slave = share->slave;
1300 unsigned int k;
1301 snd_output_printf(out, "Share PCM\n");
1302 snd_output_printf(out, " Channel bindings:\n");
1303 for (k = 0; k < share->channels; ++k)
1304 snd_output_printf(out, " %d: %d\n", k, share->slave_channels[k]);
1305 if (pcm->setup) {
1306 snd_output_printf(out, "Its setup is:\n");
1307 snd_pcm_dump_setup(pcm, out);
1308 }
1309 snd_output_printf(out, "Slave: ");
1310 snd_pcm_dump(slave->pcm, out);
1311 }
1312
1313 static const snd_pcm_ops_t snd_pcm_share_ops = {
1314 .close = snd_pcm_share_close,
1315 .info = snd_pcm_share_info,
1316 .hw_refine = snd_pcm_share_hw_refine,
1317 .hw_params = snd_pcm_share_hw_params,
1318 .hw_free = snd_pcm_share_hw_free,
1319 .sw_params = snd_pcm_share_sw_params,
1320 .channel_info = snd_pcm_share_channel_info,
1321 .dump = snd_pcm_share_dump,
1322 .nonblock = snd_pcm_share_nonblock,
1323 .async = snd_pcm_share_async,
1324 .mmap = snd_pcm_share_mmap,
1325 .munmap = snd_pcm_share_munmap,
1326 };
1327
1328 static const snd_pcm_fast_ops_t snd_pcm_share_fast_ops = {
1329 .status = snd_pcm_share_status,
1330 .state = snd_pcm_share_state,
1331 .hwsync = snd_pcm_share_hwsync,
1332 .delay = snd_pcm_share_delay,
1333 .prepare = snd_pcm_share_prepare,
1334 .reset = snd_pcm_share_reset,
1335 .start = snd_pcm_share_start,
1336 .drop = snd_pcm_share_drop,
1337 .drain = snd_pcm_share_drain,
1338 .pause = snd_pcm_share_pause,
1339 .writei = snd_pcm_mmap_writei,
1340 .writen = snd_pcm_mmap_writen,
1341 .readi = snd_pcm_mmap_readi,
1342 .readn = snd_pcm_mmap_readn,
1343 .rewindable = snd_pcm_share_rewindable,
1344 .rewind = snd_pcm_share_rewind,
1345 .forwardable = snd_pcm_share_forwardable,
1346 .forward = snd_pcm_share_forward,
1347 .resume = snd_pcm_share_resume,
1348 .avail_update = snd_pcm_share_avail_update,
1349 .htimestamp = snd_pcm_share_htimestamp,
1350 .mmap_commit = snd_pcm_share_mmap_commit,
1351 };
1352
1353 /**
1354 * \brief Creates a new Share PCM
1355 * \param pcmp Returns created PCM handle
1356 * \param name Name of PCM
1357 * \param sname Slave name
1358 * \param sformat Slave format
1359 * \param srate Slave rate
1360 * \param schannels Slave channels
1361 * \param speriod_time Slave period time
1362 * \param sbuffer_time Slave buffer time
1363 * \param channels Count of channels
1364 * \param channels_map Map of channels
1365 * \param stream Direction
1366 * \param mode PCM mode
1367 * \retval zero on success otherwise a negative error code
1368 * \warning Using of this function might be dangerous in the sense
1369 * of compatibility reasons. The prototype might be freely
1370 * changed in future.
1371 */
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)1372 int snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname,
1373 snd_pcm_format_t sformat, int srate,
1374 unsigned int schannels,
1375 int speriod_time, int sbuffer_time,
1376 unsigned int channels, unsigned int *channels_map,
1377 snd_pcm_stream_t stream, int mode)
1378 {
1379 snd_pcm_t *pcm;
1380 snd_pcm_share_t *share;
1381 int err;
1382 struct list_head *i;
1383 char slave_map[32] = { 0 };
1384 unsigned int k;
1385 snd_pcm_share_slave_t *slave = NULL;
1386 int sd[2];
1387
1388 assert(pcmp);
1389 assert(channels > 0 && sname && channels_map);
1390
1391 for (k = 0; k < channels; ++k) {
1392 if (channels_map[k] >= sizeof(slave_map) / sizeof(slave_map[0])) {
1393 SNDERR("Invalid slave channel (%d) in binding", channels_map[k]);
1394 return -EINVAL;
1395 }
1396 if (slave_map[channels_map[k]]) {
1397 SNDERR("Repeated slave channel (%d) in binding", channels_map[k]);
1398 return -EINVAL;
1399 }
1400 slave_map[channels_map[k]] = 1;
1401 assert((unsigned)channels_map[k] < schannels);
1402 }
1403
1404 share = calloc(1, sizeof(snd_pcm_share_t));
1405 if (!share)
1406 return -ENOMEM;
1407
1408 share->channels = channels;
1409 share->slave_channels = calloc(channels, sizeof(*share->slave_channels));
1410 if (!share->slave_channels) {
1411 free(share);
1412 return -ENOMEM;
1413 }
1414 memcpy(share->slave_channels, channels_map, channels * sizeof(*share->slave_channels));
1415
1416 err = snd_pcm_new(&pcm, SND_PCM_TYPE_SHARE, name, stream, mode);
1417 if (err < 0) {
1418 free(share->slave_channels);
1419 free(share);
1420 return err;
1421 }
1422 err = socketpair(AF_LOCAL, SOCK_STREAM, 0, sd);
1423 if (err < 0) {
1424 snd_pcm_free(pcm);
1425 free(share->slave_channels);
1426 free(share);
1427 return -errno;
1428 }
1429
1430 if (stream == SND_PCM_STREAM_PLAYBACK) {
1431 int bufsize = 1;
1432 err = setsockopt(sd[0], SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
1433 if (err >= 0) {
1434 struct pollfd pfd;
1435 pfd.fd = sd[0];
1436 pfd.events = POLLOUT;
1437 while ((err = poll(&pfd, 1, 0)) == 1) {
1438 char buf[1];
1439 err = write(sd[0], buf, 1);
1440 assert(err != 0);
1441 if (err != 1)
1442 break;
1443 }
1444 }
1445 }
1446 if (err < 0) {
1447 err = -errno;
1448 close(sd[0]);
1449 close(sd[1]);
1450 snd_pcm_free(pcm);
1451 free(share->slave_channels);
1452 free(share);
1453 return err;
1454 }
1455
1456 Pthread_mutex_lock(&snd_pcm_share_slaves_mutex);
1457 list_for_each(i, &snd_pcm_share_slaves) {
1458 snd_pcm_share_slave_t *s = list_entry(i, snd_pcm_share_slave_t, list);
1459 if (s->pcm->name && strcmp(s->pcm->name, sname) == 0) {
1460 slave = s;
1461 break;
1462 }
1463 }
1464 if (!slave) {
1465 snd_pcm_t *spcm;
1466 err = snd_pcm_open(&spcm, sname, stream, mode);
1467 if (err < 0) {
1468 Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex);
1469 close(sd[0]);
1470 close(sd[1]);
1471 snd_pcm_free(pcm);
1472 free(share->slave_channels);
1473 free(share);
1474 return err;
1475 }
1476 /* FIXME: bellow is a real ugly hack to get things working */
1477 /* there is a memory leak somewhere, but I'm unable to trace it --jk */
1478 slave = calloc(1, sizeof(snd_pcm_share_slave_t) * 8);
1479 if (!slave) {
1480 Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex);
1481 snd_pcm_close(spcm);
1482 close(sd[0]);
1483 close(sd[1]);
1484 snd_pcm_free(pcm);
1485 free(share->slave_channels);
1486 free(share);
1487 return err;
1488 }
1489 INIT_LIST_HEAD(&slave->clients);
1490 slave->pcm = spcm;
1491 slave->channels = schannels;
1492 slave->format = sformat;
1493 slave->rate = srate;
1494 slave->period_time = speriod_time;
1495 slave->buffer_time = sbuffer_time;
1496 pthread_mutex_init(&slave->mutex, NULL);
1497 pthread_cond_init(&slave->poll_cond, NULL);
1498 list_add_tail(&slave->list, &snd_pcm_share_slaves);
1499 Pthread_mutex_lock(&slave->mutex);
1500 err = pthread_create(&slave->thread, NULL, snd_pcm_share_thread, slave);
1501 assert(err == 0);
1502 Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex);
1503 } else {
1504 Pthread_mutex_lock(&slave->mutex);
1505 Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex);
1506 list_for_each(i, &slave->clients) {
1507 snd_pcm_share_t *sh = list_entry(i, snd_pcm_share_t, list);
1508 for (k = 0; k < sh->channels; ++k) {
1509 if (slave_map[sh->slave_channels[k]]) {
1510 SNDERR("Slave channel %d is already in use", sh->slave_channels[k]);
1511 Pthread_mutex_unlock(&slave->mutex);
1512 close(sd[0]);
1513 close(sd[1]);
1514 snd_pcm_free(pcm);
1515 free(share->slave_channels);
1516 free(share);
1517 return -EBUSY;
1518 }
1519 }
1520 }
1521 }
1522
1523 share->slave = slave;
1524 share->pcm = pcm;
1525 share->client_socket = sd[0];
1526 share->slave_socket = sd[1];
1527
1528 pcm->mmap_rw = 1;
1529 pcm->ops = &snd_pcm_share_ops;
1530 pcm->fast_ops = &snd_pcm_share_fast_ops;
1531 pcm->private_data = share;
1532 pcm->poll_fd = share->client_socket;
1533 pcm->poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
1534 pcm->tstamp_type = slave->pcm->tstamp_type;
1535 snd_pcm_set_hw_ptr(pcm, &share->hw_ptr, -1, 0);
1536 snd_pcm_set_appl_ptr(pcm, &share->appl_ptr, -1, 0);
1537
1538 slave->open_count++;
1539 list_add_tail(&share->list, &slave->clients);
1540
1541 Pthread_mutex_unlock(&slave->mutex);
1542
1543 *pcmp = pcm;
1544 return 0;
1545 }
1546
1547 /*! \page pcm_plugins
1548
1549 \section pcm_plugins_share Plugin: Share
1550
1551 This plugin allows sharing of multiple channels with more clients. The access
1552 to each channel is exlusive (samples are not mixed together). It means, if
1553 the channel zero is used with first client, the channel cannot be used with
1554 second one. If you are looking for a mixing plugin, use the
1555 \ref pcm_plugins_dmix "dmix plugin".
1556
1557 The difference from \ref pcm_plugins_dshare "dshare plugin" is that
1558 share plugin requires the server program "aserver", while dshare plugin
1559 doesn't need the explicit server but access to the shared buffer.
1560
1561 \code
1562 pcm.name {
1563 type share # Share PCM
1564 slave STR # Slave name
1565 # or
1566 slave { # Slave definition
1567 pcm STR # Slave PCM name
1568 [format STR] # Slave format
1569 [channels INT] # Slave channels
1570 [rate INT] # Slave rate
1571 [period_time INT] # Slave period time in us
1572 [buffer_time INT] # Slave buffer time in us
1573 }
1574 bindings {
1575 N INT # Slave channel INT for client channel N
1576 }
1577 }
1578 \endcode
1579
1580 \subsection pcm_plugins_share_funcref Function reference
1581
1582 <UL>
1583 <LI>snd_pcm_share_open()
1584 <LI>_snd_pcm_share_open()
1585 </UL>
1586
1587 */
1588
1589 /**
1590 * \brief Creates a new Share PCM
1591 * \param pcmp Returns created PCM handle
1592 * \param name Name of PCM
1593 * \param root Root configuration node
1594 * \param conf Configuration node with Share PCM description
1595 * \param stream Stream type
1596 * \param mode Stream mode
1597 * \retval zero on success otherwise a negative error code
1598 * \warning Using of this function might be dangerous in the sense
1599 * of compatibility reasons. The prototype might be freely
1600 * changed in future.
1601 */
_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)1602 int _snd_pcm_share_open(snd_pcm_t **pcmp, const char *name,
1603 snd_config_t *root, snd_config_t *conf,
1604 snd_pcm_stream_t stream, int mode)
1605 {
1606 snd_config_iterator_t i, next;
1607 const char *sname = NULL;
1608 snd_config_t *bindings = NULL;
1609 int err;
1610 snd_config_t *slave = NULL, *sconf;
1611 unsigned int *channels_map = NULL;
1612 unsigned int channels = 0;
1613 snd_pcm_format_t sformat = SND_PCM_FORMAT_UNKNOWN;
1614 int schannels = -1;
1615 int srate = -1;
1616 int speriod_time= -1, sbuffer_time = -1;
1617 unsigned int schannel_max = 0;
1618
1619 snd_config_for_each(i, next, conf) {
1620 snd_config_t *n = snd_config_iterator_entry(i);
1621 const char *id;
1622 if (snd_config_get_id(n, &id) < 0)
1623 continue;
1624 if (snd_pcm_conf_generic_id(id))
1625 continue;
1626 if (strcmp(id, "slave") == 0) {
1627 slave = n;
1628 continue;
1629 }
1630 if (strcmp(id, "bindings") == 0) {
1631 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
1632 SNDERR("Invalid type for %s", id);
1633 return -EINVAL;
1634 }
1635 bindings = n;
1636 continue;
1637 }
1638 SNDERR("Unknown field %s", id);
1639 return -EINVAL;
1640 }
1641 if (!slave) {
1642 SNDERR("slave is not defined");
1643 return -EINVAL;
1644 }
1645 err = snd_pcm_slave_conf(root, slave, &sconf, 5,
1646 SND_PCM_HW_PARAM_FORMAT, 0, &sformat,
1647 SND_PCM_HW_PARAM_CHANNELS, 0, &schannels,
1648 SND_PCM_HW_PARAM_RATE, 0, &srate,
1649 SND_PCM_HW_PARAM_PERIOD_TIME, 0, &speriod_time,
1650 SND_PCM_HW_PARAM_BUFFER_TIME, 0, &sbuffer_time);
1651 if (err < 0)
1652 return err;
1653
1654 /* FIXME: nothing strictly forces to have named definition */
1655 err = snd_config_get_string(sconf, &sname);
1656 sname = err >= 0 && sname ? strdup(sname) : NULL;
1657 snd_config_delete(sconf);
1658 if (sname == NULL) {
1659 SNDERR("slave.pcm is not a string");
1660 return err;
1661 }
1662
1663 if (!bindings) {
1664 SNDERR("bindings is not defined");
1665 err = -EINVAL;
1666 goto _free;
1667 }
1668 snd_config_for_each(i, next, bindings) {
1669 long cchannel = -1;
1670 snd_config_t *n = snd_config_iterator_entry(i);
1671 const char *id;
1672 if (snd_config_get_id(n, &id) < 0)
1673 continue;
1674 err = safe_strtol(id, &cchannel);
1675 if (err < 0 || cchannel < 0) {
1676 SNDERR("Invalid client channel in binding: %s", id);
1677 err = -EINVAL;
1678 goto _free;
1679 }
1680 if ((unsigned)cchannel >= channels)
1681 channels = cchannel + 1;
1682 }
1683 if (channels == 0) {
1684 SNDERR("No bindings defined");
1685 err = -EINVAL;
1686 goto _free;
1687 }
1688 channels_map = calloc(channels, sizeof(*channels_map));
1689 if (! channels_map) {
1690 err = -ENOMEM;
1691 goto _free;
1692 }
1693
1694 snd_config_for_each(i, next, bindings) {
1695 snd_config_t *n = snd_config_iterator_entry(i);
1696 const char *id;
1697 long cchannel;
1698 long schannel = -1;
1699 if (snd_config_get_id(n, &id) < 0)
1700 continue;
1701 cchannel = atoi(id);
1702 err = snd_config_get_integer(n, &schannel);
1703 if (err < 0) {
1704 goto _free;
1705 }
1706 assert(schannel >= 0);
1707 assert(schannels <= 0 || schannel < schannels);
1708 channels_map[cchannel] = schannel;
1709 if ((unsigned)schannel > schannel_max)
1710 schannel_max = schannel;
1711 }
1712 if (schannels <= 0)
1713 schannels = schannel_max + 1;
1714 err = snd_pcm_share_open(pcmp, name, sname, sformat, srate,
1715 (unsigned int) schannels,
1716 speriod_time, sbuffer_time,
1717 channels, channels_map, stream, mode);
1718 _free:
1719 free(channels_map);
1720 free((char *)sname);
1721 return err;
1722 }
1723 #ifndef DOC_HIDDEN
1724 SND_DLSYM_BUILD_VERSION(_snd_pcm_share_open, SND_PCM_DLSYM_VERSION);
1725 #endif
1726