Android 錄音數據傳輸

今天來看看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);
發佈了82 篇原創文章 · 獲贊 5 · 訪問量 22萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章