<commit_before>/**
 * \file pcm/pcm_null.c
 * \ingroup PCM_Plugins
 * \brief PCM Null Plugin Interface
 * \author <NAME> <<EMAIL>>
 * \date 2000-2001
 */
/*
 *  PCM - Null plugin
 *  Copyright (c) 2000 by <NAME> <<EMAIL>>
 *
 *
 *   This library is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as
 *   published by the Free Software Foundation; either version 2.1 of
 *   the License, or (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public
 *   License along with this library; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 */
  
#include <byteswap.h>
#include <limits.h>
#include <sys/shm.h>
#include "pcm_local.h"
#include "pcm_plugin.h"

#ifndef PIC
/* entry for static linking */
const char *_snd_module_pcm_null = "";
#endif

#ifndef DOC_HIDDEN
typedef struct {
	snd_timestamp_t trigger_tstamp;
	snd_pcm_state_t state;
	int shmid;
	snd_pcm_uframes_t appl_ptr;
	snd_pcm_uframes_t hw_ptr;
	int poll_fd;
} snd_pcm_null_t;
#endif

static int snd_pcm_null_close(snd_pcm_t *pcm)
{
	snd_pcm_null_t *null = pcm->private_data;
	close(null->poll_fd);
	free(null);
	return 0;
}

static int snd_pcm_null_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
{
	return 0;
}

static int snd_pcm_null_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int sig ATTRIBUTE_UNUSED, pid_t pid ATTRIBUTE_UNUSED)
{
	return -ENOSYS;
}

static int snd_pcm_null_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_info_t * info)
{
	memset(info, 0, sizeof(*info));
	info->stream = pcm->stream;
	info->card = -1;
	strncpy(info->id, pcm->name, sizeof(info->id));
	strncpy(info->name, pcm->name, sizeof(info->name));
	strncpy(info->subname, pcm->name, sizeof(info->subname));
	info->subdevices_count = 1;
	return 0;
}

static int snd_pcm_null_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
{
	snd_pcm_null_t *null = pcm->private_data;
	return snd_pcm_channel_info_shm(pcm, info, null->shmid);
}

static int snd_pcm_null_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
{
	snd_pcm_null_t *null = pcm->private_data;
	memset(status, 0, sizeof(*status));
	status->state = null->state;
	status->trigger_tstamp = null->trigger_tstamp;
	gettimeofday(&status->tstamp, 0);
	status->avail = pcm->buffer_size;
	status->avail_max = status->avail;
	return 0;
}

static snd_pcm_state_t snd_pcm_null_state(snd_pcm_t *pcm)
{
	snd_pcm_null_t *null = pcm->private_data;
	return null->state;
}

static int snd_pcm_null_delay(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sframes_t *delayp)
{
	*delayp = 0;
	return 0;
}

static int snd_pcm_null_prepare(snd_pcm_t *pcm)
{
	snd_pcm_null_t *null = pcm->private_data;
	null->state = SND_PCM_STATE_PREPARED;
	*pcm->appl.ptr = 0;
	*pcm->hw.ptr = 0;
	return 0;
}

static int snd_pcm_null_reset(snd_pcm_t *pcm)
{
	*pcm->appl.ptr = 0;
	*pcm->hw.ptr = 0;
	return 0;
}

static int snd_pcm_null_start(snd_pcm_t *pcm)
{
	snd_pcm_null_t *null = pcm->private_data;
	assert(null->state == SND_PCM_STATE_PREPARED);
	null->state = SND_PCM_STATE_RUNNING;
	if (pcm->stream == SND_PCM_STREAM_CAPTURE)
		*pcm->hw.ptr = *pcm->appl.ptr + pcm->buffer_size;
	else
		*pcm->hw.ptr = *pcm->appl.ptr;
	return 0;
}

static int snd_pcm_null_drop(snd_pcm_t *pcm)
{
	snd_pcm_null_t *null = pcm->private_data;
	assert(null->state != SND_PCM_STATE_OPEN);
	null->state = SND_PCM_STATE_SETUP;
	return 0;
}

static int snd_pcm_null_drain(snd_pcm_t *pcm)
{
	snd_pcm_null_t *null = pcm->private_data;
	assert(null->state != SND_PCM_STATE_OPEN);
	null->state = SND_PCM_STATE_SETUP;
	return 0;
}

