From be5b2ce72c67383885154ac97c6d34c581ea4205 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 12 Feb 2003 20:59:38 +0000 Subject: [PATCH] Added jack plugin --- src/hwdep/hwdep.c | 2 +- src/pcm/Makefile.am | 9 +- src/pcm/pcm_jack.c | 565 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/pcm/pcm_symbols.c | 4 +- 4 files changed, 576 insertions(+), 4 deletions(-) create mode 100644 src/pcm/pcm_jack.c diff --git a/src/hwdep/hwdep.c b/src/hwdep/hwdep.c index c8285926..c47939ea 100644 --- a/src/hwdep/hwdep.c +++ b/src/hwdep/hwdep.c @@ -52,7 +52,7 @@ static int snd_hwdep_open_conf(snd_hwdep_t **hwdep, #ifndef PIC extern void *snd_hwdep_open_symbols(void); #endif - void *h; + void *h = NULL; if (snd_config_get_type(hwdep_conf) != SND_CONFIG_TYPE_COMPOUND) { if (name) SNDERR("Invalid type for HWDEP %s definition", name); diff --git a/src/pcm/Makefile.am b/src/pcm/Makefile.am index d83cb33a..da570be3 100644 --- a/src/pcm/Makefile.am +++ b/src/pcm/Makefile.am @@ -1,6 +1,11 @@ - EXTRA_LTLIBRARIES = libpcm.la +if HAVE_JACK +JACK_PLUGIN = pcm_jack.c +else !HAVE_JACK +JACK_PLUGIN = +endif !HAVE_JACK + libpcm_la_SOURCES = atomic.c mask.c interval.c \ pcm.c pcm_params.c \ pcm_hw.c pcm_plugin.c pcm_copy.c pcm_linear.c \ @@ -8,7 +13,7 @@ libpcm_la_SOURCES = atomic.c mask.c interval.c \ pcm_rate.c pcm_plug.c pcm_misc.c pcm_mmap.c pcm_multi.c \ pcm_shm.c pcm_file.c pcm_null.c pcm_share.c \ pcm_meter.c pcm_hooks.c pcm_lfloat.c pcm_ladspa.c \ - pcm_dmix.c pcm_symbols.c + pcm_dmix.c pcm_symbols.c $(JACK_PLUGIN) noinst_HEADERS = pcm_local.h pcm_plugin.h mask.h mask_inline.h \ interval.h interval_inline.h plugin_ops.h ladspa.h diff --git a/src/pcm/pcm_jack.c b/src/pcm/pcm_jack.c new file mode 100644 index 00000000..f0c44ef9 --- /dev/null +++ b/src/pcm/pcm_jack.c @@ -0,0 +1,565 @@ +/** + * \file pcm/pcm_jack.c + * \ingroup PCM_Plugins + * \brief PCM Jack Plugin Interface + * \author Maarten de Boer + * \date 2003 + */ +/* + * PCM - File plugin + * Copyright (c) 2003 by Maarten de Boer + * + * + * 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 + * + */ + +#ifdef HAVE_JACK +#define USE_JACK +#endif + +#include +#include +#include +#include +#include "pcm_local.h" +#ifdef USE_JACK +#include +#endif + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_jack = ""; +#endif + +#ifndef DOC_HIDDEN + +typedef enum _jack_format { + SND_PCM_JACK_FORMAT_RAW +} snd_pcm_jack_format_t; + +typedef struct { + char *fname; + int fd; + int format; + snd_timestamp_t trigger_tstamp; + snd_pcm_state_t state; + snd_pcm_uframes_t appl_ptr; + snd_pcm_uframes_t hw_ptr; + +#ifdef USE_JACK + jack_port_t **ports; + jack_client_t *client; +#endif +} snd_pcm_jack_t; + +#endif /* DOC_HIDDEN */ + +static int snd_pcm_jack_close(snd_pcm_t *pcm) +{ + snd_pcm_jack_t *jack = pcm->private_data; + int err = 0; + + printf("snd_pcm_jack_close\n"); fflush(stdout); +#ifdef USE_JACK + if (jack->client) + jack_client_close(jack->client); +#endif + free(jack); + return err; +} + +static int snd_pcm_jack_nonblock(snd_pcm_t *pcm, int nonblock) +{ + snd_pcm_jack_t *jack = pcm->private_data; + printf("snd_pcm_jack_nonblock\n"); fflush(stdout); + return 0; +} + +static int snd_pcm_jack_async(snd_pcm_t *pcm, int sig, pid_t pid) +{ + printf("snd_pcm_jack_async\n"); fflush(stdout); + return -ENOSYS; +} + +static int snd_pcm_jack_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + snd_pcm_jack_t *jack = pcm->private_data; + unsigned short events; + char buf[1]; + + printf("snd_pcm_jack_poll_revents\n"); fflush(stdout); + + assert(pfds && nfds == 1 && revents); + + read(pfds[0].fd, buf, 1); + + *revents = pfds[0].revents; + return 0; +} + +static int snd_pcm_jack_info(snd_pcm_t *pcm, snd_pcm_info_t * info) +{ + printf("snd_pcm_jack_info\n"); fflush(stdout); + 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_jack_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info) +{ + snd_pcm_jack_t *jack = pcm->private_data; + printf("snd_pcm_jack_channel_info\n"); fflush(stdout); + return snd_pcm_channel_info_shm(pcm, info, -1); +} + +static int snd_pcm_jack_status(snd_pcm_t *pcm, snd_pcm_status_t * status) +{ + snd_pcm_jack_t *jack = pcm->private_data; + printf("snd_pcm_jack_status\n"); fflush(stdout); + memset(status, 0, sizeof(*status)); + status->state = jack->state; + status->trigger_tstamp = jack->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_jack_state(snd_pcm_t *pcm) +{ + snd_pcm_jack_t *jack = pcm->private_data; + printf("snd_pcm_jack_state\n"); fflush(stdout); + return jack->state; +} + +static int snd_pcm_jack_hwsync(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + printf("snd_pcm_jack_hwsync\n"); fflush(stdout); + return 0; +} + +static int snd_pcm_jack_delay(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sframes_t *delayp) +{ + printf("snd_pcm_jack_delay\n"); fflush(stdout); + *delayp = snd_pcm_mmap_hw_avail(pcm); + return 0; +} + +#ifdef USE_JACK +int +snd_pcm_jack_process_cb (jack_nframes_t nframes, snd_pcm_t *pcm) +{ + snd_pcm_jack_t *jack = pcm->private_data; + const snd_pcm_channel_area_t *areas; + snd_pcm_uframes_t xfer = 0; + snd_pcm_channel_area_t area; + char buf[1]; + + area.addr = jack_port_get_buffer (jack->ports[0], nframes); + area.first = 0; + area.step = pcm->sample_bits; + + areas = snd_pcm_mmap_areas(pcm); + + while (xfer < nframes) + { + snd_pcm_uframes_t frames = nframes - xfer; + snd_pcm_uframes_t offset = snd_pcm_mmap_hw_offset(pcm); + snd_pcm_uframes_t cont = pcm->buffer_size - offset; + + if (cont < frames) + frames = cont; + + printf("snd_pcm_jack_process_cb hw=%d=%d + nframes=%d / frames=%d / bufsize=%d\n", + offset,jack->hw_ptr,nframes,frames,pcm->buffer_size); fflush(stdout); + + snd_pcm_area_copy(&area, xfer, &areas[0], offset, frames, pcm->format); + + snd_pcm_mmap_hw_forward(pcm,frames); + xfer += frames; + } + write(jack->fd,buf,1); /* for polling */ + + printf("jack_process = %d\n",snd_pcm_mmap_hw_offset(pcm)); fflush(stdout); + + return 0; +} +#endif + +static int snd_pcm_jack_prepare(snd_pcm_t *pcm) +{ + int i; + + snd_pcm_jack_t *jack = pcm->private_data; + printf("snd_pcm_jack_prepare\n"); fflush(stdout); + jack->state = SND_PCM_STATE_PREPARED; + *pcm->appl.ptr = 0; + *pcm->hw.ptr = 0; + + jack->appl_ptr = jack->hw_ptr = 0; + +#ifdef USE_JACK + jack->ports = calloc (pcm->channels, sizeof(jack_port_t*)); + for (i = 0; i < pcm->channels; i++) + { + char port_name[32]; + sprintf(port_name,"chn%03d\n",i); + jack->ports[i] = jack_port_register ( + jack->client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + } + + jack_set_process_callback (jack->client, + (JackProcessCallback)snd_pcm_jack_process_cb, pcm); + jack_activate (jack->client); + + for (i = 0; i < pcm->channels; i++) + { + if (jack_connect (jack->client, jack_port_name (jack->ports[i]), "alsa_pcm:playback_1")) + { + fprintf (stderr, "cannot connect output ports\n"); + exit(-1); + }else{ + printf("connected %s to alsa_pcm:playback_1",jack_port_name(jack->ports[i])); + } + } +#endif + + return 0; +} + +static int snd_pcm_jack_reset(snd_pcm_t *pcm) +{ + printf("snd_pcm_jack_reset\n"); fflush(stdout); + *pcm->appl.ptr = 0; + *pcm->hw.ptr = 0; + return 0; +} + +static int snd_pcm_jack_start(snd_pcm_t *pcm) +{ + snd_pcm_jack_t *jack = pcm->private_data; + assert(jack->state == SND_PCM_STATE_PREPARED); + + printf("snd_pcm_jack_start\n"); fflush(stdout); + + jack->state = SND_PCM_STATE_RUNNING; + + return 0; +} + +static int snd_pcm_jack_drop(snd_pcm_t *pcm) +{ + snd_pcm_jack_t *jack = pcm->private_data; + printf("snd_pcm_jack_drop\n"); fflush(stdout); + assert(jack->state != SND_PCM_STATE_OPEN); + jack->state = SND_PCM_STATE_SETUP; + return 0; +} + +static int snd_pcm_jack_drain(snd_pcm_t *pcm) +{ + snd_pcm_jack_t *jack = pcm->private_data; + printf("snd_pcm_jack_drain\n"); fflush(stdout); + assert(jack->state != SND_PCM_STATE_OPEN); + jack->state = SND_PCM_STATE_SETUP; + return 0; +} + +static int snd_pcm_jack_pause(snd_pcm_t *pcm, int enable) +{ + snd_pcm_jack_t *jack = pcm->private_data; + printf("snd_pcm_jack_pause\n"); fflush(stdout); + if (enable) { + if (jack->state != SND_PCM_STATE_RUNNING) + return -EBADFD; + } else if (jack->state != SND_PCM_STATE_PAUSED) + return -EBADFD; + jack->state = SND_PCM_STATE_PAUSED; + return 0; +} + +static snd_pcm_sframes_t snd_pcm_jack_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_jack_t *jack = pcm->private_data; + snd_pcm_uframes_t n = snd_pcm_frames_to_bytes(pcm, frames); + snd_pcm_sframes_t ptr; + printf("snd_pcm_jack_rewind\n"); fflush(stdout); + return n; +} + +static int snd_pcm_jack_resume(snd_pcm_t *pcm) +{ + return 0; +} + +static snd_pcm_sframes_t snd_pcm_jack_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) +{ + snd_pcm_mmap_appl_forward(pcm, size); + return size; +} + +static snd_pcm_sframes_t snd_pcm_jack_avail_update(snd_pcm_t *pcm) +{ + snd_pcm_jack_t *jack = pcm->private_data; + int ret = snd_pcm_mmap_avail(pcm); + printf("snd_pcm_jack_avail_update appl=%d hw=%d ret=%d\n",jack->appl_ptr,jack->hw_ptr,ret); fflush(stdout); + return ret; +} + +static inline snd_mask_t *hw_param_mask(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) +{ + return ¶ms->masks[var - SND_PCM_HW_PARAM_FIRST_MASK]; +} + +static inline snd_interval_t *hw_param_interval(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) +{ + return ¶ms->intervals[var - SND_PCM_HW_PARAM_FIRST_INTERVAL]; +} + +static int snd_pcm_jack_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + int err; + snd_pcm_jack_t *jack = pcm->private_data; + + static snd_mask_t access = { .bits = { + (1<private_data; + int err; + + printf("snd_pcm_jack_hw_params\n"); fflush(stdout); + + return 0; +} + +static int snd_pcm_jack_hw_free(snd_pcm_t *pcm) +{ + printf("snd_pcm_jack_hw_free\n"); fflush(stdout); + return 0; +} + +static int snd_pcm_jack_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) +{ + printf("snd_pcm_jack_sw_params\n"); fflush(stdout); + return 0; +} + +static int snd_pcm_jack_mmap(snd_pcm_t *pcm) +{ + snd_pcm_jack_t *jack = pcm->private_data; + printf("snd_pcm_jack_mmap\n"); fflush(stdout); + + return 0; +} + +static int snd_pcm_jack_munmap(snd_pcm_t *pcm) +{ + snd_pcm_jack_t *jack = pcm->private_data; + return 0; +} + +static void snd_pcm_jack_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_jack_t *jack = pcm->private_data; + snd_output_printf(out, "Jack PCM\n", jack->fname); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } +} + +static snd_pcm_ops_t snd_pcm_jack_ops = { + close: snd_pcm_jack_close, + info: snd_pcm_jack_info, + hw_refine: snd_pcm_jack_hw_refine, + hw_params: snd_pcm_jack_hw_params, + hw_free: snd_pcm_jack_hw_free, + sw_params: snd_pcm_jack_sw_params, + channel_info: snd_pcm_jack_channel_info, + dump: snd_pcm_jack_dump, + nonblock: snd_pcm_jack_nonblock, + async: snd_pcm_jack_async, + poll_revents: snd_pcm_jack_poll_revents, + mmap: snd_pcm_jack_mmap, + munmap: snd_pcm_jack_munmap, +}; + +static snd_pcm_fast_ops_t snd_pcm_jack_fast_ops = { + status: snd_pcm_jack_status, + state: snd_pcm_jack_state, + hwsync: snd_pcm_jack_hwsync, + delay: snd_pcm_jack_delay, + prepare: snd_pcm_jack_prepare, + reset: snd_pcm_jack_reset, + start: snd_pcm_jack_start, + drop: snd_pcm_jack_drop, + drain: snd_pcm_jack_drain, + pause: snd_pcm_jack_pause, + rewind: snd_pcm_jack_rewind, + resume: snd_pcm_jack_resume, + writei: snd_pcm_mmap_writei, + writen: snd_pcm_mmap_writen, + readi: snd_pcm_mmap_readi, + readn: snd_pcm_mmap_readn, + avail_update: snd_pcm_jack_avail_update, + mmap_commit: snd_pcm_jack_mmap_commit, +}; + +/** + * \brief Creates a new jack 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_jack_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_stream_t stream, int mode) +{ + snd_pcm_t *pcm; + snd_pcm_jack_t *jack; + int err; + int fd[2]; + + assert(pcmp); + printf("snd_pcm_jack_open\n"); fflush(stdout); + if (stream == SND_PCM_STREAM_PLAYBACK) { + } else { + } + jack = calloc(1, sizeof(snd_pcm_jack_t)); + if (!jack) { + return -ENOMEM; + } + +#ifdef USE_JACK + jack->client = jack_client_new("alsa"); + if (jack->client==0) + return -ENOENT; +#endif + + jack->state = SND_PCM_STATE_OPEN; + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_JACK, name, stream, mode); + + if (err < 0) { + free(jack); + return err; + } + pcm->ops = &snd_pcm_jack_ops; + pcm->fast_ops = &snd_pcm_jack_fast_ops; + pcm->private_data = jack; + + pcm->mmap_rw = 1; + + socketpair(AF_LOCAL, SOCK_STREAM, 0, fd); + + jack->fd = fd[0]; + pcm->poll_fd = fd[1]; + + snd_pcm_set_hw_ptr(pcm, &jack->hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &jack->appl_ptr, -1, 0); + *pcmp = pcm; + + return 0; +} + +/*! \page pcm_plugins + +\section pcm_plugins_jack Plugin: Jack + +*/ + +/** + * \brief Creates a new Jack PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with Jack 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_jack_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root ATTRIBUTE_UNUSED, 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); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + SNDERR("Unknown field %s", id); + return -EINVAL; + } + return snd_pcm_jack_open(pcmp, name, stream, mode); +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_jack_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_symbols.c b/src/pcm/pcm_symbols.c index e18880d8..089077bb 100644 --- a/src/pcm/pcm_symbols.c +++ b/src/pcm/pcm_symbols.c @@ -39,6 +39,7 @@ extern const char *_snd_module_pcm_shm; extern const char *_snd_module_pcm_lfloat; extern const char *_snd_module_pcm_ladspa; extern const char *_snd_module_pcm_dmix; +extern const char *_snd_module_pcm_jack; static const char **snd_pcm_open_objects[] = { &_snd_module_pcm_adpcm, @@ -59,7 +60,8 @@ static const char **snd_pcm_open_objects[] = { &_snd_module_pcm_shm, &_snd_module_pcm_lfloat, &_snd_module_pcm_ladspa, - &_snd_module_pcm_dmix + &_snd_module_pcm_dmix, + &_snd_module_pcm_jack }; void *snd_pcm_open_symbols(void) -- 2.11.0