From 6a0b216dbf0dd17c3bcf100c43bddc8d81f3d792 Mon Sep 17 00:00:00 2001 From: Baozhu Zuo Date: Sat, 30 Sep 2017 15:58:30 +0800 Subject: [PATCH 1/8] enable High Pass Filter --- ac108.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ac108.c b/ac108.c index cafc10e..c4b79c2 100644 --- a/ac108.c +++ b/ac108.c @@ -840,7 +840,7 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h * 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_write(HPF_EN,0x0f,ac108); ac108_configure_clocking(ac108, rate); return 0; } From f362cdd383561e73a3b47600eb357c126a23e091 Mon Sep 17 00:00:00 2001 From: Baozhu Zuo Date: Sat, 30 Sep 2017 16:00:07 +0800 Subject: [PATCH 2/8] enable chosen single channel --- ac108_plugin/pcm_ac108.c | 393 +++++++++++++++++++++++++-------------- 1 file changed, 249 insertions(+), 144 deletions(-) diff --git a/ac108_plugin/pcm_ac108.c b/ac108_plugin/pcm_ac108.c index 5d7a19f..bd4d6b4 100644 --- a/ac108_plugin/pcm_ac108.c +++ b/ac108_plugin/pcm_ac108.c @@ -5,193 +5,291 @@ #include #include #include - +#include "ac108_help.h" #include #define ARRAY_SIZE(ary) (sizeof(ary)/sizeof(ary[0])) #define AC108_FRAME_SIZE 4096 struct ac108_t { snd_pcm_ioplug_t io; - snd_pcm_t *slave; + snd_pcm_t *pcm; snd_pcm_hw_params_t *hw_params; unsigned int last_size; unsigned int ptr; - void *buf; unsigned int latency; // Delay in usec unsigned int bufferSize; // Size of sample buffer }; - -/* set up the fixed parameters of slave PCM hw_parmas */ -static int ac108_slave_hw_params_half(struct ac108_t *rec, unsigned int rate,snd_pcm_format_t format) { +static unsigned char capture_buf[AC108_FRAME_SIZE]; +/* set up the fixed parameters of pcm PCM hw_parmas */ +static int ac108_slave_hw_params_half(struct ac108_t *capture, unsigned int rate,snd_pcm_format_t format) { int err; - snd_pcm_uframes_t bufferSize = rec->bufferSize; - unsigned int latency = rec->latency; + snd_pcm_uframes_t bufferSize = capture->bufferSize; + unsigned int latency = capture->latency; unsigned int buffer_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) { - SNDERR("Cannot get slave hw_params"); + if ((err = snd_pcm_hw_params_any(capture->pcm, capture->hw_params)) < 0) { + SNDERR("Cannot get pcm hw_params"); 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) { - SNDERR("Cannot set slave access RW_INTERLEAVED"); + SNDERR("Cannot set pcm access RW_INTERLEAVED"); goto out; } - if ((err = snd_pcm_hw_params_set_channels(rec->slave, rec->hw_params, 2)) < 0) { - SNDERR("Cannot set slave channels 2"); + if ((err = snd_pcm_hw_params_set_channels(capture->pcm, capture->hw_params, 2)) < 0) { + SNDERR("Cannot set pcm channels 2"); 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) { - SNDERR("Cannot set slave format"); + SNDERR("Cannot set pcm format"); goto out; } - if ((err = snd_pcm_hw_params_set_rate(rec->slave, rec->hw_params, rate, 0)) < 0) { - SNDERR("Cannot set slave rate %d", rate); + if ((err = snd_pcm_hw_params_set_rate(capture->pcm, capture->hw_params, rate, 0)) < 0) { + SNDERR("Cannot set pcm rate %d", rate); 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); if (buffer_time > 80000) buffer_time = 80000; 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); if (err < 0) { fprintf(stderr,"Unable to set_period_time_near"); 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); if (err < 0) { fprintf(stderr,"Unable to set_buffer_time_near"); goto out; } - rec->bufferSize = bufferSize; - rec->latency = latency; + capture->bufferSize = bufferSize; + capture->latency = latency; return 0; out: - free(rec->hw_params); - rec->hw_params = NULL; + free(capture->hw_params); + capture->hw_params = NULL; 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) { - struct ac108_t *rec = io->private_data; + struct ac108_t *capture = io->private_data; + fprintf(stderr,"ac108_start: %d\n",io->buffer_size); + if(!capture->pcm) { + fprintf(stderr, "pcm is lost\n"); + } - if(!rec->slave) { - fprintf(stderr, "slave is lost\n"); - } - - return snd_pcm_start(rec->slave); + return snd_pcm_start(capture->pcm); } static int ac108_stop(snd_pcm_ioplug_t *io) { - struct ac108_t *rec = io->private_data; + struct ac108_t *capture = io->private_data; + fprintf(stderr,"ac108_stop!\n"); - return snd_pcm_drop(rec->slave); + return snd_pcm_drop(capture->pcm); } /* * 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) { - struct ac108_t *rec = io->private_data; + + struct ac108_t *capture = io->private_data; + int bps = snd_pcm_format_width(io->format) / 8; int err, size; - - assert(rec); + + assert(capture); - size = snd_pcm_avail(rec->slave); - if (size < 0) return size; - size = size /2; - if (size > rec->last_size) { - rec->ptr += size - rec->last_size; - rec->ptr %= io->buffer_size; + size = snd_pcm_avail(capture->pcm); + if (size < 0) + return size; + + size = size/2; + + 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\n", __func__, rec->ptr,size, io->appl_ptr, io->hw_ptr); - return rec->ptr; + //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; + + return capture->ptr; } /* * transfer callback */ static snd_pcm_sframes_t ac108_transfer(snd_pcm_ioplug_t *io, - const snd_pcm_channel_area_t *areas, - snd_pcm_uframes_t offset, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, snd_pcm_uframes_t size) { - struct ac108_t *rec = io->private_data; - char *buf; - ssize_t result; - int err; + struct ac108_t *capture = io->private_data; + int chn; + unsigned char *dst_samples[io->channels]; + int dst_steps[io->channels]; + int bps = snd_pcm_format_width(io->format) / 8; /* bytes per sample */ + //int phys_bps = snd_pcm_format_physical_width(capture->format) / 8; + //int big_endian = snd_pcm_format_big_endian(capture->format) == 1; + //int to_unsigned = snd_pcm_format_unsigned(capture->format) == 1; + //int is_float = (capture->format == SND_PCM_FORMAT_FLOAT_LE ||capture->format == SND_PCM_FORMAT_FLOAT_BE); + 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); + if(snd_pcm_avail(capture->pcm) > size*2){ + if ((err = snd_pcm_readi (capture->pcm, capture_buf, size*2)) != size*2) { + fprintf (stderr, "read from audio interface failed %d %d %s!\n",size,err,snd_strerror (err)); + exit(EXIT_FAILURE); + size = 0 ; + } + }else{ + size = 0; + } +#if 1 + /* verify and prepare the contents of areas */ + for (chn = 0; chn < io->channels; chn++) { + if ((dst_areas[chn].first % 8) != 0) { + fprintf(stderr,"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) { + fprintf(stderr,"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 + //fprintf(stderr,"ac108_transfer: %d %d %d %d\n", size,dst_offset,io->channels,bps); + + // 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; + // while(1){ + // if(src_buf[0] == 0 && src_buf[0 + bps] == 1 && + // src_buf[0 + 2*bps] == 2 && src_buf[0 + 3*bps] == 3) + // break; + // else + // src_buf += 4*bps; + // } +#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,"%x %x %x %x\n",src_buf[3],src_buf[2],src_buf[1],src_buf[0]); + //fprintf(stderr,"\n"); + dst_samples[chn] += dst_steps[chn]; + } + count++; + } + +#endif + + capture->last_size -= size; + +#if 0 /* we handle only an interleaved buffer */ - buf = (char *)areas->addr + (areas->first + areas->step * offset) / 8; - result = snd_pcm_readi(rec->slave, buf, size*2); + dst_buf = (char *)areas->addr + (areas->first + areas->step * offset) / 8; + buf = dst_buf; + + snd_pcm_readi(capture->pcm, capture_buf, size/2); +#if 1 + for(a = 0; a < size*2;a++){ + fprintf(stderr,"%x ",capture_buf[a]); + if(a%4 == 0) + fprintf(stderr,"\n"); + } +#endif + memcpy((char*)dst_buf,capture_buf,size/2); + + fprintf(stderr,"ac108_transfer: %d %d %d \n", size,offset,io->channels); + if (result <= 0) { fprintf(stderr, "%s out error:%d %d\n", __func__, result); return result; } - rec->last_size -= size; - - + capture->last_size -= size; +#endif 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) { - 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(rec->slave); + return snd_pcm_poll_descriptors_count(capture->pcm); } static int ac108_poll_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfd, 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(rec->slave, pfd, space); + return snd_pcm_poll_descriptors(capture->pcm, pfd, space); } static int ac108_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfd, 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(rec->slave, pfd, nfds, revents); + return snd_pcm_poll_descriptors_revents(capture->pcm, pfd, nfds, revents); } /* * close callback */ static int ac108_close(snd_pcm_ioplug_t *io) { - struct ac108_t *rec = io->private_data; + struct ac108_t *capture = io->private_data; + fprintf(stderr,"ac108_close\n"); + if (capture->pcm) + snd_pcm_close(capture->pcm); - if (rec->slave) return snd_pcm_close(rec->slave); return 0; } -static int setSoftwareParams(struct ac108_t *rec) { +static int setSoftwareParams(struct ac108_t *capture) { snd_pcm_sw_params_t *softwareParams; int err; @@ -201,21 +299,21 @@ static int setSoftwareParams(struct ac108_t *rec) { snd_pcm_sw_params_alloca(&softwareParams); // 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) { fprintf(stderr, "Unable to get software parameters: %s", snd_strerror(err)); goto done; } // 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; 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); if (err < 0) { fprintf(stderr, "Unable to set start threshold to %lu frames: %s", @@ -223,7 +321,7 @@ static int setSoftwareParams(struct ac108_t *rec) { 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); if (err < 0) { fprintf(stderr, "Unable to set stop threshold to %lu frames: %s", @@ -232,7 +330,7 @@ static int setSoftwareParams(struct ac108_t *rec) { } // Allow the transfer to start when at least periodSize samples can be // processed. - err = snd_pcm_sw_params_set_avail_min(rec->slave, softwareParams, + err = snd_pcm_sw_params_set_avail_min(capture->pcm, softwareParams, periodSize); if (err < 0) { fprintf(stderr, "Unable to configure available minimum to %lu: %s", @@ -241,7 +339,7 @@ static int setSoftwareParams(struct ac108_t *rec) { } // 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", snd_strerror(err)); @@ -256,77 +354,71 @@ done: /* * 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, // snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED) { static int ac108_hw_params(snd_pcm_ioplug_t *io) { - struct ac108_t *rec = io->private_data; + struct ac108_t *capture = io->private_data; snd_pcm_sw_params_t *sparams; snd_pcm_uframes_t period_size; snd_pcm_uframes_t buffer_size; int err; - if (!rec->hw_params) { - err = ac108_slave_hw_params_half(rec, 2*io->rate,io->format); + if (!capture->hw_params) { + err = ac108_slave_hw_params_half(capture, 2*io->rate,io->format); if (err < 0) { fprintf(stderr, "ac108_slave_hw_params_half error\n"); return err; } } 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) { - SNDERR("Cannot set slave period size %ld", period_size); + SNDERR("Cannot set pcm period size %ld", period_size); return err; } 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) { - SNDERR("Cannot set slave buffer size %ld", buffer_size); + SNDERR("Cannot set pcm buffer size %ld", buffer_size); return err; } - if ((err = snd_pcm_hw_params(rec->slave, rec->hw_params)) < 0) { - SNDERR("Cannot set slave hw_params"); + if ((err = snd_pcm_hw_params(capture->pcm, capture->hw_params)) < 0) { + SNDERR("Cannot set pcm hw_params"); return err; } - - setSoftwareParams(rec); - + setSoftwareParams(capture); + fprintf(stderr, "ac108_hw_params\n"); return 0; } /* * hw_free callback */ static int ac108_hw_free(snd_pcm_ioplug_t *io) { - struct ac108_t *rec = io->private_data; - free(rec->hw_params); - if (rec->buf != NULL) { - free(rec->buf); - rec->buf = NULL; - } - rec->hw_params = NULL; - - return snd_pcm_hw_free(rec->slave); + struct ac108_t *capture = io->private_data; + free(capture->hw_params); + capture->hw_params = NULL; + fprintf(stderr,"ac108_hw_free\n"); + + return snd_pcm_hw_free(capture->pcm); } static int ac108_prepare(snd_pcm_ioplug_t *io) { - struct ac108_t *rec = io->private_data; - rec->ptr = 0; - rec->last_size =0; - if (rec->buf == NULL) { - rec->buf = malloc(io->buffer_size); - } - - return snd_pcm_prepare(rec->slave); + struct ac108_t *capture = io->private_data; + capture->ptr = 0; + capture->last_size =0; + fprintf(stderr,"ac108_prepare\n"); + return snd_pcm_prepare(capture->pcm); } static int ac108_drain(snd_pcm_ioplug_t *io) { - struct ac108_t *rec = io->private_data; - return snd_pcm_drain(rec->slave); + struct ac108_t *capture = io->private_data; + + return snd_pcm_drain(capture->pcm); } static int ac108_sw_params(snd_pcm_ioplug_t *io, snd_pcm_sw_params_t *params) { - struct ac108_t *rec = io->private_data; + struct ac108_t *capture = io->private_data; return 0; } @@ -356,10 +448,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[] = { - SND_PCM_ACCESS_RW_INTERLEAVED, - SND_PCM_ACCESS_RW_NONINTERLEAVED + SND_PCM_ACCESS_RW_INTERLEAVED }; unsigned int formats[] = { SND_PCM_FORMAT_S32, SND_PCM_FORMAT_S16 }; @@ -374,30 +465,43 @@ static int ac108_set_hw_constraint(struct ac108_t *rec) { 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, ARRAY_SIZE(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 || - (err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_CHANNELS, - 4, 4)) < 0 || - (err = snd_pcm_ioplug_set_param_list(&rec->io, SND_PCM_IOPLUG_HW_RATE, - ARRAY_SIZE(rates), rates)) < 0) return err; - err = snd_pcm_ioplug_set_param_minmax(&rec->io, - SND_PCM_IOPLUG_HW_BUFFER_BYTES, + (err = snd_pcm_ioplug_set_param_minmax(&capture->io, SND_PCM_IOPLUG_HW_CHANNELS, + 1, 4)) < 0 || + (err = snd_pcm_ioplug_set_param_list(&capture->io, SND_PCM_IOPLUG_HW_RATE, + ARRAY_SIZE(rates), rates)) < 0) { + 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); - 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, - SND_PCM_IOPLUG_HW_PERIOD_BYTES, + err = snd_pcm_ioplug_set_param_minmax(&capture->io,SND_PCM_IOPLUG_HW_PERIOD_BYTES, 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, - 3, 1024); + err = snd_pcm_ioplug_set_param_minmax(&capture->io, SND_PCM_IOPLUG_HW_PERIODS,3, 1024); + if (err < 0) { + SNDERR("ioplug cannot set ac108 hw periods"); + return err; + } return 0; } @@ -412,7 +516,7 @@ SND_PCM_PLUGIN_DEFINE_FUNC(ac108) { const char *pcm_string = NULL; snd_pcm_format_t format = SND_PCM_FORMAT_S32_LE; char devstr[128], tmpcard[8]; - struct ac108_t *rec; + struct ac108_t *capture; int channels; struct pollfd fds; if (stream != SND_PCM_STREAM_CAPTURE) { @@ -449,36 +553,37 @@ SND_PCM_PLUGIN_DEFINE_FUNC(ac108) { } } - rec = calloc(1, sizeof(*rec)); - if (!rec) { + + capture = calloc(1, sizeof(*capture)); + if (!capture) { SNDERR("cannot allocate"); 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; - + //SND_PCM_NONBLOCK - rec->io.version = SND_PCM_IOPLUG_VERSION; - rec->io.name = "AC108 decode Plugin"; - rec->io.mmap_rw = 0; - rec->io.callback = &a108_ops; - rec->io.private_data = rec; + capture->io.version = SND_PCM_IOPLUG_VERSION; + capture->io.name = "AC108 decode Plugin"; + capture->io.mmap_rw = 0; + capture->io.callback = &a108_ops; + 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 = ac108_set_hw_constraint(rec)) < 0) { - snd_pcm_ioplug_delete(&rec->io); + if ((err = ac108_set_hw_constraint(capture)) < 0) { + snd_pcm_ioplug_delete(&capture->io); return err; } - *pcmp = rec->io.pcm; + *pcmp = capture->io.pcm; return 0; error: - if (rec->slave) snd_pcm_close(rec->slave); - free(rec); + if (capture->pcm) snd_pcm_close(capture->pcm); + free(capture); return err; } From 932d2ab1c55530f8d02ac74068d0cec8261cbb53 Mon Sep 17 00:00:00 2001 From: Baozhu Zuo Date: Sat, 30 Sep 2017 16:01:18 +0800 Subject: [PATCH 3/8] add some helper function --- ac108_plugin/ac108_help.c | 77 +++++++++++++++++++++ ac108_plugin/ac108_help.h | 11 +++ ac108_plugin/libasound_module_pcm_ac108.so | Bin 32668 -> 41116 bytes 3 files changed, 88 insertions(+) create mode 100644 ac108_plugin/ac108_help.c create mode 100644 ac108_plugin/ac108_help.h diff --git a/ac108_plugin/ac108_help.c b/ac108_plugin/ac108_help.c new file mode 100644 index 0000000..cb5fd81 --- /dev/null +++ b/ac108_plugin/ac108_help.c @@ -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; +} + diff --git a/ac108_plugin/ac108_help.h b/ac108_plugin/ac108_help.h new file mode 100644 index 0000000..97adb84 --- /dev/null +++ b/ac108_plugin/ac108_help.h @@ -0,0 +1,11 @@ +#include +#include +#include +#include +#include +#include +#include + +void generate_sine(const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + int count, double *_phase); diff --git a/ac108_plugin/libasound_module_pcm_ac108.so b/ac108_plugin/libasound_module_pcm_ac108.so index 68ee4847015ae9a25e4d5e6fdab956a3dba9676e..fc527856cdf315d08b485edde2368407ca49f2cb 100755 GIT binary patch literal 41116 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 From 3c4fc91f89e7567d273d2a28c9fb45fe7a0d4ca2 Mon Sep 17 00:00:00 2001 From: Baozhu Zuo Date: Mon, 9 Oct 2017 11:14:27 +0800 Subject: [PATCH 4/8] use the real rate value config clocking --- ac108.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ac108.c b/ac108.c index c4b79c2..fe1dfe1 100644 --- a/ac108.c +++ b/ac108.c @@ -841,7 +841,7 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h */ 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; } From 125e5188e5e67498e95b3613a761563df1cde8bb Mon Sep 17 00:00:00 2001 From: Baozhu Zuo Date: Mon, 9 Oct 2017 14:56:26 +0800 Subject: [PATCH 5/8] use two channel transfer 4 channels, rate should be double --- ac108.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ac108.c b/ac108.c index fe1dfe1..279b132 100644 --- a/ac108.c +++ b/ac108.c @@ -777,7 +777,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)); 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; break; } From b28887adab81d7aa1168d5d3aec421b51e21ea86 Mon Sep 17 00:00:00 2001 From: Baozhu Zuo Date: Mon, 9 Oct 2017 14:57:05 +0800 Subject: [PATCH 6/8] add ac108_help to makefile --- ac108_plugin/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ac108_plugin/Makefile b/ac108_plugin/Makefile index fede526..2a32ae9 100644 --- a/ac108_plugin/Makefile +++ b/ac108_plugin/Makefile @@ -9,7 +9,7 @@ CFLAGS += -I. -Wall -funroll-loops -ffast-math -fPIC -DPIC -O0 -g LD := gcc LDFLAGS += -Wall -shared -lasound -SND_PCM_OBJECTS = pcm_ac108.o +SND_PCM_OBJECTS = pcm_ac108.o ac108_help.o SND_PCM_LIBS = SND_PCM_BIN = libasound_module_pcm_ac108.so From 12bac6756a1146eb285e244d766c8b773637b0e2 Mon Sep 17 00:00:00 2001 From: Baozhu Zuo Date: Mon, 9 Oct 2017 14:58:35 +0800 Subject: [PATCH 7/8] remove debug message, increase ac108 buf size --- ac108_plugin/libasound_module_pcm_ac108.so | Bin 41116 -> 40648 bytes ac108_plugin/pcm_ac108.c | 104 +++++---------------- 2 files changed, 25 insertions(+), 79 deletions(-) diff --git a/ac108_plugin/libasound_module_pcm_ac108.so b/ac108_plugin/libasound_module_pcm_ac108.so index fc527856cdf315d08b485edde2368407ca49f2cb..ca8ca04d6a121767c1a26c3c00f3f38825cffb3f 100755 GIT binary patch literal 40648 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 #define ARRAY_SIZE(ary) (sizeof(ary)/sizeof(ary[0])) -#define AC108_FRAME_SIZE 4096 +#define AC108_FRAME_SIZE 40960 struct ac108_t { snd_pcm_ioplug_t io; snd_pcm_t *pcm; @@ -62,13 +62,13 @@ static int ac108_slave_hw_params_half(struct ac108_t *capture, unsigned int rate err = snd_pcm_hw_params_set_period_time_near(capture->pcm, capture->hw_params, &period_time, 0); if (err < 0) { - fprintf(stderr,"Unable to set_period_time_near"); + SNDERR("Unable to set_period_time_near"); goto out; } err = snd_pcm_hw_params_set_buffer_time_near(capture->pcm, capture->hw_params, &buffer_time, 0); if (err < 0) { - fprintf(stderr,"Unable to set_buffer_time_near"); + SNDERR("Unable to set_buffer_time_near"); goto out; } @@ -88,9 +88,8 @@ out: */ static int ac108_start(snd_pcm_ioplug_t *io) { struct ac108_t *capture = io->private_data; - fprintf(stderr,"ac108_start: %d\n",io->buffer_size); if(!capture->pcm) { - fprintf(stderr, "pcm is lost\n"); + SNDERR( "pcm is lost\n"); } return snd_pcm_start(capture->pcm); @@ -98,7 +97,6 @@ static int ac108_start(snd_pcm_ioplug_t *io) { static int ac108_stop(snd_pcm_ioplug_t *io) { struct ac108_t *capture = io->private_data; - fprintf(stderr,"ac108_stop!\n"); return snd_pcm_drop(capture->pcm); } @@ -110,8 +108,7 @@ static int ac108_stop(snd_pcm_ioplug_t *io) { static snd_pcm_sframes_t ac108_pointer(snd_pcm_ioplug_t *io) { struct ac108_t *capture = io->private_data; - int bps = snd_pcm_format_width(io->format) / 8; - int err, size; + int size; assert(capture); @@ -145,22 +142,18 @@ static snd_pcm_sframes_t ac108_transfer(snd_pcm_ioplug_t *io, unsigned char *dst_samples[io->channels]; int dst_steps[io->channels]; int bps = snd_pcm_format_width(io->format) / 8; /* bytes per sample */ - //int phys_bps = snd_pcm_format_physical_width(capture->format) / 8; - //int big_endian = snd_pcm_format_big_endian(capture->format) == 1; - //int to_unsigned = snd_pcm_format_unsigned(capture->format) == 1; - //int is_float = (capture->format == SND_PCM_FORMAT_FLOAT_LE ||capture->format == SND_PCM_FORMAT_FLOAT_BE); int i; int count = 0; int err = 0; unsigned char *src_buf; - unsigned char *src_data[4][4]; + unsigned char src_data[4][4]; memset(capture_buf,0,AC108_FRAME_SIZE); if(snd_pcm_avail(capture->pcm) > size*2){ if ((err = snd_pcm_readi (capture->pcm, capture_buf, size*2)) != size*2) { - fprintf (stderr, "read from audio interface failed %d %d %s!\n",size,err,snd_strerror (err)); + SNDERR("read from audio interface failed %ld %d %s!\n",size,err,snd_strerror (err)); exit(EXIT_FAILURE); size = 0 ; } @@ -171,20 +164,18 @@ static snd_pcm_sframes_t ac108_transfer(snd_pcm_ioplug_t *io, /* verify and prepare the contents of areas */ for (chn = 0; chn < io->channels; chn++) { if ((dst_areas[chn].first % 8) != 0) { - fprintf(stderr,"dst_areas[%i].first == %i, aborting...\n", chn, dst_areas[chn].first); + 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) { - fprintf(stderr,"dst_areas[%i].step == %i, aborting...\n", chn, dst_areas[chn].step); + 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 - //fprintf(stderr,"ac108_transfer: %d %d %d %d\n", size,dst_offset,io->channels,bps); - // for(i = 0; i < size*2*bps;i++){ // fprintf(stderr,"%x ",capture_buf[i]); // if(i%4 == 0) @@ -193,13 +184,6 @@ static snd_pcm_sframes_t ac108_transfer(snd_pcm_ioplug_t *io, //generate_sine(dst_areas, dst_offset,size, &count); src_buf = capture_buf; - // while(1){ - // if(src_buf[0] == 0 && src_buf[0 + bps] == 1 && - // src_buf[0 + 2*bps] == 2 && src_buf[0 + 3*bps] == 3) - // break; - // else - // src_buf += 4*bps; - // } #if 1 while(count < size){ for(chn = 0; chn < 4; chn++){ @@ -214,7 +198,6 @@ static snd_pcm_sframes_t ac108_transfer(snd_pcm_ioplug_t *io, *(dst_samples[chn] + i) = src_data[chn][i]; //fprintf(stderr,"%x ",*(dst_samples[chn] + i)); } - //fprintf(stderr,"%x %x %x %x\n",src_buf[3],src_buf[2],src_buf[1],src_buf[0]); //fprintf(stderr,"\n"); dst_samples[chn] += dst_steps[chn]; } @@ -225,29 +208,6 @@ static snd_pcm_sframes_t ac108_transfer(snd_pcm_ioplug_t *io, capture->last_size -= size; -#if 0 - /* we handle only an interleaved buffer */ - dst_buf = (char *)areas->addr + (areas->first + areas->step * offset) / 8; - buf = dst_buf; - - snd_pcm_readi(capture->pcm, capture_buf, size/2); -#if 1 - for(a = 0; a < size*2;a++){ - fprintf(stderr,"%x ",capture_buf[a]); - if(a%4 == 0) - fprintf(stderr,"\n"); - } -#endif - memcpy((char*)dst_buf,capture_buf,size/2); - - fprintf(stderr,"ac108_transfer: %d %d %d \n", size,offset,io->channels); - - if (result <= 0) { - fprintf(stderr, "%s out error:%d %d\n", __func__, result); - return result; - } - capture->last_size -= size; -#endif return size; } @@ -257,7 +217,6 @@ static snd_pcm_sframes_t ac108_transfer(snd_pcm_ioplug_t *io, static int ac108_poll_descriptors_count(snd_pcm_ioplug_t *io) { struct ac108_t *capture = io->private_data; - //fprintf(stderr, "%s\n", __FUNCTION__); return snd_pcm_poll_descriptors_count(capture->pcm); } @@ -265,7 +224,6 @@ static int ac108_poll_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfd, unsigned int space) { struct ac108_t *capture = io->private_data; - //fprintf(stderr, "%s\n", __FUNCTION__); return snd_pcm_poll_descriptors(capture->pcm, pfd, space); } @@ -273,7 +231,6 @@ static int ac108_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfd, unsigned int nfds, unsigned short *revents) { struct ac108_t *capture = io->private_data; - //fprintf(stderr, "%s\n", __FUNCTION__); return snd_pcm_poll_descriptors_revents(capture->pcm, pfd, nfds, revents); } @@ -282,7 +239,6 @@ static int ac108_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfd, */ static int ac108_close(snd_pcm_ioplug_t *io) { struct ac108_t *capture = io->private_data; - fprintf(stderr,"ac108_close\n"); if (capture->pcm) snd_pcm_close(capture->pcm); @@ -301,7 +257,7 @@ static int setSoftwareParams(struct ac108_t *capture) { // Get the current software parameters err = snd_pcm_sw_params_current(capture->pcm, softwareParams); 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; } @@ -316,7 +272,7 @@ static int setSoftwareParams(struct ac108_t *capture) { err = snd_pcm_sw_params_set_start_threshold(capture->pcm, softwareParams, startThreshold); 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)); goto done; } @@ -324,7 +280,7 @@ static int setSoftwareParams(struct ac108_t *capture) { err = snd_pcm_sw_params_set_stop_threshold(capture->pcm, softwareParams, stopThreshold); 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)); goto done; } @@ -333,15 +289,15 @@ static int setSoftwareParams(struct ac108_t *capture) { err = snd_pcm_sw_params_set_avail_min(capture->pcm, softwareParams, periodSize); 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)); goto done; } // Commit the software parameters back to the device. err = snd_pcm_sw_params(capture->pcm, softwareParams); - if (err < 0) fprintf(stderr, "Unable to configure software parameters: %s", - snd_strerror(err)); + if (err < 0) + SNDERR("Unable to configure software parameters: %s",snd_strerror(err)); @@ -356,18 +312,15 @@ done: * * Set up pcm PCM according to the current parameters */ -//static int ac108_hw_params(snd_pcm_ioplug_t *io, -// snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED) { -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) { struct ac108_t *capture = io->private_data; - snd_pcm_sw_params_t *sparams; snd_pcm_uframes_t period_size; snd_pcm_uframes_t buffer_size; int err; if (!capture->hw_params) { err = ac108_slave_hw_params_half(capture, 2*io->rate,io->format); if (err < 0) { - fprintf(stderr, "ac108_slave_hw_params_half error\n"); + SNDERR("ac108_slave_hw_params_half error\n"); return err; } } @@ -388,7 +341,6 @@ static int ac108_hw_params(snd_pcm_ioplug_t *io) { return err; } setSoftwareParams(capture); - fprintf(stderr, "ac108_hw_params\n"); return 0; } /* @@ -398,7 +350,6 @@ static int ac108_hw_free(snd_pcm_ioplug_t *io) { struct ac108_t *capture = io->private_data; free(capture->hw_params); capture->hw_params = NULL; - fprintf(stderr,"ac108_hw_free\n"); return snd_pcm_hw_free(capture->pcm); @@ -409,7 +360,6 @@ static int ac108_prepare(snd_pcm_ioplug_t *io) { struct ac108_t *capture = io->private_data; capture->ptr = 0; capture->last_size =0; - fprintf(stderr,"ac108_prepare\n"); return snd_pcm_prepare(capture->pcm); } static int ac108_drain(snd_pcm_ioplug_t *io) { @@ -417,12 +367,11 @@ static int ac108_drain(snd_pcm_ioplug_t *io) { return snd_pcm_drain(capture->pcm); } +#if 0 static int ac108_sw_params(snd_pcm_ioplug_t *io, snd_pcm_sw_params_t *params) { - struct ac108_t *capture = io->private_data; - return 0; } - +#endif static int ac108_delay(snd_pcm_ioplug_t * io, snd_pcm_sframes_t * delayp){ return 0; @@ -458,11 +407,12 @@ static int ac108_set_hw_constraint(struct ac108_t *capture) { unsigned int rates[] = { 8000, 16000, - 48000 + 32000, + 44100, + 48000, + 96000 }; int err; - snd_pcm_uframes_t buffer_max; - unsigned int period_bytes, max_periods; err = snd_pcm_ioplug_set_param_list(&capture->io, @@ -479,7 +429,8 @@ static int ac108_set_hw_constraint(struct ac108_t *capture) { (err = snd_pcm_ioplug_set_param_minmax(&capture->io, SND_PCM_IOPLUG_HW_CHANNELS, 1, 4)) < 0 || (err = snd_pcm_ioplug_set_param_list(&capture->io, SND_PCM_IOPLUG_HW_RATE, - ARRAY_SIZE(rates), rates)) < 0) { + ARRAY_SIZE(rates), rates)) < 0) + { SNDERR("ioplug cannot set ac108 format channel rate!"); return err; } @@ -505,20 +456,15 @@ static int ac108_set_hw_constraint(struct ac108_t *capture) { return 0; } -/* /* * Main entry point */ SND_PCM_PLUGIN_DEFINE_FUNC(ac108) { snd_config_iterator_t i, next; int err; - const char *card = NULL; const char *pcm_string = NULL; - snd_pcm_format_t format = SND_PCM_FORMAT_S32_LE; - char devstr[128], tmpcard[8]; struct ac108_t *capture; int channels; - struct pollfd fds; if (stream != SND_PCM_STREAM_CAPTURE) { SNDERR("a108 is only for capture"); return -EINVAL; From 76a01405134d1ea6d1d9d369397a4f7666247340 Mon Sep 17 00:00:00 2001 From: Baozhu Zuo Date: Mon, 9 Oct 2017 15:00:40 +0800 Subject: [PATCH 8/8] remove ac108 debug macro --- ac108.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ac108.c b/ac108.c index 279b132..0823660 100644 --- a/ac108.c +++ b/ac108.c @@ -8,7 +8,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#define DEBUG 1 #include #include #include