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