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