今天来看看Android中的录音数据是怎么来的。


从AudioRecord开始看吧。


AudioRecord中可以取得录音数据的接口是:AudioRecord::read。
首先调用函数obtainBuffer取得录音数据的地址。
然后用memcpy将录音数据copy出来。


看样子,数据来源是obtainBuffer函数了。


来看看函数AudioRecord::obtainBuffer。
其主要功能就是对传入的audioBuffer进行赋值。
audioBuffer是Buffer* 类型。


看看Buffer类:


class Buffer
{
public:
enum {
MUTE = 0x00000001
};
uint32_t flags;
int channelCount;
int format;
size_t frameCount;
size_t size;
union {
void* raw;
short* i16;
int8_t* i8;
};
};

其中保存数据的是下面这块东东:
union {
void* raw;
short* i16;
int8_t* i8;
};

函数AudioRecord::obtainBuffer中对这块东东赋值的代码如下:
audioBuffer->raw = (int8_t*)cblk->buffer(u);


cblk的来历:
audio_track_cblk_t* cblk = mCblk;

mCblk的赋值在函数AudioRecord::openRecord中被赋值:
mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); // 可见mCblk头部保存的是结构体的信息,后面跟的是数据

函数audio_track_cblk_t::buffer的实现:
void* audio_track_cblk_t::buffer(uint64_t offset) const
{
return (int8_t *)this->buffers + (offset - userBase) * this->frameSize;
}


可见数据就保存在audio_track_cblk_t结构体中。


是什么地方往结构体audio_track_cblk_t中写的数据呢?


发现函数AudioRecord::obtainBuffer中,在获取buffer地址时,首先会调用函数audio_track_cblk_t::framesReady来判断有多少数据准备好了。


想起来在播放数据的时候,使用audio_track_cblk_t中的数据时,也调用了函数audio_track_cblk_t::framesReady。
而往audio_track_cblk_t中写数据时,调用了函数audio_track_cblk_t::framesAvailable。


录音肯定也是这样的了。
也就是说,找到调用函数audio_track_cblk_t::framesAvailable的地方,也就找到了往audio_track_cblk_t中写数据的地方。


录音相关,调用audio_track_cblk_t::framesAvailable的地方如下:
AudioFlinger::RecordThread::RecordTrack::getNextBuffer函数。


函数AudioFlinger::RecordThread::RecordTrack::getNextBuffer的主要作用是给传入的AudioBufferProvider::Buffer赋值。


AudioBufferProvider::Buffer结构体类型:
struct Buffer {
union {
void* raw;
short* i16;
int8_t* i8;
};
size_t frameCount;
};

保存数据的是下面这块东东:
union {
void* raw;
short* i16;
int8_t* i8;
};

函数AudioFlinger::RecordThread::RecordTrack::getNextBuffer对这块东东赋值的代码如下:
buffer->raw = getBuffer(s, framesReq);

函数AudioFlinger::ThreadBase::TrackBase::getBuffer返回了一个int8_t型指针bufferStart。
对bufferStart赋值的代码如下:
int8_t *bufferStart = (int8_t *)mBuffer + (offset-cblk->serverBase)*cblk->frameSize;


mBuffer的赋值在AudioFlinger::ThreadBase::TrackBase::TrackBase的构造函数中:
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
mCblk 的来历:
mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer()); 或 new(mCblk) audio_track_cblk_t();
这个在研究播放音频流的时候已经看过,这儿就不重复了。


肯定是哪个地方调用了函数AudioFlinger::RecordThread::RecordTrack::getNextBuffer,获取一段buffer,然后将录音数据写入到这个buffer。


搜搜调用函数AudioFlinger::RecordThread::RecordTrack::getNextBuffer的地方,录音相关的调用有以下:
AudioFlinger::RecordThread::threadLoop函数


AudioFlinger::RecordThread::threadLoop函数中,调用函数AudioFlinger::RecordThread::RecordTrack::getNextBuffer获取了buffer。
然后将buffer赋值给了dst:
int8_t *dst = buffer.i8 + (buffer.frameCount - framesOut) * mActiveTrack->mCblk->frameSize;


