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