static int snd_pcm_null_pause(snd_pcm_t *pcm, int enable)
{
	snd_pcm_null_t *null = pcm->private_data;
	if (enable) {
		if (null->state != SND_PCM_STATE_RUNNING)
			return -EBADFD;
	} else if (null->state != SND_PCM_STATE_PAUSED)
		return -EBADFD;
	null->state = SND_PCM_STATE_PAUSED;
	return 0;
}

static snd_pcm_sframes_t snd_pcm_null_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
{
	snd_pcm_null_t *null = pcm->private_data;
	switch (null->state) {
	case SND_PCM_STATE_RUNNING:
		snd_pcm_mmap_hw_backward(pcm, frames);
		/* Fall through */
	case SND_PCM_STATE_PREPARED:
		snd_pcm_mmap_appl_backward(pcm, frames);
		return frames;
	default:
		return -EBADFD;
	}
}

static int snd_pcm_null_resume(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
	return 0;
}

static snd_pcm_sframes_t snd_pcm_null_fwd(snd_pcm_t *pcm, snd_pcm_uframes_t size)
{
	snd_pcm_null_t *null = pcm->private_data;
	switch (null->state) {
	case SND_PCM_STATE_RUNNING:
		snd_pcm_mmap_hw_forward(pcm, size);
		/* Fall through */
	case SND_PCM_STATE_PREPARED:
		snd_pcm_mmap_appl_forward(pcm, size);
		return size;
	default:
		return -EBADFD;
	}
}

static snd_pcm_sframes_t snd_pcm_null_xfer_areas(snd_pcm_t *pcm,
						 const snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED,
						 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
						 snd_pcm_uframes_t size)
{
	snd_pcm_mmap_appl_forward(pcm, size);
	snd_pcm_mmap_hw_forward(pcm, size);
	return size;
}

