1d5ac70f0Sopenharmony_ci/**
2d5ac70f0Sopenharmony_ci * \file pcm/pcm_null.c
3d5ac70f0Sopenharmony_ci * \ingroup PCM_Plugins
4d5ac70f0Sopenharmony_ci * \brief PCM Null Plugin Interface
5d5ac70f0Sopenharmony_ci * \author Abramo Bagnara <abramo@alsa-project.org>
6d5ac70f0Sopenharmony_ci * \date 2000-2001
7d5ac70f0Sopenharmony_ci */
8d5ac70f0Sopenharmony_ci/*
9d5ac70f0Sopenharmony_ci *  PCM - Null plugin
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 "pcm_plugin.h"
31d5ac70f0Sopenharmony_ci#include "bswap.h"
32d5ac70f0Sopenharmony_ci#include <limits.h>
33d5ac70f0Sopenharmony_ci
34d5ac70f0Sopenharmony_ci#ifndef PIC
35d5ac70f0Sopenharmony_ci/* entry for static linking */
36d5ac70f0Sopenharmony_ciconst char *_snd_module_pcm_null = "";
37d5ac70f0Sopenharmony_ci#endif
38d5ac70f0Sopenharmony_ci
39d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
40d5ac70f0Sopenharmony_citypedef struct {
41d5ac70f0Sopenharmony_ci	snd_htimestamp_t trigger_tstamp;
42d5ac70f0Sopenharmony_ci	snd_pcm_state_t state;
43d5ac70f0Sopenharmony_ci	snd_pcm_uframes_t appl_ptr;
44d5ac70f0Sopenharmony_ci	snd_pcm_uframes_t hw_ptr;
45d5ac70f0Sopenharmony_ci	int poll_fd;
46d5ac70f0Sopenharmony_ci	snd_pcm_chmap_query_t **chmap;
47d5ac70f0Sopenharmony_ci} snd_pcm_null_t;
48d5ac70f0Sopenharmony_ci#endif
49d5ac70f0Sopenharmony_ci
50d5ac70f0Sopenharmony_cistatic int snd_pcm_null_close(snd_pcm_t *pcm)
51d5ac70f0Sopenharmony_ci{
52d5ac70f0Sopenharmony_ci	snd_pcm_null_t *null = pcm->private_data;
53d5ac70f0Sopenharmony_ci	close(null->poll_fd);
54d5ac70f0Sopenharmony_ci	free(null);
55d5ac70f0Sopenharmony_ci	return 0;
56d5ac70f0Sopenharmony_ci}
57d5ac70f0Sopenharmony_ci
58d5ac70f0Sopenharmony_cistatic int snd_pcm_null_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
59d5ac70f0Sopenharmony_ci{
60d5ac70f0Sopenharmony_ci	return 0;
61d5ac70f0Sopenharmony_ci}
62d5ac70f0Sopenharmony_ci
63d5ac70f0Sopenharmony_cistatic int snd_pcm_null_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int sig ATTRIBUTE_UNUSED, pid_t pid ATTRIBUTE_UNUSED)
64d5ac70f0Sopenharmony_ci{
65d5ac70f0Sopenharmony_ci	return -ENOSYS;
66d5ac70f0Sopenharmony_ci}
67d5ac70f0Sopenharmony_ci
68d5ac70f0Sopenharmony_cistatic int snd_pcm_null_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
69d5ac70f0Sopenharmony_ci{
70d5ac70f0Sopenharmony_ci	memset(info, 0, sizeof(*info));
71d5ac70f0Sopenharmony_ci	info->stream = pcm->stream;
72d5ac70f0Sopenharmony_ci	info->card = -1;
73d5ac70f0Sopenharmony_ci	if (pcm->name) {
74d5ac70f0Sopenharmony_ci		snd_strlcpy((char *)info->id, pcm->name, sizeof(info->id));
75d5ac70f0Sopenharmony_ci		snd_strlcpy((char *)info->name, pcm->name, sizeof(info->name));
76d5ac70f0Sopenharmony_ci		snd_strlcpy((char *)info->subname, pcm->name, sizeof(info->subname));
77d5ac70f0Sopenharmony_ci	}
78d5ac70f0Sopenharmony_ci	info->subdevices_count = 1;
79d5ac70f0Sopenharmony_ci	return 0;
80d5ac70f0Sopenharmony_ci}
81d5ac70f0Sopenharmony_ci
82d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_null_avail_update(snd_pcm_t *pcm)
83d5ac70f0Sopenharmony_ci{
84d5ac70f0Sopenharmony_ci	snd_pcm_null_t *null = pcm->private_data;
85d5ac70f0Sopenharmony_ci        if (null->state == SND_PCM_STATE_PREPARED) {
86d5ac70f0Sopenharmony_ci                /* it is required to return the correct avail count for */
87d5ac70f0Sopenharmony_ci                /* the prepared stream, otherwise the start is not called */
88d5ac70f0Sopenharmony_ci                return snd_pcm_mmap_avail(pcm);
89d5ac70f0Sopenharmony_ci        }
90d5ac70f0Sopenharmony_ci	return pcm->buffer_size;
91d5ac70f0Sopenharmony_ci}
92d5ac70f0Sopenharmony_ci
93d5ac70f0Sopenharmony_cistatic int snd_pcm_null_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
94d5ac70f0Sopenharmony_ci{
95d5ac70f0Sopenharmony_ci	snd_pcm_null_t *null = pcm->private_data;
96d5ac70f0Sopenharmony_ci	memset(status, 0, sizeof(*status));
97d5ac70f0Sopenharmony_ci	status->state = null->state;
98d5ac70f0Sopenharmony_ci	status->trigger_tstamp = null->trigger_tstamp;
99d5ac70f0Sopenharmony_ci	status->appl_ptr = *pcm->appl.ptr;
100d5ac70f0Sopenharmony_ci	status->hw_ptr = *pcm->hw.ptr;
101d5ac70f0Sopenharmony_ci	gettimestamp(&status->tstamp, pcm->tstamp_type);
102d5ac70f0Sopenharmony_ci	status->avail = snd_pcm_null_avail_update(pcm);
103d5ac70f0Sopenharmony_ci	status->avail_max = pcm->buffer_size;
104d5ac70f0Sopenharmony_ci	return 0;
105d5ac70f0Sopenharmony_ci}
106d5ac70f0Sopenharmony_ci
107d5ac70f0Sopenharmony_cistatic snd_pcm_state_t snd_pcm_null_state(snd_pcm_t *pcm)
108d5ac70f0Sopenharmony_ci{
109d5ac70f0Sopenharmony_ci	snd_pcm_null_t *null = pcm->private_data;
110d5ac70f0Sopenharmony_ci	return null->state;
111d5ac70f0Sopenharmony_ci}
112d5ac70f0Sopenharmony_ci
113d5ac70f0Sopenharmony_cistatic int snd_pcm_null_hwsync(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
114d5ac70f0Sopenharmony_ci{
115d5ac70f0Sopenharmony_ci	return 0;
116d5ac70f0Sopenharmony_ci}
117d5ac70f0Sopenharmony_ci
118d5ac70f0Sopenharmony_cistatic int snd_pcm_null_delay(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sframes_t *delayp)
119d5ac70f0Sopenharmony_ci{
120d5ac70f0Sopenharmony_ci	*delayp = 0;
121d5ac70f0Sopenharmony_ci	return 0;
122d5ac70f0Sopenharmony_ci}
123d5ac70f0Sopenharmony_ci
124d5ac70f0Sopenharmony_cistatic int snd_pcm_null_reset(snd_pcm_t *pcm)
125d5ac70f0Sopenharmony_ci{
126d5ac70f0Sopenharmony_ci	*pcm->appl.ptr = 0;
127d5ac70f0Sopenharmony_ci	*pcm->hw.ptr = 0;
128d5ac70f0Sopenharmony_ci	return 0;
129d5ac70f0Sopenharmony_ci}
130d5ac70f0Sopenharmony_ci
131d5ac70f0Sopenharmony_cistatic int snd_pcm_null_prepare(snd_pcm_t *pcm)
132d5ac70f0Sopenharmony_ci{
133d5ac70f0Sopenharmony_ci	snd_pcm_null_t *null = pcm->private_data;
134d5ac70f0Sopenharmony_ci	null->state = SND_PCM_STATE_PREPARED;
135d5ac70f0Sopenharmony_ci	return snd_pcm_null_reset(pcm);
136d5ac70f0Sopenharmony_ci}
137d5ac70f0Sopenharmony_ci
138d5ac70f0Sopenharmony_cistatic int snd_pcm_null_start(snd_pcm_t *pcm)
139d5ac70f0Sopenharmony_ci{
140d5ac70f0Sopenharmony_ci	snd_pcm_null_t *null = pcm->private_data;
141d5ac70f0Sopenharmony_ci	assert(null->state == SND_PCM_STATE_PREPARED);
142d5ac70f0Sopenharmony_ci	null->state = SND_PCM_STATE_RUNNING;
143d5ac70f0Sopenharmony_ci	if (pcm->stream == SND_PCM_STREAM_CAPTURE)
144d5ac70f0Sopenharmony_ci		*pcm->hw.ptr = *pcm->appl.ptr + pcm->buffer_size;
145d5ac70f0Sopenharmony_ci	else
146d5ac70f0Sopenharmony_ci		*pcm->hw.ptr = *pcm->appl.ptr;
147d5ac70f0Sopenharmony_ci	return 0;
148d5ac70f0Sopenharmony_ci}
149d5ac70f0Sopenharmony_ci
150d5ac70f0Sopenharmony_cistatic int snd_pcm_null_drop(snd_pcm_t *pcm)
151d5ac70f0Sopenharmony_ci{
152d5ac70f0Sopenharmony_ci	snd_pcm_null_t *null = pcm->private_data;
153d5ac70f0Sopenharmony_ci	assert(null->state != SND_PCM_STATE_OPEN);
154d5ac70f0Sopenharmony_ci	null->state = SND_PCM_STATE_SETUP;
155d5ac70f0Sopenharmony_ci	return 0;
156d5ac70f0Sopenharmony_ci}
157d5ac70f0Sopenharmony_ci
158d5ac70f0Sopenharmony_cistatic int snd_pcm_null_drain(snd_pcm_t *pcm)
159d5ac70f0Sopenharmony_ci{
160d5ac70f0Sopenharmony_ci	snd_pcm_null_t *null = pcm->private_data;
161d5ac70f0Sopenharmony_ci	assert(null->state != SND_PCM_STATE_OPEN);
162d5ac70f0Sopenharmony_ci	null->state = SND_PCM_STATE_SETUP;
163d5ac70f0Sopenharmony_ci	return 0;
164d5ac70f0Sopenharmony_ci}
165d5ac70f0Sopenharmony_ci
166d5ac70f0Sopenharmony_cistatic int snd_pcm_null_pause(snd_pcm_t *pcm, int enable)
167d5ac70f0Sopenharmony_ci{
168d5ac70f0Sopenharmony_ci	snd_pcm_null_t *null = pcm->private_data;
169d5ac70f0Sopenharmony_ci	if (enable) {
170d5ac70f0Sopenharmony_ci		if (null->state != SND_PCM_STATE_RUNNING)
171d5ac70f0Sopenharmony_ci			return -EBADFD;
172d5ac70f0Sopenharmony_ci		null->state = SND_PCM_STATE_PAUSED;
173d5ac70f0Sopenharmony_ci	} else {
174d5ac70f0Sopenharmony_ci		if (null->state != SND_PCM_STATE_PAUSED)
175d5ac70f0Sopenharmony_ci			return -EBADFD;
176d5ac70f0Sopenharmony_ci		null->state = SND_PCM_STATE_RUNNING;
177d5ac70f0Sopenharmony_ci	}
178d5ac70f0Sopenharmony_ci	return 0;
179d5ac70f0Sopenharmony_ci}
180d5ac70f0Sopenharmony_ci
181d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_null_rewindable(snd_pcm_t *pcm)
182d5ac70f0Sopenharmony_ci{
183d5ac70f0Sopenharmony_ci	return pcm->buffer_size;
184d5ac70f0Sopenharmony_ci}
185d5ac70f0Sopenharmony_ci
186d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_null_forwardable(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
187d5ac70f0Sopenharmony_ci{
188d5ac70f0Sopenharmony_ci	return 0;
189d5ac70f0Sopenharmony_ci}
190d5ac70f0Sopenharmony_ci
191d5ac70f0Sopenharmony_ci
192d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_null_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
193d5ac70f0Sopenharmony_ci{
194d5ac70f0Sopenharmony_ci	snd_pcm_null_t *null = pcm->private_data;
195d5ac70f0Sopenharmony_ci	switch (null->state) {
196d5ac70f0Sopenharmony_ci	case SND_PCM_STATE_RUNNING:
197d5ac70f0Sopenharmony_ci		snd_pcm_mmap_hw_backward(pcm, frames);
198d5ac70f0Sopenharmony_ci		/* Fall through */
199d5ac70f0Sopenharmony_ci	case SND_PCM_STATE_PREPARED:
200d5ac70f0Sopenharmony_ci		snd_pcm_mmap_appl_backward(pcm, frames);
201d5ac70f0Sopenharmony_ci		return frames;
202d5ac70f0Sopenharmony_ci	default:
203d5ac70f0Sopenharmony_ci		return -EBADFD;
204d5ac70f0Sopenharmony_ci	}
205d5ac70f0Sopenharmony_ci}
206d5ac70f0Sopenharmony_ci
207d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_null_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
208d5ac70f0Sopenharmony_ci{
209d5ac70f0Sopenharmony_ci	snd_pcm_null_t *null = pcm->private_data;
210d5ac70f0Sopenharmony_ci	switch (null->state) {
211d5ac70f0Sopenharmony_ci	case SND_PCM_STATE_RUNNING:
212d5ac70f0Sopenharmony_ci		snd_pcm_mmap_hw_forward(pcm, frames);
213d5ac70f0Sopenharmony_ci		/* Fall through */
214d5ac70f0Sopenharmony_ci	case SND_PCM_STATE_PREPARED:
215d5ac70f0Sopenharmony_ci		snd_pcm_mmap_appl_forward(pcm, frames);
216d5ac70f0Sopenharmony_ci		return frames;
217d5ac70f0Sopenharmony_ci	default:
218d5ac70f0Sopenharmony_ci		return -EBADFD;
219d5ac70f0Sopenharmony_ci	}
220d5ac70f0Sopenharmony_ci}
221d5ac70f0Sopenharmony_ci
222d5ac70f0Sopenharmony_cistatic int snd_pcm_null_resume(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
223d5ac70f0Sopenharmony_ci{
224d5ac70f0Sopenharmony_ci	return 0;
225d5ac70f0Sopenharmony_ci}
226d5ac70f0Sopenharmony_ci
227d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_null_xfer_areas(snd_pcm_t *pcm,
228d5ac70f0Sopenharmony_ci						 const snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED,
229d5ac70f0Sopenharmony_ci						 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
230d5ac70f0Sopenharmony_ci						 snd_pcm_uframes_t size)
231d5ac70f0Sopenharmony_ci{
232d5ac70f0Sopenharmony_ci	snd_pcm_mmap_appl_forward(pcm, size);
233d5ac70f0Sopenharmony_ci	snd_pcm_mmap_hw_forward(pcm, size);
234d5ac70f0Sopenharmony_ci	return size;
235d5ac70f0Sopenharmony_ci}
236d5ac70f0Sopenharmony_ci
237d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_null_writei(snd_pcm_t *pcm, const void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
238d5ac70f0Sopenharmony_ci{
239d5ac70f0Sopenharmony_ci	return snd_pcm_write_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
240d5ac70f0Sopenharmony_ci}
241d5ac70f0Sopenharmony_ci
242d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_null_writen(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
243d5ac70f0Sopenharmony_ci{
244d5ac70f0Sopenharmony_ci	return snd_pcm_write_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
245d5ac70f0Sopenharmony_ci}
246d5ac70f0Sopenharmony_ci
247d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_null_readi(snd_pcm_t *pcm, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
248d5ac70f0Sopenharmony_ci{
249d5ac70f0Sopenharmony_ci	return snd_pcm_read_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
250d5ac70f0Sopenharmony_ci}
251d5ac70f0Sopenharmony_ci
252d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_null_readn(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
253d5ac70f0Sopenharmony_ci{
254d5ac70f0Sopenharmony_ci	return snd_pcm_read_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
255d5ac70f0Sopenharmony_ci}
256d5ac70f0Sopenharmony_ci
257d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_null_mmap_commit(snd_pcm_t *pcm,
258d5ac70f0Sopenharmony_ci						  snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
259d5ac70f0Sopenharmony_ci						  snd_pcm_uframes_t size)
260d5ac70f0Sopenharmony_ci{
261d5ac70f0Sopenharmony_ci	return snd_pcm_null_forward(pcm, size);
262d5ac70f0Sopenharmony_ci}
263d5ac70f0Sopenharmony_ci
264d5ac70f0Sopenharmony_cistatic int snd_pcm_null_hw_refine(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
265d5ac70f0Sopenharmony_ci{
266d5ac70f0Sopenharmony_ci	int err;
267d5ac70f0Sopenharmony_ci
268d5ac70f0Sopenharmony_ci	/* Do not return a period size of 0 because for example portaudio cannot
269d5ac70f0Sopenharmony_ci	 * handle it.
270d5ac70f0Sopenharmony_ci	 */
271d5ac70f0Sopenharmony_ci	err = _snd_pcm_hw_param_set_min(params, SND_PCM_HW_PARAM_PERIOD_SIZE, 1,
272d5ac70f0Sopenharmony_ci					0);
273d5ac70f0Sopenharmony_ci	if (err < 0)
274d5ac70f0Sopenharmony_ci		return err;
275d5ac70f0Sopenharmony_ci
276d5ac70f0Sopenharmony_ci	err = snd_pcm_hw_refine_soft(pcm, params);
277d5ac70f0Sopenharmony_ci	params->info = SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID |
278d5ac70f0Sopenharmony_ci		       SND_PCM_INFO_RESUME | SND_PCM_INFO_PAUSE;
279d5ac70f0Sopenharmony_ci	params->fifo_size = 0;
280d5ac70f0Sopenharmony_ci	return err;
281d5ac70f0Sopenharmony_ci}
282d5ac70f0Sopenharmony_ci
283d5ac70f0Sopenharmony_cistatic int snd_pcm_null_hw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t * params ATTRIBUTE_UNUSED)
284d5ac70f0Sopenharmony_ci{
285d5ac70f0Sopenharmony_ci	return 0;
286d5ac70f0Sopenharmony_ci}
287d5ac70f0Sopenharmony_ci
288d5ac70f0Sopenharmony_cistatic int snd_pcm_null_hw_free(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
289d5ac70f0Sopenharmony_ci{
290d5ac70f0Sopenharmony_ci	return 0;
291d5ac70f0Sopenharmony_ci}
292d5ac70f0Sopenharmony_ci
293d5ac70f0Sopenharmony_cistatic int snd_pcm_null_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t * params ATTRIBUTE_UNUSED)
294d5ac70f0Sopenharmony_ci{
295d5ac70f0Sopenharmony_ci	return 0;
296d5ac70f0Sopenharmony_ci}
297d5ac70f0Sopenharmony_ci
298d5ac70f0Sopenharmony_cistatic snd_pcm_chmap_query_t **snd_pcm_null_query_chmaps(snd_pcm_t *pcm)
299d5ac70f0Sopenharmony_ci{
300d5ac70f0Sopenharmony_ci	snd_pcm_null_t *null = pcm->private_data;
301d5ac70f0Sopenharmony_ci
302d5ac70f0Sopenharmony_ci	if (null->chmap)
303d5ac70f0Sopenharmony_ci		return _snd_pcm_copy_chmap_query(null->chmap);
304d5ac70f0Sopenharmony_ci	return NULL;
305d5ac70f0Sopenharmony_ci}
306d5ac70f0Sopenharmony_ci
307d5ac70f0Sopenharmony_cistatic snd_pcm_chmap_t *snd_pcm_null_get_chmap(snd_pcm_t *pcm)
308d5ac70f0Sopenharmony_ci{
309d5ac70f0Sopenharmony_ci	snd_pcm_null_t *null = pcm->private_data;
310d5ac70f0Sopenharmony_ci
311d5ac70f0Sopenharmony_ci	if (null->chmap)
312d5ac70f0Sopenharmony_ci		return _snd_pcm_choose_fixed_chmap(pcm, null->chmap);
313d5ac70f0Sopenharmony_ci	return NULL;
314d5ac70f0Sopenharmony_ci}
315d5ac70f0Sopenharmony_ci
316d5ac70f0Sopenharmony_cistatic void snd_pcm_null_dump(snd_pcm_t *pcm, snd_output_t *out)
317d5ac70f0Sopenharmony_ci{
318d5ac70f0Sopenharmony_ci	snd_output_printf(out, "Null PCM\n");
319d5ac70f0Sopenharmony_ci	if (pcm->setup) {
320d5ac70f0Sopenharmony_ci		snd_output_printf(out, "Its setup is:\n");
321d5ac70f0Sopenharmony_ci		snd_pcm_dump_setup(pcm, out);
322d5ac70f0Sopenharmony_ci	}
323d5ac70f0Sopenharmony_ci}
324d5ac70f0Sopenharmony_ci
325d5ac70f0Sopenharmony_cistatic const snd_pcm_ops_t snd_pcm_null_ops = {
326d5ac70f0Sopenharmony_ci	.close = snd_pcm_null_close,
327d5ac70f0Sopenharmony_ci	.info = snd_pcm_null_info,
328d5ac70f0Sopenharmony_ci	.hw_refine = snd_pcm_null_hw_refine,
329d5ac70f0Sopenharmony_ci	.hw_params = snd_pcm_null_hw_params,
330d5ac70f0Sopenharmony_ci	.hw_free = snd_pcm_null_hw_free,
331d5ac70f0Sopenharmony_ci	.sw_params = snd_pcm_null_sw_params,
332d5ac70f0Sopenharmony_ci	.channel_info = snd_pcm_generic_channel_info,
333d5ac70f0Sopenharmony_ci	.dump = snd_pcm_null_dump,
334d5ac70f0Sopenharmony_ci	.nonblock = snd_pcm_null_nonblock,
335d5ac70f0Sopenharmony_ci	.async = snd_pcm_null_async,
336d5ac70f0Sopenharmony_ci	.mmap = snd_pcm_generic_mmap,
337d5ac70f0Sopenharmony_ci	.munmap = snd_pcm_generic_munmap,
338d5ac70f0Sopenharmony_ci	.query_chmaps = snd_pcm_null_query_chmaps,
339d5ac70f0Sopenharmony_ci	.get_chmap = snd_pcm_null_get_chmap,
340d5ac70f0Sopenharmony_ci	.set_chmap = NULL,
341d5ac70f0Sopenharmony_ci};
342d5ac70f0Sopenharmony_ci
343d5ac70f0Sopenharmony_cistatic const snd_pcm_fast_ops_t snd_pcm_null_fast_ops = {
344d5ac70f0Sopenharmony_ci	.status = snd_pcm_null_status,
345d5ac70f0Sopenharmony_ci	.state = snd_pcm_null_state,
346d5ac70f0Sopenharmony_ci	.hwsync = snd_pcm_null_hwsync,
347d5ac70f0Sopenharmony_ci	.delay = snd_pcm_null_delay,
348d5ac70f0Sopenharmony_ci	.prepare = snd_pcm_null_prepare,
349d5ac70f0Sopenharmony_ci	.reset = snd_pcm_null_reset,
350d5ac70f0Sopenharmony_ci	.start = snd_pcm_null_start,
351d5ac70f0Sopenharmony_ci	.drop = snd_pcm_null_drop,
352d5ac70f0Sopenharmony_ci	.drain = snd_pcm_null_drain,
353d5ac70f0Sopenharmony_ci	.pause = snd_pcm_null_pause,
354d5ac70f0Sopenharmony_ci	.rewindable = snd_pcm_null_rewindable,
355d5ac70f0Sopenharmony_ci	.rewind = snd_pcm_null_rewind,
356d5ac70f0Sopenharmony_ci	.forwardable = snd_pcm_null_forwardable,
357d5ac70f0Sopenharmony_ci	.forward = snd_pcm_null_forward,
358d5ac70f0Sopenharmony_ci	.resume = snd_pcm_null_resume,
359d5ac70f0Sopenharmony_ci	.writei = snd_pcm_null_writei,
360d5ac70f0Sopenharmony_ci	.writen = snd_pcm_null_writen,
361d5ac70f0Sopenharmony_ci	.readi = snd_pcm_null_readi,
362d5ac70f0Sopenharmony_ci	.readn = snd_pcm_null_readn,
363d5ac70f0Sopenharmony_ci	.avail_update = snd_pcm_null_avail_update,
364d5ac70f0Sopenharmony_ci	.mmap_commit = snd_pcm_null_mmap_commit,
365d5ac70f0Sopenharmony_ci	.htimestamp = snd_pcm_generic_real_htimestamp,
366d5ac70f0Sopenharmony_ci};
367d5ac70f0Sopenharmony_ci
368d5ac70f0Sopenharmony_ci/**
369d5ac70f0Sopenharmony_ci * \brief Creates a new null PCM
370d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle
371d5ac70f0Sopenharmony_ci * \param name Name of PCM
372d5ac70f0Sopenharmony_ci * \param stream Stream type
373d5ac70f0Sopenharmony_ci * \param mode Stream mode
374d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code
375d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense
376d5ac70f0Sopenharmony_ci *          of compatibility reasons. The prototype might be freely
377d5ac70f0Sopenharmony_ci *          changed in future.
378d5ac70f0Sopenharmony_ci */
379d5ac70f0Sopenharmony_ciint snd_pcm_null_open(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode)
380d5ac70f0Sopenharmony_ci{
381d5ac70f0Sopenharmony_ci	snd_pcm_t *pcm;
382d5ac70f0Sopenharmony_ci	snd_pcm_null_t *null;
383d5ac70f0Sopenharmony_ci	int fd;
384d5ac70f0Sopenharmony_ci	int err;
385d5ac70f0Sopenharmony_ci	assert(pcmp);
386d5ac70f0Sopenharmony_ci	if (stream == SND_PCM_STREAM_PLAYBACK) {
387d5ac70f0Sopenharmony_ci		fd = open("/dev/null", O_WRONLY);
388d5ac70f0Sopenharmony_ci		if (fd < 0) {
389d5ac70f0Sopenharmony_ci			SYSERR("Cannot open /dev/null");
390d5ac70f0Sopenharmony_ci			return -errno;
391d5ac70f0Sopenharmony_ci		}
392d5ac70f0Sopenharmony_ci	} else {
393d5ac70f0Sopenharmony_ci		fd = open("/dev/full", O_RDONLY);
394d5ac70f0Sopenharmony_ci		if (fd < 0) {
395d5ac70f0Sopenharmony_ci			SYSERR("Cannot open /dev/full");
396d5ac70f0Sopenharmony_ci			return -errno;
397d5ac70f0Sopenharmony_ci		}
398d5ac70f0Sopenharmony_ci	}
399d5ac70f0Sopenharmony_ci	null = calloc(1, sizeof(snd_pcm_null_t));
400d5ac70f0Sopenharmony_ci	if (!null) {
401d5ac70f0Sopenharmony_ci		close(fd);
402d5ac70f0Sopenharmony_ci		return -ENOMEM;
403d5ac70f0Sopenharmony_ci	}
404d5ac70f0Sopenharmony_ci	null->poll_fd = fd;
405d5ac70f0Sopenharmony_ci	null->state = SND_PCM_STATE_OPEN;
406d5ac70f0Sopenharmony_ci
407d5ac70f0Sopenharmony_ci	err = snd_pcm_new(&pcm, SND_PCM_TYPE_NULL, name, stream, mode);
408d5ac70f0Sopenharmony_ci	if (err < 0) {
409d5ac70f0Sopenharmony_ci		close(fd);
410d5ac70f0Sopenharmony_ci		free(null);
411d5ac70f0Sopenharmony_ci		return err;
412d5ac70f0Sopenharmony_ci	}
413d5ac70f0Sopenharmony_ci	pcm->ops = &snd_pcm_null_ops;
414d5ac70f0Sopenharmony_ci	pcm->fast_ops = &snd_pcm_null_fast_ops;
415d5ac70f0Sopenharmony_ci	pcm->private_data = null;
416d5ac70f0Sopenharmony_ci	pcm->poll_fd = fd;
417d5ac70f0Sopenharmony_ci	pcm->poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
418d5ac70f0Sopenharmony_ci	snd_pcm_set_hw_ptr(pcm, &null->hw_ptr, -1, 0);
419d5ac70f0Sopenharmony_ci	snd_pcm_set_appl_ptr(pcm, &null->appl_ptr, -1, 0);
420d5ac70f0Sopenharmony_ci	*pcmp = pcm;
421d5ac70f0Sopenharmony_ci
422d5ac70f0Sopenharmony_ci	return 0;
423d5ac70f0Sopenharmony_ci}
424d5ac70f0Sopenharmony_ci
425d5ac70f0Sopenharmony_ci/*! \page pcm_plugins
426d5ac70f0Sopenharmony_ci
427d5ac70f0Sopenharmony_ci\section pcm_plugins_null Plugin: Null
428d5ac70f0Sopenharmony_ci
429d5ac70f0Sopenharmony_ciThis plugin discards contents of a PCM stream or creates a stream with zero
430d5ac70f0Sopenharmony_cisamples.
431d5ac70f0Sopenharmony_ci
432d5ac70f0Sopenharmony_ciNote: This implementation uses devices /dev/null (playback, must be writable)
433d5ac70f0Sopenharmony_ciand /dev/full (capture, must be readable).
434d5ac70f0Sopenharmony_ci
435d5ac70f0Sopenharmony_ci\code
436d5ac70f0Sopenharmony_cipcm.name {
437d5ac70f0Sopenharmony_ci        type null               # Null PCM
438d5ac70f0Sopenharmony_ci	[chmap MAP]		# Provide channel maps; MAP is a string array
439d5ac70f0Sopenharmony_ci}
440d5ac70f0Sopenharmony_ci\endcode
441d5ac70f0Sopenharmony_ci
442d5ac70f0Sopenharmony_ci\subsection pcm_plugins_null_funcref Function reference
443d5ac70f0Sopenharmony_ci
444d5ac70f0Sopenharmony_ci<UL>
445d5ac70f0Sopenharmony_ci  <LI>snd_pcm_null_open()
446d5ac70f0Sopenharmony_ci  <LI>_snd_pcm_null_open()
447d5ac70f0Sopenharmony_ci</UL>
448d5ac70f0Sopenharmony_ci
449d5ac70f0Sopenharmony_ci*/
450d5ac70f0Sopenharmony_ci
451d5ac70f0Sopenharmony_ci/**
452d5ac70f0Sopenharmony_ci * \brief Creates a new Null PCM
453d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle
454d5ac70f0Sopenharmony_ci * \param name Name of PCM
455d5ac70f0Sopenharmony_ci * \param root Root configuration node
456d5ac70f0Sopenharmony_ci * \param conf Configuration node with Null PCM description
457d5ac70f0Sopenharmony_ci * \param stream Stream type
458d5ac70f0Sopenharmony_ci * \param mode Stream mode
459d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code
460d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense
461d5ac70f0Sopenharmony_ci *          of compatibility reasons. The prototype might be freely
462d5ac70f0Sopenharmony_ci *          changed in future.
463d5ac70f0Sopenharmony_ci */
464d5ac70f0Sopenharmony_ciint _snd_pcm_null_open(snd_pcm_t **pcmp, const char *name,
465d5ac70f0Sopenharmony_ci		       snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf,
466d5ac70f0Sopenharmony_ci		       snd_pcm_stream_t stream, int mode)
467d5ac70f0Sopenharmony_ci{
468d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
469d5ac70f0Sopenharmony_ci	snd_pcm_null_t *null;
470d5ac70f0Sopenharmony_ci	snd_pcm_chmap_query_t **chmap = NULL;
471d5ac70f0Sopenharmony_ci	int err;
472d5ac70f0Sopenharmony_ci
473d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, conf) {
474d5ac70f0Sopenharmony_ci		snd_config_t *n = snd_config_iterator_entry(i);
475d5ac70f0Sopenharmony_ci		const char *id;
476d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
477d5ac70f0Sopenharmony_ci			continue;
478d5ac70f0Sopenharmony_ci		if (snd_pcm_conf_generic_id(id))
479d5ac70f0Sopenharmony_ci			continue;
480d5ac70f0Sopenharmony_ci		if (strcmp(id, "chmap") == 0) {
481d5ac70f0Sopenharmony_ci			snd_pcm_free_chmaps(chmap);
482d5ac70f0Sopenharmony_ci			chmap = _snd_pcm_parse_config_chmaps(n);
483d5ac70f0Sopenharmony_ci			if (!chmap) {
484d5ac70f0Sopenharmony_ci				SNDERR("Invalid channel map for %s", id);
485d5ac70f0Sopenharmony_ci				return -EINVAL;
486d5ac70f0Sopenharmony_ci			}
487d5ac70f0Sopenharmony_ci			continue;
488d5ac70f0Sopenharmony_ci		}
489d5ac70f0Sopenharmony_ci		SNDERR("Unknown field %s", id);
490d5ac70f0Sopenharmony_ci		snd_pcm_free_chmaps(chmap);
491d5ac70f0Sopenharmony_ci		return -EINVAL;
492d5ac70f0Sopenharmony_ci	}
493d5ac70f0Sopenharmony_ci	err = snd_pcm_null_open(pcmp, name, stream, mode);
494d5ac70f0Sopenharmony_ci	if (err < 0) {
495d5ac70f0Sopenharmony_ci		snd_pcm_free_chmaps(chmap);
496d5ac70f0Sopenharmony_ci		return err;
497d5ac70f0Sopenharmony_ci	}
498d5ac70f0Sopenharmony_ci
499d5ac70f0Sopenharmony_ci	null = (*pcmp)->private_data;
500d5ac70f0Sopenharmony_ci	null->chmap = chmap;
501d5ac70f0Sopenharmony_ci	return 0;
502d5ac70f0Sopenharmony_ci}
503d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
504d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(_snd_pcm_null_open, SND_PCM_DLSYM_VERSION);
505d5ac70f0Sopenharmony_ci#endif
506