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