static snd_pcm_sframes_t snd_pcm_null_writei(snd_pcm_t *pcm, const void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
{
	return snd_pcm_write_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
}

static snd_pcm_sframes_t snd_pcm_null_writen(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
{
	return snd_pcm_write_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
}

static snd_pcm_sframes_t snd_pcm_null_readi(snd_pcm_t *pcm, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
{
	return snd_pcm_read_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
}

static snd_pcm_sframes_t snd_pcm_null_readn(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
{
	return snd_pcm_read_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
}

static snd_pcm_sframes_t snd_pcm_null_mmap_commit(snd_pcm_t *pcm,
						  snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
						  snd_pcm_uframes_t size)
{
	snd_pcm_sframes_t res;
	
	res = snd_pcm_null_fwd(pcm, size);
	if (res < 0)
		return res;
	return res;
}

static snd_pcm_sframes_t snd_pcm_null_avail_update(snd_pcm_t *pcm)
{
	return pcm->buffer_size;
}

static int snd_pcm_null_hw_refine(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
{
	int err = snd_pcm_hw_refine_soft(pcm, params);
	params->fifo_size = 0;
	return err;
}

static int snd_pcm_null_hw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t * params ATTRIBUTE_UNUSED)
{
	return 0;
}

static int snd_pcm_null_hw_free(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
	return 0;
}

static int snd_pcm_null_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t * params ATTRIBUTE_UNUSED)
{
	return 0;
}

static int snd_pcm_null_mmap(snd_pcm_t *pcm)
{
	snd_pcm_null_t *null = pcm->private_data;
	if (!(pcm->info & SND_PCM_INFO_MMAP)) {
		size_t size = snd_pcm_frames_to_bytes(pcm, pcm->buffer_size);
		int id = shmget(IPC_PRIVATE, size, 0666);
		if (id < 0) {
			SYSERR("shmget failed");
			return -errno;
		}
		null->shmid = id;
	}
	return 0;
}

static int snd_pcm_null_munmap(snd_pcm_t *pcm)
{
	snd_pcm_null_t *null = pcm->private_data;
	if (shmctl(null->shmid, IPC_RMID, 0) < 0) {
		SYSERR("shmctl IPC_RMID failed");
			return -errno;
	}
	return 0;
}

static void snd_pcm_null_dump(snd_pcm_t *pcm, snd_output_t *out)
{
	snd_output_printf(out, "Null PCM\n");
	if (pcm->setup) {
		snd_output_printf(out, "Its setup is:\n");
		snd_pcm_dump_setup(pcm, out);
	}
}

static snd_pcm_ops_t snd_pcm_null_ops = {
	close: snd_pcm_null_close,
	info: snd_pcm_null_info,
	hw_refine: snd_pcm_null_hw_refine,
	hw_params: snd_pcm_null_hw_params,
	hw_free: snd_pcm_null_hw_free,
	sw_params: snd_pcm_null_sw_params,
	channel_info: snd_pcm_null_channel_info,
	dump: snd_pcm_null_dump,
	nonblock: snd_pcm_null_nonblock,
	async: snd_pcm_null_async,
	mmap: snd_pcm_null_mmap,
	munmap: snd_pcm_null_munmap,
};

static snd_pcm_fast_ops_t snd_pcm_null_fast_ops = {
	status: snd_pcm_null_status,
	state: snd_pcm_null_state,
	delay: snd_pcm_null_delay,
	prepare: snd_pcm_null_prepare,
	reset: snd_pcm_null_reset,
	start: snd_pcm_null_start,
	drop: snd_pcm_null_drop,
	drain: snd_pcm_null_drain,
	pause: snd_pcm_null_pause,
	rewind: snd_pcm_null_rewind,
	resume: snd_pcm_null_resume,
	writei: snd_pcm_null_writei,
	writen: snd_pcm_null_writen,
	readi: snd_pcm_null_readi,
	readn: snd_pcm_null_readn,
	avail_update: snd_pcm_null_avail_update,
	mmap_commit: snd_pcm_null_mmap_commit,
};

/**
 * \brief Creates a new null PCM
 * \param pcmp Returns created PCM handle
 * \param name Name of PCM
 * \param stream Stream type
 * \param mode Stream mode
 * \retval zero on success otherwise a negative error code
 * \warning Using of this function might be dangerous in the sense
 *          of compatibility reasons. The prototype might be freely
 *          changed in future.
 */
int snd_pcm_null_open(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode)
{
	snd_pcm_t *pcm;
	snd_pcm_null_t *null;
	int fd;
	int err;
	assert(pcmp);
	if (stream == SND_PCM_STREAM_PLAYBACK) {
		fd = open("/dev/null", O_WRONLY);
		if (fd < 0) {
			SYSERR("Cannot open /dev/null");
			return -errno;
		}
	} else {
		fd = open("/dev/full", O_RDONLY);
		if (fd < 0) {
			SYSERR("Cannot open /dev/full");
			return -errno;
		}
	}
	null = calloc(1, sizeof(snd_pcm_null_t));
	if (!null) {
		close(fd);
		return -ENOMEM;
	}
	null->poll_fd = fd;
	null->state = SND_PCM_STATE_OPEN;
	
	err = snd_pcm_new(&pcm, SND_PCM_TYPE_NULL, name, stream, mode);
	if (err < 0) {
		close(fd);
		free(null);
		return err;
	}
	pcm->ops = &snd_pcm_null_ops;
	pcm->fast_ops = &snd_pcm_null_fast_ops;
	pcm->private_data = null;
	pcm->poll_fd = fd;
	snd_pcm_set_hw_ptr(pcm, &null->hw_ptr, -1, 0);
	snd_pcm_set_appl_ptr(pcm, &null->appl_ptr, -1, 0);
	*pcmp = pcm;

	return 0;
}

/*! \page pcm_plugins

\section pcm_plugins_null Plugin: Null

This plugin discards contents of a PCM stream or creates a stream with zero
samples.

Note: This implementation uses devices /dev/null (playback, must be writable)
and /dev/full (capture, must be readable).

\code
pcm.name {
        type null               # Null PCM
}
\endcode

\subsection pcm_plugins_null_funcref Function reference

<UL>
  <LI>snd_pcm_null_open()
  <LI>_snd_pcm_null_open()
</UL>

*/

/**
 * \brief Creates a new Null PCM
 * \param pcmp Returns created PCM handle
 * \param name Name of PCM
 * \param root Root configuration node
 * \param conf Configuration node with Null PCM description
 * \param stream Stream type
 * \param mode Stream mode
 * \retval zero on success otherwise a negative error code
 * \warning Using of this function might be dangerous in the sense
 *          of compatibility reasons. The prototype might be freely
 *          changed in future.
 */
int _snd_pcm_null_open(snd_pcm_t **pcmp, const char *name,
		       snd_config_t *conf, 
		       snd_pcm_stream_t stream, int mode)
{
	snd_config_iterator_t i, next;
	snd_config_for_each(i, next, conf) {
		snd_config_t *n = snd_config_iterator_entry(i);<commit_msg>fixed missing root argument. now null plugin works fine.<commit_after>/**
 * \file pcm/pcm_null.c
 * \ingroup PCM_Plugins
 * \brief PCM Null Plugin Interface
 * \author <NAME> <<EMAIL>>
 * \date 2000-2001
 */
/*
 *  PCM - Null plugin
 *  Copyright (c) 2000 by <NAME> <<EMAIL>>
 *
 *
 *   This library is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as
 *   published by the Free Software Foundation; either version 2.1 of
 *   the License, or (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public
 *   License along with this library; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 */
  
#include <byteswap.h>
#include <limits.h>
#include <sys/shm.h>
#include "pcm_local.h"
#include "pcm_plugin.h"

#ifndef PIC
/* entry for static linking */
const char *_snd_module_pcm_null = "";
#endif

#ifndef DOC_HIDDEN
typedef struct {
	snd_timestamp_t trigger_tstamp;
	snd_pcm_state_t state;
	int shmid;
	snd_pcm_uframes_t appl_ptr;
	snd_pcm_uframes_t hw_ptr;
	int poll_fd;
} snd_pcm_null_t;
#endif

static int snd_pcm_null_close(snd_pcm_t *pcm)
{
	snd_pcm_null_t *null = pcm->private_data;
	close(null->poll_fd);
	free(null);
	return 0;
}

static int snd_pcm_null_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
{
	return 0;
}

static int snd_pcm_null_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int sig ATTRIBUTE_UNUSED, pid_t pid ATTRIBUTE_UNUSED)
{
	return -ENOSYS;
}

static int snd_pcm_null_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_info_t * info)
{
	memset(info, 0, sizeof(*info));
	info->stream = pcm->stream;
	info->card = -1;
	strncpy(info->id, pcm->name, sizeof(info->id));
	strncpy(info->name, pcm->name, sizeof(info->name));
	strncpy(info->subname, pcm->name, sizeof(info->subname));
	info->subdevices_count = 1;
	return 0;
}

static int snd_pcm_null_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
{
	snd_pcm_null_t *null = pcm->private_data;
	return snd_pcm_channel_info_shm(pcm, info, null->shmid);
}

static int snd_pcm_null_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
{
	snd_pcm_null_t *null = pcm->private_data;
	memset(status, 0, sizeof(*status));
	status->state = null->state;
	status->trigger_tstamp = null->trigger_tstamp;
	gettimeofday(&status->tstamp, 0);
	status->avail = pcm->buffer_size;
	status->avail_max = status->avail;
	return 0;
}

static snd_pcm_state_t snd_pcm_null_state(snd_pcm_t *pcm)
{
	snd_pcm_null_t *null = pcm->private_data;
	return null->state;
}

static int snd_pcm_null_delay(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sframes_t *delayp)
{
	*delayp = 0;
	return 0;
}

static int snd_pcm_null_prepare(snd_pcm_t *pcm)
{
	snd_pcm_null_t *null = pcm->private_data;
	null->state = SND_PCM_STATE_PREPARED;
	*pcm->appl.ptr = 0;
	*pcm->hw.ptr = 0;
	return 0;
}

static int snd_pcm_null_reset(snd_pcm_t *pcm)
{
	*pcm->appl.ptr = 0;
	*pcm->hw.ptr = 0;
	return 0;
}

static int snd_pcm_null_start(snd_pcm_t *pcm)
{
	snd_pcm_null_t *null = pcm->private_data;
	assert(null->state == SND_PCM_STATE_PREPARED);
	null->state = SND_PCM_STATE_RUNNING;
	if (pcm->stream == SND_PCM_STREAM_CAPTURE)
		*pcm->hw.ptr = *pcm->appl.ptr + pcm->buffer_size;
	else
		*pcm->hw.ptr = *pcm->appl.ptr;
	return 0;
}

static int snd_pcm_null_drop(snd_pcm_t *pcm)
{
	snd_pcm_null_t *null = pcm->private_data;
	assert(null->state != SND_PCM_STATE_OPEN);
	null->state = SND_PCM_STATE_SETUP;
	return 0;
}

static int snd_pcm_null_drain(snd_pcm_t *pcm)
{
	snd_pcm_null_t *null = pcm->private_data;
	assert(null->state != SND_PCM_STATE_OPEN);
	null->state = SND_PCM_STATE_SETUP;
	return 0;
}

static int snd_pcm_null_pause(snd_pcm_t *pcm, int enable)
{
	snd_pcm_null_t *null = pcm->private_data;
	if (enable) {
		if (null->state != SND_PCM_STATE_RUNNING)
			return -EBADFD;
	} else if (null->state != SND_PCM_STATE_PAUSED)
		return -EBADFD;
	null->state = SND_PCM_STATE_PAUSED;
	return 0;
}

static snd_pcm_sframes_t snd_pcm_null_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
{
	snd_pcm_null_t *null = pcm->private_data;
	switch (null->state) {
	case SND_PCM_STATE_RUNNING:
		snd_pcm_mmap_hw_backward(pcm, frames);
		/* Fall through */
	case SND_PCM_STATE_PREPARED:
		snd_pcm_mmap_appl_backward(pcm, frames);
		return frames;
	default:
		return -EBADFD;
	}
}

static int snd_pcm_null_resume(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
	return 0;
}

static snd_pcm_sframes_t snd_pcm_null_fwd(snd_pcm_t *pcm, snd_pcm_uframes_t size)
{
	snd_pcm_null_t *null = pcm->private_data;
	switch (null->state) {
	case SND_PCM_STATE_RUNNING:
		snd_pcm_mmap_hw_forward(pcm, size);
		/* Fall through */
	case SND_PCM_STATE_PREPARED:
		snd_pcm_mmap_appl_forward(pcm, size);
		return size;
	default:
		return -EBADFD;
	}
}

static snd_pcm_sframes_t snd_pcm_null_xfer_areas(snd_pcm_t *pcm,
						 const snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED,
						 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
						 snd_pcm_uframes_t size)
{
	snd_pcm_mmap_appl_forward(pcm, size);
	snd_pcm_mmap_hw_forward(pcm, size);
	return size;
}

static snd_pcm_sframes_t snd_pcm_null_writei(snd_pcm_t *pcm, const void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
{
	return snd_pcm_write_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
}

static snd_pcm_sframes_t snd_pcm_null_writen(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
{
	return snd_pcm_write_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
}

static snd_pcm_sframes_t snd_pcm_null_readi(snd_pcm_t *pcm, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
{
	return snd_pcm_read_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
}

static snd_pcm_sframes_t snd_pcm_null_readn(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size)
{
	return snd_pcm_read_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
}

static snd_pcm_sframes_t snd_pcm_null_mmap_commit(snd_pcm_t *pcm,
						  snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
						  snd_pcm_uframes_t size)
{
	snd_pcm_sframes_t res;
	
	res = snd_pcm_null_fwd(pcm, size);
	if (res < 0)
		return res;
	return res;
}

static snd_pcm_sframes_t snd_pcm_null_avail_update(snd_pcm_t *pcm)
{
	return pcm->buffer_size;
}

static int snd_pcm_null_hw_refine(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
{
	int err = snd_pcm_hw_refine_soft(pcm, params);
	params->fifo_size = 0;
	return err;
}

static int snd_pcm_null_hw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t * params ATTRIBUTE_UNUSED)
{
	return 0;
}

static int snd_pcm_null_hw_free(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
	return 0;
}

static int snd_pcm_null_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t * params ATTRIBUTE_UNUSED)
{
	return 0;
}

static int snd_pcm_null_mmap(snd_pcm_t *pcm)
{
	snd_pcm_null_t *null = pcm->private_data;
	if (!(pcm->info & SND_PCM_INFO_MMAP)) {
		size_t size = snd_pcm_frames_to_bytes(pcm, pcm->buffer_size);
		int id = shmget(IPC_PRIVATE, size, 0666);
		if (id < 0) {
			SYSERR("shmget failed");
			return -errno;
		}
		null->shmid = id;
	}
	return 0;
}

static int snd_pcm_null_munmap(snd_pcm_t *pcm)
{
	snd_pcm_null_t *null = pcm->private_data;
	if (shmctl(null->shmid, IPC_RMID, 0) < 0) {
		SYSERR("shmctl IPC_RMID failed");
			return -errno;
	}
	return 0;
}

static void snd_pcm_null_dump(snd_pcm_t *pcm, snd_output_t *out)
{
	snd_output_printf(out, "Null PCM\n");
	if (pcm->setup) {
		snd_output_printf(out, "Its setup is:\n");
		snd_pcm_dump_setup(pcm, out);
	}
}

static snd_pcm_ops_t snd_pcm_null_ops = {
	close: snd_pcm_null_close,
	info: snd_pcm_null_info,
	hw_refine: snd_pcm_null_hw_refine,
	hw_params: snd_pcm_null_hw_params,
	hw_free: snd_pcm_null_hw_free,
	sw_params: snd_pcm_null_sw_params,
	channel_info: snd_pcm_null_channel_info,
	dump: snd_pcm_null_dump,
	nonblock: snd_pcm_null_nonblock,
	async: snd_pcm_null_async,
	mmap: snd_pcm_null_mmap,
	munmap: snd_pcm_null_munmap,
};

static snd_pcm_fast_ops_t snd_pcm_null_fast_ops = {
	status: snd_pcm_null_status,
	state: snd_pcm_null_state,
	delay: snd_pcm_null_delay,
	prepare: snd_pcm_null_prepare,
	reset: snd_pcm_null_reset,
	start: snd_pcm_null_start,
	drop: snd_pcm_null_drop,
	drain: snd_pcm_null_drain,
	pause: snd_pcm_null_pause,
	rewind: snd_pcm_null_rewind,
	resume: snd_pcm_null_resume,
	writei: snd_pcm_null_writei,
	writen: snd_pcm_null_writen,
	readi: snd_pcm_null_readi,
	readn: snd_pcm_null_readn,
	avail_update: snd_pcm_null_avail_update,
	mmap_commit: snd_pcm_null_mmap_commit,
};

/**
 * \brief Creates a new null PCM
 * \param pcmp Returns created PCM handle
 * \param name Name of PCM
 * \param stream Stream type
 * \param mode Stream mode
 * \retval zero on success otherwise a negative error code
 * \warning Using of this function might be dangerous in the sense
 *          of compatibility reasons. The prototype might be freely
 *          changed in future.
 */
int snd_pcm_null_open(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode)
{
	snd_pcm_t *pcm;
	snd_pcm_null_t *null;
	int fd;
	int err;
	assert(pcmp);
	if (stream == SND_PCM_STREAM_PLAYBACK) {
		fd = open("/dev/null", O_WRONLY);
		if (fd < 0) {
			SYSERR("Cannot open /dev/null");
			return -errno;
		}
	} else {
		fd = open("/dev/full", O_RDONLY);
		if (fd < 0) {
			SYSERR("Cannot open /dev/full");
			return -errno;
		}
	}
	null = calloc(1, sizeof(snd_pcm_null_t));
	if (!null) {
		close(fd);
		return -ENOMEM;
	}
	null->poll_fd = fd;
	null->state = SND_PCM_STATE_OPEN;
	
	err = snd_pcm_new(&pcm, SND_PCM_TYPE_NULL, name, stream, mode);
	if (err < 0) {
		close(fd);
		free(null);
		return err;
	}
	pcm->ops = &snd_pcm_null_ops;
	pcm->fast_ops = &snd_pcm_null_fast_ops;
	pcm->private_data = null;
	pcm->poll_fd = fd;
	snd_pcm_set_hw_ptr(pcm, &null->hw_ptr, -1, 0);
	snd_pcm_set_appl_ptr(pcm, &null->appl_ptr, -1, 0);
	*pcmp = pcm;

	return 0;
}

/*! \page pcm_plugins

\section pcm_plugins_null Plugin: Null

This plugin discards contents of a PCM stream or creates a stream with zero
samples.

Note: This implementation uses devices /dev/null (playback, must be writable)
and /dev/full (capture, must be readable).

\code
pcm.name {
        type null               # Null PCM
}
\endcode

\subsection pcm_plugins_null_funcref Function reference

<UL>
  <LI>snd_pcm_null_open()
  <LI>_snd_pcm_null_open()
</UL>

*/

/**
 * \brief Creates a new Null PCM
 * \param pcmp Returns created PCM handle
 * \param name Name of PCM
 * \param root Root configuration node
 * \param conf Configuration node with Null PCM description
 * \param stream Stream type
 * \param mode Stream mode
 * \retval zero on success otherwise a negative error code
 * \warning Using of this function might be dangerous in the sense
 *          of compatibility reasons. The prototype might be freely
 *          changed in future.
 */
int _snd_pcm_null_open(snd_pcm_t **pcmp, const char *name,
		       snd_config_t *root, snd_config_t *conf, 
		       snd_pcm_stream_t stream, int mode)
{
	snd_config_iterator_t i, next;
	snd_config_for_each(i, next, conf) {
		snd_config_t *n = snd_config_iterator_entry(i);
{'fraction_non_alphanumeric': 0.10312541210602665, 'fraction_numerical': 0.006769528330915645, 'mean_word_length': 4.883113524696147, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 179, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2052365', 'n_tokens_mistral': 9458, 'n_tokens_neox': 9215, 'n_words': 2051}