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

Android 录音数据传输相关推荐

  1. iphone8 android传文件,如何从iPhone或Android将数据传输到新的iPhone 8

    第1部分:如何将数据传输到新的iPhone 8? Wondershare MobileTrans提供了一种快速可靠的方式将数据从一个设备移动到另一个设备.它具有直接的电话到电话传输功能,支持所有主要数 ...

  2. Android录音转为MP2的实现

    Android录音转为MP2的实现 利用Android提供的AudioRecord类以及开源编码库twolame,实现了android手机边录音边编码,录音完成直接得到MP2音频文件.由于Androi ...

  3. Android录音下————AudioRecord源码分析

    Android录音下----AudioRecord源码分析 文章目录 Android录音下----AudioRecord源码分析 一.概述 1.主要分析点 2.储备知识 二.getMinBufferS ...

  4. android 录音的格式,Android录音mp3格式实例详解

    Android录音支持的格式有amr.aac,但这两种音频格式在跨平台上表现并不好. MP3显然才是跨平台的最佳选择. 项目地址 实现思路概述 在分析代码前,我们需要明确几个问题 1. 如何最终生成M ...

  5. Android音频录制方案,Android录音,录制其他App播放的声音

    Android录音,录制其他App播放的声音 从Android10(SDK 29)版本开始,可以设置录音App的源为其他App,这样就可以录制其他App播放的声音 此方案有以下注意几点 设置了源为其他 ...

  6. Android录音amr实时转成MP3格式

    文章目录 MP3 录音使用说明 步骤一:下载NDK,并配置(Mac) 步骤二:修改C代码相关路径,编译成so库 步骤三:应用层代码代码调用系统AudioRecord类开始录音 开始录音 start() ...

  7. Android录音并进行本地转码为MP3

    ** Android录音并进行本地转码 ** 通过安卓手机进行录音, 录音后,使用lame进行转码操作 开发中需要使用这个功能,只是一个简单的进行转码的工具,具体的代码信息如下 项目的基本结构图 1. ...

  8. Android录音-SoundTouch移植到Android

    Android录音-SoundTouch移植到Android 文章目录 Android录音-SoundTouch移植到Android 一.SoundTouch介绍 二.移植SoundTouch(And ...

  9. Androidの录音实现

    Androidの录音实现 1. 录音功能需要使用android.media.MediaRecorder来完成,这里我们列出几个重要的使用方法,也是最常用的录音接口. 1.MediaRecorder r ...

最新文章

  1. 数据质量和模型调优哪个更重要?
  2. Mybatis【一对多、多对一、多对多】知识要点
  3. 软件测试真实项目_企业中软件测试的项目流程
  4. 自学python清单-我的2018学习清单
  5. centos进入单用户模式
  6. MathType中的一些精彩技巧
  7. POJ 3259 SPFA
  8. how is SAP UI5 Model.setProperty implemented
  9. 克制懒惰之飞鸽传书版
  10. Costco的中国门徒已经参透了零售成功秘笈
  11. git与svn, tfs等源代码管理器的协同
  12. u3d一个GameObject绑定两个AudioSource
  13. stm32读取驾驶模拟器数据 stm32F407读取joystick数据
  14. js禁止退出当前页面
  15. shell应用之监测电脑内存、负载和磁盘的使用情况
  16. 3.Ubuntu/Deepin下安装Monaco/Menlo字体
  17. sqlplus linux 连接数据库,sqlplus连接Oracle
  18. 关于奥威亚自动录播系统的设置使用小笔记
  19. df满足条件的值修改_python – 如何根据其他列中的条件将pandas df列中的多个值更改为np.nan?...
  20. spacy实体关系抽取_使用spacy从Wikipedia文章中命名实体识别

热门文章

  1. 学计算机去银行工作有什么要求,进入银行工作需要什么条件
  2. Elasticsearch/Kibana/X-pack/Logstash 6.x版本的安装
  3. Linux怎么接移动热点,Linux网络配置:手提在连接WIFI热点情况下,Ubuntu16.04中怎样配置网络?...
  4. Uniapp之使用h5+打开地图导航
  5. Python学习笔记九10:shelve模块
  6. 直方图均衡化 matlab代码,基于matlab的直方图均衡化代码
  7. 2022-2028全球疤痕护理产品行业调研及趋势分析报告
  8. 虚拟世界和现实世界的未来
  9. java通过麒麟实现开机自启动,京东四面:说说Tomcat 在 SpringBoot 中是如何启动的!...
  10. 实践:uniapp中webview内置网页与app实时通讯