External PCM IO Plugin development

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Takashi & alsa-devel,

I am playing with embedded Linux box based on kernel 2.4.36. Our box
is equipped with proprietary chip which allows PCM playback using user
space DMA pool API.  My target is to enable audio playback for ALSA
clients by redirecting PCM stream into proprietary chip. I did a
little RTFM and with a lot of help from this list discovered that
fortunately ALSA expendable architecture allows such things as a part
of PCM External Plugin SDK.

So I downloaded and installed following ALSA 1.0.16 distribution components:
- driver configured with "./configure  --with-cards=seq-dummy,dummy
--with-kernel=/path/to/my/linux-2.4.36"
- lib configured with "./configure --with-pcm-plugins=all"

I looked at Jack IO plugin at plugins and started with skeleton plugin
of my own: pcm_sigma.c (attached).
I hope to redirect PCM into my plugin using following /etc/asound.conf
=============
pcm.!default {
        type sigma
}
=============

What I see when I fire ALSA client ( friefox with YouTube flash ) that ALSA
1. loads/links my module: ALSA lib dlmisc.c:51:(snd_dlopen) snd_dlopen
name = (/usr/lib/alsa-lib/libasound_module_pcm_sigma.so)
2. calls open interface of the module: _snd_pcm_sigma_open @ pcm_sigma.c:118

snd_pcm_sigma_open @ pcm_sigma.c:86
3. calls close interface of the module: snd_pcm_sigma_close @ pcm_sigma.c:23
4. goto 2

So basically what I see is an infinite open/close loop without any
call to other interfaces of the module. I hoped to get my hands on PCM
stream and start to push it into our proprietary chip :(.

QUESTIONS:
Is my PCM IO Plugin approach correct?
Is my configuration (/etc/asound.conf) correct?
Is my implemention of PCM IO plugin interface correct? Should I
implement additional methods?
What do you think causes infinite open/close loop?

Thank you for your help,
Alexander Indenbaum
#include <asoundlib.h>
#include <pcm_external.h>

#define TRACE() fprintf(stderr, "%s @ %s:%d\n", __FUNCTION__, __FILE__, __LINE__)
#define UNUSED_ARGS(args)  do {} while ((args) && !(args))

typedef struct {
	snd_pcm_ioplug_t  io;
        // state
} snd_pcm_sigma_t;

static void snd_pcm_sigma_free(snd_pcm_sigma_t *sigma)
{
	if (sigma) {
		free(sigma);
	}
}


static int snd_pcm_sigma_close(snd_pcm_ioplug_t *io)
{
	snd_pcm_sigma_t *sigma;
	TRACE();

	sigma = io->private_data;
	snd_pcm_sigma_free(sigma);
	return 0;
}

static snd_pcm_sframes_t snd_pcm_sigma_pointer(snd_pcm_ioplug_t *io)
{
	UNUSED_ARGS(io);
    	TRACE();

	return 0;
}

static int snd_pcm_sigma_prepare(snd_pcm_ioplug_t *io)
{
	UNUSED_ARGS(io);
    	TRACE();
	return 0;
}

static int snd_pcm_sigma_start(snd_pcm_ioplug_t *io)
{
	UNUSED_ARGS(io);
    	TRACE();
	return 0;
}

static int snd_pcm_sigma_stop(snd_pcm_ioplug_t *io)
{
	UNUSED_ARGS(io);
    	TRACE();
	return 0;
}

static snd_pcm_sframes_t snd_pcm_sigma_transfer(snd_pcm_ioplug_t *io,
						const snd_pcm_channel_area_t *areas,
						snd_pcm_uframes_t offset,
						snd_pcm_uframes_t size)
{
	UNUSED_ARGS(io && areas && offset && size);
    	TRACE();
	return 0;
}

static snd_pcm_ioplug_callback_t sigma_pcm_callback = {
	.close = snd_pcm_sigma_close,
	.start = snd_pcm_sigma_start,
	.stop = snd_pcm_sigma_stop,
	.pointer = snd_pcm_sigma_pointer,
	.prepare = snd_pcm_sigma_prepare,
	.transfer = snd_pcm_sigma_transfer
};

static int snd_pcm_sigma_open(snd_pcm_t **pcmp, const char *name,
			     snd_config_t *playback_conf,
			     snd_config_t *capture_conf,
			     snd_pcm_stream_t stream, int mode)
{
	int err;
	snd_pcm_sigma_t *sigma;

    	TRACE();

	UNUSED_ARGS(pcmp && playback_conf && capture_conf);
	sigma = calloc(1, sizeof(*sigma));
	if (!sigma)
		return -ENOMEM;

	sigma->io.version = SND_PCM_IOPLUG_VERSION;
	sigma->io.name = "ALSA <-> SIGMA PCM I/O Plugin";
	sigma->io.callback = &sigma_pcm_callback;
	sigma->io.private_data = sigma;

	err = snd_pcm_ioplug_create(&sigma->io, name, stream, mode);
	if (err < 0) {
		snd_pcm_sigma_free(sigma);
		return err;
	}

	*pcmp = sigma->io.pcm;

	return 0;
}


SND_PCM_PLUGIN_DEFINE_FUNC(sigma)
{
	snd_config_iterator_t i, next;
	snd_config_t *playback_conf = NULL;
	snd_config_t *capture_conf = NULL;
	int err;
	
	UNUSED_ARGS(root);
    	TRACE();

	snd_config_for_each(i, next, conf) {
		snd_config_t *n = snd_config_iterator_entry(i);
		const char *id;
		if (snd_config_get_id(n, &id) < 0)
			continue;
		if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0)
			continue;
		/*
		if (strcmp(id, "playback_ports") == 0) {
			if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
				SNDERR("Invalid type for %s", id);
				return -EINVAL;
			}
			playback_conf = n;
			continue;
		}
		if (strcmp(id, "capture_ports") == 0) {
			if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
				SNDERR("Invalid type for %s", id);
				return -EINVAL;
			}
			capture_conf = n;
			continue;
		}
		*/
		SNDERR("Unknown field %s", id);
		return -EINVAL;
	}

	err = snd_pcm_sigma_open(pcmp, name, playback_conf, capture_conf, stream, mode);

	return err;
}

SND_PCM_PLUGIN_SYMBOL(sigma);
_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxx
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux