|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \file pcm/pcm_meter.c
|
|
Packit Service |
db8eaa |
* \brief Helper functions for #SND_PCM_TYPE_METER PCM scopes
|
|
Packit Service |
db8eaa |
* \author Abramo Bagnara <abramo@alsa-project.org>
|
|
Packit Service |
db8eaa |
* \date 2001
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* Helper functions for #SND_PCM_TYPE_METER PCM scopes
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
/*
|
|
Packit Service |
db8eaa |
* PCM - Meter plugin
|
|
Packit Service |
db8eaa |
* Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org>
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* This library is free software; you can redistribute it and/or modify
|
|
Packit Service |
db8eaa |
* it under the terms of the GNU Lesser General Public License as
|
|
Packit Service |
db8eaa |
* published by the Free Software Foundation; either version 2.1 of
|
|
Packit Service |
db8eaa |
* the License, or (at your option) any later version.
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
db8eaa |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
db8eaa |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
db8eaa |
* GNU Lesser General Public License for more details.
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
db8eaa |
* License along with this library; if not, write to the Free Software
|
|
Packit Service |
db8eaa |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#include "bswap.h"
|
|
Packit Service |
db8eaa |
#include <time.h>
|
|
Packit Service |
db8eaa |
#include <pthread.h>
|
|
Packit Service |
db8eaa |
#include <dlfcn.h>
|
|
Packit Service |
db8eaa |
#include "pcm_local.h"
|
|
Packit Service |
db8eaa |
#include "pcm_plugin.h"
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#define atomic_read(ptr) __atomic_load_n(ptr, __ATOMIC_SEQ_CST )
|
|
Packit Service |
db8eaa |
#define atomic_add(ptr, n) __atomic_add_fetch(ptr, n, __ATOMIC_SEQ_CST)
|
|
Packit Service |
db8eaa |
#define atomic_dec(ptr) __atomic_sub_fetch(ptr, 1, __ATOMIC_SEQ_CST)
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#ifndef PIC
|
|
Packit Service |
db8eaa |
/* entry for static linking */
|
|
Packit Service |
db8eaa |
const char *_snd_module_pcm_meter = "";
|
|
Packit Service |
db8eaa |
#endif
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#ifndef DOC_HIDDEN
|
|
Packit Service |
db8eaa |
#define FREQUENCY 50
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
struct _snd_pcm_scope {
|
|
Packit Service |
db8eaa |
int enabled;
|
|
Packit Service |
db8eaa |
char *name;
|
|
Packit Service |
db8eaa |
const snd_pcm_scope_ops_t *ops;
|
|
Packit Service |
db8eaa |
void *private_data;
|
|
Packit Service |
db8eaa |
struct list_head list;
|
|
Packit Service |
db8eaa |
};
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
typedef struct _snd_pcm_meter {
|
|
Packit Service |
db8eaa |
snd_pcm_generic_t gen;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t rptr;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t buf_size;
|
|
Packit Service |
db8eaa |
snd_pcm_channel_area_t *buf_areas;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t now;
|
|
Packit Service |
db8eaa |
unsigned char *buf;
|
|
Packit Service |
db8eaa |
struct list_head scopes;
|
|
Packit Service |
db8eaa |
int closed;
|
|
Packit Service |
db8eaa |
int running;
|
|
Packit Service |
db8eaa |
int reset;
|
|
Packit Service |
db8eaa |
pthread_t thread;
|
|
Packit Service |
db8eaa |
pthread_mutex_t update_mutex;
|
|
Packit Service |
db8eaa |
pthread_mutex_t running_mutex;
|
|
Packit Service |
db8eaa |
pthread_cond_t running_cond;
|
|
Packit Service |
db8eaa |
struct timespec delay;
|
|
Packit Service |
db8eaa |
void *dl_handle;
|
|
Packit Service |
db8eaa |
} snd_pcm_meter_t;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static void snd_pcm_meter_add_frames(snd_pcm_t *pcm,
|
|
Packit Service |
db8eaa |
const snd_pcm_channel_area_t *areas,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t ptr,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t frames)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
if (frames > pcm->buffer_size)
|
|
Packit Service |
db8eaa |
frames = pcm->buffer_size;
|
|
Packit Service |
db8eaa |
while (frames > 0) {
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t n = frames;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t dst_offset = ptr % meter->buf_size;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t src_offset = ptr % pcm->buffer_size;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t dst_cont = meter->buf_size - dst_offset;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t src_cont = pcm->buffer_size - src_offset;
|
|
Packit Service |
db8eaa |
if (n > dst_cont)
|
|
Packit Service |
db8eaa |
n = dst_cont;
|
|
Packit Service |
db8eaa |
if (n > src_cont)
|
|
Packit Service |
db8eaa |
n = src_cont;
|
|
Packit Service |
db8eaa |
snd_pcm_areas_copy(meter->buf_areas, dst_offset,
|
|
Packit Service |
db8eaa |
areas, src_offset,
|
|
Packit Service |
db8eaa |
pcm->channels, n, pcm->format);
|
|
Packit Service |
db8eaa |
frames -= n;
|
|
Packit Service |
db8eaa |
ptr += n;
|
|
Packit Service |
db8eaa |
if (ptr == pcm->boundary)
|
|
Packit Service |
db8eaa |
ptr = 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static void snd_pcm_meter_update_main(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_sframes_t frames;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t rptr, old_rptr;
|
|
Packit Service |
db8eaa |
const snd_pcm_channel_area_t *areas;
|
|
Packit Service |
db8eaa |
int locked;
|
|
Packit Service |
db8eaa |
locked = (pthread_mutex_trylock(&meter->update_mutex) >= 0);
|
|
Packit Service |
db8eaa |
areas = snd_pcm_mmap_areas(pcm);
|
|
Packit Service |
db8eaa |
rptr = *pcm->hw.ptr;
|
|
Packit Service |
db8eaa |
old_rptr = meter->rptr;
|
|
Packit Service |
db8eaa |
meter->rptr = rptr;
|
|
Packit Service |
db8eaa |
frames = rptr - old_rptr;
|
|
Packit Service |
db8eaa |
if (frames < 0)
|
|
Packit Service |
db8eaa |
frames += pcm->boundary;
|
|
Packit Service |
db8eaa |
if (frames > 0) {
|
|
Packit Service |
db8eaa |
assert((snd_pcm_uframes_t) frames <= pcm->buffer_size);
|
|
Packit Service |
db8eaa |
snd_pcm_meter_add_frames(pcm, areas, old_rptr,
|
|
Packit Service |
db8eaa |
(snd_pcm_uframes_t) frames);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (locked)
|
|
Packit Service |
db8eaa |
pthread_mutex_unlock(&meter->update_mutex);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_meter_update_scope(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_sframes_t frames;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t rptr, old_rptr;
|
|
Packit Service |
db8eaa |
const snd_pcm_channel_area_t *areas;
|
|
Packit Service |
db8eaa |
int reset = 0;
|
|
Packit Service |
db8eaa |
/* Wait main thread */
|
|
Packit Service |
db8eaa |
pthread_mutex_lock(&meter->update_mutex);
|
|
Packit Service |
db8eaa |
areas = snd_pcm_mmap_areas(pcm);
|
|
Packit Service |
db8eaa |
_again:
|
|
Packit Service |
db8eaa |
rptr = *pcm->hw.ptr;
|
|
Packit Service |
db8eaa |
old_rptr = meter->rptr;
|
|
Packit Service |
db8eaa |
if (atomic_read(&meter->reset)) {
|
|
Packit Service |
db8eaa |
reset = 1;
|
|
Packit Service |
db8eaa |
atomic_dec(&meter->reset);
|
|
Packit Service |
db8eaa |
goto _again;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
meter->rptr = rptr;
|
|
Packit Service |
db8eaa |
frames = rptr - old_rptr;
|
|
Packit Service |
db8eaa |
if (frames < 0)
|
|
Packit Service |
db8eaa |
frames += pcm->boundary;
|
|
Packit Service |
db8eaa |
if (frames > 0) {
|
|
Packit Service |
db8eaa |
assert((snd_pcm_uframes_t) frames <= pcm->buffer_size);
|
|
Packit Service |
db8eaa |
snd_pcm_meter_add_frames(pcm, areas, old_rptr,
|
|
Packit Service |
db8eaa |
(snd_pcm_uframes_t) frames);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
pthread_mutex_unlock(&meter->update_mutex);
|
|
Packit Service |
db8eaa |
return reset;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_scope_remove(snd_pcm_scope_t *scope)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
free(scope->name);
|
|
Packit Service |
db8eaa |
scope->ops->close(scope);
|
|
Packit Service |
db8eaa |
list_del(&scope->list);
|
|
Packit Service |
db8eaa |
free(scope);
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_scope_enable(snd_pcm_scope_t *scope)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
assert(!scope->enabled);
|
|
Packit Service |
db8eaa |
err = scope->ops->enable(scope);
|
|
Packit Service |
db8eaa |
scope->enabled = (err >= 0);
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_scope_disable(snd_pcm_scope_t *scope)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
assert(scope->enabled);
|
|
Packit Service |
db8eaa |
scope->ops->disable(scope);
|
|
Packit Service |
db8eaa |
scope->enabled = 0;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static void *snd_pcm_meter_thread(void *data)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_t *pcm = data;
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_t *spcm = meter->gen.slave;
|
|
Packit Service |
db8eaa |
struct list_head *pos;
|
|
Packit Service |
db8eaa |
snd_pcm_scope_t *scope;
|
|
Packit Service |
db8eaa |
int reset;
|
|
Packit Service |
db8eaa |
list_for_each(pos, &meter->scopes) {
|
|
Packit Service |
db8eaa |
scope = list_entry(pos, snd_pcm_scope_t, list);
|
|
Packit Service |
db8eaa |
snd_pcm_scope_enable(scope);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
while (!meter->closed) {
|
|
Packit Service |
db8eaa |
snd_pcm_sframes_t now;
|
|
Packit Service |
db8eaa |
snd_pcm_status_t status;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
pthread_mutex_lock(&meter->running_mutex);
|
|
Packit Service |
db8eaa |
err = snd_pcm_status(spcm, &status);
|
|
Packit Service |
db8eaa |
assert(err >= 0);
|
|
Packit Service |
db8eaa |
if (status.state != SND_PCM_STATE_RUNNING &&
|
|
Packit Service |
db8eaa |
(status.state != SND_PCM_STATE_DRAINING ||
|
|
Packit Service |
db8eaa |
spcm->stream != SND_PCM_STREAM_PLAYBACK)) {
|
|
Packit Service |
db8eaa |
if (meter->running) {
|
|
Packit Service |
db8eaa |
list_for_each(pos, &meter->scopes) {
|
|
Packit Service |
db8eaa |
scope = list_entry(pos, snd_pcm_scope_t, list);
|
|
Packit Service |
db8eaa |
scope->ops->stop(scope);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
meter->running = 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
pthread_cond_wait(&meter->running_cond,
|
|
Packit Service |
db8eaa |
&meter->running_mutex);
|
|
Packit Service |
db8eaa |
pthread_mutex_unlock(&meter->running_mutex);
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
pthread_mutex_unlock(&meter->running_mutex);
|
|
Packit Service |
db8eaa |
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
|
Packit Service |
db8eaa |
now = status.appl_ptr - status.delay;
|
|
Packit Service |
db8eaa |
if (now < 0)
|
|
Packit Service |
db8eaa |
now += pcm->boundary;
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
now = status.appl_ptr + status.delay;
|
|
Packit Service |
db8eaa |
if ((snd_pcm_uframes_t) now >= pcm->boundary)
|
|
Packit Service |
db8eaa |
now -= pcm->boundary;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
meter->now = now;
|
|
Packit Service |
db8eaa |
if (pcm->stream == SND_PCM_STREAM_CAPTURE)
|
|
Packit Service |
db8eaa |
reset = snd_pcm_meter_update_scope(pcm);
|
|
Packit Service |
db8eaa |
else {
|
|
Packit Service |
db8eaa |
reset = 0;
|
|
Packit Service |
db8eaa |
while (atomic_read(&meter->reset)) {
|
|
Packit Service |
db8eaa |
reset = 1;
|
|
Packit Service |
db8eaa |
atomic_dec(&meter->reset);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (reset) {
|
|
Packit Service |
db8eaa |
list_for_each(pos, &meter->scopes) {
|
|
Packit Service |
db8eaa |
scope = list_entry(pos, snd_pcm_scope_t, list);
|
|
Packit Service |
db8eaa |
if (scope->enabled)
|
|
Packit Service |
db8eaa |
scope->ops->reset(scope);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (!meter->running) {
|
|
Packit Service |
db8eaa |
list_for_each(pos, &meter->scopes) {
|
|
Packit Service |
db8eaa |
scope = list_entry(pos, snd_pcm_scope_t, list);
|
|
Packit Service |
db8eaa |
if (scope->enabled)
|
|
Packit Service |
db8eaa |
scope->ops->start(scope);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
meter->running = 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
list_for_each(pos, &meter->scopes) {
|
|
Packit Service |
db8eaa |
scope = list_entry(pos, snd_pcm_scope_t, list);
|
|
Packit Service |
db8eaa |
if (scope->enabled)
|
|
Packit Service |
db8eaa |
scope->ops->update(scope);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
nanosleep(&meter->delay, NULL);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
list_for_each(pos, &meter->scopes) {
|
|
Packit Service |
db8eaa |
scope = list_entry(pos, snd_pcm_scope_t, list);
|
|
Packit Service |
db8eaa |
if (scope->enabled)
|
|
Packit Service |
db8eaa |
snd_pcm_scope_disable(scope);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return NULL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_meter_close(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
struct list_head *pos, *npos;
|
|
Packit Service |
db8eaa |
int err = 0;
|
|
Packit Service |
db8eaa |
pthread_mutex_destroy(&meter->update_mutex);
|
|
Packit Service |
db8eaa |
pthread_mutex_destroy(&meter->running_mutex);
|
|
Packit Service |
db8eaa |
pthread_cond_destroy(&meter->running_cond);
|
|
Packit Service |
db8eaa |
if (meter->gen.close_slave)
|
|
Packit Service |
db8eaa |
err = snd_pcm_close(meter->gen.slave);
|
|
Packit Service |
db8eaa |
list_for_each_safe(pos, npos, &meter->scopes) {
|
|
Packit Service |
db8eaa |
snd_pcm_scope_t *scope;
|
|
Packit Service |
db8eaa |
scope = list_entry(pos, snd_pcm_scope_t, list);
|
|
Packit Service |
db8eaa |
snd_pcm_scope_remove(scope);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (meter->dl_handle)
|
|
Packit Service |
db8eaa |
snd_dlclose(meter->dl_handle);
|
|
Packit Service |
db8eaa |
free(meter);
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_meter_prepare(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
atomic_add(&meter->reset, 1);
|
|
Packit Service |
db8eaa |
err = snd_pcm_prepare(meter->gen.slave);
|
|
Packit Service |
db8eaa |
if (err >= 0) {
|
|
Packit Service |
db8eaa |
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
|
|
Packit Service |
db8eaa |
meter->rptr = *pcm->appl.ptr;
|
|
Packit Service |
db8eaa |
else
|
|
Packit Service |
db8eaa |
meter->rptr = *pcm->hw.ptr;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_meter_reset(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
int err = snd_pcm_reset(meter->gen.slave);
|
|
Packit Service |
db8eaa |
if (err >= 0) {
|
|
Packit Service |
db8eaa |
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
|
|
Packit Service |
db8eaa |
meter->rptr = *pcm->appl.ptr;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_meter_start(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
pthread_mutex_lock(&meter->running_mutex);
|
|
Packit Service |
db8eaa |
err = snd_pcm_start(meter->gen.slave);
|
|
Packit Service |
db8eaa |
if (err >= 0)
|
|
Packit Service |
db8eaa |
pthread_cond_signal(&meter->running_cond);
|
|
Packit Service |
db8eaa |
pthread_mutex_unlock(&meter->running_mutex);
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static snd_pcm_sframes_t snd_pcm_meter_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_sframes_t err = snd_pcm_rewind(meter->gen.slave, frames);
|
|
Packit Service |
db8eaa |
if (err > 0 && pcm->stream == SND_PCM_STREAM_PLAYBACK)
|
|
Packit Service |
db8eaa |
meter->rptr = *pcm->appl.ptr;
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static snd_pcm_sframes_t snd_pcm_meter_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_sframes_t err = INTERNAL(snd_pcm_forward)(meter->gen.slave, frames);
|
|
Packit Service |
db8eaa |
if (err > 0 && pcm->stream == SND_PCM_STREAM_PLAYBACK)
|
|
Packit Service |
db8eaa |
meter->rptr = *pcm->appl.ptr;
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static snd_pcm_sframes_t snd_pcm_meter_mmap_commit(snd_pcm_t *pcm,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t offset,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t size)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t old_rptr = *pcm->appl.ptr;
|
|
Packit Service |
db8eaa |
snd_pcm_sframes_t result = snd_pcm_mmap_commit(meter->gen.slave, offset, size);
|
|
Packit Service |
db8eaa |
if (result <= 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
|
Packit Service |
db8eaa |
snd_pcm_meter_add_frames(pcm, snd_pcm_mmap_areas(pcm), old_rptr, result);
|
|
Packit Service |
db8eaa |
meter->rptr = *pcm->appl.ptr;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static snd_pcm_sframes_t snd_pcm_meter_avail_update(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_sframes_t result = snd_pcm_avail_update(meter->gen.slave);
|
|
Packit Service |
db8eaa |
if (result <= 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
if (pcm->stream == SND_PCM_STREAM_CAPTURE)
|
|
Packit Service |
db8eaa |
snd_pcm_meter_update_main(pcm);
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_meter_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM };
|
|
Packit Service |
db8eaa |
err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
|
|
Packit Service |
db8eaa |
&access_mask);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_meter_hw_refine_sprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP };
|
|
Packit Service |
db8eaa |
_snd_pcm_hw_params_any(sparams);
|
|
Packit Service |
db8eaa |
_snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
|
|
Packit Service |
db8eaa |
&saccess_mask);
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_meter_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
|
|
Packit Service |
db8eaa |
snd_pcm_hw_params_t *sparams)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS;
|
|
Packit Service |
db8eaa |
err = _snd_pcm_hw_params_refine(sparams, links, params);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_meter_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
|
|
Packit Service |
db8eaa |
snd_pcm_hw_params_t *sparams)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS;
|
|
Packit Service |
db8eaa |
err = _snd_pcm_hw_params_refine(params, links, sparams);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_meter_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
return snd_pcm_hw_refine(meter->gen.slave, params);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_meter_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
return _snd_pcm_hw_params_internal(meter->gen.slave, params);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_meter_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return snd_pcm_hw_refine_slave(pcm, params,
|
|
Packit Service |
db8eaa |
snd_pcm_meter_hw_refine_cprepare,
|
|
Packit Service |
db8eaa |
snd_pcm_meter_hw_refine_cchange,
|
|
Packit Service |
db8eaa |
snd_pcm_meter_hw_refine_sprepare,
|
|
Packit Service |
db8eaa |
snd_pcm_meter_hw_refine_schange,
|
|
Packit Service |
db8eaa |
snd_pcm_meter_hw_refine_slave);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_meter_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
unsigned int channel;
|
|
Packit Service |
db8eaa |
snd_pcm_t *slave = meter->gen.slave;
|
|
Packit Service |
db8eaa |
size_t buf_size_bytes;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
err = snd_pcm_hw_params_slave(pcm, params,
|
|
Packit Service |
db8eaa |
snd_pcm_meter_hw_refine_cchange,
|
|
Packit Service |
db8eaa |
snd_pcm_meter_hw_refine_sprepare,
|
|
Packit Service |
db8eaa |
snd_pcm_meter_hw_refine_schange,
|
|
Packit Service |
db8eaa |
snd_pcm_meter_hw_params_slave);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
/* more than 1 second of buffer */
|
|
Packit Service |
db8eaa |
meter->buf_size = slave->buffer_size;
|
|
Packit Service |
db8eaa |
while (meter->buf_size < slave->rate)
|
|
Packit Service |
db8eaa |
meter->buf_size *= 2;
|
|
Packit Service |
db8eaa |
buf_size_bytes = snd_pcm_frames_to_bytes(slave, meter->buf_size);
|
|
Packit Service |
db8eaa |
assert(!meter->buf);
|
|
Packit Service |
db8eaa |
meter->buf = malloc(buf_size_bytes);
|
|
Packit Service |
db8eaa |
if (!meter->buf)
|
|
Packit Service |
db8eaa |
return -ENOMEM;
|
|
Packit Service |
db8eaa |
meter->buf_areas = malloc(sizeof(*meter->buf_areas) * slave->channels);
|
|
Packit Service |
db8eaa |
if (!meter->buf_areas) {
|
|
Packit Service |
db8eaa |
free(meter->buf);
|
|
Packit Service |
db8eaa |
return -ENOMEM;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
for (channel = 0; channel < slave->channels; ++channel) {
|
|
Packit Service |
db8eaa |
snd_pcm_channel_area_t *a = &meter->buf_areas[channel];
|
|
Packit Service |
db8eaa |
a->addr = meter->buf + buf_size_bytes / slave->channels * channel;
|
|
Packit Service |
db8eaa |
a->first = 0;
|
|
Packit Service |
db8eaa |
a->step = slave->sample_bits;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
meter->closed = 0;
|
|
Packit Service |
db8eaa |
err = pthread_create(&meter->thread, NULL, snd_pcm_meter_thread, pcm);
|
|
Packit Service |
db8eaa |
assert(err == 0);
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_meter_hw_free(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
meter->closed = 1;
|
|
Packit Service |
db8eaa |
pthread_mutex_lock(&meter->running_mutex);
|
|
Packit Service |
db8eaa |
pthread_cond_signal(&meter->running_cond);
|
|
Packit Service |
db8eaa |
pthread_mutex_unlock(&meter->running_mutex);
|
|
Packit Service |
db8eaa |
err = pthread_join(meter->thread, 0);
|
|
Packit Service |
db8eaa |
assert(err == 0);
|
|
Packit Service |
db8eaa |
free(meter->buf);
|
|
Packit Service |
db8eaa |
free(meter->buf_areas);
|
|
Packit Service |
db8eaa |
meter->buf = NULL;
|
|
Packit Service |
db8eaa |
meter->buf_areas = NULL;
|
|
Packit Service |
db8eaa |
return snd_pcm_hw_free(meter->gen.slave);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static void snd_pcm_meter_dump(snd_pcm_t *pcm, snd_output_t *out)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_output_printf(out, "Meter PCM\n");
|
|
Packit Service |
db8eaa |
if (pcm->setup) {
|
|
Packit Service |
db8eaa |
snd_output_printf(out, "Its setup is:\n");
|
|
Packit Service |
db8eaa |
snd_pcm_dump_setup(pcm, out);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
snd_output_printf(out, "Slave: ");
|
|
Packit Service |
db8eaa |
snd_pcm_dump(meter->gen.slave, out);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static const snd_pcm_ops_t snd_pcm_meter_ops = {
|
|
Packit Service |
db8eaa |
.close = snd_pcm_meter_close,
|
|
Packit Service |
db8eaa |
.info = snd_pcm_generic_info,
|
|
Packit Service |
db8eaa |
.hw_refine = snd_pcm_meter_hw_refine,
|
|
Packit Service |
db8eaa |
.hw_params = snd_pcm_meter_hw_params,
|
|
Packit Service |
db8eaa |
.hw_free = snd_pcm_meter_hw_free,
|
|
Packit Service |
db8eaa |
.sw_params = snd_pcm_generic_sw_params,
|
|
Packit Service |
db8eaa |
.channel_info = snd_pcm_generic_channel_info,
|
|
Packit Service |
db8eaa |
.dump = snd_pcm_meter_dump,
|
|
Packit Service |
db8eaa |
.nonblock = snd_pcm_generic_nonblock,
|
|
Packit Service |
db8eaa |
.async = snd_pcm_generic_async,
|
|
Packit Service |
db8eaa |
.mmap = snd_pcm_generic_mmap,
|
|
Packit Service |
db8eaa |
.munmap = snd_pcm_generic_munmap,
|
|
Packit Service |
db8eaa |
.query_chmaps = snd_pcm_generic_query_chmaps,
|
|
Packit Service |
db8eaa |
.get_chmap = snd_pcm_generic_get_chmap,
|
|
Packit Service |
db8eaa |
.set_chmap = snd_pcm_generic_set_chmap,
|
|
Packit Service |
db8eaa |
};
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static const snd_pcm_fast_ops_t snd_pcm_meter_fast_ops = {
|
|
Packit Service |
db8eaa |
.status = snd_pcm_generic_status,
|
|
Packit Service |
db8eaa |
.state = snd_pcm_generic_state,
|
|
Packit Service |
db8eaa |
.hwsync = snd_pcm_generic_hwsync,
|
|
Packit Service |
db8eaa |
.delay = snd_pcm_generic_delay,
|
|
Packit Service |
db8eaa |
.prepare = snd_pcm_meter_prepare,
|
|
Packit Service |
db8eaa |
.reset = snd_pcm_meter_reset,
|
|
Packit Service |
db8eaa |
.start = snd_pcm_meter_start,
|
|
Packit Service |
db8eaa |
.drop = snd_pcm_generic_drop,
|
|
Packit Service |
db8eaa |
.drain = snd_pcm_generic_drain,
|
|
Packit Service |
db8eaa |
.pause = snd_pcm_generic_pause,
|
|
Packit Service |
db8eaa |
.rewindable = snd_pcm_generic_rewindable,
|
|
Packit Service |
db8eaa |
.rewind = snd_pcm_meter_rewind,
|
|
Packit Service |
db8eaa |
.forwardable = snd_pcm_generic_forwardable,
|
|
Packit Service |
db8eaa |
.forward = snd_pcm_meter_forward,
|
|
Packit Service |
db8eaa |
.resume = snd_pcm_generic_resume,
|
|
Packit Service |
db8eaa |
.writei = snd_pcm_mmap_writei,
|
|
Packit Service |
db8eaa |
.writen = snd_pcm_mmap_writen,
|
|
Packit Service |
db8eaa |
.readi = snd_pcm_mmap_readi,
|
|
Packit Service |
db8eaa |
.readn = snd_pcm_mmap_readn,
|
|
Packit Service |
db8eaa |
.avail_update = snd_pcm_meter_avail_update,
|
|
Packit Service |
db8eaa |
.mmap_commit = snd_pcm_meter_mmap_commit,
|
|
Packit Service |
db8eaa |
.htimestamp = snd_pcm_generic_htimestamp,
|
|
Packit Service |
db8eaa |
.poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
|
|
Packit Service |
db8eaa |
.poll_descriptors = snd_pcm_generic_poll_descriptors,
|
|
Packit Service |
db8eaa |
.poll_revents = snd_pcm_generic_poll_revents,
|
|
Packit Service |
db8eaa |
.may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min,
|
|
Packit Service |
db8eaa |
};
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Creates a new Meter PCM
|
|
Packit Service |
db8eaa |
* \param pcmp Returns created PCM handle
|
|
Packit Service |
db8eaa |
* \param name Name of PCM
|
|
Packit Service |
db8eaa |
* \param frequency Update frequency
|
|
Packit Service |
db8eaa |
* \param slave Slave PCM handle
|
|
Packit Service |
db8eaa |
* \param close_slave When set, the slave PCM handle is closed with copy PCM
|
|
Packit Service |
db8eaa |
* \retval zero on success otherwise a negative error code
|
|
Packit Service |
db8eaa |
* \warning Using of this function might be dangerous in the sense
|
|
Packit Service |
db8eaa |
* of compatibility reasons. The prototype might be freely
|
|
Packit Service |
db8eaa |
* changed in future.
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
int snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name, unsigned int frequency,
|
|
Packit Service |
db8eaa |
snd_pcm_t *slave, int close_slave)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_t *pcm;
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
assert(pcmp);
|
|
Packit Service |
db8eaa |
meter = calloc(1, sizeof(snd_pcm_meter_t));
|
|
Packit Service |
db8eaa |
if (!meter)
|
|
Packit Service |
db8eaa |
return -ENOMEM;
|
|
Packit Service |
db8eaa |
meter->gen.slave = slave;
|
|
Packit Service |
db8eaa |
meter->gen.close_slave = close_slave;
|
|
Packit Service |
db8eaa |
meter->delay.tv_sec = 0;
|
|
Packit Service |
db8eaa |
meter->delay.tv_nsec = 1000000000 / frequency;
|
|
Packit Service |
db8eaa |
INIT_LIST_HEAD(&meter->scopes);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
err = snd_pcm_new(&pcm, SND_PCM_TYPE_METER, name, slave->stream, slave->mode);
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
free(meter);
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
pcm->mmap_rw = 1;
|
|
Packit Service |
db8eaa |
pcm->mmap_shadow = 1;
|
|
Packit Service |
db8eaa |
pcm->ops = &snd_pcm_meter_ops;
|
|
Packit Service |
db8eaa |
pcm->fast_ops = &snd_pcm_meter_fast_ops;
|
|
Packit Service |
db8eaa |
pcm->private_data = meter;
|
|
Packit Service |
db8eaa |
pcm->poll_fd = slave->poll_fd;
|
|
Packit Service |
db8eaa |
pcm->poll_events = slave->poll_events;
|
|
Packit Service |
db8eaa |
pcm->tstamp_type = slave->tstamp_type;
|
|
Packit Service |
db8eaa |
snd_pcm_link_hw_ptr(pcm, slave);
|
|
Packit Service |
db8eaa |
snd_pcm_link_appl_ptr(pcm, slave);
|
|
Packit Service |
db8eaa |
*pcmp = pcm;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
pthread_mutex_init(&meter->update_mutex, NULL);
|
|
Packit Service |
db8eaa |
pthread_mutex_init(&meter->running_mutex, NULL);
|
|
Packit Service |
db8eaa |
pthread_cond_init(&meter->running_cond, NULL);
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_meter_add_scope_conf(snd_pcm_t *pcm, const char *name,
|
|
Packit Service |
db8eaa |
snd_config_t *root, snd_config_t *conf)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
char buf[256], errbuf[256];
|
|
Packit Service |
db8eaa |
snd_config_iterator_t i, next;
|
|
Packit Service |
db8eaa |
const char *id;
|
|
Packit Service |
db8eaa |
const char *lib = NULL, *open_name = NULL, *str = NULL;
|
|
Packit Service |
db8eaa |
snd_config_t *c, *type_conf = NULL;
|
|
Packit Service |
db8eaa |
int (*open_func)(snd_pcm_t *, const char *,
|
|
Packit Service |
db8eaa |
snd_config_t *, snd_config_t *) = NULL;
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
void *h = NULL;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) {
|
|
Packit Service |
db8eaa |
SNDERR("Invalid type for scope %s", str);
|
|
Packit Service |
db8eaa |
err = -EINVAL;
|
|
Packit Service |
db8eaa |
goto _err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
err = snd_config_search(conf, "type", &c);
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
SNDERR("type is not defined");
|
|
Packit Service |
db8eaa |
goto _err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
err = snd_config_get_id(c, &id;;
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
SNDERR("unable to get id");
|
|
Packit Service |
db8eaa |
goto _err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
err = snd_config_get_string(c, &str);
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
SNDERR("Invalid type for %s", id);
|
|
Packit Service |
db8eaa |
goto _err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
err = snd_config_search_definition(root, "pcm_scope_type", str, &type_conf);
|
|
Packit Service |
db8eaa |
if (err >= 0) {
|
|
Packit Service |
db8eaa |
snd_config_for_each(i, next, type_conf) {
|
|
Packit Service |
db8eaa |
snd_config_t *n = snd_config_iterator_entry(i);
|
|
Packit Service |
db8eaa |
const char *id;
|
|
Packit Service |
db8eaa |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
if (strcmp(id, "comment") == 0)
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
if (strcmp(id, "lib") == 0) {
|
|
Packit Service |
db8eaa |
err = snd_config_get_string(n, &lib);
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
SNDERR("Invalid type for %s", id);
|
|
Packit Service |
db8eaa |
goto _err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (strcmp(id, "open") == 0) {
|
|
Packit Service |
db8eaa |
err = snd_config_get_string(n, &open_name);
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
SNDERR("Invalid type for %s", id);
|
|
Packit Service |
db8eaa |
goto _err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
SNDERR("Unknown field %s", id);
|
|
Packit Service |
db8eaa |
err = -EINVAL;
|
|
Packit Service |
db8eaa |
goto _err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (!open_name) {
|
|
Packit Service |
db8eaa |
open_name = buf;
|
|
Packit Service |
db8eaa |
snprintf(buf, sizeof(buf), "_snd_pcm_scope_%s_open", str);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
h = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf));
|
|
Packit Service |
db8eaa |
open_func = h ? dlsym(h, open_name) : NULL;
|
|
Packit Service |
db8eaa |
err = 0;
|
|
Packit Service |
db8eaa |
if (!h) {
|
|
Packit Service |
db8eaa |
SNDERR("Cannot open shared library %s (%s)", lib, errbuf);
|
|
Packit Service |
db8eaa |
err = -ENOENT;
|
|
Packit Service |
db8eaa |
} else if (!open_func) {
|
|
Packit Service |
db8eaa |
SNDERR("symbol %s is not defined inside %s", open_name, lib);
|
|
Packit Service |
db8eaa |
snd_dlclose(h);
|
|
Packit Service |
db8eaa |
err = -ENXIO;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
_err:
|
|
Packit Service |
db8eaa |
if (type_conf)
|
|
Packit Service |
db8eaa |
snd_config_delete(type_conf);
|
|
Packit Service |
db8eaa |
if (! err) {
|
|
Packit Service |
db8eaa |
err = open_func(pcm, name, root, conf);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
snd_dlclose(h);
|
|
Packit Service |
db8eaa |
else
|
|
Packit Service |
db8eaa |
meter->dl_handle = h;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/*! \page pcm_plugins
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
\section pcm_plugins_meter Plugin: Meter
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
Show meter (visual waveform representation).
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
\code
|
|
Packit Service |
db8eaa |
pcm_scope_type.NAME {
|
|
Packit Service |
db8eaa |
[lib STR] # Library file (default libasound.so)
|
|
Packit Service |
db8eaa |
[open STR] # Open function (default _snd_pcm_scope_NAME_open)
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
pcm_scope.name {
|
|
Packit Service |
db8eaa |
type STR # Scope type
|
|
Packit Service |
db8eaa |
...
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
pcm.name {
|
|
Packit Service |
db8eaa |
type meter # Meter PCM
|
|
Packit Service |
db8eaa |
slave STR # Slave name
|
|
Packit Service |
db8eaa |
# or
|
|
Packit Service |
db8eaa |
slave { # Slave definition
|
|
Packit Service |
db8eaa |
pcm STR # Slave PCM name
|
|
Packit Service |
db8eaa |
# or
|
|
Packit Service |
db8eaa |
pcm { } # Slave PCM definition
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
[frequency INT] # Updates per second
|
|
Packit Service |
db8eaa |
scopes {
|
|
Packit Service |
db8eaa |
ID STR # Scope name (see pcm_scope)
|
|
Packit Service |
db8eaa |
# or
|
|
Packit Service |
db8eaa |
ID { } # Scope definition (see pcm_scope)
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
\endcode
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
\subsection pcm_plugins_meter_funcref Function reference
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
snd_pcm_meter_open()
|
|
Packit Service |
db8eaa |
_snd_pcm_meter_open()
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Creates a new Meter PCM
|
|
Packit Service |
db8eaa |
* \param pcmp Returns created PCM handle
|
|
Packit Service |
db8eaa |
* \param name Name of PCM
|
|
Packit Service |
db8eaa |
* \param root Root configuration node
|
|
Packit Service |
db8eaa |
* \param conf Configuration node with Meter PCM description
|
|
Packit Service |
db8eaa |
* \param stream Stream type
|
|
Packit Service |
db8eaa |
* \param mode Stream mode
|
|
Packit Service |
db8eaa |
* \retval zero on success otherwise a negative error code
|
|
Packit Service |
db8eaa |
* \warning Using of this function might be dangerous in the sense
|
|
Packit Service |
db8eaa |
* of compatibility reasons. The prototype might be freely
|
|
Packit Service |
db8eaa |
* changed in future.
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
int _snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name,
|
|
Packit Service |
db8eaa |
snd_config_t *root, snd_config_t *conf,
|
|
Packit Service |
db8eaa |
snd_pcm_stream_t stream, int mode)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_config_iterator_t i, next;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
snd_pcm_t *spcm;
|
|
Packit Service |
db8eaa |
snd_config_t *slave = NULL, *sconf;
|
|
Packit Service |
db8eaa |
long frequency = -1;
|
|
Packit Service |
db8eaa |
snd_config_t *scopes = NULL;
|
|
Packit Service |
db8eaa |
snd_config_for_each(i, next, conf) {
|
|
Packit Service |
db8eaa |
snd_config_t *n = snd_config_iterator_entry(i);
|
|
Packit Service |
db8eaa |
const char *id;
|
|
Packit Service |
db8eaa |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
if (snd_pcm_conf_generic_id(id))
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
if (strcmp(id, "slave") == 0) {
|
|
Packit Service |
db8eaa |
slave = n;
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (strcmp(id, "frequency") == 0) {
|
|
Packit Service |
db8eaa |
err = snd_config_get_integer(n, &frequency);
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
SNDERR("Invalid type for %s", id);
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (strcmp(id, "scopes") == 0) {
|
|
Packit Service |
db8eaa |
if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
|
|
Packit Service |
db8eaa |
SNDERR("Invalid type for %s", id);
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
scopes = n;
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
SNDERR("Unknown field %s", id);
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (!slave) {
|
|
Packit Service |
db8eaa |
SNDERR("slave is not defined");
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
|
|
Packit Service |
db8eaa |
snd_config_delete(sconf);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
err = snd_pcm_meter_open(pcmp, name, frequency > 0 ? (unsigned int) frequency : FREQUENCY, spcm, 1);
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
snd_pcm_close(spcm);
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (!scopes)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
snd_config_for_each(i, next, scopes) {
|
|
Packit Service |
db8eaa |
snd_config_t *n = snd_config_iterator_entry(i);
|
|
Packit Service |
db8eaa |
const char *id, *str;
|
|
Packit Service |
db8eaa |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
if (snd_config_get_string(n, &str) >= 0) {
|
|
Packit Service |
db8eaa |
err = snd_config_search_definition(root, "pcm_scope", str, &n);
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
SNDERR("unknown pcm_scope %s", str);
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
err = snd_pcm_meter_add_scope_conf(*pcmp, id, root, n);
|
|
Packit Service |
db8eaa |
snd_config_delete(n);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
} else
|
|
Packit Service |
db8eaa |
err = snd_pcm_meter_add_scope_conf(*pcmp, id, root, n);
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
snd_pcm_close(*pcmp);
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
SND_DLSYM_BUILD_VERSION(_snd_pcm_meter_open, SND_PCM_DLSYM_VERSION);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#endif
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Add a scope to a #SND_PCM_TYPE_METER PCM
|
|
Packit Service |
db8eaa |
* \param pcm PCM handle
|
|
Packit Service |
db8eaa |
* \param scope Scope handle
|
|
Packit Service |
db8eaa |
* \return 0 on success otherwise a negative error code
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
int snd_pcm_meter_add_scope(snd_pcm_t *pcm, snd_pcm_scope_t *scope)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter;
|
|
Packit Service |
db8eaa |
assert(pcm->type == SND_PCM_TYPE_METER);
|
|
Packit Service |
db8eaa |
meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
list_add_tail(&scope->list, &meter->scopes);
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Search an installed scope inside a #SND_PCM_TYPE_METER PCM
|
|
Packit Service |
db8eaa |
* \param pcm PCM handle
|
|
Packit Service |
db8eaa |
* \param name scope name
|
|
Packit Service |
db8eaa |
* \return pointer to found scope or NULL if none is found
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
snd_pcm_scope_t *snd_pcm_meter_search_scope(snd_pcm_t *pcm, const char *name)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter;
|
|
Packit Service |
db8eaa |
struct list_head *pos;
|
|
Packit Service |
db8eaa |
assert(pcm->type == SND_PCM_TYPE_METER);
|
|
Packit Service |
db8eaa |
meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
list_for_each(pos, &meter->scopes) {
|
|
Packit Service |
db8eaa |
snd_pcm_scope_t *scope;
|
|
Packit Service |
db8eaa |
scope = list_entry(pos, snd_pcm_scope_t, list);
|
|
Packit Service |
db8eaa |
if (scope->name && strcmp(scope->name, name) == 0)
|
|
Packit Service |
db8eaa |
return scope;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return NULL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Get meter buffer size from a #SND_PCM_TYPE_METER PCM
|
|
Packit Service |
db8eaa |
* \param pcm PCM handle
|
|
Packit Service |
db8eaa |
* \return meter buffer size in frames
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t snd_pcm_meter_get_bufsize(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter;
|
|
Packit Service |
db8eaa |
assert(pcm->type == SND_PCM_TYPE_METER);
|
|
Packit Service |
db8eaa |
meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
assert(meter->gen.slave->setup);
|
|
Packit Service |
db8eaa |
return meter->buf_size;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Get meter channels from a #SND_PCM_TYPE_METER PCM
|
|
Packit Service |
db8eaa |
* \param pcm PCM handle
|
|
Packit Service |
db8eaa |
* \return meter channels count
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
unsigned int snd_pcm_meter_get_channels(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter;
|
|
Packit Service |
db8eaa |
assert(pcm->type == SND_PCM_TYPE_METER);
|
|
Packit Service |
db8eaa |
meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
assert(meter->gen.slave->setup);
|
|
Packit Service |
db8eaa |
return meter->gen.slave->channels;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Get meter rate from a #SND_PCM_TYPE_METER PCM
|
|
Packit Service |
db8eaa |
* \param pcm PCM handle
|
|
Packit Service |
db8eaa |
* \return approximate rate
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
unsigned int snd_pcm_meter_get_rate(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter;
|
|
Packit Service |
db8eaa |
assert(pcm->type == SND_PCM_TYPE_METER);
|
|
Packit Service |
db8eaa |
meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
assert(meter->gen.slave->setup);
|
|
Packit Service |
db8eaa |
return meter->gen.slave->rate;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Get meter "now" frame pointer from a #SND_PCM_TYPE_METER PCM
|
|
Packit Service |
db8eaa |
* \param pcm PCM handle
|
|
Packit Service |
db8eaa |
* \return "now" frame pointer in frames (0 ... boundary - 1) see #snd_pcm_meter_get_boundary
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t snd_pcm_meter_get_now(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter;
|
|
Packit Service |
db8eaa |
assert(pcm->type == SND_PCM_TYPE_METER);
|
|
Packit Service |
db8eaa |
meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
assert(meter->gen.slave->setup);
|
|
Packit Service |
db8eaa |
return meter->now;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Get boundary for frame pointers from a #SND_PCM_TYPE_METER PCM
|
|
Packit Service |
db8eaa |
* \param pcm PCM handle
|
|
Packit Service |
db8eaa |
* \return boundary in frames
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t snd_pcm_meter_get_boundary(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter;
|
|
Packit Service |
db8eaa |
assert(pcm->type == SND_PCM_TYPE_METER);
|
|
Packit Service |
db8eaa |
meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
assert(meter->gen.slave->setup);
|
|
Packit Service |
db8eaa |
return meter->gen.slave->boundary;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Set name of a #SND_PCM_TYPE_METER PCM scope
|
|
Packit Service |
db8eaa |
* \param scope PCM meter scope
|
|
Packit Service |
db8eaa |
* \param val scope name
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
void snd_pcm_scope_set_name(snd_pcm_scope_t *scope, const char *val)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
scope->name = strdup(val);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Get name of a #SND_PCM_TYPE_METER PCM scope
|
|
Packit Service |
db8eaa |
* \param scope PCM meter scope
|
|
Packit Service |
db8eaa |
* \return scope name
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
const char *snd_pcm_scope_get_name(snd_pcm_scope_t *scope)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return scope->name;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Set callbacks for a #SND_PCM_TYPE_METER PCM scope
|
|
Packit Service |
db8eaa |
* \param scope PCM meter scope
|
|
Packit Service |
db8eaa |
* \param val callbacks
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
void snd_pcm_scope_set_ops(snd_pcm_scope_t *scope, const snd_pcm_scope_ops_t *val)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
scope->ops = val;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Get callbacks private value for a #SND_PCM_TYPE_METER PCM scope
|
|
Packit Service |
db8eaa |
* \param scope PCM meter scope
|
|
Packit Service |
db8eaa |
* \return Private data value
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
void *snd_pcm_scope_get_callback_private(snd_pcm_scope_t *scope)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return scope->private_data;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Get callbacks private value for a #SND_PCM_TYPE_METER PCM scope
|
|
Packit Service |
db8eaa |
* \param scope PCM meter scope
|
|
Packit Service |
db8eaa |
* \param val Private data value
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
void snd_pcm_scope_set_callback_private(snd_pcm_scope_t *scope, void *val)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
scope->private_data = val;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#ifndef DOC_HIDDEN
|
|
Packit Service |
db8eaa |
typedef struct _snd_pcm_scope_s16 {
|
|
Packit Service |
db8eaa |
snd_pcm_t *pcm;
|
|
Packit Service |
db8eaa |
snd_pcm_adpcm_state_t *adpcm_states;
|
|
Packit Service |
db8eaa |
unsigned int index;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t old;
|
|
Packit Service |
db8eaa |
int16_t *buf;
|
|
Packit Service |
db8eaa |
snd_pcm_channel_area_t *buf_areas;
|
|
Packit Service |
db8eaa |
} snd_pcm_scope_s16_t;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int s16_enable(snd_pcm_scope_t *scope)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_scope_s16_t *s16 = scope->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = s16->pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_t *spcm = meter->gen.slave;
|
|
Packit Service |
db8eaa |
snd_pcm_channel_area_t *a;
|
|
Packit Service |
db8eaa |
unsigned int c;
|
|
Packit Service |
db8eaa |
int idx;
|
|
Packit Service |
db8eaa |
if (spcm->format == SND_PCM_FORMAT_S16 &&
|
|
Packit Service |
db8eaa |
spcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED) {
|
|
Packit Service |
db8eaa |
s16->buf = (int16_t *) meter->buf;
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
switch (spcm->format) {
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_A_LAW:
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_MU_LAW:
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_IMA_ADPCM:
|
|
Packit Service |
db8eaa |
idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, SND_PCM_FORMAT_S16);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_S8:
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_S16_LE:
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_S16_BE:
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_S24_LE:
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_S24_BE:
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_S32_LE:
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_S32_BE:
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_U8:
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_U16_LE:
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_U16_BE:
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_U24_LE:
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_U24_BE:
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_U32_LE:
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_U32_BE:
|
|
Packit Service |
db8eaa |
idx = snd_pcm_linear_convert_index(spcm->format, SND_PCM_FORMAT_S16);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
default:
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
s16->index = idx;
|
|
Packit Service |
db8eaa |
if (spcm->format == SND_PCM_FORMAT_IMA_ADPCM) {
|
|
Packit Service |
db8eaa |
s16->adpcm_states = calloc(spcm->channels, sizeof(*s16->adpcm_states));
|
|
Packit Service |
db8eaa |
if (!s16->adpcm_states)
|
|
Packit Service |
db8eaa |
return -ENOMEM;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
s16->buf = malloc(meter->buf_size * 2 * spcm->channels);
|
|
Packit Service |
db8eaa |
if (!s16->buf) {
|
|
Packit Service |
db8eaa |
free(s16->adpcm_states);
|
|
Packit Service |
db8eaa |
return -ENOMEM;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
a = calloc(spcm->channels, sizeof(*a));
|
|
Packit Service |
db8eaa |
if (!a) {
|
|
Packit Service |
db8eaa |
free(s16->buf);
|
|
Packit Service |
db8eaa |
free(s16->adpcm_states);
|
|
Packit Service |
db8eaa |
return -ENOMEM;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
s16->buf_areas = a;
|
|
Packit Service |
db8eaa |
for (c = 0; c < spcm->channels; c++, a++) {
|
|
Packit Service |
db8eaa |
a->addr = s16->buf + c * meter->buf_size;
|
|
Packit Service |
db8eaa |
a->first = 0;
|
|
Packit Service |
db8eaa |
a->step = 16;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static void s16_disable(snd_pcm_scope_t *scope)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_scope_s16_t *s16 = scope->private_data;
|
|
Packit Service |
db8eaa |
free(s16->adpcm_states);
|
|
Packit Service |
db8eaa |
s16->adpcm_states = NULL;
|
|
Packit Service |
db8eaa |
free(s16->buf);
|
|
Packit Service |
db8eaa |
s16->buf = NULL;
|
|
Packit Service |
db8eaa |
free(s16->buf_areas);
|
|
Packit Service |
db8eaa |
s16->buf_areas = 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static void s16_close(snd_pcm_scope_t *scope)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_scope_s16_t *s16 = scope->private_data;
|
|
Packit Service |
db8eaa |
free(s16);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static void s16_start(snd_pcm_scope_t *scope ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static void s16_stop(snd_pcm_scope_t *scope ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static void s16_update(snd_pcm_scope_t *scope)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_scope_s16_t *s16 = scope->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = s16->pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_t *spcm = meter->gen.slave;
|
|
Packit Service |
db8eaa |
snd_pcm_sframes_t size;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t offset;
|
|
Packit Service |
db8eaa |
size = meter->now - s16->old;
|
|
Packit Service |
db8eaa |
if (size < 0)
|
|
Packit Service |
db8eaa |
size += spcm->boundary;
|
|
Packit Service |
db8eaa |
if (size > (snd_pcm_sframes_t)s16->pcm->buffer_size)
|
|
Packit Service |
db8eaa |
size = s16->pcm->buffer_size;
|
|
Packit Service |
db8eaa |
offset = s16->old % meter->buf_size;
|
|
Packit Service |
db8eaa |
while (size > 0) {
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t frames = size;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t cont = meter->buf_size - offset;
|
|
Packit Service |
db8eaa |
if (frames > cont)
|
|
Packit Service |
db8eaa |
frames = cont;
|
|
Packit Service |
db8eaa |
switch (spcm->format) {
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_A_LAW:
|
|
Packit Service |
db8eaa |
snd_pcm_alaw_decode(s16->buf_areas, offset,
|
|
Packit Service |
db8eaa |
meter->buf_areas, offset,
|
|
Packit Service |
db8eaa |
spcm->channels, frames,
|
|
Packit Service |
db8eaa |
s16->index);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_MU_LAW:
|
|
Packit Service |
db8eaa |
snd_pcm_mulaw_decode(s16->buf_areas, offset,
|
|
Packit Service |
db8eaa |
meter->buf_areas, offset,
|
|
Packit Service |
db8eaa |
spcm->channels, frames,
|
|
Packit Service |
db8eaa |
s16->index);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case SND_PCM_FORMAT_IMA_ADPCM:
|
|
Packit Service |
db8eaa |
snd_pcm_adpcm_decode(s16->buf_areas, offset,
|
|
Packit Service |
db8eaa |
meter->buf_areas, offset,
|
|
Packit Service |
db8eaa |
spcm->channels, frames,
|
|
Packit Service |
db8eaa |
s16->index,
|
|
Packit Service |
db8eaa |
s16->adpcm_states);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
default:
|
|
Packit Service |
db8eaa |
snd_pcm_linear_convert(s16->buf_areas, offset,
|
|
Packit Service |
db8eaa |
meter->buf_areas, offset,
|
|
Packit Service |
db8eaa |
spcm->channels, frames,
|
|
Packit Service |
db8eaa |
s16->index);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (frames == cont)
|
|
Packit Service |
db8eaa |
offset = 0;
|
|
Packit Service |
db8eaa |
else
|
|
Packit Service |
db8eaa |
offset += frames;
|
|
Packit Service |
db8eaa |
size -= frames;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
s16->old = meter->now;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static void s16_reset(snd_pcm_scope_t *scope)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_scope_s16_t *s16 = scope->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter = s16->pcm->private_data;
|
|
Packit Service |
db8eaa |
s16->old = meter->now;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static const snd_pcm_scope_ops_t s16_ops = {
|
|
Packit Service |
db8eaa |
.enable = s16_enable,
|
|
Packit Service |
db8eaa |
.disable = s16_disable,
|
|
Packit Service |
db8eaa |
.close = s16_close,
|
|
Packit Service |
db8eaa |
.start = s16_start,
|
|
Packit Service |
db8eaa |
.stop = s16_stop,
|
|
Packit Service |
db8eaa |
.update = s16_update,
|
|
Packit Service |
db8eaa |
.reset = s16_reset,
|
|
Packit Service |
db8eaa |
};
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#endif
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Add a s16 pseudo scope to a #SND_PCM_TYPE_METER PCM
|
|
Packit Service |
db8eaa |
* \param pcm The pcm handle
|
|
Packit Service |
db8eaa |
* \param name Scope name
|
|
Packit Service |
db8eaa |
* \param scopep Pointer to newly created and added scope
|
|
Packit Service |
db8eaa |
* \return 0 on success otherwise a negative error code
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* s16 pseudo scope convert #SND_PCM_TYPE_METER PCM frames in CPU endian
|
|
Packit Service |
db8eaa |
* 16 bit frames for use with other scopes. Don't forget to insert it before
|
|
Packit Service |
db8eaa |
* and to not insert it more time (see #snd_pcm_meter_search_scope)
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
int snd_pcm_scope_s16_open(snd_pcm_t *pcm, const char *name,
|
|
Packit Service |
db8eaa |
snd_pcm_scope_t **scopep)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter;
|
|
Packit Service |
db8eaa |
snd_pcm_scope_t *scope;
|
|
Packit Service |
db8eaa |
snd_pcm_scope_s16_t *s16;
|
|
Packit Service |
db8eaa |
assert(pcm->type == SND_PCM_TYPE_METER);
|
|
Packit Service |
db8eaa |
meter = pcm->private_data;
|
|
Packit Service |
db8eaa |
scope = calloc(1, sizeof(*scope));
|
|
Packit Service |
db8eaa |
if (!scope)
|
|
Packit Service |
db8eaa |
return -ENOMEM;
|
|
Packit Service |
db8eaa |
s16 = calloc(1, sizeof(*s16));
|
|
Packit Service |
db8eaa |
if (!s16) {
|
|
Packit Service |
db8eaa |
free(scope);
|
|
Packit Service |
db8eaa |
return -ENOMEM;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (name)
|
|
Packit Service |
db8eaa |
scope->name = strdup(name);
|
|
Packit Service |
db8eaa |
s16->pcm = pcm;
|
|
Packit Service |
db8eaa |
scope->ops = &s16_ops;
|
|
Packit Service |
db8eaa |
scope->private_data = s16;
|
|
Packit Service |
db8eaa |
list_add_tail(&scope->list, &meter->scopes);
|
|
Packit Service |
db8eaa |
*scopep = scope;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Get s16 pseudo scope frames buffer for a channel
|
|
Packit Service |
db8eaa |
* \param scope s16 pseudo scope handle
|
|
Packit Service |
db8eaa |
* \param channel Channel
|
|
Packit Service |
db8eaa |
* \return Pointer to channel buffer
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
int16_t *snd_pcm_scope_s16_get_channel_buffer(snd_pcm_scope_t *scope,
|
|
Packit Service |
db8eaa |
unsigned int channel)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_scope_s16_t *s16;
|
|
Packit Service |
db8eaa |
snd_pcm_meter_t *meter;
|
|
Packit Service |
db8eaa |
assert(scope->ops == &s16_ops);
|
|
Packit Service |
db8eaa |
s16 = scope->private_data;
|
|
Packit Service |
db8eaa |
meter = s16->pcm->private_data;
|
|
Packit Service |
db8eaa |
assert(meter->gen.slave->setup);
|
|
Packit Service |
db8eaa |
assert(s16->buf_areas);
|
|
Packit Service |
db8eaa |
assert(channel < meter->gen.slave->channels);
|
|
Packit Service |
db8eaa |
return s16->buf_areas[channel].addr;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief allocate an invalid #snd_pcm_scope_t using standard malloc
|
|
Packit Service |
db8eaa |
* \param ptr returned pointer
|
|
Packit Service |
db8eaa |
* \return 0 on success otherwise negative error code
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
int snd_pcm_scope_malloc(snd_pcm_scope_t **ptr)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
assert(ptr);
|
|
Packit Service |
db8eaa |
*ptr = calloc(1, sizeof(snd_pcm_scope_t));
|
|
Packit Service |
db8eaa |
if (!*ptr)
|
|
Packit Service |
db8eaa |
return -ENOMEM;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|