diff options
author | Takashi Iwai <tiwai@suse.de> | 2006-02-21 16:13:57 +0000 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2006-02-21 16:13:57 +0000 |
commit | 6890d16836e85deed9e8ca91d095473347013ccc (patch) | |
tree | bf5fa3bcb64af29d6264ff925f8e667e02bd16fc /pcm | |
parent | 6074e887419c70bed8a9177a4d78357156c7c611 (diff) |
Structure reorganziation, added polyp plugin
- Reorganized the directory structure: Now each plugin(s) is loaded
in own subdirectory.
- Added polypaudio plugin by Pierre Ossman <ossman@cendio.se>
- Fixed COPYING file to LGPL (under which all codes are released, so far)
Diffstat (limited to 'pcm')
-rw-r--r-- | pcm/Makefile.am | 2 | ||||
-rw-r--r-- | pcm/jack/Makefile.am | 10 | ||||
-rw-r--r-- | pcm/jack/README | 46 | ||||
-rw-r--r-- | pcm/jack/pcm_jack.c | 428 | ||||
-rw-r--r-- | pcm/oss/Makefile.am | 10 | ||||
-rw-r--r-- | pcm/oss/README | 33 | ||||
-rw-r--r-- | pcm/oss/pcm_oss.c | 423 |
7 files changed, 0 insertions, 952 deletions
diff --git a/pcm/Makefile.am b/pcm/Makefile.am deleted file mode 100644 index 9f0dd9a..0000000 --- a/pcm/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -SUBDIRS = oss jack - diff --git a/pcm/jack/Makefile.am b/pcm/jack/Makefile.am deleted file mode 100644 index e71ce65..0000000 --- a/pcm/jack/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -asound_module_pcm_jack_LTLIBRARIES = libasound_module_pcm_jack.la - -asound_module_pcm_jackdir = $(libdir)/alsa-lib - -AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ @JACK_CFLAGS@ -libasound_module_pcm_jack_la_SOURCES = pcm_jack.c -libasound_module_pcm_jack_la_LDFLAGS = -module -avoid-version -export-dynamic -libasound_module_pcm_jack_la_LIBADD = @ALSA_LIBS@ @JACK_LIBS@ - -EXTRA_DIST = README diff --git a/pcm/jack/README b/pcm/jack/README deleted file mode 100644 index 4579174..0000000 --- a/pcm/jack/README +++ /dev/null @@ -1,46 +0,0 @@ -JACK <--> ALSA PCM plugin -========================= - -This plugin converts the ALSA API over JACK (Jack Audio Connection -Kit, http://jackit.sf.net) API. ALSA native applications can work -transparently together with jackd for both playback and capture. - - ALSA apps (playback) -> ALSA-lib -> JACK plugin -> JACK deamon - ALSA apps (capture) <- ALSA-lib <- JACK plugin <- JACK daemon - -This plugin provides the PCM type "jack". The typical configuration -looks like below: - - pcm.jack { - type jack - playback_ports { - 0 alsa_pcm:playback_1 - 1 alsa_pcm:playback_1 - } - capture_ports { - 0 alsa_pcm:capture_1 - 1 alsa_pcm:pcapture_1 - } - } - -Put the above to ~/.asoundrc (or /etc/asound.conf), and use "jack" PCM -with your ALSA apps. For example, - - % aplay -Djack foo.wav - -The jack plugin can have two config options: playback_ports and -capture_ports. Both are compound type config, including the following -format: - { - channel port-name - channel port-name - ... - } -The first argument is the channel number (zero-based) and the second -is the corresponding JACK port name. - -The plugin is installed in /usr/lib/alsa-lib directory as default, -which is the default search path of additional plugins for alsa-lib. -On a 64bit system like x86-64, the proper prefix option (typically, ---prefix=/usr/lib64) must be given to configure script. - diff --git a/pcm/jack/pcm_jack.c b/pcm/jack/pcm_jack.c deleted file mode 100644 index 855f837..0000000 --- a/pcm/jack/pcm_jack.c +++ /dev/null @@ -1,428 +0,0 @@ -/* - * PCM - JACK plugin - * - * Copyright (c) 2003 by Maarten de Boer <mdeboer@iua.upf.es> - * 2005 Takashi Iwai <tiwai@suse.de> - * - * 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 <sys/shm.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <jack/jack.h> -#include <alsa/asoundlib.h> -#include <alsa/pcm_external.h> - -typedef enum _jack_format { - SND_PCM_JACK_FORMAT_RAW -} snd_pcm_jack_format_t; - -typedef struct { - snd_pcm_ioplug_t io; - - int fd; - int activated; /* jack is activated? */ - - char **port_names; - unsigned int num_ports; - unsigned int hw_ptr; - unsigned int sample_bits; - - unsigned int channels; - snd_pcm_channel_area_t *areas; - - jack_port_t **ports; - jack_client_t *client; -} snd_pcm_jack_t; - -static void snd_pcm_jack_free(snd_pcm_jack_t *jack) -{ - if (jack) { - unsigned int i; - if (jack->client) - jack_client_close(jack->client); - if (jack->port_names) { - for (i = 0; i < jack->num_ports; i++) - free(jack->port_names[i]); - free(jack->port_names); - } - close(jack->fd); - close(jack->io.poll_fd); - free(jack->areas); - free(jack); - } -} - -static int snd_pcm_jack_close(snd_pcm_ioplug_t *io) -{ - snd_pcm_jack_t *jack = io->private_data; - snd_pcm_jack_free(jack); - return 0; -} - -static int snd_pcm_jack_poll_revents(snd_pcm_ioplug_t *io, - struct pollfd *pfds, unsigned int nfds, - unsigned short *revents) -{ - static char buf[1]; - - assert(pfds && nfds == 1 && revents); - - read(pfds[0].fd, buf, 1); - - *revents = pfds[0].revents; - return 0; -} - -static snd_pcm_sframes_t snd_pcm_jack_pointer(snd_pcm_ioplug_t *io) -{ - snd_pcm_jack_t *jack = io->private_data; - return jack->hw_ptr; -} - -static int -snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t *io) -{ - snd_pcm_jack_t *jack = io->private_data; - const snd_pcm_channel_area_t *areas; - snd_pcm_uframes_t xfer = 0; - static char buf[1]; - unsigned int channel; - - for (channel = 0; channel < io->channels; channel++) { - jack->areas[channel].addr = - jack_port_get_buffer (jack->ports[channel], nframes); - jack->areas[channel].first = 0; - jack->areas[channel].step = jack->sample_bits; - } - - if (io->state != SND_PCM_STATE_RUNNING) { - if (io->stream == SND_PCM_STREAM_PLAYBACK) { - for (channel = 0; channel < io->channels; channel++) - snd_pcm_area_silence(&jack->areas[channel], 0, nframes, io->format); - return 0; - } - } - - areas = snd_pcm_ioplug_mmap_areas(io); - - while (xfer < nframes) { - snd_pcm_uframes_t frames = nframes - xfer; - snd_pcm_uframes_t offset = jack->hw_ptr; - snd_pcm_uframes_t cont = io->buffer_size - offset; - - if (cont < frames) - frames = cont; - - for (channel = 0; channel < io->channels; channel++) { - if (io->stream == SND_PCM_STREAM_PLAYBACK) - snd_pcm_area_copy(&jack->areas[channel], xfer, &areas[channel], offset, frames, io->format); - else - snd_pcm_area_copy(&areas[channel], offset, &jack->areas[channel], xfer, frames, io->format); - } - - jack->hw_ptr += frames; - jack->hw_ptr %= io->buffer_size; - xfer += frames; - } - - write(jack->fd, buf, 1); /* for polling */ - - return 0; -} - -static int snd_pcm_jack_prepare(snd_pcm_ioplug_t *io) -{ - snd_pcm_jack_t *jack = io->private_data; - unsigned int i; - - jack->hw_ptr = 0; - - if (jack->ports) - return 0; - - jack->ports = calloc(io->channels, sizeof(jack_port_t*)); - - for (i = 0; i < io->channels; i++) { - char port_name[32]; - if (io->stream == SND_PCM_STREAM_PLAYBACK) { - - sprintf(port_name, "out_%03d\n", i); - jack->ports[i] = jack_port_register(jack->client, port_name, - JACK_DEFAULT_AUDIO_TYPE, - JackPortIsOutput, 0); - } else { - sprintf(port_name, "in_%03d\n", i); - jack->ports[i] = jack_port_register(jack->client, port_name, - JACK_DEFAULT_AUDIO_TYPE, - JackPortIsInput, 0); - } - } - - jack_set_process_callback(jack->client, - (JackProcessCallback)snd_pcm_jack_process_cb, io); - return 0; -} - -static int snd_pcm_jack_start(snd_pcm_ioplug_t *io) -{ - snd_pcm_jack_t *jack = io->private_data; - unsigned int i; - - if (jack_activate (jack->client)) - return -EIO; - - jack->activated = 1; - - for (i = 0; i < io->channels && i < jack->num_ports; i++) { - if (jack->port_names[i]) { - const char *src, *dst; - if (io->stream == SND_PCM_STREAM_PLAYBACK) { - src = jack_port_name(jack->ports[i]); - dst = jack->port_names[i]; - } else { - src = jack->port_names[i]; - dst = jack_port_name(jack->ports[i]); - } - if (jack_connect(jack->client, src, dst)) { - fprintf(stderr, "cannot connect %s to %s\n", src, dst); - return -EIO; - } - } - } - - return 0; -} - -static int snd_pcm_jack_stop(snd_pcm_ioplug_t *io) -{ - snd_pcm_jack_t *jack = io->private_data; - - if (jack->activated) { - jack_deactivate(jack->client); - jack->activated = 0; - } -#if 0 - unsigned i; - for (i = 0; i < io->channels; i++) { - if (jack->ports[i]) { - jack_port_unregister(jack->client, jack->ports[i]); - jack->ports[i] = NULL; - } - } -#endif - return 0; -} - -static snd_pcm_ioplug_callback_t jack_pcm_callback = { - .close = snd_pcm_jack_close, - .start = snd_pcm_jack_start, - .stop = snd_pcm_jack_stop, - .pointer = snd_pcm_jack_pointer, - .prepare = snd_pcm_jack_prepare, - .poll_revents = snd_pcm_jack_poll_revents, -}; - -#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof(ary[0])) - -static int jack_set_hw_constraint(snd_pcm_jack_t *jack) -{ - unsigned int access_list[] = { - SND_PCM_ACCESS_MMAP_INTERLEAVED, - SND_PCM_ACCESS_MMAP_NONINTERLEAVED, - SND_PCM_ACCESS_RW_INTERLEAVED, - SND_PCM_ACCESS_RW_NONINTERLEAVED - }; - unsigned int format = SND_PCM_FORMAT_FLOAT; - unsigned int rate = jack_get_sample_rate(jack->client); - int err; - - jack->sample_bits = snd_pcm_format_physical_width(format); - if ((err = snd_pcm_ioplug_set_param_list(&jack->io, SND_PCM_IOPLUG_HW_ACCESS, - ARRAY_SIZE(access_list), access_list)) < 0 || - (err = snd_pcm_ioplug_set_param_list(&jack->io, SND_PCM_IOPLUG_HW_FORMAT, - 1, &format)) < 0 || - (err = snd_pcm_ioplug_set_param_minmax(&jack->io, SND_PCM_IOPLUG_HW_CHANNELS, - jack->channels, jack->channels)) < 0 || - (err = snd_pcm_ioplug_set_param_minmax(&jack->io, SND_PCM_IOPLUG_HW_RATE, - rate, rate)) < 0 || - (err = snd_pcm_ioplug_set_param_minmax(&jack->io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, - 128, 64*1024)) < 0 || - (err = snd_pcm_ioplug_set_param_minmax(&jack->io, SND_PCM_IOPLUG_HW_PERIODS, - 2, 64)) < 0) - return err; - - return 0; -} - -static int parse_ports(snd_pcm_jack_t *jack, snd_config_t *conf) -{ - snd_config_iterator_t i, next; - char **ports = NULL; - unsigned int cnt = 0; - unsigned int channel; - - if (conf) { - 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; - cnt++; - } - jack->port_names = ports = calloc(cnt, sizeof(char*)); - if (ports == NULL) - return -ENOMEM; - jack->num_ports = cnt; - snd_config_for_each(i, next, conf) { - snd_config_t *n = snd_config_iterator_entry(i); - const char *id; - const char *port; - - if (snd_config_get_id(n, &id) < 0) - continue; - channel = atoi(id); - if (snd_config_get_string(n, &port) < 0) - continue; - ports[channel] = port ? strdup(port) : NULL; - } - } - return 0; -} - -static int snd_pcm_jack_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) -{ - snd_pcm_jack_t *jack; - int err; - int fd[2]; - static unsigned int num = 0; - char jack_client_name[32]; - - assert(pcmp); - jack = calloc(1, sizeof(*jack)); - if (!jack) - return -ENOMEM; - - err = parse_ports(jack, stream == SND_PCM_STREAM_PLAYBACK ? - playback_conf : capture_conf); - if (err) { - snd_pcm_jack_free(jack); - return err; - } - - jack->channels = jack->num_ports; - if (jack->channels == 0) { - SNDERR("define the %s_ports section", - stream == SND_PCM_STREAM_PLAYBACK ? "playback" : "capture"); - snd_pcm_jack_free(jack); - return -EINVAL; - } - - if (snprintf(jack_client_name, sizeof(jack_client_name), "alsa-jack.%s%s.%d.%d", name, - stream == SND_PCM_STREAM_PLAYBACK ? "P" : "C", getpid(), num++) - >= (int)sizeof(jack_client_name)) { - fprintf(stderr, "%s: WARNING: JACK client name '%s' truncated to %d characters, might not be unique\n", - __func__, jack_client_name, (int)strlen(jack_client_name)); - } - - jack->client = jack_client_new(jack_client_name); - - if (jack->client == 0) { - snd_pcm_jack_free(jack); - return -ENOENT; - } - - jack->areas = calloc(jack->channels, sizeof(snd_pcm_channel_area_t)); - if (! jack->areas) { - snd_pcm_jack_free(jack); - return -ENOMEM; - } - - socketpair(AF_LOCAL, SOCK_STREAM, 0, fd); - - jack->fd = fd[0]; - - jack->io.version = SND_PCM_IOPLUG_VERSION; - jack->io.name = "ALSA <-> JACK PCM I/O Plugin"; - jack->io.callback = &jack_pcm_callback; - jack->io.private_data = jack; - jack->io.poll_fd = fd[1]; - jack->io.poll_events = POLLIN; - jack->io.mmap_rw = 1; - - err = snd_pcm_ioplug_create(&jack->io, name, stream, mode); - if (err < 0) { - snd_pcm_jack_free(jack); - return err; - } - - err = jack_set_hw_constraint(jack); - if (err < 0) { - snd_pcm_ioplug_delete(&jack->io); - return err; - } - - *pcmp = jack->io.pcm; - - return 0; -} - - -SND_PCM_PLUGIN_DEFINE_FUNC(jack) -{ - snd_config_iterator_t i, next; - snd_config_t *playback_conf = NULL; - snd_config_t *capture_conf = NULL; - int err; - - 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_jack_open(pcmp, name, playback_conf, capture_conf, stream, mode); - - return err; -} - -SND_PCM_PLUGIN_SYMBOL(jack); diff --git a/pcm/oss/Makefile.am b/pcm/oss/Makefile.am deleted file mode 100644 index c907231..0000000 --- a/pcm/oss/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -asound_module_pcm_oss_LTLIBRARIES = libasound_module_pcm_oss.la - -asound_module_pcm_ossdir = $(libdir)/alsa-lib - -AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ -libasound_module_pcm_oss_la_SOURCES = pcm_oss.c -libasound_module_pcm_oss_la_LDFLAGS = -module -avoid-version -export-dynamic -libasound_module_pcm_oss_la_LIBADD = @ALSA_LIBS@ - -EXTRA_DIST = README diff --git a/pcm/oss/README b/pcm/oss/README deleted file mode 100644 index 42b73cb..0000000 --- a/pcm/oss/README +++ /dev/null @@ -1,33 +0,0 @@ -OSS <--> ALSA PCM plugin -======================== - -This plugin converts the ALSA API over OSS API. With this plugin, -ALSA native apps can run on OSS drivers. - -This plugin provides the PCM type "oss". The typical configuration -looks like below: - - pcm.oss { - type oss - device /dev/dsp - } - -Put the above to ~/.asoundrc (or /etc/asound.conf), and use "oss" PCM -with your ALSA apps. For example, - - % aplay -Doss foo.wav - -For playing arbitrary formats, you should use "plug" layer together, - - % aplay -Dplug:oss foo.wav - -The oss plugin can have an option: device. This specifies the device -file path of OSS to open. If not given, /dev/dsp is used. - -The function supported by this plugin is limited. For example, you -cannot use dmix together with this plugin. Don't expect too much :) - -The plugin is installed in /usr/lib/alsa-lib directory as default, -which is the default search path of additional plugins for alsa-lib. -On a 64bit system like x86-64, the proper prefix option (typically, ---prefix=/usr/lib64) must be given to configure script. diff --git a/pcm/oss/pcm_oss.c b/pcm/oss/pcm_oss.c deleted file mode 100644 index fb520f8..0000000 --- a/pcm/oss/pcm_oss.c +++ /dev/null @@ -1,423 +0,0 @@ -/* - * ALSA <-> OSS PCM I/O plugin - * - * Copyright (c) 2005 by Takashi Iwai <tiwai@suse.de> - * - * 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 <stdio.h> -#include <sys/ioctl.h> -#include <alsa/asoundlib.h> -#include <alsa/pcm_external.h> -#include <linux/soundcard.h> - -typedef struct snd_pcm_oss { - snd_pcm_ioplug_t io; - char *device; - int fd; - int fragment_set; - int caps; - int format; - unsigned int period_shift; - unsigned int periods; - unsigned int frame_bytes; -} snd_pcm_oss_t; - -static snd_pcm_sframes_t oss_write(snd_pcm_ioplug_t *io, - const snd_pcm_channel_area_t *areas, - snd_pcm_uframes_t offset, - snd_pcm_uframes_t size) -{ - snd_pcm_oss_t *oss = io->private_data; - const char *buf; - ssize_t result; - - /* we handle only an interleaved buffer */ - buf = (char *)areas->addr + (areas->first + areas->step * offset) / 8; - size *= oss->frame_bytes; - result = write(oss->fd, buf, size); - if (result <= 0) - return result; - return result / oss->frame_bytes; -} - -static snd_pcm_sframes_t oss_read(snd_pcm_ioplug_t *io, - const snd_pcm_channel_area_t *areas, - snd_pcm_uframes_t offset, - snd_pcm_uframes_t size) -{ - snd_pcm_oss_t *oss = io->private_data; - char *buf; - ssize_t result; - - /* we handle only an interleaved buffer */ - buf = (char *)areas->addr + (areas->first + areas->step * offset) / 8; - size *= oss->frame_bytes; - result = read(oss->fd, buf, size); - if (result <= 0) - return result; - return result / oss->frame_bytes; -} - -static snd_pcm_sframes_t oss_pointer(snd_pcm_ioplug_t *io) -{ - snd_pcm_oss_t *oss = io->private_data; - struct count_info info; - int ptr; - - if (ioctl(oss->fd, io->stream == SND_PCM_STREAM_PLAYBACK ? - SNDCTL_DSP_GETOPTR : SNDCTL_DSP_GETIPTR, &info) < 0) { - fprintf(stderr, "*** OSS: oss_pointer error\n"); - return 0; - } - ptr = snd_pcm_bytes_to_frames(io->pcm, info.ptr); - return ptr; -} - -static int oss_start(snd_pcm_ioplug_t *io) -{ - snd_pcm_oss_t *oss = io->private_data; - int tmp = io->stream == SND_PCM_STREAM_PLAYBACK ? - PCM_ENABLE_OUTPUT : PCM_ENABLE_INPUT; - - if (ioctl(oss->fd, SNDCTL_DSP_SETTRIGGER, &tmp) < 0) { - fprintf(stderr, "*** OSS: trigger failed\n"); - if (io->stream == SND_PCM_STREAM_CAPTURE) - /* fake read to trigger */ - read(oss->fd, &tmp, 0); - } - return 0; -} - -static int oss_stop(snd_pcm_ioplug_t *io) -{ - snd_pcm_oss_t *oss = io->private_data; - int tmp = 0; - - ioctl(oss->fd, SNDCTL_DSP_SETTRIGGER, &tmp); - return 0; -} - -static int oss_drain(snd_pcm_ioplug_t *io) -{ - snd_pcm_oss_t *oss = io->private_data; - - if (io->stream == SND_PCM_STREAM_PLAYBACK) - ioctl(oss->fd, SNDCTL_DSP_SYNC); - return 0; -} - -static int oss_prepare(snd_pcm_ioplug_t *io) -{ - snd_pcm_oss_t *oss = io->private_data; - int tmp; - - ioctl(oss->fd, SNDCTL_DSP_RESET); - - tmp = io->channels; - if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &tmp) < 0) { - perror("SNDCTL_DSP_CHANNELS"); - return -EINVAL; - } - tmp = oss->format; - if (ioctl(oss->fd, SNDCTL_DSP_SETFMT, &tmp) < 0) { - perror("SNDCTL_DSP_SETFMT"); - return -EINVAL; - } - tmp = io->rate; - if (ioctl(oss->fd, SNDCTL_DSP_SPEED, &tmp) < 0 || - tmp > io->rate * 1.01 || tmp < io->rate * 0.99) { - perror("SNDCTL_DSP_SPEED"); - return -EINVAL; - } - return 0; -} - -static int oss_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params) -{ - snd_pcm_oss_t *oss = io->private_data; - int i, tmp, err; - unsigned int period_bytes; - long oflags, flags; - - oss->frame_bytes = (snd_pcm_format_physical_width(io->format) * io->channels) / 8; - switch (io->format) { - case SND_PCM_FORMAT_U8: - oss->format = AFMT_U8; - break; - case SND_PCM_FORMAT_S16_LE: - oss->format = AFMT_S16_LE; - break; - case SND_PCM_FORMAT_S16_BE: - oss->format = AFMT_S16_BE; - break; - default: - fprintf(stderr, "*** OSS: unsupported format %s\n", snd_pcm_format_name(io->format)); - return -EINVAL; - } - period_bytes = io->period_size * oss->frame_bytes; - oss->period_shift = 0; - for (i = 31; i >= 4; i--) { - if (period_bytes & (1U << i)) { - oss->period_shift = i; - break; - } - } - if (! oss->period_shift) { - fprintf(stderr, "*** OSS: invalid period size %d\n", (int)io->period_size); - return -EINVAL; - } - - _retry: - tmp = oss->period_shift | (oss->periods << 16); - if (ioctl(oss->fd, SNDCTL_DSP_SETFRAGMENT, &tmp) < 0) { - if (! oss->fragment_set) { - perror("SNDCTL_DSP_SETFRAGMENT"); - fprintf(stderr, "*** period shift = %d, periods = %d\n", oss->period_shift, oss->periods); - return -EINVAL; - } - /* OSS has no proper way to reinitialize the fragments */ - /* try to reopen the device */ - close(oss->fd); - oss->fd = open(oss->device, io->stream == SND_PCM_STREAM_PLAYBACK ? - O_WRONLY : O_RDONLY); - if (oss->fd < 0) { - err = -errno; - SNDERR("Cannot reopen the device %s", oss->device); - return err; - } - io->poll_fd = oss->fd; - io->poll_events = io->stream == SND_PCM_STREAM_PLAYBACK ? - POLLOUT : POLLIN; - snd_pcm_ioplug_reinit_status(io); - oss->fragment_set = 0; - goto _retry; - } - oss->fragment_set = 1; - - if ((flags = fcntl(oss->fd, F_GETFL)) < 0) { - err = -errno; - perror("F_GETFL"); - } else { - oflags = flags; - if (io->nonblock) - flags |= O_NONBLOCK; - else - flags &= ~O_NONBLOCK; - if (flags != oflags && - fcntl(oss->fd, F_SETFL, flags) < 0) { - err = -errno; - perror("F_SETFL"); - } - } - - return 0; -} - -#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof(ary[0])) - -static int oss_hw_constraint(snd_pcm_oss_t *oss) -{ - snd_pcm_ioplug_t *io = &oss->io; - static snd_pcm_access_t access_list[] = { - SND_PCM_ACCESS_RW_INTERLEAVED, - SND_PCM_ACCESS_MMAP_INTERLEAVED - }; - unsigned int nformats; - unsigned int format[5]; - unsigned int nchannels; - unsigned int channel[6]; - /* period and buffer bytes must be power of two */ - static unsigned int bytes_list[] = { - 1U<<8, 1U<<9, 1U<<10, 1U<<11, 1U<<12, 1U<<13, 1U<<14, 1U<<15, - 1U<<16, 1U<<17, 1U<<18, 1U<<19, 1U<<20, 1U<<21, 1U<<22, 1U<<23 - }; - int i, err, tmp; - - /* check trigger */ - oss->caps = 0; - if (ioctl(oss->fd, SNDCTL_DSP_GETCAPS, &oss->caps) >= 0) { - if (! (oss->caps & DSP_CAP_TRIGGER)) - fprintf(stderr, "*** OSS: trigger is not supported!\n"); - } - - /* access type - interleaved only */ - if ((err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS, - ARRAY_SIZE(access_list), access_list)) < 0) - return err; - - /* supported formats */ - tmp = 0; - ioctl(oss->fd, SNDCTL_DSP_GETFMTS, &tmp); - nformats = 0; - if (tmp & AFMT_U8) - format[nformats++] = SND_PCM_FORMAT_U8; - if (tmp & AFMT_S16_LE) - format[nformats++] = SND_PCM_FORMAT_S16_LE; - if (tmp & AFMT_S16_BE) - format[nformats++] = SND_PCM_FORMAT_S16_BE; - if (tmp & AFMT_MU_LAW) - format[nformats++] = SND_PCM_FORMAT_MU_LAW; - if (! nformats) - format[nformats++] = SND_PCM_FORMAT_S16; - if ((err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT, - nformats, format)) < 0) - return err; - - /* supported channels */ - nchannels = 0; - for (i = 0; i < 6; i++) { - tmp = i + 1; - if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &tmp) >= 0) - channel[nchannels++] = tmp; - } - if (! nchannels) /* assume 2ch stereo */ - err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS, - 2, 2); - else - err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_CHANNELS, - nchannels, channel); - if (err < 0) - return err; - - /* supported rates */ - /* FIXME: should query? */ - err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE, 8000, 480000); - if (err < 0) - return err; - - /* period size (in power of two) */ - err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, - ARRAY_SIZE(bytes_list), bytes_list); - if (err < 0) - return err; - /* periods */ - err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS, 2, 1024); - if (err < 0) - return err; - /* buffer size (in power of two) */ - err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_BUFFER_BYTES, - ARRAY_SIZE(bytes_list), bytes_list); - if (err < 0) - return err; - - return 0; -} - - -static int oss_close(snd_pcm_ioplug_t *io) -{ - snd_pcm_oss_t *oss = io->private_data; - - close(oss->fd); - free(oss->device); - free(oss); - return 0; -} - -static snd_pcm_ioplug_callback_t oss_playback_callback = { - .start = oss_start, - .stop = oss_stop, - .transfer = oss_write, - .pointer = oss_pointer, - .close = oss_close, - .hw_params = oss_hw_params, - .prepare = oss_prepare, - .drain = oss_drain, -}; - -static snd_pcm_ioplug_callback_t oss_capture_callback = { - .start = oss_start, - .stop = oss_stop, - .transfer = oss_read, - .pointer = oss_pointer, - .close = oss_close, - .hw_params = oss_hw_params, - .prepare = oss_prepare, - .drain = oss_drain, -}; - - -SND_PCM_PLUGIN_DEFINE_FUNC(oss) -{ - snd_config_iterator_t i, next; - const char *device = "/dev/dsp"; - int err; - snd_pcm_oss_t *oss; - - 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, "device") == 0) { - if (snd_config_get_string(n, &device) < 0) { - SNDERR("Invalid type for %s", id); - return -EINVAL; - } - continue; - } - SNDERR("Unknown field %s", id); - return -EINVAL; - } - - oss = calloc(1, sizeof(*oss)); - oss->device = strdup(device); - if (oss->device == NULL) { - SNDERR("cannot allocate"); - free(oss); - return -ENOMEM; - } - oss->fd = open(device, stream == SND_PCM_STREAM_PLAYBACK ? - O_WRONLY : O_RDONLY); - if (oss->fd < 0) { - err = -errno; - SNDERR("Cannot open device %s", device); - goto error; - } - - oss->io.version = SND_PCM_IOPLUG_VERSION; - oss->io.name = "ALSA <-> OSS PCM I/O Plugin"; - oss->io.poll_fd = oss->fd; - oss->io.poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; - oss->io.mmap_rw = 0; - oss->io.callback = stream == SND_PCM_STREAM_PLAYBACK ? - &oss_playback_callback : &oss_capture_callback; - oss->io.private_data = oss; - - err = snd_pcm_ioplug_create(&oss->io, name, stream, mode); - if (err < 0) - goto error; - - if ((err = oss_hw_constraint(oss)) < 0) { - snd_pcm_ioplug_delete(&oss->io); - return err; - } - - *pcmp = oss->io.pcm; - return 0; - - error: - if (oss->fd >= 0) - close(oss->fd); - free(oss->device); - free(oss); - return err; -} - -SND_PCM_PLUGIN_SYMBOL(oss); |