4 * \brief PCM Null Plugin Interface
5 * \author Abramo Bagnara <abramo@alsa-project.org>
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
32 #include "pcm_local.h"
33 #include "pcm_plugin.h"
36 /* entry for static linking */
37 const char *_snd_module_pcm_null = "";
42 snd_timestamp_t trigger_tstamp;
43 snd_pcm_state_t state;
45 snd_pcm_uframes_t appl_ptr;
46 snd_pcm_uframes_t hw_ptr;
51 static int snd_pcm_null_close(snd_pcm_t *pcm)
53 snd_pcm_null_t *null = pcm->private_data;
59 static int snd_pcm_null_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
64 static int snd_pcm_null_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int sig ATTRIBUTE_UNUSED, pid_t pid ATTRIBUTE_UNUSED)
69 static int snd_pcm_null_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_info_t * info)
71 memset(info, 0, sizeof(*info));
72 info->stream = pcm->stream;
74 strncpy(info->id, pcm->name, sizeof(info->id));
75 strncpy(info->name, pcm->name, sizeof(info->name));
76 strncpy(info->subname, pcm->name, sizeof(info->subname));
77 info->subdevices_count = 1;
81 static int snd_pcm_null_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
83 snd_pcm_null_t *null = pcm->private_data;
84 return snd_pcm_channel_info_shm(pcm, info, null->shmid);
87 static int snd_pcm_null_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
89 snd_pcm_null_t *null = pcm->private_data;
90 memset(status, 0, sizeof(*status));
91 status->state = null->state;
92 status->trigger_tstamp = null->trigger_tstamp;
93 gettimeofday(&status->tstamp, 0);
94 status->avail = pcm->buffer_size;
95 status->avail_max = status->avail;
99 static snd_pcm_state_t snd_pcm_null_state(snd_pcm_t *pcm)
101 snd_pcm_null_t *null = pcm->private_data;
105 static int snd_pcm_null_hwsync(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
110 static int snd_pcm_null_delay(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sframes_t *delayp)
116 static int snd_pcm_null_prepare(snd_pcm_t *pcm)
118 snd_pcm_null_t *null = pcm->private_data;
119 null->state = SND_PCM_STATE_PREPARED;
125 static int snd_pcm_null_reset(snd_pcm_t *pcm)
132 static int snd_pcm_null_start(snd_pcm_t *pcm)
134 snd_pcm_null_t *null = pcm->private_data;
135 assert(null->state == SND_PCM_STATE_PREPARED);
136 null->state = SND_PCM_STATE_RUNNING;
137 if (pcm->stream == SND_PCM_STREAM_CAPTURE)
138 *pcm->hw.ptr = *pcm->appl.ptr + pcm->buffer_size;
140 *pcm->hw.ptr = *pcm->appl.ptr;
144 static int snd_pcm_null_drop(snd_pcm_t *pcm)
146 snd_pcm_null_t *null = pcm->private_data;
147 assert(null->state != SND_PCM_STATE_OPEN);
148 null->state = SND_PCM_STATE_SETUP;
152 static int snd_pcm_null_drain(snd_pcm_t *pcm)
154 snd_pcm_null_t *null = pcm->private_data;
155 assert(null->state != SND_PCM_STATE_OPEN);
156 null->state = SND_PCM_STATE_SETUP;
160 static int snd_pcm_null_pause(snd_pcm_t *pcm, int enable)
162 snd_pcm_null_t *null = pcm->private_data;
164 if (null->state != SND_PCM_STATE_RUNNING)
166 } else if (null->state != SND_PCM_STATE_PAUSED)
168 null->state = SND_PCM_STATE_PAUSED;
172 static snd_pcm_sframes_t snd_pcm_null_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
174 snd_pcm_null_t *null = pcm->private_data;
175 switch (null->state) {
176 case SND_PCM_STATE_RUNNING:
177 snd_pcm_mmap_hw_backward(pcm, frames);
179 case SND_PCM_STATE_PREPARED:
180 snd_pcm_mmap_appl_backward(pcm, frames);
187 static int snd_pcm_null_resume(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
192 static snd_pcm_sframes_t snd_pcm_null_fwd(snd_pcm_t *pcm, snd_pcm_uframes_t size)
194 snd_pcm_null_t *null = pcm->private_data;
195 switch (null->state) {
196 case SND_PCM_STATE_RUNNING:
197 snd_pcm_mmap_hw_forward(pcm, size);
199 case SND_PCM_STATE_PREPARED:
200 snd_pcm_mmap_appl_forward(pcm, size);
207 static snd_pcm_sframes_t snd_pcm_null_xfer_areas(snd_pcm_t *pcm,
208 const snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED,
209 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
210 snd_pcm_uframes_t size)
212 snd_pcm_mmap_appl_forward(pcm, size);
213 snd_pcm_mmap_hw_forward(pcm, size);
217 static snd_pcm_sframes_t snd_pcm_null_writei(snd_pcm_t *pcm, const void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
219 return snd_pcm_write_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
222 static snd_pcm_sframes_t snd_pcm_null_writen(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
224 return snd_pcm_write_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
227 static snd_pcm_sframes_t snd_pcm_null_readi(snd_pcm_t *pcm, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
229 return snd_pcm_read_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
232 static snd_pcm_sframes_t snd_pcm_null_readn(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
234 return snd_pcm_read_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
237 static snd_pcm_sframes_t snd_pcm_null_mmap_commit(snd_pcm_t *pcm,
238 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
239 snd_pcm_uframes_t size)
241 snd_pcm_sframes_t res;
243 res = snd_pcm_null_fwd(pcm, size);
249 static snd_pcm_sframes_t snd_pcm_null_avail_update(snd_pcm_t *pcm)
251 return pcm->buffer_size;
254 static int snd_pcm_null_hw_refine(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
256 int err = snd_pcm_hw_refine_soft(pcm, params);
257 params->fifo_size = 0;
261 static int snd_pcm_null_hw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t * params ATTRIBUTE_UNUSED)
266 static int snd_pcm_null_hw_free(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
271 static int snd_pcm_null_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t * params ATTRIBUTE_UNUSED)
276 static int snd_pcm_null_mmap(snd_pcm_t *pcm)
278 snd_pcm_null_t *null = pcm->private_data;
279 if (!(pcm->info & SND_PCM_INFO_MMAP)) {
280 size_t size = snd_pcm_frames_to_bytes(pcm, pcm->buffer_size);
281 int id = shmget(IPC_PRIVATE, size, 0666);
283 SYSERR("shmget failed");
291 static int snd_pcm_null_munmap(snd_pcm_t *pcm)
293 snd_pcm_null_t *null = pcm->private_data;
294 if (shmctl(null->shmid, IPC_RMID, 0) < 0) {
295 SYSERR("shmctl IPC_RMID failed");
301 static void snd_pcm_null_dump(snd_pcm_t *pcm, snd_output_t *out)
303 snd_output_printf(out, "Null PCM\n");
305 snd_output_printf(out, "Its setup is:\n");
306 snd_pcm_dump_setup(pcm, out);
310 static snd_pcm_ops_t snd_pcm_null_ops = {
311 close: snd_pcm_null_close,
312 info: snd_pcm_null_info,
313 hw_refine: snd_pcm_null_hw_refine,
314 hw_params: snd_pcm_null_hw_params,
315 hw_free: snd_pcm_null_hw_free,
316 sw_params: snd_pcm_null_sw_params,
317 channel_info: snd_pcm_null_channel_info,
318 dump: snd_pcm_null_dump,
319 nonblock: snd_pcm_null_nonblock,
320 async: snd_pcm_null_async,
321 mmap: snd_pcm_null_mmap,
322 munmap: snd_pcm_null_munmap,
325 static snd_pcm_fast_ops_t snd_pcm_null_fast_ops = {
326 status: snd_pcm_null_status,
327 state: snd_pcm_null_state,
328 hwsync: snd_pcm_null_hwsync,
329 delay: snd_pcm_null_delay,
330 prepare: snd_pcm_null_prepare,
331 reset: snd_pcm_null_reset,
332 start: snd_pcm_null_start,
333 drop: snd_pcm_null_drop,
334 drain: snd_pcm_null_drain,
335 pause: snd_pcm_null_pause,
336 rewind: snd_pcm_null_rewind,
337 resume: snd_pcm_null_resume,
338 writei: snd_pcm_null_writei,
339 writen: snd_pcm_null_writen,
340 readi: snd_pcm_null_readi,
341 readn: snd_pcm_null_readn,
342 avail_update: snd_pcm_null_avail_update,
343 mmap_commit: snd_pcm_null_mmap_commit,
347 * \brief Creates a new null PCM
348 * \param pcmp Returns created PCM handle
349 * \param name Name of PCM
350 * \param stream Stream type
351 * \param mode Stream mode
352 * \retval zero on success otherwise a negative error code
353 * \warning Using of this function might be dangerous in the sense
354 * of compatibility reasons. The prototype might be freely
357 int snd_pcm_null_open(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode)
360 snd_pcm_null_t *null;
364 if (stream == SND_PCM_STREAM_PLAYBACK) {
365 fd = open("/dev/null", O_WRONLY);
367 SYSERR("Cannot open /dev/null");
371 fd = open("/dev/full", O_RDONLY);
373 SYSERR("Cannot open /dev/full");
377 null = calloc(1, sizeof(snd_pcm_null_t));
383 null->state = SND_PCM_STATE_OPEN;
385 err = snd_pcm_new(&pcm, SND_PCM_TYPE_NULL, name, stream, mode);
391 pcm->ops = &snd_pcm_null_ops;
392 pcm->fast_ops = &snd_pcm_null_fast_ops;
393 pcm->private_data = null;
395 snd_pcm_set_hw_ptr(pcm, &null->hw_ptr, -1, 0);
396 snd_pcm_set_appl_ptr(pcm, &null->appl_ptr, -1, 0);
402 /*! \page pcm_plugins
404 \section pcm_plugins_null Plugin: Null
406 This plugin discards contents of a PCM stream or creates a stream with zero
409 Note: This implementation uses devices /dev/null (playback, must be writable)
410 and /dev/full (capture, must be readable).
418 \subsection pcm_plugins_null_funcref Function reference
421 <LI>snd_pcm_null_open()
422 <LI>_snd_pcm_null_open()
428 * \brief Creates a new Null PCM
429 * \param pcmp Returns created PCM handle
430 * \param name Name of PCM
431 * \param root Root configuration node
432 * \param conf Configuration node with Null PCM description
433 * \param stream Stream type
434 * \param mode Stream mode
435 * \retval zero on success otherwise a negative error code
436 * \warning Using of this function might be dangerous in the sense
437 * of compatibility reasons. The prototype might be freely
440 int _snd_pcm_null_open(snd_pcm_t **pcmp, const char *name,
441 snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf,
442 snd_pcm_stream_t stream, int mode)
444 snd_config_iterator_t i, next;
445 snd_config_for_each(i, next, conf) {
446 snd_config_t *n = snd_config_iterator_entry(i);
448 if (snd_config_get_id(n, &id) < 0)
450 if (snd_pcm_conf_generic_id(id))
452 SNDERR("Unknown field %s", id);
455 return snd_pcm_null_open(pcmp, name, stream, mode);
458 SND_DLSYM_BUILD_VERSION(_snd_pcm_null_open, SND_PCM_DLSYM_VERSION);