下面要分两种情况来讨论了:
+++++++++++++++++++++++++++++++++++++++不需要resampling的情况-start++++++++++++++++++++++++++++++++++++++++++++++
往dst写数据的有以下两个地方:
while (framesIn--) {
*dst16++ = *src16;
*dst16++ = *src16++;
}
或:
while (framesIn--) {
*dst16++ = (int16_t)(((int32_t)*src16 + (int32_t)*(src16 + 1)) >> 1);
src16 += 2;
}

也就是说数据来源是src了,看看src的由来。
int8_t *src = (int8_t *)mRsmpInBuffer + mRsmpInIndex * mFrameSize;


对mRsmpInBuffer赋值的地方在函数AudioFlinger::RecordThread::readInputParameters中:
mRsmpInBuffer = new int16_t[mFrameCount * mChannelCount];


这儿只是new了个buffer,寻找数据来源,还要看哪儿往里面写数据了。
往 mRsmpInBuffer中写数据的地方也在AudioFlinger::RecordThread::threadLoop函数中:
mBytesRead = mInput->read(mRsmpInBuffer, mInputBytes);
----------------------------------------不需要resampling的情况-end-----------------------------------------------
+++++++++++++++++++++++++++++++++++++++需要resampling的情况-start++++++++++++++++++++++++++++++++++++++++++++++
往dst写数据的地方:
while (framesOut--) {
*dst++ = (int16_t)(((int32_t)*src + (int32_t)*(src + 1)) >> 1);
src += 2;
}

也就是说数据来源是src了,看看src的由来。
int16_t *src = (int16_t *)mRsmpOutBuffer;

对mRsmpInBuffer赋值的地方在函数AudioFlinger::RecordThread::readInputParameters中:
mRsmpInBuffer = new int16_t[mFrameCount * mChannelCount];


这儿只是new了个buffer,寻找数据来源,还要看哪儿往里面写数据了。
往 mRsmpInBuffer中写数据的地方在AudioFlinger::RecordThread::getNextBuffer函数中:
mBytesRead = mInput->read(mRsmpInBuffer, mInputBytes);

下面看看对AudioFlinger::RecordThread::getNextBuffer函数的调用:


首先函数AudioFlinger::RecordThread::threadLoop中调用了函数AudioResamplerOrder1::resample。
mResampler->resample(mRsmpOutBuffer, framesOut, this);
函数AudioResamplerOrder1::resample调用了函数AudioResamplerOrder1::resampleMono16:
resampleMono16(out, outFrameCount, provider);
函数AudioResamplerOrder1::resampleMono16中调用了函数AudioFlinger::RecordThread::getNextBuffer:
provider->getNextBuffer(&mBuffer);

mResampler的赋值在函数AudioFlinger::RecordThread::readInputParameters中:
mResampler = AudioResampler::create(16, channelCount, mReqSampleRate);

函数AudioResampler::create根据参数,返回不同的resampler:
switch (quality) {
default:
case LOW_QUALITY:
LOGV("Create linear Resampler");
resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
break;
case MED_QUALITY:
LOGV("Create cubic Resampler");
resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
break;
case HIGH_QUALITY:
LOGV("Create sinc Resampler");
resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
break;
}

从上面对函数AudioFlinger::RecordThread::getNextBuffer的调用可知,mRsmpOutBuffer最终作为参数out传给了函数AudioResamplerOrder1::resampleMono16。
最终往mRsmpOutBuffer中写数据的地方是在函数AudioResamplerOrder1::resampleMono16中:


// handle boundary case
while (inputIndex == 0) {
// LOGE("boundary case\n");
int32_t sample = Interp(mX0L, in[0], phaseFraction);
out[outputIndex++] += vl * sample;
out[outputIndex++] += vr * sample;
Advance(&inputIndex, &phaseFraction, phaseIncrement);
if (outputIndex == outputSampleCount)
break;
}

或:


while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
int32_t sample = Interp(in[inputIndex-1], in[inputIndex],
phaseFraction);
out[outputIndex++] += vl * sample;
out[outputIndex++] += vr * sample;
Advance(&inputIndex, &phaseFraction, phaseIncrement);
}

