commit
9e6b2472e3
6 changed files with 316 additions and 178 deletions
7
ac108.c
7
ac108.c
|
@ -8,7 +8,6 @@
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
* published by the Free Software Foundation.
|
* published by the Free Software Foundation.
|
||||||
*/
|
*/
|
||||||
#define DEBUG 1
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
@ -777,7 +776,7 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
|
||||||
|
|
||||||
dev_dbg(dai->dev,"rate:%d \n", params_rate(params));
|
dev_dbg(dai->dev,"rate:%d \n", params_rate(params));
|
||||||
for (i = 0; i < ARRAY_SIZE(ac108_sample_rate); i++) {
|
for (i = 0; i < ARRAY_SIZE(ac108_sample_rate); i++) {
|
||||||
if (ac108_sample_rate[i].real_val == params_rate(params)) {
|
if (ac108_sample_rate[i].real_val ==( params_rate(params)/2)) {
|
||||||
rate = i;
|
rate = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -840,8 +839,8 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
|
||||||
* ADC Sample Rate synchronised with I2S1 clock zone
|
* ADC Sample Rate synchronised with I2S1 clock zone
|
||||||
*/
|
*/
|
||||||
ac108_multi_chips_update_bits(ADC_SPRC, 0x0f << ADC_FS_I2S1, ac108_sample_rate[rate].reg_val << ADC_FS_I2S1, ac108);
|
ac108_multi_chips_update_bits(ADC_SPRC, 0x0f << ADC_FS_I2S1, ac108_sample_rate[rate].reg_val << ADC_FS_I2S1, ac108);
|
||||||
|
ac108_multi_chips_write(HPF_EN,0x0f,ac108);
|
||||||
ac108_configure_clocking(ac108, rate);
|
ac108_configure_clocking(ac108, ac108_sample_rate[rate].real_val);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ CFLAGS += -I. -Wall -funroll-loops -ffast-math -fPIC -DPIC -O0 -g
|
||||||
LD := gcc
|
LD := gcc
|
||||||
LDFLAGS += -Wall -shared -lasound
|
LDFLAGS += -Wall -shared -lasound
|
||||||
|
|
||||||
SND_PCM_OBJECTS = pcm_ac108.o
|
SND_PCM_OBJECTS = pcm_ac108.o ac108_help.o
|
||||||
SND_PCM_LIBS =
|
SND_PCM_LIBS =
|
||||||
SND_PCM_BIN = libasound_module_pcm_ac108.so
|
SND_PCM_BIN = libasound_module_pcm_ac108.so
|
||||||
|
|
||||||
|
|
77
ac108_plugin/ac108_help.c
Normal file
77
ac108_plugin/ac108_help.c
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#include "ac108_help.h"
|
||||||
|
|
||||||
|
void generate_sine(const snd_pcm_channel_area_t *areas,
|
||||||
|
snd_pcm_uframes_t offset,
|
||||||
|
int count, double *_phase)
|
||||||
|
{
|
||||||
|
snd_pcm_format_t format = SND_PCM_FORMAT_S32; /* sample format */
|
||||||
|
unsigned int rate = 16000; /* stream rate */
|
||||||
|
unsigned int channels = 4; /* count of channels */
|
||||||
|
unsigned int buffer_time = 500000; /* ring buffer length in us */
|
||||||
|
unsigned int period_time = 100000; /* period time in us */
|
||||||
|
double freq = 160; /* sinusoidal wave frequency in Hz */
|
||||||
|
int verbose = 0; /* verbose flag */
|
||||||
|
int resample = 1; /* enable alsa-lib resampling */
|
||||||
|
int period_event = 0; /* produce poll event after each period */
|
||||||
|
|
||||||
|
static double max_phase = 2. * M_PI;
|
||||||
|
double phase = *_phase;
|
||||||
|
double step = max_phase*freq/(double)rate;
|
||||||
|
unsigned char *samples[channels];
|
||||||
|
int steps[channels];
|
||||||
|
unsigned int chn;
|
||||||
|
int format_bits = snd_pcm_format_width(format);
|
||||||
|
unsigned int maxval = (1 << (format_bits - 1)) - 1;
|
||||||
|
int bps = format_bits / 8; /* bytes per sample */
|
||||||
|
int phys_bps = snd_pcm_format_physical_width(format) / 8;
|
||||||
|
int big_endian = snd_pcm_format_big_endian(format) == 1;
|
||||||
|
int to_unsigned = snd_pcm_format_unsigned(format) == 1;
|
||||||
|
int is_float = (format == SND_PCM_FORMAT_FLOAT_LE ||
|
||||||
|
format == SND_PCM_FORMAT_FLOAT_BE);
|
||||||
|
|
||||||
|
/* verify and prepare the contents of areas */
|
||||||
|
for (chn = 0; chn < channels; chn++) {
|
||||||
|
if ((areas[chn].first % 8) != 0) {
|
||||||
|
printf("areas[%i].first == %i, aborting...\n", chn, areas[chn].first);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
samples[chn] = /*(signed short *)*/(((unsigned char *)areas[chn].addr) + (areas[chn].first / 8));
|
||||||
|
if ((areas[chn].step % 16) != 0) {
|
||||||
|
printf("areas[%i].step == %i, aborting...\n", chn, areas[chn].step);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
steps[chn] = areas[chn].step / 8;
|
||||||
|
samples[chn] += offset * steps[chn];
|
||||||
|
}
|
||||||
|
/* fill the channel areas */
|
||||||
|
while (count-- > 0) {
|
||||||
|
union {
|
||||||
|
float f;
|
||||||
|
int i;
|
||||||
|
} fval;
|
||||||
|
int res, i;
|
||||||
|
if (is_float) {
|
||||||
|
fval.f = sin(phase);
|
||||||
|
res = fval.i;
|
||||||
|
} else
|
||||||
|
res = sin(phase) * maxval;
|
||||||
|
if (to_unsigned)
|
||||||
|
res ^= 1U << (format_bits - 1);
|
||||||
|
for (chn = 0; chn < channels; chn++) {
|
||||||
|
/* Generate data in native endian format */
|
||||||
|
if (big_endian) {
|
||||||
|
for (i = 0; i < bps; i++)
|
||||||
|
*(samples[chn] + phys_bps - 1 - i) = (res >> i * 8) & 0xff;
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < bps; i++)
|
||||||
|
*(samples[chn] + i) = (res >> i * 8) & 0xff;
|
||||||
|
}
|
||||||
|
samples[chn] += steps[chn];
|
||||||
|
}
|
||||||
|
phase += step;
|
||||||
|
if (phase >= max_phase)
|
||||||
|
phase -= max_phase;
|
||||||
|
}
|
||||||
|
*_phase = phase;
|
||||||
|
}
|
||||||
|
|
11
ac108_plugin/ac108_help.h
Normal file
11
ac108_plugin/ac108_help.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <alsa/asoundlib.h>
|
||||||
|
#include <alsa/pcm_external.h>
|
||||||
|
#include <alsa/pcm_plugin.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
void generate_sine(const snd_pcm_channel_area_t *areas,
|
||||||
|
snd_pcm_uframes_t offset,
|
||||||
|
int count, double *_phase);
|
Binary file not shown.
|
@ -5,193 +5,247 @@
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
#include <alsa/pcm_external.h>
|
#include <alsa/pcm_external.h>
|
||||||
#include <alsa/pcm_plugin.h>
|
#include <alsa/pcm_plugin.h>
|
||||||
|
#include "ac108_help.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof(ary[0]))
|
#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof(ary[0]))
|
||||||
#define AC108_FRAME_SIZE 4096
|
#define AC108_FRAME_SIZE 40960
|
||||||
struct ac108_t {
|
struct ac108_t {
|
||||||
snd_pcm_ioplug_t io;
|
snd_pcm_ioplug_t io;
|
||||||
snd_pcm_t *slave;
|
snd_pcm_t *pcm;
|
||||||
snd_pcm_hw_params_t *hw_params;
|
snd_pcm_hw_params_t *hw_params;
|
||||||
unsigned int last_size;
|
unsigned int last_size;
|
||||||
unsigned int ptr;
|
unsigned int ptr;
|
||||||
void *buf;
|
|
||||||
unsigned int latency; // Delay in usec
|
unsigned int latency; // Delay in usec
|
||||||
unsigned int bufferSize; // Size of sample buffer
|
unsigned int bufferSize; // Size of sample buffer
|
||||||
};
|
};
|
||||||
|
static unsigned char capture_buf[AC108_FRAME_SIZE];
|
||||||
/* set up the fixed parameters of slave PCM hw_parmas */
|
/* set up the fixed parameters of pcm PCM hw_parmas */
|
||||||
static int ac108_slave_hw_params_half(struct ac108_t *rec, unsigned int rate,snd_pcm_format_t format) {
|
static int ac108_slave_hw_params_half(struct ac108_t *capture, unsigned int rate,snd_pcm_format_t format) {
|
||||||
int err;
|
int err;
|
||||||
snd_pcm_uframes_t bufferSize = rec->bufferSize;
|
snd_pcm_uframes_t bufferSize = capture->bufferSize;
|
||||||
unsigned int latency = rec->latency;
|
unsigned int latency = capture->latency;
|
||||||
|
|
||||||
unsigned int buffer_time = 0;
|
unsigned int buffer_time = 0;
|
||||||
unsigned int period_time = 0;
|
unsigned int period_time = 0;
|
||||||
if ((err = snd_pcm_hw_params_malloc(&rec->hw_params)) < 0) return err;
|
if ((err = snd_pcm_hw_params_malloc(&capture->hw_params)) < 0) return err;
|
||||||
|
|
||||||
if ((err = snd_pcm_hw_params_any(rec->slave, rec->hw_params)) < 0) {
|
if ((err = snd_pcm_hw_params_any(capture->pcm, capture->hw_params)) < 0) {
|
||||||
SNDERR("Cannot get slave hw_params");
|
SNDERR("Cannot get pcm hw_params");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if ((err = snd_pcm_hw_params_set_access(rec->slave, rec->hw_params,
|
if ((err = snd_pcm_hw_params_set_access(capture->pcm, capture->hw_params,
|
||||||
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
|
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
|
||||||
SNDERR("Cannot set slave access RW_INTERLEAVED");
|
SNDERR("Cannot set pcm access RW_INTERLEAVED");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if ((err = snd_pcm_hw_params_set_channels(rec->slave, rec->hw_params, 2)) < 0) {
|
if ((err = snd_pcm_hw_params_set_channels(capture->pcm, capture->hw_params, 2)) < 0) {
|
||||||
SNDERR("Cannot set slave channels 2");
|
SNDERR("Cannot set pcm channels 2");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if ((err = snd_pcm_hw_params_set_format(rec->slave, rec->hw_params,
|
if ((err = snd_pcm_hw_params_set_format(capture->pcm, capture->hw_params,
|
||||||
format)) < 0) {
|
format)) < 0) {
|
||||||
SNDERR("Cannot set slave format");
|
SNDERR("Cannot set pcm format");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if ((err = snd_pcm_hw_params_set_rate(rec->slave, rec->hw_params, rate, 0)) < 0) {
|
if ((err = snd_pcm_hw_params_set_rate(capture->pcm, capture->hw_params, rate, 0)) < 0) {
|
||||||
SNDERR("Cannot set slave rate %d", rate);
|
SNDERR("Cannot set pcm rate %d", rate);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snd_pcm_hw_params_get_buffer_time_max(rec->hw_params,
|
err = snd_pcm_hw_params_get_buffer_time_max(capture->hw_params,
|
||||||
&buffer_time, 0);
|
&buffer_time, 0);
|
||||||
if (buffer_time > 80000)
|
if (buffer_time > 80000)
|
||||||
buffer_time = 80000;
|
buffer_time = 80000;
|
||||||
period_time = buffer_time / 4;
|
period_time = buffer_time / 4;
|
||||||
|
|
||||||
err = snd_pcm_hw_params_set_period_time_near(rec->slave, rec->hw_params,
|
err = snd_pcm_hw_params_set_period_time_near(capture->pcm, capture->hw_params,
|
||||||
&period_time, 0);
|
&period_time, 0);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
fprintf(stderr,"Unable to set_period_time_near");
|
SNDERR("Unable to set_period_time_near");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
err = snd_pcm_hw_params_set_buffer_time_near(rec->slave, rec->hw_params,
|
err = snd_pcm_hw_params_set_buffer_time_near(capture->pcm, capture->hw_params,
|
||||||
&buffer_time, 0);
|
&buffer_time, 0);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
fprintf(stderr,"Unable to set_buffer_time_near");
|
SNDERR("Unable to set_buffer_time_near");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
rec->bufferSize = bufferSize;
|
capture->bufferSize = bufferSize;
|
||||||
rec->latency = latency;
|
capture->latency = latency;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
free(rec->hw_params);
|
free(capture->hw_params);
|
||||||
rec->hw_params = NULL;
|
capture->hw_params = NULL;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* start and stop callbacks - just trigger slave PCM
|
* start and stop callbacks - just trigger pcm PCM
|
||||||
*/
|
*/
|
||||||
static int ac108_start(snd_pcm_ioplug_t *io) {
|
static int ac108_start(snd_pcm_ioplug_t *io) {
|
||||||
struct ac108_t *rec = io->private_data;
|
struct ac108_t *capture = io->private_data;
|
||||||
|
if(!capture->pcm) {
|
||||||
|
SNDERR( "pcm is lost\n");
|
||||||
|
}
|
||||||
|
|
||||||
if(!rec->slave) {
|
return snd_pcm_start(capture->pcm);
|
||||||
fprintf(stderr, "slave is lost\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return snd_pcm_start(rec->slave);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ac108_stop(snd_pcm_ioplug_t *io) {
|
static int ac108_stop(snd_pcm_ioplug_t *io) {
|
||||||
struct ac108_t *rec = io->private_data;
|
struct ac108_t *capture = io->private_data;
|
||||||
|
|
||||||
return snd_pcm_drop(rec->slave);
|
return snd_pcm_drop(capture->pcm);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* pointer callback
|
* pointer callback
|
||||||
*
|
*
|
||||||
* Calculate the current position from the delay of slave PCM
|
* Calculate the current position from the delay of pcm PCM
|
||||||
*/
|
*/
|
||||||
static snd_pcm_sframes_t ac108_pointer(snd_pcm_ioplug_t *io) {
|
static snd_pcm_sframes_t ac108_pointer(snd_pcm_ioplug_t *io) {
|
||||||
struct ac108_t *rec = io->private_data;
|
|
||||||
int err, size;
|
|
||||||
|
|
||||||
assert(rec);
|
struct ac108_t *capture = io->private_data;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
assert(capture);
|
||||||
|
|
||||||
|
|
||||||
size = snd_pcm_avail(rec->slave);
|
size = snd_pcm_avail(capture->pcm);
|
||||||
if (size < 0) return size;
|
if (size < 0)
|
||||||
size = size /2;
|
return size;
|
||||||
if (size > rec->last_size) {
|
|
||||||
rec->ptr += size - rec->last_size;
|
size = size/2;
|
||||||
rec->ptr %= io->buffer_size;
|
|
||||||
|
if (size > capture->last_size) {
|
||||||
|
capture->ptr += size - capture->last_size;
|
||||||
|
capture->ptr %= io->buffer_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
rec->last_size = size;
|
//fprintf(stderr, "%s :%d %d %d %d %d %d\n", __func__,capture->ptr ,capture->last_size,size, io->buffer_size,io->appl_ptr, io->hw_ptr);
|
||||||
|
capture->last_size = size;
|
||||||
//fprintf(stderr, "%s :%d %d %d %d\n", __func__, rec->ptr,size, io->appl_ptr, io->hw_ptr);
|
|
||||||
return rec->ptr;
|
return capture->ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* transfer callback
|
* transfer callback
|
||||||
*/
|
*/
|
||||||
static snd_pcm_sframes_t ac108_transfer(snd_pcm_ioplug_t *io,
|
static snd_pcm_sframes_t ac108_transfer(snd_pcm_ioplug_t *io,
|
||||||
const snd_pcm_channel_area_t *areas,
|
const snd_pcm_channel_area_t *dst_areas,
|
||||||
snd_pcm_uframes_t offset,
|
snd_pcm_uframes_t dst_offset,
|
||||||
snd_pcm_uframes_t size) {
|
snd_pcm_uframes_t size) {
|
||||||
struct ac108_t *rec = io->private_data;
|
struct ac108_t *capture = io->private_data;
|
||||||
char *buf;
|
int chn;
|
||||||
ssize_t result;
|
unsigned char *dst_samples[io->channels];
|
||||||
int err;
|
int dst_steps[io->channels];
|
||||||
|
int bps = snd_pcm_format_width(io->format) / 8; /* bytes per sample */
|
||||||
|
int i;
|
||||||
|
int count = 0;
|
||||||
|
int err = 0;
|
||||||
|
unsigned char *src_buf;
|
||||||
|
unsigned char src_data[4][4];
|
||||||
|
|
||||||
|
|
||||||
|
memset(capture_buf,0,AC108_FRAME_SIZE);
|
||||||
|
|
||||||
/* we handle only an interleaved buffer */
|
if(snd_pcm_avail(capture->pcm) > size*2){
|
||||||
buf = (char *)areas->addr + (areas->first + areas->step * offset) / 8;
|
if ((err = snd_pcm_readi (capture->pcm, capture_buf, size*2)) != size*2) {
|
||||||
result = snd_pcm_readi(rec->slave, buf, size*2);
|
SNDERR("read from audio interface failed %ld %d %s!\n",size,err,snd_strerror (err));
|
||||||
if (result <= 0) {
|
exit(EXIT_FAILURE);
|
||||||
fprintf(stderr, "%s out error:%d %d\n", __func__, result);
|
size = 0 ;
|
||||||
return result;
|
}
|
||||||
|
}else{
|
||||||
|
size = 0;
|
||||||
}
|
}
|
||||||
rec->last_size -= size;
|
#if 1
|
||||||
|
/* verify and prepare the contents of areas */
|
||||||
|
for (chn = 0; chn < io->channels; chn++) {
|
||||||
|
if ((dst_areas[chn].first % 8) != 0) {
|
||||||
|
SNDERR("dst_areas[%i].first == %i, aborting...\n", chn, dst_areas[chn].first);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
dst_samples[chn] = /*(signed short *)*/(((unsigned char *)dst_areas[chn].addr) + (dst_areas[chn].first / 8));
|
||||||
|
if ((dst_areas[chn].step % 16) != 0) {
|
||||||
|
SNDERR("dst_areas[%i].step == %i, aborting...\n", chn, dst_areas[chn].step);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
dst_steps[chn] = dst_areas[chn].step / 8;
|
||||||
|
dst_samples[chn] += dst_offset * dst_steps[chn];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// for(i = 0; i < size*2*bps;i++){
|
||||||
|
// fprintf(stderr,"%x ",capture_buf[i]);
|
||||||
|
// if(i%4 == 0)
|
||||||
|
// fprintf(stderr,"\n");
|
||||||
|
// }
|
||||||
|
|
||||||
|
//generate_sine(dst_areas, dst_offset,size, &count);
|
||||||
|
src_buf = capture_buf;
|
||||||
|
#if 1
|
||||||
|
while(count < size){
|
||||||
|
for(chn = 0; chn < 4; chn++){
|
||||||
|
for (i = 0; i < bps; i++){
|
||||||
|
src_data[chn][i] = src_buf[i];
|
||||||
|
}
|
||||||
|
src_buf += bps ;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(chn = 0; chn < io->channels; chn++){
|
||||||
|
for (i = 0; i < bps; i++){
|
||||||
|
*(dst_samples[chn] + i) = src_data[chn][i];
|
||||||
|
//fprintf(stderr,"%x ",*(dst_samples[chn] + i));
|
||||||
|
}
|
||||||
|
//fprintf(stderr,"\n");
|
||||||
|
dst_samples[chn] += dst_steps[chn];
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
capture->last_size -= size;
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* poll-related callbacks - just pass to slave PCM
|
* poll-related callbacks - just pass to pcm PCM
|
||||||
*/
|
*/
|
||||||
static int ac108_poll_descriptors_count(snd_pcm_ioplug_t *io) {
|
static int ac108_poll_descriptors_count(snd_pcm_ioplug_t *io) {
|
||||||
struct ac108_t *rec = io->private_data;
|
struct ac108_t *capture = io->private_data;
|
||||||
|
|
||||||
//fprintf(stderr, "%s\n", __FUNCTION__);
|
return snd_pcm_poll_descriptors_count(capture->pcm);
|
||||||
return snd_pcm_poll_descriptors_count(rec->slave);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ac108_poll_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfd,
|
static int ac108_poll_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfd,
|
||||||
unsigned int space) {
|
unsigned int space) {
|
||||||
struct ac108_t *rec = io->private_data;
|
struct ac108_t *capture = io->private_data;
|
||||||
|
|
||||||
//fprintf(stderr, "%s\n", __FUNCTION__);
|
return snd_pcm_poll_descriptors(capture->pcm, pfd, space);
|
||||||
return snd_pcm_poll_descriptors(rec->slave, pfd, space);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ac108_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfd,
|
static int ac108_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfd,
|
||||||
unsigned int nfds, unsigned short *revents) {
|
unsigned int nfds, unsigned short *revents) {
|
||||||
struct ac108_t *rec = io->private_data;
|
struct ac108_t *capture = io->private_data;
|
||||||
|
|
||||||
//fprintf(stderr, "%s\n", __FUNCTION__);
|
return snd_pcm_poll_descriptors_revents(capture->pcm, pfd, nfds, revents);
|
||||||
return snd_pcm_poll_descriptors_revents(rec->slave, pfd, nfds, revents);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* close callback
|
* close callback
|
||||||
*/
|
*/
|
||||||
static int ac108_close(snd_pcm_ioplug_t *io) {
|
static int ac108_close(snd_pcm_ioplug_t *io) {
|
||||||
struct ac108_t *rec = io->private_data;
|
struct ac108_t *capture = io->private_data;
|
||||||
|
if (capture->pcm)
|
||||||
|
snd_pcm_close(capture->pcm);
|
||||||
|
|
||||||
if (rec->slave) return snd_pcm_close(rec->slave);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int setSoftwareParams(struct ac108_t *rec) {
|
static int setSoftwareParams(struct ac108_t *capture) {
|
||||||
snd_pcm_sw_params_t *softwareParams;
|
snd_pcm_sw_params_t *softwareParams;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -201,49 +255,49 @@ static int setSoftwareParams(struct ac108_t *rec) {
|
||||||
snd_pcm_sw_params_alloca(&softwareParams);
|
snd_pcm_sw_params_alloca(&softwareParams);
|
||||||
|
|
||||||
// Get the current software parameters
|
// Get the current software parameters
|
||||||
err = snd_pcm_sw_params_current(rec->slave, softwareParams);
|
err = snd_pcm_sw_params_current(capture->pcm, softwareParams);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
fprintf(stderr, "Unable to get software parameters: %s", snd_strerror(err));
|
SNDERR("Unable to get software parameters: %s", snd_strerror(err));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure ALSA to start the transfer when the buffer is almost full.
|
// Configure ALSA to start the transfer when the buffer is almost full.
|
||||||
snd_pcm_get_params(rec->slave, &bufferSize, &periodSize);
|
snd_pcm_get_params(capture->pcm, &bufferSize, &periodSize);
|
||||||
|
|
||||||
|
|
||||||
startThreshold = 1;
|
startThreshold = 1;
|
||||||
stopThreshold = bufferSize;
|
stopThreshold = bufferSize;
|
||||||
|
|
||||||
|
|
||||||
err = snd_pcm_sw_params_set_start_threshold(rec->slave, softwareParams,
|
err = snd_pcm_sw_params_set_start_threshold(capture->pcm, softwareParams,
|
||||||
startThreshold);
|
startThreshold);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
fprintf(stderr, "Unable to set start threshold to %lu frames: %s",
|
SNDERR("Unable to set start threshold to %lu frames: %s",
|
||||||
startThreshold, snd_strerror(err));
|
startThreshold, snd_strerror(err));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snd_pcm_sw_params_set_stop_threshold(rec->slave, softwareParams,
|
err = snd_pcm_sw_params_set_stop_threshold(capture->pcm, softwareParams,
|
||||||
stopThreshold);
|
stopThreshold);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
fprintf(stderr, "Unable to set stop threshold to %lu frames: %s",
|
SNDERR("Unable to set stop threshold to %lu frames: %s",
|
||||||
stopThreshold, snd_strerror(err));
|
stopThreshold, snd_strerror(err));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
// Allow the transfer to start when at least periodSize samples can be
|
// Allow the transfer to start when at least periodSize samples can be
|
||||||
// processed.
|
// processed.
|
||||||
err = snd_pcm_sw_params_set_avail_min(rec->slave, softwareParams,
|
err = snd_pcm_sw_params_set_avail_min(capture->pcm, softwareParams,
|
||||||
periodSize);
|
periodSize);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
fprintf(stderr, "Unable to configure available minimum to %lu: %s",
|
SNDERR("Unable to configure available minimum to %lu: %s",
|
||||||
periodSize, snd_strerror(err));
|
periodSize, snd_strerror(err));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commit the software parameters back to the device.
|
// Commit the software parameters back to the device.
|
||||||
err = snd_pcm_sw_params(rec->slave, softwareParams);
|
err = snd_pcm_sw_params(capture->pcm, softwareParams);
|
||||||
if (err < 0) fprintf(stderr, "Unable to configure software parameters: %s",
|
if (err < 0)
|
||||||
snd_strerror(err));
|
SNDERR("Unable to configure software parameters: %s",snd_strerror(err));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -256,81 +310,68 @@ done:
|
||||||
/*
|
/*
|
||||||
* hw_params callback
|
* hw_params callback
|
||||||
*
|
*
|
||||||
* Set up slave PCM according to the current parameters
|
* Set up pcm PCM according to the current parameters
|
||||||
*/
|
*/
|
||||||
//static int ac108_hw_params(snd_pcm_ioplug_t *io,
|
static int ac108_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params) {
|
||||||
// snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED) {
|
struct ac108_t *capture = io->private_data;
|
||||||
static int ac108_hw_params(snd_pcm_ioplug_t *io) {
|
|
||||||
struct ac108_t *rec = io->private_data;
|
|
||||||
snd_pcm_sw_params_t *sparams;
|
|
||||||
snd_pcm_uframes_t period_size;
|
snd_pcm_uframes_t period_size;
|
||||||
snd_pcm_uframes_t buffer_size;
|
snd_pcm_uframes_t buffer_size;
|
||||||
int err;
|
int err;
|
||||||
if (!rec->hw_params) {
|
if (!capture->hw_params) {
|
||||||
err = ac108_slave_hw_params_half(rec, 2*io->rate,io->format);
|
err = ac108_slave_hw_params_half(capture, 2*io->rate,io->format);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
fprintf(stderr, "ac108_slave_hw_params_half error\n");
|
SNDERR("ac108_slave_hw_params_half error\n");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
period_size = io->period_size;
|
period_size = io->period_size;
|
||||||
if ((err = snd_pcm_hw_params_set_period_size_near(rec->slave, rec->hw_params,
|
if ((err = snd_pcm_hw_params_set_period_size_near(capture->pcm, capture->hw_params,
|
||||||
&period_size, NULL)) < 0) {
|
&period_size, NULL)) < 0) {
|
||||||
SNDERR("Cannot set slave period size %ld", period_size);
|
SNDERR("Cannot set pcm period size %ld", period_size);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
buffer_size = io->buffer_size;
|
buffer_size = io->buffer_size;
|
||||||
if ((err = snd_pcm_hw_params_set_buffer_size_near(rec->slave, rec->hw_params,
|
if ((err = snd_pcm_hw_params_set_buffer_size_near(capture->pcm, capture->hw_params,
|
||||||
&buffer_size)) < 0) {
|
&buffer_size)) < 0) {
|
||||||
SNDERR("Cannot set slave buffer size %ld", buffer_size);
|
SNDERR("Cannot set pcm buffer size %ld", buffer_size);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
if ((err = snd_pcm_hw_params(rec->slave, rec->hw_params)) < 0) {
|
if ((err = snd_pcm_hw_params(capture->pcm, capture->hw_params)) < 0) {
|
||||||
SNDERR("Cannot set slave hw_params");
|
SNDERR("Cannot set pcm hw_params");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
setSoftwareParams(capture);
|
||||||
setSoftwareParams(rec);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* hw_free callback
|
* hw_free callback
|
||||||
*/
|
*/
|
||||||
static int ac108_hw_free(snd_pcm_ioplug_t *io) {
|
static int ac108_hw_free(snd_pcm_ioplug_t *io) {
|
||||||
struct ac108_t *rec = io->private_data;
|
struct ac108_t *capture = io->private_data;
|
||||||
free(rec->hw_params);
|
free(capture->hw_params);
|
||||||
if (rec->buf != NULL) {
|
capture->hw_params = NULL;
|
||||||
free(rec->buf);
|
|
||||||
rec->buf = NULL;
|
return snd_pcm_hw_free(capture->pcm);
|
||||||
}
|
|
||||||
rec->hw_params = NULL;
|
|
||||||
|
|
||||||
return snd_pcm_hw_free(rec->slave);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int ac108_prepare(snd_pcm_ioplug_t *io) {
|
static int ac108_prepare(snd_pcm_ioplug_t *io) {
|
||||||
struct ac108_t *rec = io->private_data;
|
struct ac108_t *capture = io->private_data;
|
||||||
rec->ptr = 0;
|
capture->ptr = 0;
|
||||||
rec->last_size =0;
|
capture->last_size =0;
|
||||||
if (rec->buf == NULL) {
|
return snd_pcm_prepare(capture->pcm);
|
||||||
rec->buf = malloc(io->buffer_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return snd_pcm_prepare(rec->slave);
|
|
||||||
}
|
}
|
||||||
static int ac108_drain(snd_pcm_ioplug_t *io) {
|
static int ac108_drain(snd_pcm_ioplug_t *io) {
|
||||||
struct ac108_t *rec = io->private_data;
|
struct ac108_t *capture = io->private_data;
|
||||||
return snd_pcm_drain(rec->slave);
|
|
||||||
|
return snd_pcm_drain(capture->pcm);
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
static int ac108_sw_params(snd_pcm_ioplug_t *io, snd_pcm_sw_params_t *params) {
|
static int ac108_sw_params(snd_pcm_ioplug_t *io, snd_pcm_sw_params_t *params) {
|
||||||
struct ac108_t *rec = io->private_data;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
static int ac108_delay(snd_pcm_ioplug_t * io, snd_pcm_sframes_t * delayp){
|
static int ac108_delay(snd_pcm_ioplug_t * io, snd_pcm_sframes_t * delayp){
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -356,10 +397,9 @@ static snd_pcm_ioplug_callback_t a108_ops = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static int ac108_set_hw_constraint(struct ac108_t *rec) {
|
static int ac108_set_hw_constraint(struct ac108_t *capture) {
|
||||||
static unsigned int accesses[] = {
|
static unsigned int accesses[] = {
|
||||||
SND_PCM_ACCESS_RW_INTERLEAVED,
|
SND_PCM_ACCESS_RW_INTERLEAVED
|
||||||
SND_PCM_ACCESS_RW_NONINTERLEAVED
|
|
||||||
};
|
};
|
||||||
unsigned int formats[] = { SND_PCM_FORMAT_S32,
|
unsigned int formats[] = { SND_PCM_FORMAT_S32,
|
||||||
SND_PCM_FORMAT_S16 };
|
SND_PCM_FORMAT_S16 };
|
||||||
|
@ -367,54 +407,64 @@ static int ac108_set_hw_constraint(struct ac108_t *rec) {
|
||||||
unsigned int rates[] = {
|
unsigned int rates[] = {
|
||||||
8000,
|
8000,
|
||||||
16000,
|
16000,
|
||||||
48000
|
32000,
|
||||||
|
44100,
|
||||||
|
48000,
|
||||||
|
96000
|
||||||
};
|
};
|
||||||
int err;
|
int err;
|
||||||
snd_pcm_uframes_t buffer_max;
|
|
||||||
unsigned int period_bytes, max_periods;
|
|
||||||
|
|
||||||
|
|
||||||
err = snd_pcm_ioplug_set_param_list(&rec->io,
|
err = snd_pcm_ioplug_set_param_list(&capture->io,
|
||||||
SND_PCM_IOPLUG_HW_ACCESS,
|
SND_PCM_IOPLUG_HW_ACCESS,
|
||||||
ARRAY_SIZE(accesses),
|
ARRAY_SIZE(accesses),
|
||||||
accesses);
|
accesses);
|
||||||
if (err < 0) return err;
|
if (err < 0){
|
||||||
|
SNDERR("ioplug cannot set ac108 hw access");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
if ((err = snd_pcm_ioplug_set_param_list(&rec->io, SND_PCM_IOPLUG_HW_FORMAT,
|
if ((err = snd_pcm_ioplug_set_param_list(&capture->io, SND_PCM_IOPLUG_HW_FORMAT,
|
||||||
ARRAY_SIZE(formats), formats)) < 0 ||
|
ARRAY_SIZE(formats), formats)) < 0 ||
|
||||||
(err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_CHANNELS,
|
(err = snd_pcm_ioplug_set_param_minmax(&capture->io, SND_PCM_IOPLUG_HW_CHANNELS,
|
||||||
4, 4)) < 0 ||
|
1, 4)) < 0 ||
|
||||||
(err = snd_pcm_ioplug_set_param_list(&rec->io, SND_PCM_IOPLUG_HW_RATE,
|
(err = snd_pcm_ioplug_set_param_list(&capture->io, SND_PCM_IOPLUG_HW_RATE,
|
||||||
ARRAY_SIZE(rates), rates)) < 0) return err;
|
ARRAY_SIZE(rates), rates)) < 0)
|
||||||
err = snd_pcm_ioplug_set_param_minmax(&rec->io,
|
{
|
||||||
SND_PCM_IOPLUG_HW_BUFFER_BYTES,
|
SNDERR("ioplug cannot set ac108 format channel rate!");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
err = snd_pcm_ioplug_set_param_minmax(&capture->io,SND_PCM_IOPLUG_HW_BUFFER_BYTES,
|
||||||
1, 4 * 1024 * 1024);
|
1, 4 * 1024 * 1024);
|
||||||
if (err < 0) return err;
|
if (err < 0){
|
||||||
|
SNDERR("ioplug cannot set ac108 hw buffer bytes");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
err = snd_pcm_ioplug_set_param_minmax(&rec->io,
|
err = snd_pcm_ioplug_set_param_minmax(&capture->io,SND_PCM_IOPLUG_HW_PERIOD_BYTES,
|
||||||
SND_PCM_IOPLUG_HW_PERIOD_BYTES,
|
|
||||||
128, 2 * 1024 * 1024);
|
128, 2 * 1024 * 1024);
|
||||||
if (err < 0) return err;
|
if (err < 0) {
|
||||||
|
SNDERR("ioplug cannot set ac108 hw period bytes");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_PERIODS,
|
err = snd_pcm_ioplug_set_param_minmax(&capture->io, SND_PCM_IOPLUG_HW_PERIODS,3, 1024);
|
||||||
3, 1024);
|
if (err < 0) {
|
||||||
|
SNDERR("ioplug cannot set ac108 hw periods");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
/*
|
/*
|
||||||
* Main entry point
|
* Main entry point
|
||||||
*/
|
*/
|
||||||
SND_PCM_PLUGIN_DEFINE_FUNC(ac108) {
|
SND_PCM_PLUGIN_DEFINE_FUNC(ac108) {
|
||||||
snd_config_iterator_t i, next;
|
snd_config_iterator_t i, next;
|
||||||
int err;
|
int err;
|
||||||
const char *card = NULL;
|
|
||||||
const char *pcm_string = NULL;
|
const char *pcm_string = NULL;
|
||||||
snd_pcm_format_t format = SND_PCM_FORMAT_S32_LE;
|
struct ac108_t *capture;
|
||||||
char devstr[128], tmpcard[8];
|
|
||||||
struct ac108_t *rec;
|
|
||||||
int channels;
|
int channels;
|
||||||
struct pollfd fds;
|
|
||||||
if (stream != SND_PCM_STREAM_CAPTURE) {
|
if (stream != SND_PCM_STREAM_CAPTURE) {
|
||||||
SNDERR("a108 is only for capture");
|
SNDERR("a108 is only for capture");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -449,36 +499,37 @@ SND_PCM_PLUGIN_DEFINE_FUNC(ac108) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rec = calloc(1, sizeof(*rec));
|
|
||||||
if (!rec) {
|
capture = calloc(1, sizeof(*capture));
|
||||||
|
if (!capture) {
|
||||||
SNDERR("cannot allocate");
|
SNDERR("cannot allocate");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
err = snd_pcm_open(&rec->slave, pcm_string, stream, mode);
|
err = snd_pcm_open(&capture->pcm, pcm_string, stream, mode);
|
||||||
if (err < 0) goto error;
|
if (err < 0) goto error;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//SND_PCM_NONBLOCK
|
//SND_PCM_NONBLOCK
|
||||||
rec->io.version = SND_PCM_IOPLUG_VERSION;
|
capture->io.version = SND_PCM_IOPLUG_VERSION;
|
||||||
rec->io.name = "AC108 decode Plugin";
|
capture->io.name = "AC108 decode Plugin";
|
||||||
rec->io.mmap_rw = 0;
|
capture->io.mmap_rw = 0;
|
||||||
rec->io.callback = &a108_ops;
|
capture->io.callback = &a108_ops;
|
||||||
rec->io.private_data = rec;
|
capture->io.private_data = capture;
|
||||||
|
|
||||||
err = snd_pcm_ioplug_create(&rec->io, name, stream, mode);
|
err = snd_pcm_ioplug_create(&capture->io, name, stream, mode);
|
||||||
if (err < 0) goto error;
|
if (err < 0) goto error;
|
||||||
|
|
||||||
if ((err = ac108_set_hw_constraint(rec)) < 0) {
|
if ((err = ac108_set_hw_constraint(capture)) < 0) {
|
||||||
snd_pcm_ioplug_delete(&rec->io);
|
snd_pcm_ioplug_delete(&capture->io);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
*pcmp = rec->io.pcm;
|
*pcmp = capture->io.pcm;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (rec->slave) snd_pcm_close(rec->slave);
|
if (capture->pcm) snd_pcm_close(capture->pcm);
|
||||||
free(rec);
|
free(capture);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue