Lines Matching defs:*
2 * \file pcm/pcm_null.c
3 * \ingroup PCM_Plugins
4 * \brief PCM Null Plugin Interface
5 * \author Abramo Bagnara <abramo@alsa-project.org>
6 * \date 2000-2001
9 * PCM - Null plugin
10 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
13 * This library is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as
15 * published by the Free Software Foundation; either version 2.1 of
16 * the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include <byteswap.h>
30 #include <limits.h>
31 #include <sys/shm.h>
32 #include "pcm_local.h"
33 #include "pcm_plugin.h"
35 #ifndef PIC
36 /* entry for static linking */
37 const char *_snd_module_pcm_null = "";
38 #endif
40 #ifndef DOC_HIDDEN
41 typedef struct {
42 snd_htimestamp_t trigger_tstamp;
43 snd_pcm_state_t state;
44 snd_pcm_uframes_t appl_ptr;
45 snd_pcm_uframes_t hw_ptr;
46 int poll_fd;
47 } snd_pcm_null_t;
48 #endif
50 static int snd_pcm_null_close(snd_pcm_t *pcm)
52 snd_pcm_null_t *null = pcm->private_data;
53 close(null->poll_fd);
54 free(null);
55 return 0;
58 static int snd_pcm_null_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
60 return 0;
63 static int snd_pcm_null_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int sig ATTRIBUTE_UNUSED, pid_t pid ATTRIBUTE_UNUSED)
65 return -ENOSYS;
68 static int snd_pcm_null_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
70 memset(info, 0, sizeof(*info));
71 info->stream = pcm->stream;
72 info->card = -1;
73 if (pcm->name) {
74 strncpy((char *)info->id, pcm->name, sizeof(info->id));
75 strncpy((char *)info->name, pcm->name, sizeof(info->name));
76 strncpy((char *)info->subname, pcm->name, sizeof(info->subname));
78 info->subdevices_count = 1;
79 return 0;
82 static int snd_pcm_null_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
84 snd_pcm_null_t *null = pcm->private_data;
85 memset(status, 0, sizeof(*status));
86 status->state = null->state;
87 status->trigger_tstamp = null->trigger_tstamp;
88 gettimestamp(&status->tstamp, pcm->monotonic);
89 status->avail = pcm->buffer_size;
90 status->avail_max = status->avail;
91 return 0;
94 static snd_pcm_state_t snd_pcm_null_state(snd_pcm_t *pcm)
96 snd_pcm_null_t *null = pcm->private_data;
97 return null->state;
100 static int snd_pcm_null_hwsync(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
102 return 0;
105 static int snd_pcm_null_delay(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sframes_t *delayp)
107 *delayp = 0;
108 return 0;
111 static int snd_pcm_null_prepare(snd_pcm_t *pcm)
113 snd_pcm_null_t *null = pcm->private_data;
114 null->state = SND_PCM_STATE_PREPARED;
115 *pcm->appl.ptr = 0;
116 *pcm->hw.ptr = 0;
117 return 0;
120 static int snd_pcm_null_reset(snd_pcm_t *pcm)
122 *pcm->appl.ptr = 0;
123 *pcm->hw.ptr = 0;
124 return 0;
127 static int snd_pcm_null_start(snd_pcm_t *pcm)
129 snd_pcm_null_t *null = pcm->private_data;
130 assert(null->state == SND_PCM_STATE_PREPARED);
131 null->state = SND_PCM_STATE_RUNNING;
132 if (pcm->stream == SND_PCM_STREAM_CAPTURE)
133 *pcm->hw.ptr = *pcm->appl.ptr + pcm->buffer_size;
134 else
135 *pcm->hw.ptr = *pcm->appl.ptr;
136 return 0;
139 static int snd_pcm_null_drop(snd_pcm_t *pcm)
141 snd_pcm_null_t *null = pcm->private_data;
142 assert(null->state != SND_PCM_STATE_OPEN);
143 null->state = SND_PCM_STATE_SETUP;
144 return 0;
147 static int snd_pcm_null_drain(snd_pcm_t *pcm)
149 snd_pcm_null_t *null = pcm->private_data;
150 assert(null->state != SND_PCM_STATE_OPEN);
151 null->state = SND_PCM_STATE_SETUP;
152 return 0;
155 static int snd_pcm_null_pause(snd_pcm_t *pcm, int enable)
157 snd_pcm_null_t *null = pcm->private_data;
158 if (enable) {
159 if (null->state != SND_PCM_STATE_RUNNING)
160 return -EBADFD;
161 null->state = SND_PCM_STATE_PAUSED;
162 } else {
163 if (null->state != SND_PCM_STATE_PAUSED)
164 return -EBADFD;
165 null->state = SND_PCM_STATE_RUNNING;
167 return 0;
170 static snd_pcm_sframes_t snd_pcm_null_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
172 snd_pcm_null_t *null = pcm->private_data;
173 switch (null->state) {
174 case SND_PCM_STATE_RUNNING:
175 snd_pcm_mmap_hw_backward(pcm, frames);
176 /* Fall through */
177 case SND_PCM_STATE_PREPARED:
178 snd_pcm_mmap_appl_backward(pcm, frames);
179 return frames;
180 default:
181 return -EBADFD;
185 static snd_pcm_sframes_t snd_pcm_null_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
187 snd_pcm_null_t *null = pcm->private_data;
188 switch (null->state) {
189 case SND_PCM_STATE_RUNNING:
190 snd_pcm_mmap_hw_forward(pcm, frames);
191 /* Fall through */
192 case SND_PCM_STATE_PREPARED:
193 snd_pcm_mmap_appl_forward(pcm, frames);
194 return frames;
195 default:
196 return -EBADFD;
200 static int snd_pcm_null_resume(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
202 return 0;
205 static snd_pcm_sframes_t snd_pcm_null_xfer_areas(snd_pcm_t *pcm,
206 const snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED,
207 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
208 snd_pcm_uframes_t size)
210 snd_pcm_mmap_appl_forward(pcm, size);
211 snd_pcm_mmap_hw_forward(pcm, size);
212 return size;
215 static snd_pcm_sframes_t snd_pcm_null_writei(snd_pcm_t *pcm, const void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
217 return snd_pcm_write_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
220 static snd_pcm_sframes_t snd_pcm_null_writen(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
222 return snd_pcm_write_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
225 static snd_pcm_sframes_t snd_pcm_null_readi(snd_pcm_t *pcm, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
227 return snd_pcm_read_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
230 static snd_pcm_sframes_t snd_pcm_null_readn(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
232 return snd_pcm_read_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
235 static snd_pcm_sframes_t snd_pcm_null_mmap_commit(snd_pcm_t *pcm,
236 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
237 snd_pcm_uframes_t size)
239 return snd_pcm_null_forward(pcm, size);
242 static snd_pcm_sframes_t snd_pcm_null_avail_update(snd_pcm_t *pcm)
244 return pcm->buffer_size;
247 static int snd_pcm_null_hw_refine(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
249 int err = snd_pcm_hw_refine_soft(pcm, params);
250 params->info = SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID |
251 SND_PCM_INFO_RESUME | SND_PCM_INFO_PAUSE;
252 params->fifo_size = 0;
253 return err;
256 static int snd_pcm_null_hw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t * params ATTRIBUTE_UNUSED)
258 return 0;
261 static int snd_pcm_null_hw_free(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
263 return 0;
266 static int snd_pcm_null_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t * params ATTRIBUTE_UNUSED)
268 return 0;
271 static void snd_pcm_null_dump(snd_pcm_t *pcm, snd_output_t *out)
273 snd_output_printf(out, "Null PCM\n");
274 if (pcm->setup) {
275 snd_output_printf(out, "Its setup is:\n");
276 snd_pcm_dump_setup(pcm, out);
280 static const snd_pcm_ops_t snd_pcm_null_ops = {
281 .close = snd_pcm_null_close,
282 .info = snd_pcm_null_info,
283 .hw_refine = snd_pcm_null_hw_refine,
284 .hw_params = snd_pcm_null_hw_params,
285 .hw_free = snd_pcm_null_hw_free,
286 .sw_params = snd_pcm_null_sw_params,
287 .channel_info = snd_pcm_generic_channel_info,
288 .dump = snd_pcm_null_dump,
289 .nonblock = snd_pcm_null_nonblock,
290 .async = snd_pcm_null_async,
291 .mmap = snd_pcm_generic_mmap,
292 .munmap = snd_pcm_generic_munmap,
295 static const snd_pcm_fast_ops_t snd_pcm_null_fast_ops = {
296 .status = snd_pcm_null_status,
297 .state = snd_pcm_null_state,
298 .hwsync = snd_pcm_null_hwsync,
299 .delay = snd_pcm_null_delay,
300 .prepare = snd_pcm_null_prepare,
301 .reset = snd_pcm_null_reset,
302 .start = snd_pcm_null_start,
303 .drop = snd_pcm_null_drop,
304 .drain = snd_pcm_null_drain,
305 .pause = snd_pcm_null_pause,
306 .rewind = snd_pcm_null_rewind,
307 .forward = snd_pcm_null_forward,
308 .resume = snd_pcm_null_resume,
309 .writei = snd_pcm_null_writei,
310 .writen = snd_pcm_null_writen,
311 .readi = snd_pcm_null_readi,
312 .readn = snd_pcm_null_readn,
313 .avail_update = snd_pcm_null_avail_update,
314 .mmap_commit = snd_pcm_null_mmap_commit,
315 .htimestamp = snd_pcm_generic_real_htimestamp,
319 * \brief Creates a new null PCM
320 * \param pcmp Returns created PCM handle
321 * \param name Name of PCM
322 * \param stream Stream type
323 * \param mode Stream mode
324 * \retval zero on success otherwise a negative error code
325 * \warning Using of this function might be dangerous in the sense
326 * of compatibility reasons. The prototype might be freely
327 * changed in future.
329 int snd_pcm_null_open(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode)
331 snd_pcm_t *pcm;
332 snd_pcm_null_t *null;
333 int fd;
334 int err;
335 assert(pcmp);
336 if (stream == SND_PCM_STREAM_PLAYBACK) {
337 fd = open("/dev/null", O_WRONLY);
338 if (fd < 0) {
339 SYSERR("Cannot open /dev/null");
340 return -errno;
342 } else {
343 fd = open("/dev/full", O_RDONLY);
344 if (fd < 0) {
345 SYSERR("Cannot open /dev/full");
346 return -errno;
349 null = calloc(1, sizeof(snd_pcm_null_t));
350 if (!null) {
351 close(fd);
352 return -ENOMEM;
354 null->poll_fd = fd;
355 null->state = SND_PCM_STATE_OPEN;
357 err = snd_pcm_new(&pcm, SND_PCM_TYPE_NULL, name, stream, mode);
358 if (err < 0) {
359 close(fd);
360 free(null);
361 return err;
363 pcm->ops = &snd_pcm_null_ops;
364 pcm->fast_ops = &snd_pcm_null_fast_ops;
365 pcm->private_data = null;
366 pcm->poll_fd = fd;
367 pcm->poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
368 snd_pcm_set_hw_ptr(pcm, &null->hw_ptr, -1, 0);
369 snd_pcm_set_appl_ptr(pcm, &null->appl_ptr, -1, 0);
370 *pcmp = pcm;
372 return 0;
375 /*! \page pcm_plugins
377 \section pcm_plugins_null Plugin: Null
379 This plugin discards contents of a PCM stream or creates a stream with zero
380 samples.
382 Note: This implementation uses devices /dev/null (playback, must be writable)
383 and /dev/full (capture, must be readable).
385 \code
386 pcm.name {
387 type null # Null PCM
389 \endcode
391 \subsection pcm_plugins_null_funcref Function reference
393 <UL>
394 <LI>snd_pcm_null_open()
395 <LI>_snd_pcm_null_open()
396 </UL>
401 * \brief Creates a new Null PCM
402 * \param pcmp Returns created PCM handle
403 * \param name Name of PCM
404 * \param root Root configuration node
405 * \param conf Configuration node with Null PCM description
406 * \param stream Stream type
407 * \param mode Stream mode
408 * \retval zero on success otherwise a negative error code
409 * \warning Using of this function might be dangerous in the sense
410 * of compatibility reasons. The prototype might be freely
411 * changed in future.
413 int _snd_pcm_null_open(snd_pcm_t **pcmp, const char *name,
414 snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf,
415 snd_pcm_stream_t stream, int mode)
417 snd_config_iterator_t i, next;
418 snd_config_for_each(i, next, conf) {
419 snd_config_t *n = snd_config_iterator_entry(i);
420 const char *id;
421 if (snd_config_get_id(n, &id) < 0)
422 continue;
423 if (snd_pcm_conf_generic_id(id))
424 continue;
425 SNDERR("Unknown field %s", id);
426 return -EINVAL;
428 return snd_pcm_null_open(pcmp, name, stream, mode);
430 #ifndef DOC_HIDDEN
431 SND_DLSYM_BUILD_VERSION(_snd_pcm_null_open, SND_PCM_DLSYM_VERSION);
432 #endif