From: Abramo Bagnara Date: Thu, 1 Mar 2001 22:47:34 +0000 (+0000) Subject: Added pcm_meter skeleton X-Git-Tag: v1.0.3~935 X-Git-Url: https://git.alsa-project.org/?a=commitdiff_plain;h=d87059867bc14360091c2f9fdee80d4764d0d1a3;p=alsa-lib.git Added pcm_meter skeleton --- diff --git a/src/pcm/Makefile.am b/src/pcm/Makefile.am index 84d5adbb..47fccb76 100644 --- a/src/pcm/Makefile.am +++ b/src/pcm/Makefile.am @@ -5,7 +5,7 @@ libpcm_la_SOURCES = atomic.c mask.c interval.c \ pcm.c pcm_m4.c pcm_hw.c pcm_plugin.c pcm_copy.c pcm_linear.c \ pcm_route.c pcm_mulaw.c pcm_alaw.c pcm_adpcm.c \ pcm_rate.c pcm_plug.c pcm_misc.c pcm_mmap.c pcm_multi.c \ - pcm_shm.c pcm_file.c pcm_share.c pcm_null.c \ + pcm_shm.c pcm_file.c pcm_share.c pcm_null.c pcm_meter.c \ pcm_params.c noinst_HEADERS = atomic.h pcm_local.h pcm_plugin.h mask.h mask_inline.h \ interval.h interval_inline.h plugin_ops.h diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index 199db0d1..4234fbf8 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -166,7 +166,26 @@ struct _snd_pcm { void *private_data; }; +#define ROUTE_PLUGIN_FLOAT 1 +#define ROUTE_PLUGIN_RESOLUTION 16 + +#if ROUTE_PLUGIN_FLOAT +typedef float snd_pcm_route_ttable_entry_t; +#define HALF 0.5 +#define FULL 1.0 +#else +typedef int snd_pcm_route_ttable_entry_t; +#define HALF (ROUTE_PLUGIN_RESOLUTION / 2) +#define FULL ROUTE_PLUGIN_RESOLUTION +#endif + int snd_pcm_hw_open(snd_pcm_t **pcm, const char *name, int card, int device, int subdevice, snd_pcm_stream_t stream, int mode); +int snd_pcm_plug_open(snd_pcm_t **pcmp, + const char *name, + snd_pcm_route_ttable_entry_t *ttable, + unsigned int tt_ssize, + unsigned int tt_cused, unsigned int tt_sused, + snd_pcm_t *slave, int close_slave); int snd_pcm_plug_open_hw(snd_pcm_t **pcm, const char *name, int card, int device, int subdevice, snd_pcm_stream_t stream, int mode); int snd_pcm_shm_open(snd_pcm_t **pcmp, const char *name, const char *socket, const char *sname, snd_pcm_stream_t stream, int mode); int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, const char *fname, int fd, const char *fmt, snd_pcm_t *slave, int close_slave); diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c new file mode 100644 index 00000000..279f22db --- /dev/null +++ b/src/pcm/pcm_meter.c @@ -0,0 +1,686 @@ +/* + * PCM - Meter plugin + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include "pcm_local.h" +#include "pcm_plugin.h" +#include "list.h" + +#define FPS 50 + +typedef struct _snd_pcm_meter_scope snd_pcm_meter_scope_t; + +struct _snd_pcm_meter_scope { + snd_pcm_t *pcm; + char *name; + void (*init)(snd_pcm_meter_scope_t *scope); + void (*start)(snd_pcm_meter_scope_t *scope); + void (*stop)(snd_pcm_meter_scope_t *scope); + void (*update)(snd_pcm_meter_scope_t *scope); + void (*reset)(snd_pcm_meter_scope_t *scope); + void (*close)(snd_pcm_meter_scope_t *scope); + void *private_data; + struct list_head list; +}; + +typedef struct _snd_pcm_meter { + snd_pcm_t *slave; + int close_slave; + snd_pcm_uframes_t rptr; + snd_pcm_uframes_t buf_size; + snd_pcm_channel_area_t *buf_areas; + snd_pcm_uframes_t now; + char *buf; + pthread_t thread; + int closed; + struct list_head scopes; + int running; + atomic_t reset; + pthread_mutex_t update_mutex; + pthread_mutex_t running_mutex; + pthread_cond_t running_cond; +} snd_pcm_meter_t; + +void debug_init(snd_pcm_meter_scope_t *scope ATTRIBUTE_UNUSED) +{ + fprintf(stderr, "init\n"); +} + +void debug_start(snd_pcm_meter_scope_t *scope ATTRIBUTE_UNUSED) +{ + fprintf(stderr, "start\n"); +} + +void debug_stop(snd_pcm_meter_scope_t *scope ATTRIBUTE_UNUSED) +{ + fprintf(stderr, "stop\n"); +} + +void debug_update(snd_pcm_meter_scope_t *scope ATTRIBUTE_UNUSED) +{ + snd_pcm_meter_t *meter = scope->pcm->private_data; + fprintf(stderr, "update %ld\r", meter->now); +} + +void debug_reset(snd_pcm_meter_scope_t *scope ATTRIBUTE_UNUSED) +{ + fprintf(stderr, "reset\n"); +} + +void debug_close(snd_pcm_meter_scope_t *scope ATTRIBUTE_UNUSED) +{ + fprintf(stderr, "close\n"); +} + +snd_pcm_meter_scope_t debug_scope = { + name: "debug", + init: debug_init, + start: debug_start, + stop: debug_stop, + update: debug_update, + reset: debug_reset, + close: debug_close, + pcm: NULL, + list: { 0, 0 }, + private_data: NULL, +}; + +void snd_pcm_meter_add_scope(snd_pcm_t *pcm, snd_pcm_meter_scope_t *scope) +{ + snd_pcm_meter_t *meter = pcm->private_data; + scope->pcm = pcm; + list_add_tail(&scope->list, &meter->scopes); + scope->init(scope); +} + +void snd_pcm_meter_add_frames(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t ptr, + snd_pcm_uframes_t frames) +{ + snd_pcm_meter_t *meter = pcm->private_data; + while (frames > 0) { + snd_pcm_uframes_t n = frames; + snd_pcm_uframes_t dst_offset = ptr % meter->buf_size; + snd_pcm_uframes_t src_offset = ptr % pcm->buffer_size; + snd_pcm_uframes_t dst_cont = meter->buf_size - dst_offset; + snd_pcm_uframes_t src_cont = pcm->buffer_size - src_offset; + if (n > dst_cont) + n = dst_cont; + if (n > src_cont) + n = src_cont; + snd_pcm_areas_copy(meter->buf_areas, dst_offset, + areas, src_offset, + pcm->channels, n, pcm->format); + frames -= n; + ptr += n; + if (ptr == pcm->boundary) + ptr = 0; + } +} + +static void snd_pcm_meter_update_main(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + snd_pcm_sframes_t frames; + snd_pcm_uframes_t rptr, old_rptr; + const snd_pcm_channel_area_t *areas; + int locked; + locked = (pthread_mutex_trylock(&meter->update_mutex) >= 0); + areas = snd_pcm_mmap_areas(pcm); + rptr = *pcm->hw_ptr; + old_rptr = meter->rptr; + meter->rptr = rptr; + frames = rptr - old_rptr; + if (frames < 0) + frames += pcm->boundary; + if (frames > 0) { + assert((snd_pcm_uframes_t) frames <= pcm->buffer_size); + snd_pcm_meter_add_frames(pcm, areas, old_rptr, frames); + } + if (locked) + pthread_mutex_unlock(&meter->update_mutex); +} + +static int snd_pcm_meter_update_scope(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + snd_pcm_sframes_t frames; + snd_pcm_uframes_t rptr, old_rptr; + const snd_pcm_channel_area_t *areas; + int reset = 0; + /* Wait main thread */ + pthread_mutex_lock(&meter->update_mutex); + areas = snd_pcm_mmap_areas(pcm); + _again: + rptr = *pcm->hw_ptr; + old_rptr = meter->rptr; + rmb(); + if (atomic_read(&meter->reset)) { + reset = 1; + atomic_dec(&meter->reset); + goto _again; + } + meter->rptr = rptr; + frames = rptr - old_rptr; + if (frames < 0) + frames += pcm->boundary; + if (frames > 0) { + assert((snd_pcm_uframes_t) frames <= pcm->buffer_size); + snd_pcm_meter_add_frames(pcm, areas, old_rptr, frames); + } + pthread_mutex_unlock(&meter->update_mutex); + return reset; +} + +static void *snd_pcm_meter_thread(void *data) +{ + snd_pcm_t *pcm = data; + snd_pcm_meter_t *meter = pcm->private_data; + snd_pcm_t *spcm = meter->slave; + struct list_head *pos; + snd_pcm_meter_scope_t *scope; + int reset; + struct timespec delay = { + tv_sec: 0, + tv_nsec: 1000000000 / FPS, + }; + while (!meter->closed) { + snd_pcm_sframes_t now; + snd_pcm_status_t status; + int err; + pthread_mutex_lock(&meter->running_mutex); + err = snd_pcm_status(spcm, &status); + assert(err >= 0); + if (status.state != SND_PCM_STATE_RUNNING && + (status.state != SND_PCM_STATE_DRAINING || + spcm->stream != SND_PCM_STREAM_PLAYBACK)) { + if (meter->running) { + list_for_each(pos, &meter->scopes) { + scope = list_entry(pos, snd_pcm_meter_scope_t, list); + scope->stop(scope); + } + meter->running = 0; + } + pthread_cond_wait(&meter->running_cond, + &meter->running_mutex); + pthread_mutex_unlock(&meter->running_mutex); + continue; + } + pthread_mutex_unlock(&meter->running_mutex); + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + now = status.appl_ptr - status.delay; + if (now < 0) + now += pcm->boundary; + } else { + now = status.appl_ptr + status.delay; + if ((snd_pcm_uframes_t) now >= pcm->boundary) + now -= pcm->boundary; + } + meter->now = now % meter->buf_size; + if (pcm->stream == SND_PCM_STREAM_CAPTURE) + reset = snd_pcm_meter_update_scope(pcm); + else { + reset = 0; + while (atomic_read(&meter->reset)) { + reset = 1; + atomic_dec(&meter->reset); + } + } + if (!meter->running) { + list_for_each(pos, &meter->scopes) { + scope = list_entry(pos, snd_pcm_meter_scope_t, list); + scope->start(scope); + } + meter->running = 1; + } else if (reset) { + list_for_each(pos, &meter->scopes) { + scope = list_entry(pos, snd_pcm_meter_scope_t, list); + scope->reset(scope); + } + } + list_for_each(pos, &meter->scopes) { + scope = list_entry(pos, snd_pcm_meter_scope_t, list); + scope->update(scope); + } + nanosleep(&delay, NULL); + } + list_for_each(pos, &meter->scopes) { + scope = list_entry(pos, snd_pcm_meter_scope_t, list); + scope->close(scope); + } + return NULL; +} + + +static int snd_pcm_meter_close(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + int err = 0; + if (meter->close_slave) + err = snd_pcm_close(meter->slave); + meter->closed = 1; + pthread_mutex_lock(&meter->running_mutex); + pthread_cond_signal(&meter->running_cond); + pthread_mutex_unlock(&meter->running_mutex); + err = pthread_join(meter->thread, 0); + assert(err == 0); + pthread_mutex_destroy(&meter->update_mutex); + pthread_mutex_destroy(&meter->running_mutex); + pthread_cond_destroy(&meter->running_cond); + free(meter); + return 0; +} + +static int snd_pcm_meter_nonblock(snd_pcm_t *pcm, int nonblock) +{ + snd_pcm_meter_t *meter = pcm->private_data; + return snd_pcm_nonblock(meter->slave, nonblock); +} + +static int snd_pcm_meter_async(snd_pcm_t *pcm, int sig, pid_t pid) +{ + snd_pcm_meter_t *meter = pcm->private_data; + return snd_pcm_async(meter->slave, sig, pid); +} + +static int snd_pcm_meter_info(snd_pcm_t *pcm, snd_pcm_info_t * info) +{ + snd_pcm_meter_t *meter = pcm->private_data; + return snd_pcm_info(meter->slave, info); +} + +static int snd_pcm_meter_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info) +{ + snd_pcm_meter_t *meter = pcm->private_data; + return snd_pcm_channel_info(meter->slave, info); +} + +static int snd_pcm_meter_status(snd_pcm_t *pcm, snd_pcm_status_t * status) +{ + snd_pcm_meter_t *meter = pcm->private_data; + return snd_pcm_status(meter->slave, status); +} + +static snd_pcm_state_t snd_pcm_meter_state(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + return snd_pcm_state(meter->slave); +} + +static int snd_pcm_meter_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +{ + snd_pcm_meter_t *meter = pcm->private_data; + return snd_pcm_delay(meter->slave, delayp); +} + +static int snd_pcm_meter_prepare(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + int err; + atomic_inc(&meter->reset); + err = snd_pcm_prepare(meter->slave); + if (err >= 0) { + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + meter->rptr = *pcm->appl_ptr; + else + meter->rptr = *pcm->hw_ptr; + } + return err; +} + +static int snd_pcm_meter_reset(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + int err = snd_pcm_reset(meter->slave); + if (err >= 0) { + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + meter->rptr = *pcm->appl_ptr; + } + return err; +} + +static int snd_pcm_meter_start(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + int err; + pthread_mutex_lock(&meter->running_mutex); + err = snd_pcm_start(meter->slave); + if (err >= 0) + pthread_cond_signal(&meter->running_cond); + pthread_mutex_unlock(&meter->running_mutex); + return err; +} + +static int snd_pcm_meter_drop(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + return snd_pcm_drop(meter->slave); +} + +static int snd_pcm_meter_drain(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + return snd_pcm_drain(meter->slave); +} + +static int snd_pcm_meter_pause(snd_pcm_t *pcm, int enable) +{ + snd_pcm_meter_t *meter = pcm->private_data; + return snd_pcm_pause(meter->slave, enable); +} + +static snd_pcm_sframes_t snd_pcm_meter_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_meter_t *meter = pcm->private_data; + snd_pcm_sframes_t err = snd_pcm_rewind(meter->slave, frames); + if (err > 0 && pcm->stream == SND_PCM_STREAM_PLAYBACK) + meter->rptr = *pcm->appl_ptr; + return err; +} + +static snd_pcm_sframes_t snd_pcm_meter_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t size) +{ + snd_pcm_meter_t *meter = pcm->private_data; + snd_pcm_uframes_t old_rptr = *pcm->appl_ptr; + snd_pcm_sframes_t result = snd_pcm_mmap_forward(meter->slave, size); + if (result <= 0) + return result; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + snd_pcm_meter_add_frames(pcm, snd_pcm_mmap_areas(pcm), old_rptr, result); + meter->rptr = *pcm->appl_ptr; + } + return result; +} + +static snd_pcm_sframes_t snd_pcm_meter_avail_update(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + snd_pcm_sframes_t result = snd_pcm_avail_update(meter->slave); + if (result <= 0) + return result; + if (pcm->stream == SND_PCM_STREAM_CAPTURE) + snd_pcm_meter_update_main(pcm); + return result; +} + +static int snd_pcm_meter_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) +{ + int err; + snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_PLUGIN }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} + +static int snd_pcm_meter_hw_refine_sprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + return 0; +} + +static int snd_pcm_meter_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS; + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_meter_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS; + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} + +int snd_pcm_meter_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_meter_t *meter = pcm->private_data; + return snd_pcm_hw_refine(meter->slave, params); +} + +int snd_pcm_meter_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_meter_t *meter = pcm->private_data; + return _snd_pcm_hw_params(meter->slave, params); +} + +static int snd_pcm_meter_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_meter_hw_refine_cprepare, + snd_pcm_meter_hw_refine_cchange, + snd_pcm_meter_hw_refine_sprepare, + snd_pcm_meter_hw_refine_schange, + snd_pcm_meter_hw_refine_slave); +} + +static int snd_pcm_meter_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +{ + snd_pcm_meter_t *meter = pcm->private_data; + unsigned int channel; + snd_pcm_t *slave = meter->slave; + size_t buf_size_bytes; + int err; + err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_meter_hw_refine_cchange, + snd_pcm_meter_hw_refine_sprepare, + snd_pcm_meter_hw_refine_schange, + snd_pcm_meter_hw_params_slave); + if (err < 0) + return err; + /* more than 1 second of buffer */ + meter->buf_size = slave->buffer_size; + while (meter->buf_size < slave->rate) + meter->buf_size *= 2; + buf_size_bytes = snd_pcm_frames_to_bytes(slave, meter->buf_size); + assert(!meter->buf); + meter->buf = malloc(buf_size_bytes); + meter->buf_areas = malloc(sizeof(*meter->buf_areas) * slave->channels); + for (channel = 0; channel < slave->channels; ++channel) { + snd_pcm_channel_area_t *a = &meter->buf_areas[channel]; + a->addr = meter->buf + buf_size_bytes / slave->channels * channel; + a->first = 0; + a->step = slave->sample_bits; + } + return 0; +} + +static int snd_pcm_meter_hw_free(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + if (meter->buf) { + free(meter->buf); + free(meter->buf_areas); + meter->buf = 0; + meter->buf_areas = 0; + } + return snd_pcm_hw_free(meter->slave); +} + +static int snd_pcm_meter_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) +{ + snd_pcm_meter_t *meter = pcm->private_data; + return snd_pcm_sw_params(meter->slave, params); +} + +static int snd_pcm_meter_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_pcm_meter_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + +static void snd_pcm_meter_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_meter_t *meter = pcm->private_data; + snd_output_printf(out, "Meter PCM\n"); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(meter->slave, out); +} + +snd_pcm_ops_t snd_pcm_meter_ops = { + close: snd_pcm_meter_close, + info: snd_pcm_meter_info, + hw_refine: snd_pcm_meter_hw_refine, + hw_params: snd_pcm_meter_hw_params, + hw_free: snd_pcm_meter_hw_free, + sw_params: snd_pcm_meter_sw_params, + channel_info: snd_pcm_meter_channel_info, + dump: snd_pcm_meter_dump, + nonblock: snd_pcm_meter_nonblock, + async: snd_pcm_meter_async, + mmap: snd_pcm_meter_mmap, + munmap: snd_pcm_meter_munmap, +}; + +snd_pcm_fast_ops_t snd_pcm_meter_fast_ops = { + status: snd_pcm_meter_status, + state: snd_pcm_meter_state, + delay: snd_pcm_meter_delay, + prepare: snd_pcm_meter_prepare, + reset: snd_pcm_meter_reset, + start: snd_pcm_meter_start, + drop: snd_pcm_meter_drop, + drain: snd_pcm_meter_drain, + pause: snd_pcm_meter_pause, + rewind: snd_pcm_meter_rewind, + writei: snd_pcm_mmap_writei, + writen: snd_pcm_mmap_writen, + readi: snd_pcm_mmap_readi, + readn: snd_pcm_mmap_readn, + avail_update: snd_pcm_meter_avail_update, + mmap_forward: snd_pcm_meter_mmap_forward, +}; + +int snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int close_slave) +{ + snd_pcm_t *pcm; + snd_pcm_meter_t *meter; + int err; + assert(pcmp); + meter = calloc(1, sizeof(snd_pcm_meter_t)); + if (!meter) + return -ENOMEM; + meter->slave = slave; + meter->close_slave = close_slave; + INIT_LIST_HEAD(&meter->scopes); + + pcm = calloc(1, sizeof(snd_pcm_t)); + if (!pcm) { + free(meter); + return -ENOMEM; + } + if (name) + pcm->name = strdup(name); + pcm->type = SND_PCM_TYPE_METER; + pcm->stream = slave->stream; + pcm->mode = slave->mode; + pcm->mmap_rw = 1; + pcm->ops = &snd_pcm_meter_ops; + pcm->op_arg = pcm; + pcm->fast_ops = &snd_pcm_meter_fast_ops; + pcm->fast_op_arg = pcm; + pcm->private_data = meter; + pcm->poll_fd = slave->poll_fd; + pcm->hw_ptr = slave->hw_ptr; + pcm->appl_ptr = slave->appl_ptr; + *pcmp = pcm; + +#if 1 + snd_pcm_meter_add_scope(pcm, &debug_scope); +#endif + pthread_mutex_init(&meter->update_mutex, NULL); + pthread_mutex_init(&meter->running_mutex, NULL); + pthread_cond_init(&meter->running_cond, NULL); + err = pthread_create(&meter->thread, NULL, snd_pcm_meter_thread, pcm); + assert(err == 0); + return 0; +} + +int _snd_pcm_meter_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; + const char *sname = NULL; + int err; + snd_pcm_t *spcm; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id = snd_config_get_id(n); + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "type") == 0) + continue; + if (strcmp(id, "sname") == 0) { + err = snd_config_get_string(n, &sname); + if (err < 0) { + ERR("Invalid type for %s", id); + return -EINVAL; + } + continue; + } + ERR("Unknown field %s", id); + return -EINVAL; + } + if (!sname) { + ERR("sname is not defined"); + return -EINVAL; + } + + /* This is needed cause snd_config_update may destroy config */ + sname = strdup(sname); + if (!sname) + return -ENOMEM; + err = snd_pcm_open(&spcm, sname, stream, mode); + free((void *) sname); + if (err < 0) + return err; + err = snd_pcm_meter_open(pcmp, name, spcm, 1); + if (err < 0) + snd_pcm_close(spcm); + return err; +} diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c index c0e412df..cbe52430 100644 --- a/src/pcm/pcm_plugin.c +++ b/src/pcm/pcm_plugin.c @@ -439,11 +439,7 @@ int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status) } status->appl_ptr = plugin->appl_ptr; status->hw_ptr = plugin->hw_ptr; - err = snd_pcm_plugin_avail_update(pcm); - if (err < 0) - status->avail = pcm->buffer_size; - else - status->avail = err; + status->avail = pcm->buffer_size; snd_pcm_plugin_delay(pcm, &status->delay); if (!snd_atomic_read_ok(&ratom)) { snd_atomic_read_wait(&ratom); diff --git a/src/pcm/pcm_plugin.h b/src/pcm/pcm_plugin.h index ea8190af..76aaeb48 100644 --- a/src/pcm/pcm_plugin.h +++ b/src/pcm/pcm_plugin.h @@ -98,19 +98,6 @@ extern snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops; #define RATE_MIN 4000 #define RATE_MAX 192000 -#define ROUTE_PLUGIN_FLOAT 1 -#define ROUTE_PLUGIN_RESOLUTION 16 - -#if ROUTE_PLUGIN_FLOAT -typedef float snd_pcm_route_ttable_entry_t; -#define HALF 0.5 -#define FULL 1.0 -#else -typedef int snd_pcm_route_ttable_entry_t; -#define HALF (ROUTE_PLUGIN_RESOLUTION / 2) -#define FULL ROUTE_PLUGIN_RESOLUTION -#endif - int snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format); int snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format); int snd_pcm_linear_convert_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);