in的来历:
int16_t *in = mBuffer.i16;

mBuffer的赋值:
provider->getNextBuffer(&mBuffer);

回到了刚次说的对函数AudioFlinger::RecordThread::getNextBuffer的调用。


函数AudioFlinger::RecordThread::getNextBuffer中首先调用函数AudioStreamInALSA::read获取数据指针。
mBytesRead = mInput->read(mRsmpInBuffer, mInputBytes);

然后将数据地址赋值给传入的AudioBufferProvider::Buffer指针:
buffer->raw = mRsmpInBuffer + mRsmpInIndex * channelCount;

下面看看resampling对数据的处理。


int32_t sample = Interp(in[inputIndex-1], in[inputIndex],
phaseFraction);

phaseFraction的来源:
uint32_t phaseFraction = mPhaseFraction;

phaseFraction作为参数传给了函数Advance:
Advance(&inputIndex, &phaseFraction, phaseIncrement);

函数Advance中对phaseFraction进行了赋值:
static inline void Advance(size_t* index, uint32_t* frac, uint32_t inc) {
*frac += inc;
*index += (size_t)(*frac >> kNumPhaseBits);
*frac &= kPhaseMask;
}

常量的定义:
// number of bits for phase fraction - 28 bits allows nearly 8x downsampling
static const int kNumPhaseBits = 28;


// phase mask for fraction
static const uint32_t kPhaseMask = (1LU<<kNumPhaseBits)-1;

再看看Interp函数:
static inline int32_t Interp(int32_t x0, int32_t x1, uint32_t f) {
return x0 + (((x1 - x0) * (int32_t)(f >> kPreInterpShift)) >> kNumInterpBits);
}

常量定义:
// number of bits used in interpolation multiply - 15 bits avoids overflow
static const int kNumInterpBits = 15;


// bits to shift the phase fraction down to avoid overflow
static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits;

再看vl和vr:
int32_t vl = mVolume[0];
int32_t vr = mVolume[1];

mVolume在函数AudioResampler::setVolume中被赋值:
void AudioResampler::setVolume(int16_t left, int16_t right) {
// TODO: Implement anti-zipper filter
mVolume[0] = left;
mVolume[1] = right;
}


函数AudioResampler::setVolume在函数AudioFlinger::RecordThread::readInputParameters中被调用:
mResampler->setVolume(AudioMixer::UNITY_GAIN, AudioMixer::UNITY_GAIN);

常量定义:
static const uint16_t UNITY_GAIN = 0x1000;
----------------------------------------需要resampling的情况-end-----------------------------------------------


可以,无论是否resampling,都是通过调用函数AudioStreamInALSA::read来获取数据。


函数AudioStreamInALSA::read中调用了ALSA Lib中的函数snd_pcm_mmap_readi或函数snd_pcm_readi来取得数据:
if (mHandle->mmap)
n = snd_pcm_mmap_readi(mHandle->handle, buffer, frames);
else
n = snd_pcm_readi(mHandle->handle, buffer, frames);

更多相关文章

  1. C语言的函数递归(下)
  2. Android(安卓)Handler机制之ThreadLocal
  3. Android(安卓)Framework面试题
  4. Android(安卓)Service详解(三) AIDL使用解析
  5. Android(安卓)Cursor浅析
  6. 慕课网:Android异步加载AsyncTask项目实战上
  7. 【Android】Parse 开发笔记(3)—— 实现查找附近的功能(LBS)
  8. Android中使用HttpURLConnection实现GET POST JSON数据与下载图
  9. 在 Android(安卓)应用程序中使用 Internet 数据

随机推荐

  1. 嵌入式设备Android带来的奇迹
  2. Android(安卓)使用 Jenkins 实现自动化打
  3. 在Android中,如何判断当前是否在桌面上
  4. Android(安卓)官方架构组件 Navigation
  5. Android(安卓)键盘开发心得
  6. Android异步加载全解析之大图处理
  7. Android(安卓)Service的思考(5)
  8. Android内存泄露问题分析
  9. Android中使用DrawerLayout的注意点
  10. Android(安卓)高级UI解密 (五) :PathMeasu