From 2ea218b5670b32a42a28a3e8f8a19899d20ba66a Mon Sep 17 00:00:00 2001 From: gardners Date: Fri, 11 May 2012 13:25:50 +0930 Subject: [PATCH] fast-audio getting closer to working. Figured out how to make buffer time very short (set record rate high works, setting buffer size does not). Of course this means we need to downsample and upsample. --- audio_msm_g1.c | 201 ++++++++++++++++++++++++++----------------------- 1 file changed, 105 insertions(+), 96 deletions(-) diff --git a/audio_msm_g1.c b/audio_msm_g1.c index 6fb5dbd2..fcab5bd1 100644 --- a/audio_msm_g1.c +++ b/audio_msm_g1.c @@ -20,6 +20,24 @@ Copyright (C) 2008 The Android Open Source Project */ +/* + We ask the driver to reduce it's buffer size, but it doesn't listen. + This is very strange, as looking in pcm_out.c of kernel source it appears + that it should work just fine. + + What does work, however, is increasing the sample rate, so that the buffers + empty sooner. So we use 32000Hz instead of 8000Hz so that the 2KB record buffer + holds only 1/32nd of a second instead of 1/8th of a second. + + We may need to introduce a low-pass filter to prevent aliasing, assuming that + the microphone and ACD in these phones responds to requencies above 4KHz. + */ +#define DESIRED_BUFFER_SIZE 256 +#define DESIRED_SAMPLE_RATE 32000 +#define RESAMPLE_FACTOR (DESIRED_SAMPLE_RATE/8000) +int resamplingBufferSize=0; +unsigned char *resamplingBuffer=0; + extern int playFd; extern int recordFd; extern int playBufferSize; @@ -241,6 +259,13 @@ int audio_msm_g1_start_play() { if (playFd>-1) return 0; + /* Largest possible resampling buffer required for this chipset. + (we resample so that we can use 8KHz audio for transport, + but 32KHz sample rate on the audio hardware so that buffers + correspond to a shorter period of time */ + resamplingBufferSize=2*RESAMPLE_FACTOR*8192; + resamplingBuffer=malloc(resamplingBufferSize); + /* Get audio control device */ int fd = open ("/dev/msm_snd", O_RDWR); if (fd<0) return -1; @@ -278,8 +303,8 @@ int audio_msm_g1_start_play() return WHY("Could not read audio device configuration"); } config.channel_count=1; - config.sample_rate=8000; - playBufferSize=config.buffer_size; + config.sample_rate=DESIRED_SAMPLE_RATE; + config.buffer_size=DESIRED_BUFFER_SIZE; if (ioctl(playFd, AUDIO_SET_CONFIG,&config)) { close(playFd); @@ -294,27 +319,11 @@ int audio_msm_g1_start_play() If playBufferSize equates to too long an interval, then try to reduce it in various ways. */ + ioctl(playFd, AUDIO_GET_CONFIG,&config); + playBufferSize=config.buffer_size; float bufferTime=playBufferSize/2*1.0/config.sample_rate; - if (bufferTime>0.02) { - WHYF("PLAY buf=%.3fsecs, which is too long. Trying to reduce it.", - bufferTime); + WHYF("PLAY buf=%.3fsecs.",bufferTime); - /* 64 bytes = 32 samples = ~4ms */ - config.buffer_size=64*8; - config.buffer_count=2; - if (!ioctl(playFd, AUDIO_SET_CONFIG,&config)) - { - if (!ioctl(playFd, AUDIO_GET_CONFIG,&config)) { - playBufferSize=config.buffer_size; - bufferTime=playBufferSize/2*1.0/config.sample_rate; - WHYF("Succeeded in reducing play buffer to %d bytes (%.3fsecs)", - playBufferSize,bufferTime); - goto fixedBufferSize; - } - } - } - fixedBufferSize: - /* tell hardware to start playing */ ioctl(playFd,AUDIO_START,0); @@ -344,7 +353,8 @@ int audio_msm_g1_start_record() return WHY("Could not read audio device configuration"); } config.channel_count=1; - config.sample_rate=8000; + config.sample_rate=DESIRED_SAMPLE_RATE; + config.buffer_size=DESIRED_BUFFER_SIZE; if (ioctl(recordFd, AUDIO_SET_CONFIG,&config)) { close(recordFd); @@ -355,35 +365,11 @@ int audio_msm_g1_start_record() /* If recordBufferSize equates to too long an interval, then try to reduce it in various ways. - */ + */ + ioctl(recordFd, AUDIO_GET_CONFIG,&config); recordBufferSize=config.buffer_size; float bufferTime=recordBufferSize/2*1.0/config.sample_rate; - if (bufferTime>0.02) { - WHYF("REC buf=%.3fsecs, which is too long. Trying to reduce it.", - bufferTime); - - /* 64 bytes = 32 samples = ~4ms */ - config.buffer_size=64*8; - config.buffer_count=2; - if (!ioctl(recordFd, AUDIO_SET_CONFIG,&config)) - { - if (!ioctl(playFd, AUDIO_GET_CONFIG,&config)) { - recordBufferSize=config.buffer_size; - bufferTime=recordBufferSize/2*1.0/config.sample_rate; - WHYF("Succeeded in reducing record buffer to %d bytes (%.3fsecs)", - recordBufferSize,bufferTime); - goto fixedBufferSize; - } - } - -#if 0 - /* Ask for 2x speed and 2x channels, to divide effective buffer size by 4. - */ - config.sample_rate=16000; - config.channel_count=2; -#endif - } - fixedBufferSize: + WHYF("REC buf=%.3fsecs.",bufferTime); fcntl(recordFd,F_SETFL, fcntl(recordFd, F_GETFL, NULL)|O_NONBLOCK); @@ -434,63 +420,86 @@ int audio_msm_g1_poll_fds(struct pollfd *fds,int slots) int audio_msm_g1_read(unsigned char *buffer,int maximum_count) { if (recordFd==-1) return 0; + if (!resamplingBuffer) return 0; - /* Regardless of the maximum, we must read exactly buffer sized pieces - on this audio device */ - if (maximum_countresamplingBufferSize) + maxRawBytes=resamplingBufferSize; + if (maxRawBytes>recordBufferSize) + maxRawBytes=recordBufferSize; + + fcntl(recordFd,F_SETFL,fcntl(recordFd, F_GETFL, NULL)|O_NONBLOCK); + ioctl(recordFd,AUDIO_START,0); + WHY("calling read()"); + + /* read raw samples */ + int b=read(recordFd,&resamplingBuffer[0],maxRawBytes); + if (b<1) WHYF("read failed: b=%d, err=%s",b,strerror(errno)); - else - WHYF("read %d bytes",b); - if (errno=EBADF) recordFd=-1; + if (errno==EBADF) recordFd=-1; + WHYF("read %d raw (upsampled) bytes",b); + + /* downsample to output buffer */ + { + int i; + /* copy every RESAMPLE_FACTOR-th sample (each being 16 bits) + to output buffer */ + int outpos=0; + for(i=0;i65536) - { WHY("Play marshalling buffer full"); - return 0; } - bcopy(&data[0],&playBuffer[playBufferBytes],bytes); - playBufferBytes+=bytes; - int i; - for(i=0;iplayBufferBytes) bytes=playBufferBytes-i; - WHYF("Trying to write %d bytes of audio",bytes); - ioctl(playFd,AUDIO_START,0); - fcntl(playFd,F_SETFL,fcntl(playFd, F_GETFL, NULL)|O_NONBLOCK); - int w=0; - WHYF("write(%d,&pb[%d],%d) (playBufferBytes=%d)", - playFd,i,bytes,playBufferBytes); - if ((w=write(playFd,&playBuffer[i],bytes))< - 1) - { - WHYF("Failed to write, returned %d (errno=%s)", - w,strerror(errno)); - if (errno==EBADF) playFd=-1; - break; - } else { - WHYF("Wrote %d bytes of audio",w); - i+=w; - } - WHY("after write"); - } - bcopy(&playBuffer[i],&playBuffer[0],playBufferBytes-i); - playBufferBytes-=i; + int maxBytes=bytes; + if (maxBytes*RESAMPLE_FACTOR>resamplingBufferSize) + maxBytes=resamplingBufferSize/RESAMPLE_FACTOR; + + /* upsample ready for play back. + XXX This is a really crude approach, and it could be done much better. */ + int i,j,outpos=0; + for(i=0;i