今天來看看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);