Android 錄音資料轉送

來源:互聯網
上載者:User

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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.