xref: /third_party/alsa-lib/src/pcm/pcm_dshare.c (revision d5ac70f0)
1d5ac70f0Sopenharmony_ci/**
2d5ac70f0Sopenharmony_ci * \file pcm/pcm_dshare.c
3d5ac70f0Sopenharmony_ci * \ingroup PCM_Plugins
4d5ac70f0Sopenharmony_ci * \brief PCM Direct Sharing of Channels Plugin Interface
5d5ac70f0Sopenharmony_ci * \author Jaroslav Kysela <perex@perex.cz>
6d5ac70f0Sopenharmony_ci * \date 2003
7d5ac70f0Sopenharmony_ci */
8d5ac70f0Sopenharmony_ci/*
9d5ac70f0Sopenharmony_ci *  PCM - Direct Sharing of Channels
10d5ac70f0Sopenharmony_ci *  Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
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 <stddef.h>
33d5ac70f0Sopenharmony_ci#include <unistd.h>
34d5ac70f0Sopenharmony_ci#include <signal.h>
35d5ac70f0Sopenharmony_ci#include <string.h>
36d5ac70f0Sopenharmony_ci#include <fcntl.h>
37d5ac70f0Sopenharmony_ci#include <ctype.h>
38d5ac70f0Sopenharmony_ci#include <grp.h>
39d5ac70f0Sopenharmony_ci#include <sys/ioctl.h>
40d5ac70f0Sopenharmony_ci#include <sys/mman.h>
41d5ac70f0Sopenharmony_ci#include <sys/shm.h>
42d5ac70f0Sopenharmony_ci#include <sys/sem.h>
43d5ac70f0Sopenharmony_ci#include <sys/wait.h>
44d5ac70f0Sopenharmony_ci#include <sys/socket.h>
45d5ac70f0Sopenharmony_ci#include <sys/un.h>
46d5ac70f0Sopenharmony_ci#include <sys/mman.h>
47d5ac70f0Sopenharmony_ci#include "pcm_direct.h"
48d5ac70f0Sopenharmony_ci
49d5ac70f0Sopenharmony_ci#ifndef PIC
50d5ac70f0Sopenharmony_ci/* entry for static linking */
51d5ac70f0Sopenharmony_ciconst char *_snd_module_pcm_dshare = "";
52d5ac70f0Sopenharmony_ci#endif
53d5ac70f0Sopenharmony_ci
54d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
55d5ac70f0Sopenharmony_ci/* start is pending - this state happens when rate plugin does a delayed commit */
56d5ac70f0Sopenharmony_ci#define STATE_RUN_PENDING	1024
57d5ac70f0Sopenharmony_ci#endif
58d5ac70f0Sopenharmony_ci
59d5ac70f0Sopenharmony_cistatic void do_silence(snd_pcm_t *pcm)
60d5ac70f0Sopenharmony_ci{
61d5ac70f0Sopenharmony_ci	snd_pcm_direct_t *dshare = pcm->private_data;
62d5ac70f0Sopenharmony_ci	const snd_pcm_channel_area_t *dst_areas;
63d5ac70f0Sopenharmony_ci	unsigned int chn, dchn, channels;
64d5ac70f0Sopenharmony_ci	snd_pcm_format_t format;
65d5ac70f0Sopenharmony_ci
66d5ac70f0Sopenharmony_ci	dst_areas = snd_pcm_mmap_areas(dshare->spcm);
67d5ac70f0Sopenharmony_ci	channels = dshare->channels;
68d5ac70f0Sopenharmony_ci	format = dshare->shmptr->s.format;
69d5ac70f0Sopenharmony_ci	for (chn = 0; chn < channels; chn++) {
70d5ac70f0Sopenharmony_ci		dchn = dshare->bindings ? dshare->bindings[chn] : chn;
71d5ac70f0Sopenharmony_ci		if (dchn != UINT_MAX)
72d5ac70f0Sopenharmony_ci			snd_pcm_area_silence(&dst_areas[dchn], 0,
73d5ac70f0Sopenharmony_ci					     dshare->shmptr->s.buffer_size, format);
74d5ac70f0Sopenharmony_ci	}
75d5ac70f0Sopenharmony_ci}
76d5ac70f0Sopenharmony_ci
77d5ac70f0Sopenharmony_cistatic void share_areas(snd_pcm_direct_t *dshare,
78d5ac70f0Sopenharmony_ci		      const snd_pcm_channel_area_t *src_areas,
79d5ac70f0Sopenharmony_ci		      const snd_pcm_channel_area_t *dst_areas,
80d5ac70f0Sopenharmony_ci		      snd_pcm_uframes_t src_ofs,
81d5ac70f0Sopenharmony_ci		      snd_pcm_uframes_t dst_ofs,
82d5ac70f0Sopenharmony_ci		      snd_pcm_uframes_t size)
83d5ac70f0Sopenharmony_ci{
84d5ac70f0Sopenharmony_ci	unsigned int chn, dchn, channels;
85d5ac70f0Sopenharmony_ci	snd_pcm_format_t format;
86d5ac70f0Sopenharmony_ci
87d5ac70f0Sopenharmony_ci	channels = dshare->channels;
88d5ac70f0Sopenharmony_ci	format = dshare->shmptr->s.format;
89d5ac70f0Sopenharmony_ci	if (dshare->interleaved) {
90d5ac70f0Sopenharmony_ci		unsigned int fbytes = snd_pcm_format_physical_width(format) / 8;
91d5ac70f0Sopenharmony_ci		memcpy(((char *)dst_areas[0].addr) + (dst_ofs * channels * fbytes),
92d5ac70f0Sopenharmony_ci		       ((char *)src_areas[0].addr) + (src_ofs * channels * fbytes),
93d5ac70f0Sopenharmony_ci		       size * channels * fbytes);
94d5ac70f0Sopenharmony_ci	} else {
95d5ac70f0Sopenharmony_ci		for (chn = 0; chn < channels; chn++) {
96d5ac70f0Sopenharmony_ci			dchn = dshare->bindings ? dshare->bindings[chn] : chn;
97d5ac70f0Sopenharmony_ci			if (dchn != UINT_MAX)
98d5ac70f0Sopenharmony_ci				snd_pcm_area_copy(&dst_areas[dchn], dst_ofs,
99d5ac70f0Sopenharmony_ci						  &src_areas[chn], src_ofs, size, format);
100d5ac70f0Sopenharmony_ci
101d5ac70f0Sopenharmony_ci		}
102d5ac70f0Sopenharmony_ci	}
103d5ac70f0Sopenharmony_ci}
104d5ac70f0Sopenharmony_ci
105d5ac70f0Sopenharmony_ci/*
106d5ac70f0Sopenharmony_ci *  synchronize shm ring buffer with hardware
107d5ac70f0Sopenharmony_ci */
108d5ac70f0Sopenharmony_cistatic void snd_pcm_dshare_sync_area(snd_pcm_t *pcm)
109d5ac70f0Sopenharmony_ci{
110d5ac70f0Sopenharmony_ci	snd_pcm_direct_t *dshare = pcm->private_data;
111d5ac70f0Sopenharmony_ci	snd_pcm_uframes_t slave_hw_ptr, slave_appl_ptr, slave_size;
112d5ac70f0Sopenharmony_ci	snd_pcm_uframes_t appl_ptr, size;
113d5ac70f0Sopenharmony_ci	const snd_pcm_channel_area_t *src_areas, *dst_areas;
114d5ac70f0Sopenharmony_ci
115d5ac70f0Sopenharmony_ci	/* calculate the size to transfer */
116d5ac70f0Sopenharmony_ci	size = pcm_frame_diff(dshare->appl_ptr, dshare->last_appl_ptr, pcm->boundary);
117d5ac70f0Sopenharmony_ci	if (! size)
118d5ac70f0Sopenharmony_ci		return;
119d5ac70f0Sopenharmony_ci	slave_hw_ptr = dshare->slave_hw_ptr;
120d5ac70f0Sopenharmony_ci	/* don't write on the last active period - this area may be cleared
121d5ac70f0Sopenharmony_ci	 * by the driver during write operation...
122d5ac70f0Sopenharmony_ci	 */
123d5ac70f0Sopenharmony_ci	slave_hw_ptr -= slave_hw_ptr % dshare->slave_period_size;
124d5ac70f0Sopenharmony_ci	slave_hw_ptr += dshare->slave_buffer_size;
125d5ac70f0Sopenharmony_ci	if (slave_hw_ptr >= dshare->slave_boundary)
126d5ac70f0Sopenharmony_ci		slave_hw_ptr -= dshare->slave_boundary;
127d5ac70f0Sopenharmony_ci	slave_size = pcm_frame_diff(slave_hw_ptr, dshare->slave_appl_ptr, dshare->slave_boundary);
128d5ac70f0Sopenharmony_ci	if (slave_size < size)
129d5ac70f0Sopenharmony_ci		size = slave_size;
130d5ac70f0Sopenharmony_ci	if (! size)
131d5ac70f0Sopenharmony_ci		return;
132d5ac70f0Sopenharmony_ci
133d5ac70f0Sopenharmony_ci	/* add sample areas here */
134d5ac70f0Sopenharmony_ci	src_areas = snd_pcm_mmap_areas(pcm);
135d5ac70f0Sopenharmony_ci	dst_areas = snd_pcm_mmap_areas(dshare->spcm);
136d5ac70f0Sopenharmony_ci	appl_ptr = dshare->last_appl_ptr % pcm->buffer_size;
137d5ac70f0Sopenharmony_ci	dshare->last_appl_ptr += size;
138d5ac70f0Sopenharmony_ci	dshare->last_appl_ptr %= pcm->boundary;
139d5ac70f0Sopenharmony_ci	slave_appl_ptr = dshare->slave_appl_ptr % dshare->slave_buffer_size;
140d5ac70f0Sopenharmony_ci	dshare->slave_appl_ptr += size;
141d5ac70f0Sopenharmony_ci	dshare->slave_appl_ptr %= dshare->slave_boundary;
142d5ac70f0Sopenharmony_ci	for (;;) {
143d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t transfer = size;
144d5ac70f0Sopenharmony_ci		if (appl_ptr + transfer > pcm->buffer_size)
145d5ac70f0Sopenharmony_ci			transfer = pcm->buffer_size - appl_ptr;
146d5ac70f0Sopenharmony_ci		if (slave_appl_ptr + transfer > dshare->slave_buffer_size)
147d5ac70f0Sopenharmony_ci			transfer = dshare->slave_buffer_size - slave_appl_ptr;
148d5ac70f0Sopenharmony_ci		share_areas(dshare, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
149d5ac70f0Sopenharmony_ci		size -= transfer;
150d5ac70f0Sopenharmony_ci		if (! size)
151d5ac70f0Sopenharmony_ci			break;
152d5ac70f0Sopenharmony_ci		slave_appl_ptr += transfer;
153d5ac70f0Sopenharmony_ci		slave_appl_ptr %= dshare->slave_buffer_size;
154d5ac70f0Sopenharmony_ci		appl_ptr += transfer;
155d5ac70f0Sopenharmony_ci		appl_ptr %= pcm->buffer_size;
156d5ac70f0Sopenharmony_ci	}
157d5ac70f0Sopenharmony_ci}
158d5ac70f0Sopenharmony_ci
159d5ac70f0Sopenharmony_ci/*
160d5ac70f0Sopenharmony_ci *  synchronize hardware pointer (hw_ptr) with ours
161d5ac70f0Sopenharmony_ci */
162d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr)
163d5ac70f0Sopenharmony_ci{
164d5ac70f0Sopenharmony_ci	snd_pcm_direct_t *dshare = pcm->private_data;
165d5ac70f0Sopenharmony_ci	snd_pcm_uframes_t old_slave_hw_ptr, avail;
166d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t diff;
167d5ac70f0Sopenharmony_ci
168d5ac70f0Sopenharmony_ci	old_slave_hw_ptr = dshare->slave_hw_ptr;
169d5ac70f0Sopenharmony_ci	dshare->slave_hw_ptr = slave_hw_ptr;
170d5ac70f0Sopenharmony_ci	diff = pcm_frame_diff(slave_hw_ptr, old_slave_hw_ptr, dshare->slave_boundary);
171d5ac70f0Sopenharmony_ci	if (diff == 0)		/* fast path */
172d5ac70f0Sopenharmony_ci		return 0;
173d5ac70f0Sopenharmony_ci	if (dshare->state != SND_PCM_STATE_RUNNING &&
174d5ac70f0Sopenharmony_ci	    dshare->state != SND_PCM_STATE_DRAINING)
175d5ac70f0Sopenharmony_ci		/* not really started yet - don't update hw_ptr */
176d5ac70f0Sopenharmony_ci		return 0;
177d5ac70f0Sopenharmony_ci	dshare->hw_ptr += diff;
178d5ac70f0Sopenharmony_ci	dshare->hw_ptr %= pcm->boundary;
179d5ac70f0Sopenharmony_ci	// printf("sync ptr diff = %li\n", diff);
180d5ac70f0Sopenharmony_ci	if (pcm->stop_threshold >= pcm->boundary)	/* don't care */
181d5ac70f0Sopenharmony_ci		return 0;
182d5ac70f0Sopenharmony_ci	avail = snd_pcm_mmap_playback_avail(pcm);
183d5ac70f0Sopenharmony_ci	if (avail > dshare->avail_max)
184d5ac70f0Sopenharmony_ci		dshare->avail_max = avail;
185d5ac70f0Sopenharmony_ci	if (avail >= pcm->stop_threshold) {
186d5ac70f0Sopenharmony_ci		snd_timer_stop(dshare->timer);
187d5ac70f0Sopenharmony_ci		do_silence(pcm);
188d5ac70f0Sopenharmony_ci		gettimestamp(&dshare->trigger_tstamp, pcm->tstamp_type);
189d5ac70f0Sopenharmony_ci		if (dshare->state == SND_PCM_STATE_RUNNING) {
190d5ac70f0Sopenharmony_ci			dshare->state = SND_PCM_STATE_XRUN;
191d5ac70f0Sopenharmony_ci			return -EPIPE;
192d5ac70f0Sopenharmony_ci		}
193d5ac70f0Sopenharmony_ci		dshare->state = SND_PCM_STATE_SETUP;
194d5ac70f0Sopenharmony_ci		/* clear queue to remove pending poll events */
195d5ac70f0Sopenharmony_ci		snd_pcm_direct_clear_timer_queue(dshare);
196d5ac70f0Sopenharmony_ci	}
197d5ac70f0Sopenharmony_ci	return 0;
198d5ac70f0Sopenharmony_ci}
199d5ac70f0Sopenharmony_ci
200d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm)
201d5ac70f0Sopenharmony_ci{
202d5ac70f0Sopenharmony_ci	snd_pcm_direct_t *dshare = pcm->private_data;
203d5ac70f0Sopenharmony_ci	snd_pcm_uframes_t slave_hw_ptr;
204d5ac70f0Sopenharmony_ci	int err;
205d5ac70f0Sopenharmony_ci
206d5ac70f0Sopenharmony_ci	if (dshare->slowptr)
207d5ac70f0Sopenharmony_ci		snd_pcm_hwsync(dshare->spcm);
208d5ac70f0Sopenharmony_ci	slave_hw_ptr = *dshare->spcm->hw.ptr;
209d5ac70f0Sopenharmony_ci	err = snd_pcm_direct_check_xrun(dshare, pcm);
210d5ac70f0Sopenharmony_ci	if (err < 0)
211d5ac70f0Sopenharmony_ci		return err;
212d5ac70f0Sopenharmony_ci
213d5ac70f0Sopenharmony_ci	return snd_pcm_dshare_sync_ptr0(pcm, slave_hw_ptr);
214d5ac70f0Sopenharmony_ci}
215d5ac70f0Sopenharmony_ci
216d5ac70f0Sopenharmony_ci/*
217d5ac70f0Sopenharmony_ci *  plugin implementation
218d5ac70f0Sopenharmony_ci */
219d5ac70f0Sopenharmony_ci
220d5ac70f0Sopenharmony_cistatic snd_pcm_state_t snd_pcm_dshare_state(snd_pcm_t *pcm);
221d5ac70f0Sopenharmony_ci
222d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
223d5ac70f0Sopenharmony_ci{
224d5ac70f0Sopenharmony_ci	snd_pcm_direct_t *dshare = pcm->private_data;
225d5ac70f0Sopenharmony_ci
226d5ac70f0Sopenharmony_ci	memset(status, 0, sizeof(*status));
227d5ac70f0Sopenharmony_ci	snd_pcm_status(dshare->spcm, status);
228d5ac70f0Sopenharmony_ci
229d5ac70f0Sopenharmony_ci	switch (dshare->state) {
230d5ac70f0Sopenharmony_ci	case SNDRV_PCM_STATE_DRAINING:
231d5ac70f0Sopenharmony_ci	case SNDRV_PCM_STATE_RUNNING:
232d5ac70f0Sopenharmony_ci		snd_pcm_dshare_sync_ptr0(pcm, status->hw_ptr);
233d5ac70f0Sopenharmony_ci		status->delay = snd_pcm_mmap_playback_delay(pcm);
234d5ac70f0Sopenharmony_ci		break;
235d5ac70f0Sopenharmony_ci	default:
236d5ac70f0Sopenharmony_ci		break;
237d5ac70f0Sopenharmony_ci	}
238d5ac70f0Sopenharmony_ci	status->state = snd_pcm_dshare_state(pcm);
239d5ac70f0Sopenharmony_ci	status->hw_ptr = *pcm->hw.ptr; /* boundary may be different */
240d5ac70f0Sopenharmony_ci	status->appl_ptr = *pcm->appl.ptr; /* slave PCM doesn't set appl_ptr */
241d5ac70f0Sopenharmony_ci	status->trigger_tstamp = dshare->trigger_tstamp;
242d5ac70f0Sopenharmony_ci	status->avail = snd_pcm_mmap_playback_avail(pcm);
243d5ac70f0Sopenharmony_ci	status->avail_max = status->avail > dshare->avail_max ? status->avail : dshare->avail_max;
244d5ac70f0Sopenharmony_ci	dshare->avail_max = 0;
245d5ac70f0Sopenharmony_ci	return 0;
246d5ac70f0Sopenharmony_ci}
247d5ac70f0Sopenharmony_ci
248d5ac70f0Sopenharmony_cistatic snd_pcm_state_t snd_pcm_dshare_state(snd_pcm_t *pcm)
249d5ac70f0Sopenharmony_ci{
250d5ac70f0Sopenharmony_ci	snd_pcm_direct_t *dshare = pcm->private_data;
251d5ac70f0Sopenharmony_ci
252d5ac70f0Sopenharmony_ci	snd_pcm_direct_check_xrun(dshare, pcm);
253d5ac70f0Sopenharmony_ci	if (dshare->state == STATE_RUN_PENDING)
254d5ac70f0Sopenharmony_ci		return SNDRV_PCM_STATE_RUNNING;
255d5ac70f0Sopenharmony_ci	return dshare->state;
256d5ac70f0Sopenharmony_ci}
257d5ac70f0Sopenharmony_ci
258d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
259d5ac70f0Sopenharmony_ci{
260d5ac70f0Sopenharmony_ci	snd_pcm_direct_t *dshare = pcm->private_data;
261d5ac70f0Sopenharmony_ci	int err;
262d5ac70f0Sopenharmony_ci
263d5ac70f0Sopenharmony_ci	switch (dshare->state) {
264d5ac70f0Sopenharmony_ci	case SNDRV_PCM_STATE_DRAINING:
265d5ac70f0Sopenharmony_ci	case SNDRV_PCM_STATE_RUNNING:
266d5ac70f0Sopenharmony_ci		err = snd_pcm_dshare_sync_ptr(pcm);
267d5ac70f0Sopenharmony_ci		if (err < 0)
268d5ac70f0Sopenharmony_ci			return err;
269d5ac70f0Sopenharmony_ci		/* fallthru */
270d5ac70f0Sopenharmony_ci	case SNDRV_PCM_STATE_PREPARED:
271d5ac70f0Sopenharmony_ci	case SNDRV_PCM_STATE_SUSPENDED:
272d5ac70f0Sopenharmony_ci	case STATE_RUN_PENDING:
273d5ac70f0Sopenharmony_ci		*delayp = snd_pcm_mmap_playback_delay(pcm);
274d5ac70f0Sopenharmony_ci		return 0;
275d5ac70f0Sopenharmony_ci	case SNDRV_PCM_STATE_XRUN:
276d5ac70f0Sopenharmony_ci		return -EPIPE;
277d5ac70f0Sopenharmony_ci	case SNDRV_PCM_STATE_DISCONNECTED:
278d5ac70f0Sopenharmony_ci		return -ENODEV;
279d5ac70f0Sopenharmony_ci	default:
280d5ac70f0Sopenharmony_ci		return -EBADFD;
281d5ac70f0Sopenharmony_ci	}
282d5ac70f0Sopenharmony_ci}
283d5ac70f0Sopenharmony_ci
284d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_hwsync(snd_pcm_t *pcm)
285d5ac70f0Sopenharmony_ci{
286d5ac70f0Sopenharmony_ci	snd_pcm_direct_t *dshare = pcm->private_data;
287d5ac70f0Sopenharmony_ci
288d5ac70f0Sopenharmony_ci	switch(dshare->state) {
289d5ac70f0Sopenharmony_ci	case SNDRV_PCM_STATE_DRAINING:
290d5ac70f0Sopenharmony_ci	case SNDRV_PCM_STATE_RUNNING:
291d5ac70f0Sopenharmony_ci		return snd_pcm_dshare_sync_ptr(pcm);
292d5ac70f0Sopenharmony_ci	case SNDRV_PCM_STATE_PREPARED:
293d5ac70f0Sopenharmony_ci	case SNDRV_PCM_STATE_SUSPENDED:
294d5ac70f0Sopenharmony_ci		return 0;
295d5ac70f0Sopenharmony_ci	case SNDRV_PCM_STATE_XRUN:
296d5ac70f0Sopenharmony_ci		return -EPIPE;
297d5ac70f0Sopenharmony_ci	case SNDRV_PCM_STATE_DISCONNECTED:
298d5ac70f0Sopenharmony_ci		return -ENODEV;
299d5ac70f0Sopenharmony_ci	default:
300d5ac70f0Sopenharmony_ci		return -EBADFD;
301d5ac70f0Sopenharmony_ci	}
302d5ac70f0Sopenharmony_ci}
303d5ac70f0Sopenharmony_ci
304d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_reset(snd_pcm_t *pcm)
305d5ac70f0Sopenharmony_ci{
306d5ac70f0Sopenharmony_ci	snd_pcm_direct_t *dshare = pcm->private_data;
307d5ac70f0Sopenharmony_ci	dshare->hw_ptr %= pcm->period_size;
308d5ac70f0Sopenharmony_ci	dshare->appl_ptr = dshare->last_appl_ptr = dshare->hw_ptr;
309d5ac70f0Sopenharmony_ci	snd_pcm_direct_reset_slave_ptr(pcm, dshare, *dshare->spcm->hw.ptr);
310d5ac70f0Sopenharmony_ci	return 0;
311d5ac70f0Sopenharmony_ci}
312d5ac70f0Sopenharmony_ci
313d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dshare)
314d5ac70f0Sopenharmony_ci{
315d5ac70f0Sopenharmony_ci	int err;
316d5ac70f0Sopenharmony_ci
317d5ac70f0Sopenharmony_ci	snd_pcm_hwsync(dshare->spcm);
318d5ac70f0Sopenharmony_ci	snd_pcm_direct_reset_slave_ptr(pcm, dshare, *dshare->spcm->hw.ptr);
319d5ac70f0Sopenharmony_ci	err = snd_timer_start(dshare->timer);
320d5ac70f0Sopenharmony_ci	if (err < 0)
321d5ac70f0Sopenharmony_ci		return err;
322d5ac70f0Sopenharmony_ci	dshare->state = SND_PCM_STATE_RUNNING;
323d5ac70f0Sopenharmony_ci	return 0;
324d5ac70f0Sopenharmony_ci}
325d5ac70f0Sopenharmony_ci
326d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_start(snd_pcm_t *pcm)
327d5ac70f0Sopenharmony_ci{
328d5ac70f0Sopenharmony_ci	snd_pcm_direct_t *dshare = pcm->private_data;
329d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t avail;
330d5ac70f0Sopenharmony_ci	int err;
331d5ac70f0Sopenharmony_ci
332d5ac70f0Sopenharmony_ci	if (dshare->state != SND_PCM_STATE_PREPARED)
333d5ac70f0Sopenharmony_ci		return -EBADFD;
334d5ac70f0Sopenharmony_ci	avail = snd_pcm_mmap_playback_hw_avail(pcm);
335d5ac70f0Sopenharmony_ci	if (avail == 0)
336d5ac70f0Sopenharmony_ci		dshare->state = STATE_RUN_PENDING;
337d5ac70f0Sopenharmony_ci	else if (avail < 0)
338d5ac70f0Sopenharmony_ci		return 0;
339d5ac70f0Sopenharmony_ci	else {
340d5ac70f0Sopenharmony_ci		err = snd_pcm_dshare_start_timer(pcm, dshare);
341d5ac70f0Sopenharmony_ci		if (err < 0)
342d5ac70f0Sopenharmony_ci			return err;
343d5ac70f0Sopenharmony_ci		snd_pcm_dshare_sync_area(pcm);
344d5ac70f0Sopenharmony_ci	}
345d5ac70f0Sopenharmony_ci	gettimestamp(&dshare->trigger_tstamp, pcm->tstamp_type);
346d5ac70f0Sopenharmony_ci	return 0;
347d5ac70f0Sopenharmony_ci}
348d5ac70f0Sopenharmony_ci
349d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_drop(snd_pcm_t *pcm)
350d5ac70f0Sopenharmony_ci{
351d5ac70f0Sopenharmony_ci	snd_pcm_direct_t *dshare = pcm->private_data;
352d5ac70f0Sopenharmony_ci	if (dshare->state == SND_PCM_STATE_OPEN)
353d5ac70f0Sopenharmony_ci		return -EBADFD;
354d5ac70f0Sopenharmony_ci	dshare->state = SND_PCM_STATE_SETUP;
355d5ac70f0Sopenharmony_ci	snd_pcm_direct_timer_stop(dshare);
356d5ac70f0Sopenharmony_ci	do_silence(pcm);
357d5ac70f0Sopenharmony_ci	return 0;
358d5ac70f0Sopenharmony_ci}
359d5ac70f0Sopenharmony_ci
360d5ac70f0Sopenharmony_ci/* locked version */
361d5ac70f0Sopenharmony_cistatic int __snd_pcm_dshare_drain(snd_pcm_t *pcm)
362d5ac70f0Sopenharmony_ci{
363d5ac70f0Sopenharmony_ci	snd_pcm_direct_t *dshare = pcm->private_data;
364d5ac70f0Sopenharmony_ci	snd_pcm_uframes_t stop_threshold;
365d5ac70f0Sopenharmony_ci	int err;
366d5ac70f0Sopenharmony_ci
367d5ac70f0Sopenharmony_ci	switch (snd_pcm_state(dshare->spcm)) {
368d5ac70f0Sopenharmony_ci	case SND_PCM_STATE_SUSPENDED:
369d5ac70f0Sopenharmony_ci		return -ESTRPIPE;
370d5ac70f0Sopenharmony_ci	default:
371d5ac70f0Sopenharmony_ci		break;
372d5ac70f0Sopenharmony_ci	}
373d5ac70f0Sopenharmony_ci
374d5ac70f0Sopenharmony_ci	if (dshare->state == SND_PCM_STATE_OPEN)
375d5ac70f0Sopenharmony_ci		return -EBADFD;
376d5ac70f0Sopenharmony_ci	if (pcm->mode & SND_PCM_NONBLOCK)
377d5ac70f0Sopenharmony_ci		return -EAGAIN;
378d5ac70f0Sopenharmony_ci	if (dshare->state == SND_PCM_STATE_PREPARED) {
379d5ac70f0Sopenharmony_ci		if (snd_pcm_mmap_playback_hw_avail(pcm) > 0)
380d5ac70f0Sopenharmony_ci			snd_pcm_dshare_start(pcm);
381d5ac70f0Sopenharmony_ci		else {
382d5ac70f0Sopenharmony_ci			snd_pcm_dshare_drop(pcm);
383d5ac70f0Sopenharmony_ci			return 0;
384d5ac70f0Sopenharmony_ci		}
385d5ac70f0Sopenharmony_ci	}
386d5ac70f0Sopenharmony_ci
387d5ac70f0Sopenharmony_ci	if (dshare->state == SND_PCM_STATE_XRUN) {
388d5ac70f0Sopenharmony_ci		snd_pcm_dshare_drop(pcm);
389d5ac70f0Sopenharmony_ci		return 0;
390d5ac70f0Sopenharmony_ci	}
391d5ac70f0Sopenharmony_ci
392d5ac70f0Sopenharmony_ci	stop_threshold = pcm->stop_threshold;
393d5ac70f0Sopenharmony_ci	if (pcm->stop_threshold > pcm->buffer_size)
394d5ac70f0Sopenharmony_ci		pcm->stop_threshold = pcm->buffer_size;
395d5ac70f0Sopenharmony_ci	dshare->state = SND_PCM_STATE_DRAINING;
396d5ac70f0Sopenharmony_ci	do {
397d5ac70f0Sopenharmony_ci		err = snd_pcm_dshare_sync_ptr(pcm);
398d5ac70f0Sopenharmony_ci		if (err < 0) {
399d5ac70f0Sopenharmony_ci			snd_pcm_dshare_drop(pcm);
400d5ac70f0Sopenharmony_ci			break;
401d5ac70f0Sopenharmony_ci		}
402d5ac70f0Sopenharmony_ci		if (dshare->state == SND_PCM_STATE_DRAINING) {
403d5ac70f0Sopenharmony_ci			snd_pcm_dshare_sync_area(pcm);
404d5ac70f0Sopenharmony_ci			snd_pcm_wait_nocheck(pcm, SND_PCM_WAIT_DRAIN);
405d5ac70f0Sopenharmony_ci			snd_pcm_direct_clear_timer_queue(dshare); /* force poll to wait */
406d5ac70f0Sopenharmony_ci
407d5ac70f0Sopenharmony_ci			switch (snd_pcm_state(dshare->spcm)) {
408d5ac70f0Sopenharmony_ci			case SND_PCM_STATE_SUSPENDED:
409d5ac70f0Sopenharmony_ci				return -ESTRPIPE;
410d5ac70f0Sopenharmony_ci			default:
411d5ac70f0Sopenharmony_ci				break;
412d5ac70f0Sopenharmony_ci			}
413d5ac70f0Sopenharmony_ci		}
414d5ac70f0Sopenharmony_ci	} while (dshare->state == SND_PCM_STATE_DRAINING);
415d5ac70f0Sopenharmony_ci	pcm->stop_threshold = stop_threshold;
416d5ac70f0Sopenharmony_ci	return 0;
417d5ac70f0Sopenharmony_ci}
418d5ac70f0Sopenharmony_ci
419d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_drain(snd_pcm_t *pcm)
420d5ac70f0Sopenharmony_ci{
421d5ac70f0Sopenharmony_ci	int err;
422d5ac70f0Sopenharmony_ci
423d5ac70f0Sopenharmony_ci	snd_pcm_lock(pcm);
424d5ac70f0Sopenharmony_ci	err = __snd_pcm_dshare_drain(pcm);
425d5ac70f0Sopenharmony_ci	snd_pcm_unlock(pcm);
426d5ac70f0Sopenharmony_ci	return err;
427d5ac70f0Sopenharmony_ci}
428d5ac70f0Sopenharmony_ci
429d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
430d5ac70f0Sopenharmony_ci{
431d5ac70f0Sopenharmony_ci	return -EIO;
432d5ac70f0Sopenharmony_ci}
433d5ac70f0Sopenharmony_ci
434d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dshare_rewindable(snd_pcm_t *pcm)
435d5ac70f0Sopenharmony_ci{
436d5ac70f0Sopenharmony_ci	return snd_pcm_mmap_playback_hw_rewindable(pcm);
437d5ac70f0Sopenharmony_ci}
438d5ac70f0Sopenharmony_ci
439d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dshare_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
440d5ac70f0Sopenharmony_ci{
441d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t avail;
442d5ac70f0Sopenharmony_ci
443d5ac70f0Sopenharmony_ci	avail = snd_pcm_dshare_rewindable(pcm);
444d5ac70f0Sopenharmony_ci	if (frames > (snd_pcm_uframes_t)avail)
445d5ac70f0Sopenharmony_ci		frames = avail;
446d5ac70f0Sopenharmony_ci	snd_pcm_mmap_appl_backward(pcm, frames);
447d5ac70f0Sopenharmony_ci	return frames;
448d5ac70f0Sopenharmony_ci}
449d5ac70f0Sopenharmony_ci
450d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dshare_forwardable(snd_pcm_t *pcm)
451d5ac70f0Sopenharmony_ci{
452d5ac70f0Sopenharmony_ci	return snd_pcm_mmap_playback_avail(pcm);
453d5ac70f0Sopenharmony_ci}
454d5ac70f0Sopenharmony_ci
455d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dshare_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
456d5ac70f0Sopenharmony_ci{
457d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t avail;
458d5ac70f0Sopenharmony_ci
459d5ac70f0Sopenharmony_ci	avail = snd_pcm_dshare_forwardable(pcm);
460d5ac70f0Sopenharmony_ci	if (frames > (snd_pcm_uframes_t)avail)
461d5ac70f0Sopenharmony_ci		frames = avail;
462d5ac70f0Sopenharmony_ci	snd_pcm_mmap_appl_forward(pcm, frames);
463d5ac70f0Sopenharmony_ci	return frames;
464d5ac70f0Sopenharmony_ci}
465d5ac70f0Sopenharmony_ci
466d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dshare_readi(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
467d5ac70f0Sopenharmony_ci{
468d5ac70f0Sopenharmony_ci	return -ENODEV;
469d5ac70f0Sopenharmony_ci}
470d5ac70f0Sopenharmony_ci
471d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dshare_readn(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
472d5ac70f0Sopenharmony_ci{
473d5ac70f0Sopenharmony_ci	return -ENODEV;
474d5ac70f0Sopenharmony_ci}
475d5ac70f0Sopenharmony_ci
476d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_close(snd_pcm_t *pcm)
477d5ac70f0Sopenharmony_ci{
478d5ac70f0Sopenharmony_ci	snd_pcm_direct_t *dshare = pcm->private_data;
479d5ac70f0Sopenharmony_ci
480d5ac70f0Sopenharmony_ci	if (dshare->timer)
481d5ac70f0Sopenharmony_ci		snd_timer_close(dshare->timer);
482d5ac70f0Sopenharmony_ci	if (dshare->bindings)
483d5ac70f0Sopenharmony_ci		do_silence(pcm);
484d5ac70f0Sopenharmony_ci	snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT);
485d5ac70f0Sopenharmony_ci	dshare->shmptr->u.dshare.chn_mask &= ~dshare->u.dshare.chn_mask;
486d5ac70f0Sopenharmony_ci	snd_pcm_close(dshare->spcm);
487d5ac70f0Sopenharmony_ci 	if (dshare->server)
488d5ac70f0Sopenharmony_ci 		snd_pcm_direct_server_discard(dshare);
489d5ac70f0Sopenharmony_ci 	if (dshare->client)
490d5ac70f0Sopenharmony_ci 		snd_pcm_direct_client_discard(dshare);
491d5ac70f0Sopenharmony_ci	if (snd_pcm_direct_shm_discard(dshare)) {
492d5ac70f0Sopenharmony_ci		if (snd_pcm_direct_semaphore_discard(dshare))
493d5ac70f0Sopenharmony_ci			snd_pcm_direct_semaphore_final(dshare, DIRECT_IPC_SEM_CLIENT);
494d5ac70f0Sopenharmony_ci	} else
495d5ac70f0Sopenharmony_ci		snd_pcm_direct_semaphore_final(dshare, DIRECT_IPC_SEM_CLIENT);
496d5ac70f0Sopenharmony_ci	free(dshare->bindings);
497d5ac70f0Sopenharmony_ci	pcm->private_data = NULL;
498d5ac70f0Sopenharmony_ci	free(dshare);
499d5ac70f0Sopenharmony_ci	return 0;
500d5ac70f0Sopenharmony_ci}
501d5ac70f0Sopenharmony_ci
502d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dshare_mmap_commit(snd_pcm_t *pcm,
503d5ac70f0Sopenharmony_ci						  snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
504d5ac70f0Sopenharmony_ci						  snd_pcm_uframes_t size)
505d5ac70f0Sopenharmony_ci{
506d5ac70f0Sopenharmony_ci	snd_pcm_direct_t *dshare = pcm->private_data;
507d5ac70f0Sopenharmony_ci	int err;
508d5ac70f0Sopenharmony_ci
509d5ac70f0Sopenharmony_ci	err = snd_pcm_direct_check_xrun(dshare, pcm);
510d5ac70f0Sopenharmony_ci	if (err < 0)
511d5ac70f0Sopenharmony_ci		return err;
512d5ac70f0Sopenharmony_ci	if (! size)
513d5ac70f0Sopenharmony_ci		return 0;
514d5ac70f0Sopenharmony_ci	snd_pcm_mmap_appl_forward(pcm, size);
515d5ac70f0Sopenharmony_ci	if (dshare->state == STATE_RUN_PENDING) {
516d5ac70f0Sopenharmony_ci		err = snd_pcm_dshare_start_timer(pcm, dshare);
517d5ac70f0Sopenharmony_ci		if (err < 0)
518d5ac70f0Sopenharmony_ci			return err;
519d5ac70f0Sopenharmony_ci	} else if (dshare->state == SND_PCM_STATE_RUNNING ||
520d5ac70f0Sopenharmony_ci		   dshare->state == SND_PCM_STATE_DRAINING) {
521d5ac70f0Sopenharmony_ci		if ((err = snd_pcm_dshare_sync_ptr(pcm)) < 0)
522d5ac70f0Sopenharmony_ci			return err;
523d5ac70f0Sopenharmony_ci	}
524d5ac70f0Sopenharmony_ci	if (dshare->state == SND_PCM_STATE_RUNNING ||
525d5ac70f0Sopenharmony_ci	    dshare->state == SND_PCM_STATE_DRAINING) {
526d5ac70f0Sopenharmony_ci		/* ok, we commit the changes after the validation of area */
527d5ac70f0Sopenharmony_ci		/* it's intended, although the result might be crappy */
528d5ac70f0Sopenharmony_ci		snd_pcm_dshare_sync_area(pcm);
529d5ac70f0Sopenharmony_ci		/* clear timer queue to avoid a bogus return from poll */
530d5ac70f0Sopenharmony_ci		if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min)
531d5ac70f0Sopenharmony_ci			snd_pcm_direct_clear_timer_queue(dshare);
532d5ac70f0Sopenharmony_ci	}
533d5ac70f0Sopenharmony_ci	return size;
534d5ac70f0Sopenharmony_ci}
535d5ac70f0Sopenharmony_ci
536d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dshare_avail_update(snd_pcm_t *pcm)
537d5ac70f0Sopenharmony_ci{
538d5ac70f0Sopenharmony_ci	snd_pcm_direct_t *dshare = pcm->private_data;
539d5ac70f0Sopenharmony_ci	int err;
540d5ac70f0Sopenharmony_ci
541d5ac70f0Sopenharmony_ci	if (dshare->state == SND_PCM_STATE_RUNNING ||
542d5ac70f0Sopenharmony_ci	    dshare->state == SND_PCM_STATE_DRAINING) {
543d5ac70f0Sopenharmony_ci		if ((err = snd_pcm_dshare_sync_ptr(pcm)) < 0)
544d5ac70f0Sopenharmony_ci			return err;
545d5ac70f0Sopenharmony_ci	}
546d5ac70f0Sopenharmony_ci	if (dshare->state == SND_PCM_STATE_XRUN)
547d5ac70f0Sopenharmony_ci		return -EPIPE;
548d5ac70f0Sopenharmony_ci
549d5ac70f0Sopenharmony_ci	return snd_pcm_mmap_playback_avail(pcm);
550d5ac70f0Sopenharmony_ci}
551d5ac70f0Sopenharmony_ci
552d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_htimestamp(snd_pcm_t *pcm,
553d5ac70f0Sopenharmony_ci				     snd_pcm_uframes_t *avail,
554d5ac70f0Sopenharmony_ci				     snd_htimestamp_t *tstamp)
555d5ac70f0Sopenharmony_ci{
556d5ac70f0Sopenharmony_ci	snd_pcm_direct_t *dshare = pcm->private_data;
557d5ac70f0Sopenharmony_ci	snd_pcm_uframes_t avail1;
558d5ac70f0Sopenharmony_ci	int ok = 0;
559d5ac70f0Sopenharmony_ci
560d5ac70f0Sopenharmony_ci	while (1) {
561d5ac70f0Sopenharmony_ci		if (dshare->state == SND_PCM_STATE_RUNNING ||
562d5ac70f0Sopenharmony_ci		    dshare->state == SND_PCM_STATE_DRAINING)
563d5ac70f0Sopenharmony_ci			snd_pcm_dshare_sync_ptr(pcm);
564d5ac70f0Sopenharmony_ci		avail1 = snd_pcm_mmap_playback_avail(pcm);
565d5ac70f0Sopenharmony_ci		if (ok && *avail == avail1)
566d5ac70f0Sopenharmony_ci			break;
567d5ac70f0Sopenharmony_ci		*avail = avail1;
568d5ac70f0Sopenharmony_ci		*tstamp = snd_pcm_hw_fast_tstamp(dshare->spcm);
569d5ac70f0Sopenharmony_ci		ok = 1;
570d5ac70f0Sopenharmony_ci	}
571d5ac70f0Sopenharmony_ci	return 0;
572d5ac70f0Sopenharmony_ci}
573d5ac70f0Sopenharmony_ci
574d5ac70f0Sopenharmony_cistatic void snd_pcm_dshare_dump(snd_pcm_t *pcm, snd_output_t *out)
575d5ac70f0Sopenharmony_ci{
576d5ac70f0Sopenharmony_ci	snd_pcm_direct_t *dshare = pcm->private_data;
577d5ac70f0Sopenharmony_ci
578d5ac70f0Sopenharmony_ci	snd_output_printf(out, "Direct Share PCM\n");
579d5ac70f0Sopenharmony_ci	if (pcm->setup) {
580d5ac70f0Sopenharmony_ci		snd_output_printf(out, "Its setup is:\n");
581d5ac70f0Sopenharmony_ci		snd_pcm_dump_setup(pcm, out);
582d5ac70f0Sopenharmony_ci	}
583d5ac70f0Sopenharmony_ci	if (dshare->spcm)
584d5ac70f0Sopenharmony_ci		snd_pcm_dump(dshare->spcm, out);
585d5ac70f0Sopenharmony_ci}
586d5ac70f0Sopenharmony_ci
587d5ac70f0Sopenharmony_cistatic const snd_pcm_ops_t snd_pcm_dshare_dummy_ops = {
588d5ac70f0Sopenharmony_ci	.close = snd_pcm_dshare_close,
589d5ac70f0Sopenharmony_ci};
590d5ac70f0Sopenharmony_ci
591d5ac70f0Sopenharmony_cistatic const snd_pcm_fast_ops_t snd_pcm_dshare_fast_dummy_ops;
592d5ac70f0Sopenharmony_ci
593d5ac70f0Sopenharmony_cistatic const snd_pcm_ops_t snd_pcm_dshare_ops = {
594d5ac70f0Sopenharmony_ci	.close = snd_pcm_dshare_close,
595d5ac70f0Sopenharmony_ci	.info = snd_pcm_direct_info,
596d5ac70f0Sopenharmony_ci	.hw_refine = snd_pcm_direct_hw_refine,
597d5ac70f0Sopenharmony_ci	.hw_params = snd_pcm_direct_hw_params,
598d5ac70f0Sopenharmony_ci	.hw_free = snd_pcm_direct_hw_free,
599d5ac70f0Sopenharmony_ci	.sw_params = snd_pcm_direct_sw_params,
600d5ac70f0Sopenharmony_ci	.channel_info = snd_pcm_direct_channel_info,
601d5ac70f0Sopenharmony_ci	.dump = snd_pcm_dshare_dump,
602d5ac70f0Sopenharmony_ci	.nonblock = snd_pcm_direct_nonblock,
603d5ac70f0Sopenharmony_ci	.async = snd_pcm_direct_async,
604d5ac70f0Sopenharmony_ci	.mmap = snd_pcm_direct_mmap,
605d5ac70f0Sopenharmony_ci	.munmap = snd_pcm_direct_munmap,
606d5ac70f0Sopenharmony_ci	.get_chmap = snd_pcm_direct_get_chmap,
607d5ac70f0Sopenharmony_ci	.set_chmap = snd_pcm_direct_set_chmap,
608d5ac70f0Sopenharmony_ci};
609d5ac70f0Sopenharmony_ci
610d5ac70f0Sopenharmony_cistatic const snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = {
611d5ac70f0Sopenharmony_ci	.status = snd_pcm_dshare_status,
612d5ac70f0Sopenharmony_ci	.state = snd_pcm_dshare_state,
613d5ac70f0Sopenharmony_ci	.hwsync = snd_pcm_dshare_hwsync,
614d5ac70f0Sopenharmony_ci	.delay = snd_pcm_dshare_delay,
615d5ac70f0Sopenharmony_ci	.prepare = snd_pcm_direct_prepare,
616d5ac70f0Sopenharmony_ci	.reset = snd_pcm_dshare_reset,
617d5ac70f0Sopenharmony_ci	.start = snd_pcm_dshare_start,
618d5ac70f0Sopenharmony_ci	.drop = snd_pcm_dshare_drop,
619d5ac70f0Sopenharmony_ci	.drain = snd_pcm_dshare_drain,
620d5ac70f0Sopenharmony_ci	.pause = snd_pcm_dshare_pause,
621d5ac70f0Sopenharmony_ci	.rewindable = snd_pcm_dshare_rewindable,
622d5ac70f0Sopenharmony_ci	.rewind = snd_pcm_dshare_rewind,
623d5ac70f0Sopenharmony_ci	.forwardable = snd_pcm_dshare_forwardable,
624d5ac70f0Sopenharmony_ci	.forward = snd_pcm_dshare_forward,
625d5ac70f0Sopenharmony_ci	.resume = snd_pcm_direct_resume,
626d5ac70f0Sopenharmony_ci	.link = NULL,
627d5ac70f0Sopenharmony_ci	.link_slaves = NULL,
628d5ac70f0Sopenharmony_ci	.unlink = NULL,
629d5ac70f0Sopenharmony_ci	.writei = snd_pcm_mmap_writei,
630d5ac70f0Sopenharmony_ci	.writen = snd_pcm_mmap_writen,
631d5ac70f0Sopenharmony_ci	.readi = snd_pcm_dshare_readi,
632d5ac70f0Sopenharmony_ci	.readn = snd_pcm_dshare_readn,
633d5ac70f0Sopenharmony_ci	.avail_update = snd_pcm_dshare_avail_update,
634d5ac70f0Sopenharmony_ci	.mmap_commit = snd_pcm_dshare_mmap_commit,
635d5ac70f0Sopenharmony_ci	.htimestamp = snd_pcm_dshare_htimestamp,
636d5ac70f0Sopenharmony_ci	.poll_descriptors = snd_pcm_direct_poll_descriptors,
637d5ac70f0Sopenharmony_ci	.poll_descriptors_count = NULL,
638d5ac70f0Sopenharmony_ci	.poll_revents = snd_pcm_direct_poll_revents,
639d5ac70f0Sopenharmony_ci};
640d5ac70f0Sopenharmony_ci
641d5ac70f0Sopenharmony_ci/**
642d5ac70f0Sopenharmony_ci * \brief Creates a new dshare PCM
643d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle
644d5ac70f0Sopenharmony_ci * \param name Name of PCM
645d5ac70f0Sopenharmony_ci * \param opts Direct PCM configurations
646d5ac70f0Sopenharmony_ci * \param params Parameters for slave
647d5ac70f0Sopenharmony_ci * \param root Configuration root
648d5ac70f0Sopenharmony_ci * \param sconf Slave configuration
649d5ac70f0Sopenharmony_ci * \param stream PCM Direction (stream)
650d5ac70f0Sopenharmony_ci * \param mode PCM Mode
651d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code
652d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense
653d5ac70f0Sopenharmony_ci *          of compatibility reasons. The prototype might be freely
654d5ac70f0Sopenharmony_ci *          changed in future.
655d5ac70f0Sopenharmony_ci */
656d5ac70f0Sopenharmony_ciint snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
657d5ac70f0Sopenharmony_ci			struct snd_pcm_direct_open_conf *opts,
658d5ac70f0Sopenharmony_ci			struct slave_params *params,
659d5ac70f0Sopenharmony_ci			snd_config_t *root, snd_config_t *sconf,
660d5ac70f0Sopenharmony_ci			snd_pcm_stream_t stream, int mode)
661d5ac70f0Sopenharmony_ci{
662d5ac70f0Sopenharmony_ci	snd_pcm_t *pcm, *spcm = NULL;
663d5ac70f0Sopenharmony_ci	snd_pcm_direct_t *dshare;
664d5ac70f0Sopenharmony_ci	int ret, first_instance;
665d5ac70f0Sopenharmony_ci	unsigned int chn;
666d5ac70f0Sopenharmony_ci
667d5ac70f0Sopenharmony_ci	assert(pcmp);
668d5ac70f0Sopenharmony_ci
669d5ac70f0Sopenharmony_ci	if (stream != SND_PCM_STREAM_PLAYBACK) {
670d5ac70f0Sopenharmony_ci		SNDERR("The dshare plugin supports only playback stream");
671d5ac70f0Sopenharmony_ci		return -EINVAL;
672d5ac70f0Sopenharmony_ci	}
673d5ac70f0Sopenharmony_ci
674d5ac70f0Sopenharmony_ci	ret = _snd_pcm_direct_new(&pcm, &dshare, SND_PCM_TYPE_DSHARE, name, opts, params, stream, mode);
675d5ac70f0Sopenharmony_ci	if (ret < 0)
676d5ac70f0Sopenharmony_ci		return ret;
677d5ac70f0Sopenharmony_ci	first_instance = ret;
678d5ac70f0Sopenharmony_ci
679d5ac70f0Sopenharmony_ci	if (!dshare->bindings) {
680d5ac70f0Sopenharmony_ci		pcm->ops = &snd_pcm_dshare_dummy_ops;
681d5ac70f0Sopenharmony_ci		pcm->fast_ops = &snd_pcm_dshare_fast_dummy_ops;
682d5ac70f0Sopenharmony_ci	} else {
683d5ac70f0Sopenharmony_ci		pcm->ops = &snd_pcm_dshare_ops;
684d5ac70f0Sopenharmony_ci		pcm->fast_ops = &snd_pcm_dshare_fast_ops;
685d5ac70f0Sopenharmony_ci	}
686d5ac70f0Sopenharmony_ci	pcm->private_data = dshare;
687d5ac70f0Sopenharmony_ci	dshare->state = SND_PCM_STATE_OPEN;
688d5ac70f0Sopenharmony_ci	dshare->slowptr = opts->slowptr;
689d5ac70f0Sopenharmony_ci	dshare->max_periods = opts->max_periods;
690d5ac70f0Sopenharmony_ci	dshare->var_periodsize = opts->var_periodsize;
691d5ac70f0Sopenharmony_ci	dshare->hw_ptr_alignment = opts->hw_ptr_alignment;
692d5ac70f0Sopenharmony_ci	dshare->sync_ptr = snd_pcm_dshare_sync_ptr;
693d5ac70f0Sopenharmony_ci
694d5ac70f0Sopenharmony_ci retry:
695d5ac70f0Sopenharmony_ci	if (first_instance) {
696d5ac70f0Sopenharmony_ci		/* recursion is already checked in
697d5ac70f0Sopenharmony_ci		   snd_pcm_direct_get_slave_ipc_offset() */
698d5ac70f0Sopenharmony_ci		ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
699d5ac70f0Sopenharmony_ci					 mode | SND_PCM_NONBLOCK, NULL);
700d5ac70f0Sopenharmony_ci		if (ret < 0) {
701d5ac70f0Sopenharmony_ci			SNDERR("unable to open slave");
702d5ac70f0Sopenharmony_ci			goto _err;
703d5ac70f0Sopenharmony_ci		}
704d5ac70f0Sopenharmony_ci
705d5ac70f0Sopenharmony_ci		if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
706d5ac70f0Sopenharmony_ci			SNDERR("dshare plugin can be only connected to hw plugin");
707d5ac70f0Sopenharmony_ci			goto _err;
708d5ac70f0Sopenharmony_ci		}
709d5ac70f0Sopenharmony_ci
710d5ac70f0Sopenharmony_ci		ret = snd_pcm_direct_initialize_slave(dshare, spcm, params);
711d5ac70f0Sopenharmony_ci		if (ret < 0) {
712d5ac70f0Sopenharmony_ci			SNDERR("unable to initialize slave");
713d5ac70f0Sopenharmony_ci			goto _err;
714d5ac70f0Sopenharmony_ci		}
715d5ac70f0Sopenharmony_ci
716d5ac70f0Sopenharmony_ci		dshare->spcm = spcm;
717d5ac70f0Sopenharmony_ci
718d5ac70f0Sopenharmony_ci		if (dshare->shmptr->use_server) {
719d5ac70f0Sopenharmony_ci			ret = snd_pcm_direct_server_create(dshare);
720d5ac70f0Sopenharmony_ci			if (ret < 0) {
721d5ac70f0Sopenharmony_ci				SNDERR("unable to create server");
722d5ac70f0Sopenharmony_ci				goto _err;
723d5ac70f0Sopenharmony_ci			}
724d5ac70f0Sopenharmony_ci		}
725d5ac70f0Sopenharmony_ci
726d5ac70f0Sopenharmony_ci		dshare->shmptr->type = spcm->type;
727d5ac70f0Sopenharmony_ci	} else {
728d5ac70f0Sopenharmony_ci		if (dshare->shmptr->use_server) {
729d5ac70f0Sopenharmony_ci			/* up semaphore to avoid deadlock */
730d5ac70f0Sopenharmony_ci			snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT);
731d5ac70f0Sopenharmony_ci			ret = snd_pcm_direct_client_connect(dshare);
732d5ac70f0Sopenharmony_ci			if (ret < 0) {
733d5ac70f0Sopenharmony_ci				SNDERR("unable to connect client");
734d5ac70f0Sopenharmony_ci				goto _err_nosem;
735d5ac70f0Sopenharmony_ci			}
736d5ac70f0Sopenharmony_ci
737d5ac70f0Sopenharmony_ci			snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT);
738d5ac70f0Sopenharmony_ci			ret = snd_pcm_direct_open_secondary_client(&spcm, dshare, "dshare_client");
739d5ac70f0Sopenharmony_ci			if (ret < 0)
740d5ac70f0Sopenharmony_ci				goto _err;
741d5ac70f0Sopenharmony_ci
742d5ac70f0Sopenharmony_ci		} else {
743d5ac70f0Sopenharmony_ci
744d5ac70f0Sopenharmony_ci			ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
745d5ac70f0Sopenharmony_ci						 mode | SND_PCM_NONBLOCK |
746d5ac70f0Sopenharmony_ci						 SND_PCM_APPEND,
747d5ac70f0Sopenharmony_ci						 NULL);
748d5ac70f0Sopenharmony_ci			if (ret < 0) {
749d5ac70f0Sopenharmony_ci				/* all other streams have been closed;
750d5ac70f0Sopenharmony_ci				 * retry as the first instance
751d5ac70f0Sopenharmony_ci				 */
752d5ac70f0Sopenharmony_ci				if (ret == -EBADFD) {
753d5ac70f0Sopenharmony_ci					first_instance = 1;
754d5ac70f0Sopenharmony_ci					goto retry;
755d5ac70f0Sopenharmony_ci				}
756d5ac70f0Sopenharmony_ci				SNDERR("unable to open slave");
757d5ac70f0Sopenharmony_ci				goto _err;
758d5ac70f0Sopenharmony_ci			}
759d5ac70f0Sopenharmony_ci			if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
760d5ac70f0Sopenharmony_ci				SNDERR("dshare plugin can be only connected to hw plugin");
761d5ac70f0Sopenharmony_ci				ret = -EINVAL;
762d5ac70f0Sopenharmony_ci				goto _err;
763d5ac70f0Sopenharmony_ci			}
764d5ac70f0Sopenharmony_ci
765d5ac70f0Sopenharmony_ci			ret = snd_pcm_direct_initialize_secondary_slave(dshare, spcm, params);
766d5ac70f0Sopenharmony_ci			if (ret < 0) {
767d5ac70f0Sopenharmony_ci				SNDERR("unable to initialize slave");
768d5ac70f0Sopenharmony_ci				goto _err;
769d5ac70f0Sopenharmony_ci			}
770d5ac70f0Sopenharmony_ci		}
771d5ac70f0Sopenharmony_ci
772d5ac70f0Sopenharmony_ci		dshare->spcm = spcm;
773d5ac70f0Sopenharmony_ci	}
774d5ac70f0Sopenharmony_ci
775d5ac70f0Sopenharmony_ci	for (chn = 0; dshare->bindings && (chn < dshare->channels); chn++) {
776d5ac70f0Sopenharmony_ci		unsigned int dchn = dshare->bindings ? dshare->bindings[chn] : chn;
777d5ac70f0Sopenharmony_ci		if (dchn != UINT_MAX)
778d5ac70f0Sopenharmony_ci			dshare->u.dshare.chn_mask |= (1ULL << dchn);
779d5ac70f0Sopenharmony_ci	}
780d5ac70f0Sopenharmony_ci	if (dshare->shmptr->u.dshare.chn_mask & dshare->u.dshare.chn_mask) {
781d5ac70f0Sopenharmony_ci		SNDERR("destination channel specified in bindings is already used");
782d5ac70f0Sopenharmony_ci		dshare->u.dshare.chn_mask = 0;
783d5ac70f0Sopenharmony_ci		ret = -EINVAL;
784d5ac70f0Sopenharmony_ci		goto _err;
785d5ac70f0Sopenharmony_ci	}
786d5ac70f0Sopenharmony_ci	dshare->shmptr->u.dshare.chn_mask |= dshare->u.dshare.chn_mask;
787d5ac70f0Sopenharmony_ci
788d5ac70f0Sopenharmony_ci	ret = snd_pcm_direct_initialize_poll_fd(dshare);
789d5ac70f0Sopenharmony_ci	if (ret < 0) {
790d5ac70f0Sopenharmony_ci		SNDERR("unable to initialize poll_fd");
791d5ac70f0Sopenharmony_ci		goto _err;
792d5ac70f0Sopenharmony_ci	}
793d5ac70f0Sopenharmony_ci
794d5ac70f0Sopenharmony_ci	pcm->poll_fd = dshare->poll_fd;
795d5ac70f0Sopenharmony_ci	pcm->poll_events = POLLIN;	/* it's different than other plugins */
796d5ac70f0Sopenharmony_ci	pcm->tstamp_type = spcm->tstamp_type;
797d5ac70f0Sopenharmony_ci	pcm->mmap_rw = 1;
798d5ac70f0Sopenharmony_ci	snd_pcm_set_hw_ptr(pcm, &dshare->hw_ptr, -1, 0);
799d5ac70f0Sopenharmony_ci	snd_pcm_set_appl_ptr(pcm, &dshare->appl_ptr, -1, 0);
800d5ac70f0Sopenharmony_ci
801d5ac70f0Sopenharmony_ci	snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT);
802d5ac70f0Sopenharmony_ci
803d5ac70f0Sopenharmony_ci	*pcmp = pcm;
804d5ac70f0Sopenharmony_ci	return 0;
805d5ac70f0Sopenharmony_ci
806d5ac70f0Sopenharmony_ci _err:
807d5ac70f0Sopenharmony_ci	if (dshare->shmptr != (void *) -1)
808d5ac70f0Sopenharmony_ci		dshare->shmptr->u.dshare.chn_mask &= ~dshare->u.dshare.chn_mask;
809d5ac70f0Sopenharmony_ci	if (dshare->timer)
810d5ac70f0Sopenharmony_ci		snd_timer_close(dshare->timer);
811d5ac70f0Sopenharmony_ci	if (dshare->server)
812d5ac70f0Sopenharmony_ci		snd_pcm_direct_server_discard(dshare);
813d5ac70f0Sopenharmony_ci	if (dshare->client)
814d5ac70f0Sopenharmony_ci		snd_pcm_direct_client_discard(dshare);
815d5ac70f0Sopenharmony_ci	if (spcm)
816d5ac70f0Sopenharmony_ci		snd_pcm_close(spcm);
817d5ac70f0Sopenharmony_ci	if ((dshare->shmid >= 0) && (snd_pcm_direct_shm_discard(dshare))) {
818d5ac70f0Sopenharmony_ci		if (snd_pcm_direct_semaphore_discard(dshare))
819d5ac70f0Sopenharmony_ci			snd_pcm_direct_semaphore_final(dshare, DIRECT_IPC_SEM_CLIENT);
820d5ac70f0Sopenharmony_ci	} else
821d5ac70f0Sopenharmony_ci		snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT);
822d5ac70f0Sopenharmony_ci _err_nosem:
823d5ac70f0Sopenharmony_ci	free(dshare->bindings);
824d5ac70f0Sopenharmony_ci	free(dshare);
825d5ac70f0Sopenharmony_ci	snd_pcm_free(pcm);
826d5ac70f0Sopenharmony_ci	return ret;
827d5ac70f0Sopenharmony_ci}
828d5ac70f0Sopenharmony_ci
829d5ac70f0Sopenharmony_ci/*! \page pcm_plugins
830d5ac70f0Sopenharmony_ci
831d5ac70f0Sopenharmony_ci\section pcm_plugins_dshare Plugin: dshare
832d5ac70f0Sopenharmony_ci
833d5ac70f0Sopenharmony_ciThis plugin provides sharing channels.
834d5ac70f0Sopenharmony_ciUnlike \ref pcm_plugins_share "share plugin", this plugin doesn't need
835d5ac70f0Sopenharmony_cithe explicit server program but accesses the shared buffer concurrently
836d5ac70f0Sopenharmony_cifrom each client as well as \ref pcm_plugins_dmix "dmix" and
837d5ac70f0Sopenharmony_ci\ref pcm_plugins_dsnoop "dsnoop" plugins do.
838d5ac70f0Sopenharmony_ciThe parameters below are almost identical with these plugins.
839d5ac70f0Sopenharmony_ci
840d5ac70f0Sopenharmony_ci\code
841d5ac70f0Sopenharmony_cipcm.name {
842d5ac70f0Sopenharmony_ci	type dshare		# Direct sharing
843d5ac70f0Sopenharmony_ci	ipc_key INT		# unique IPC key
844d5ac70f0Sopenharmony_ci	ipc_key_add_uid BOOL	# add current uid to unique IPC key
845d5ac70f0Sopenharmony_ci	ipc_perm INT		# IPC permissions (octal, default 0600)
846d5ac70f0Sopenharmony_ci	hw_ptr_alignment STR	# Slave application and hw pointer alignment type
847d5ac70f0Sopenharmony_ci		# STR can be one of the below strings :
848d5ac70f0Sopenharmony_ci		# no (or off)
849d5ac70f0Sopenharmony_ci		# roundup
850d5ac70f0Sopenharmony_ci		# rounddown
851d5ac70f0Sopenharmony_ci		# auto (default)
852d5ac70f0Sopenharmony_ci	tstamp_type STR		# timestamp type
853d5ac70f0Sopenharmony_ci				# STR can be one of the below strings :
854d5ac70f0Sopenharmony_ci				# default, gettimeofday, monotonic, monotonic_raw
855d5ac70f0Sopenharmony_ci	slave STR
856d5ac70f0Sopenharmony_ci	# or
857d5ac70f0Sopenharmony_ci	slave {			# Slave definition
858d5ac70f0Sopenharmony_ci		pcm STR		# slave PCM name
859d5ac70f0Sopenharmony_ci		# or
860d5ac70f0Sopenharmony_ci		pcm { }		# slave PCM definition
861d5ac70f0Sopenharmony_ci		format STR	# format definition
862d5ac70f0Sopenharmony_ci		rate INT	# rate definition
863d5ac70f0Sopenharmony_ci		channels INT
864d5ac70f0Sopenharmony_ci		period_time INT	# in usec
865d5ac70f0Sopenharmony_ci		# or
866d5ac70f0Sopenharmony_ci		period_size INT	# in frames
867d5ac70f0Sopenharmony_ci		buffer_time INT	# in usec
868d5ac70f0Sopenharmony_ci		# or
869d5ac70f0Sopenharmony_ci		buffer_size INT # in frames
870d5ac70f0Sopenharmony_ci		periods INT	# when buffer_size or buffer_time is not specified
871d5ac70f0Sopenharmony_ci	}
872d5ac70f0Sopenharmony_ci	bindings {		# note: this is client independent!!!
873d5ac70f0Sopenharmony_ci		N INT		# maps slave channel to client channel N
874d5ac70f0Sopenharmony_ci	}
875d5ac70f0Sopenharmony_ci	slowptr BOOL		# slow but more precise pointer updates
876d5ac70f0Sopenharmony_ci}
877d5ac70f0Sopenharmony_ci\endcode
878d5ac70f0Sopenharmony_ci
879d5ac70f0Sopenharmony_ci<code>hw_ptr_alignment</code> specifies slave application and hw
880d5ac70f0Sopenharmony_cipointer alignment type. By default hw_ptr_alignment is auto. Below are
881d5ac70f0Sopenharmony_cithe possible configurations:
882d5ac70f0Sopenharmony_ci- no: minimal latency with minimal frames dropped at startup. But
883d5ac70f0Sopenharmony_ci  wakeup of application (return from snd_pcm_wait() or poll()) can
884d5ac70f0Sopenharmony_ci  take up to 2 * period.
885d5ac70f0Sopenharmony_ci- roundup: It is guaranteed that all frames will be played at
886d5ac70f0Sopenharmony_ci  startup. But the latency will increase upto period-1 frames.
887d5ac70f0Sopenharmony_ci- rounddown: It is guaranteed that a wakeup will happen for each
888d5ac70f0Sopenharmony_ci  period and frames can be written from application. But on startup
889d5ac70f0Sopenharmony_ci  upto period-1 frames will be dropped.
890d5ac70f0Sopenharmony_ci- auto: Selects the best approach depending on the used period and
891d5ac70f0Sopenharmony_ci  buffer size.
892d5ac70f0Sopenharmony_ci  If the application buffer size is < 2 * application period,
893d5ac70f0Sopenharmony_ci  "roundup" will be selected to avoid under runs. If the slave_period
894d5ac70f0Sopenharmony_ci  is < 10ms we could expect that there are low latency
895d5ac70f0Sopenharmony_ci  requirements. Therefore "rounddown" will be chosen to avoid long
896d5ac70f0Sopenharmony_ci  wakeup times. Such wakeup delay could otherwise end up with Xruns in
897d5ac70f0Sopenharmony_ci  case of a dependency to another sound device (e.g. forwarding of
898d5ac70f0Sopenharmony_ci  microphone to speaker). Else "no" will be chosen.
899d5ac70f0Sopenharmony_ci
900d5ac70f0Sopenharmony_ci\subsection pcm_plugins_dshare_funcref Function reference
901d5ac70f0Sopenharmony_ci
902d5ac70f0Sopenharmony_ci<UL>
903d5ac70f0Sopenharmony_ci  <LI>snd_pcm_dshare_open()
904d5ac70f0Sopenharmony_ci  <LI>_snd_pcm_dshare_open()
905d5ac70f0Sopenharmony_ci</UL>
906d5ac70f0Sopenharmony_ci
907d5ac70f0Sopenharmony_ci*/
908d5ac70f0Sopenharmony_ci
909d5ac70f0Sopenharmony_ci/**
910d5ac70f0Sopenharmony_ci * \brief Creates a new dshare PCM
911d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle
912d5ac70f0Sopenharmony_ci * \param name Name of PCM
913d5ac70f0Sopenharmony_ci * \param root Root configuration node
914d5ac70f0Sopenharmony_ci * \param conf Configuration node with dshare PCM description
915d5ac70f0Sopenharmony_ci * \param stream PCM Stream
916d5ac70f0Sopenharmony_ci * \param mode PCM Mode
917d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense
918d5ac70f0Sopenharmony_ci *          of compatibility reasons. The prototype might be freely
919d5ac70f0Sopenharmony_ci *          changed in future.
920d5ac70f0Sopenharmony_ci */
921d5ac70f0Sopenharmony_ciint _snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
922d5ac70f0Sopenharmony_ci		       snd_config_t *root, snd_config_t *conf,
923d5ac70f0Sopenharmony_ci		       snd_pcm_stream_t stream, int mode)
924d5ac70f0Sopenharmony_ci{
925d5ac70f0Sopenharmony_ci	snd_config_t *sconf;
926d5ac70f0Sopenharmony_ci	struct slave_params params;
927d5ac70f0Sopenharmony_ci	struct snd_pcm_direct_open_conf dopen;
928d5ac70f0Sopenharmony_ci	int bsize, psize;
929d5ac70f0Sopenharmony_ci	int err;
930d5ac70f0Sopenharmony_ci
931d5ac70f0Sopenharmony_ci	err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen);
932d5ac70f0Sopenharmony_ci	if (err < 0)
933d5ac70f0Sopenharmony_ci		return err;
934d5ac70f0Sopenharmony_ci
935d5ac70f0Sopenharmony_ci	/* the default settings, it might be invalid for some hardware */
936d5ac70f0Sopenharmony_ci	params.format = SND_PCM_FORMAT_S16;
937d5ac70f0Sopenharmony_ci	params.rate = 48000;
938d5ac70f0Sopenharmony_ci	params.channels = 2;
939d5ac70f0Sopenharmony_ci	params.period_time = -1;
940d5ac70f0Sopenharmony_ci	params.buffer_time = -1;
941d5ac70f0Sopenharmony_ci	bsize = psize = -1;
942d5ac70f0Sopenharmony_ci	params.periods = 3;
943d5ac70f0Sopenharmony_ci	err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8,
944d5ac70f0Sopenharmony_ci				 SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, &params.format,
945d5ac70f0Sopenharmony_ci				 SND_PCM_HW_PARAM_RATE, 0, &params.rate,
946d5ac70f0Sopenharmony_ci				 SND_PCM_HW_PARAM_CHANNELS, 0, &params.channels,
947d5ac70f0Sopenharmony_ci				 SND_PCM_HW_PARAM_PERIOD_TIME, 0, &params.period_time,
948d5ac70f0Sopenharmony_ci				 SND_PCM_HW_PARAM_BUFFER_TIME, 0, &params.buffer_time,
949d5ac70f0Sopenharmony_ci				 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
950d5ac70f0Sopenharmony_ci				 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
951d5ac70f0Sopenharmony_ci				 SND_PCM_HW_PARAM_PERIODS, 0, &params.periods);
952d5ac70f0Sopenharmony_ci	if (err < 0)
953d5ac70f0Sopenharmony_ci		return err;
954d5ac70f0Sopenharmony_ci
955d5ac70f0Sopenharmony_ci	/* set a reasonable default */
956d5ac70f0Sopenharmony_ci	if (psize == -1 && params.period_time == -1)
957d5ac70f0Sopenharmony_ci		params.period_time = 125000;	/* 0.125 seconds */
958d5ac70f0Sopenharmony_ci
959d5ac70f0Sopenharmony_ci	if (params.format == -2)
960d5ac70f0Sopenharmony_ci		params.format = SND_PCM_FORMAT_UNKNOWN;
961d5ac70f0Sopenharmony_ci
962d5ac70f0Sopenharmony_ci	params.period_size = psize;
963d5ac70f0Sopenharmony_ci	params.buffer_size = bsize;
964d5ac70f0Sopenharmony_ci
965d5ac70f0Sopenharmony_ci	err = snd_pcm_dshare_open(pcmp, name, &dopen, &params,
966d5ac70f0Sopenharmony_ci				  root, sconf, stream, mode);
967d5ac70f0Sopenharmony_ci	snd_config_delete(sconf);
968d5ac70f0Sopenharmony_ci	return err;
969d5ac70f0Sopenharmony_ci}
970d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
971d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(_snd_pcm_dshare_open, SND_PCM_DLSYM_VERSION);
972d5ac70f0Sopenharmony_ci#endif
973