[RK3288][Android6.0] Audio录音HAL层的数据读取流程分析

Platform: Rockchip
OS: Android 6.0
Kernel: 3.10.92

用原生SoundRecorder apk为例,以sample rate, channel及buffer size这些参数为线索来跟踪,,流程如下:
openRecord_l ->
    AudioSystem::getInputForAttr ->
        aps->getInputForAttr ->
            AudioPolicyManager::getInputForAttr ->
                getInputProfile ->    根据上apk给的profileSamplingRate, profileFormat以及profileChannelMask找到对应的profile
                mpClientInterface->openInput -> 上层的录音参数传递给HAL.
                    AudioFlinger::openInput_l ->
                        inHwHal->open_input_stream ->
                        adev_open_input_stream ->    audio_hw.c
static int adev_open_input_stream(struct audio_hw_device *dev,
                                  audio_io_handle_t handle,
                                  audio_devices_t devices,
                                  struct audio_config *config,    
                                  struct audio_stream_in **stream_in,    //传进来是新的
                                  audio_input_flags_t flags,
                                  const char *address __unused,
                                  audio_source_t source __unused)
{
    struct audio_device *adev = (struct audio_device *)dev;
    struct stream_in *in;
    int ret;

    *stream_in = NULL;
    //不管它传进来是哪种,直接定死为双声道.
    config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
#ifdef ALSA_IN_DEBUG
    //用来调试抓取pcm数据
    in_debug = fopen("/data/debug.pcm","wb");//please touch /data/debug.pcm first
#endif

......
    in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
    if (!in)
        return -ENOMEM;
......
    //SoundRecorder apk使用的是8kHz的采样率.
    in->requested_rate = config->sample_rate;
......
    //上面定死为双通道.
    in->channel_mask = config->channel_mask;
......
    //默认用的是pcm_config_in
    //struct pcm_config pcm_config_in = {
    //.channels = 2,
    //.rate = 44100,
    //.period_size = 16,
    //.period_count = 128,
    //.format = PCM_FORMAT_S16_LE,
    //};
    struct pcm_config *pcm_config = flags & AUDIO_INPUT_FLAG_FAST ?
            &pcm_config_in_low_latency : &pcm_config_in;
    in->config = pcm_config;
    //用pcm_config_in的配置来计算, audio_stream_in_frame_size(&in->stream)调用的是
    //in_get_format(),固定是AUDIO_FORMAT_PCM_16_BIT, audio_channel_count_from_out_mask()用来转换
    //channel宏定义为实际的number.不过这里有疑问的是这样不是多了一个pcm_config->channels了?
    //audio_stream_in_frame_size()已经包含了channel了啊!
    in->buffer = malloc(pcm_config->period_size * pcm_config->channels
                                               * audio_stream_in_frame_size(&in->stream));
......
    //当上层采样率和HAL配置的采样率不想等时,要resample,当然,数据最终也是从resample后的buffer中获取.
    if (in->requested_rate != pcm_config->rate) {
        //和正常非resample的获取kernel录音数据方式一样.
        in->buf_provider.get_next_buffer = get_next_buffer;    
        in->buf_provider.release_buffer = release_buffer;

        ALOGD("pcm_config->rate:%d,in->requested_rate:%d,in->channel_mask:%d",
             pcm_config->rate,in->requested_rate,audio_channel_count_from_in_mask(in->channel_mask));
        ret = create_resampler(pcm_config->rate,    //44.1kHz
                               in->requested_rate,    //8kHz
                               audio_channel_count_from_in_mask(in->channel_mask),    //2
                               RESAMPLER_QUALITY_DEFAULT,
                               &in->buf_provider,
                               &in->resampler);
......
    }
......
}
数据读取:
in_read():    audio_hw.c
static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
                       size_t bytes)
{
......
    //将要读取的字节数转换成frames, 一个frame=channel * format.
    size_t frames_rq = bytes / audio_stream_in_frame_size(stream);
......
    pthread_mutex_lock(&in->lock);
    if (in->standby) {
        pthread_mutex_lock(&adev->lock);
        //打开及设置录音
        ret = start_input_stream(in);
        pthread_mutex_unlock(&adev->lock);
        if (ret < 0)
            goto exit;
        in->standby = false;
    }
    //读取数据,读取的buffer和frame count是上层提供.
    ret = read_frames(in, buffer, frames_rq);
......
}
start_input_stream():
static int start_input_stream(struct stream_in *in)
{
    struct audio_device *adev = in->dev;
    //打印信息
    in_dump(in, 0);
    //路径相关,这里不关注
    route_pcm_open(getRouteFromDevice(in->device | AUDIO_DEVICE_BIT_IN));
    //打开录音设备,设置也在里面,调用tinyalsa库里面的代码.
    in->pcm = pcm_open(PCM_CARD, PCM_DEVICE, PCM_IN, in->config);
......
    //传进来的是8kHz,HAL配置的是44.1kHz,需要重采样,这里做复位初始化工作.
    if (in->resampler)
        in->resampler->reset(in->resampler);

    in->frames_in = 0;
    adev->input_source = in->input_source;
    adev->in_device = in->device;
    adev->in_channel_mask = in->channel_mask;
......
}
read_frames:
static ssize_t read_frames(struct stream_in *in, void *buffer, ssize_t frames)
{
    //记录累积读取到帧数.
    ssize_t frames_wr = 0;
    
    size_t frame_size = audio_stream_in_frame_size(&in->stream);
    //循环读完为止
    while (frames_wr < frames) {
        //剩余要读的帧数为总共读的帧数减掉已经读到的帧数
        size_t frames_rd = frames - frames_wr;
        if (in->resampler != NULL) {
            //用从采样的库函数来获取buffer
            in->resampler->resample_from_provider(in->resampler,
                    //读一次,根据frames_wr的值偏移一下
                    (int16_t *)((char *)buffer +
                            frames_wr * frame_size),
                    //实际一次读取到的帧数
                    &frames_rd);
        } else {
......
        }
......
        //累计总共读取到的帧数.
        frames_wr += frames_rd;
    }

    return frames_wr;
}
resampler_resample_from_provider():
int resampler_resample_from_provider(struct resampler_itfe *resampler,
                       int16_t *out,
                       size_t *outFrameCount)
{
    struct resampler *rsmp = (struct resampler *)resampler;
   ......
    size_t framesRq = *outFrameCount;
    if (framesRq != rsmp->frames_rq) {
        //换算成实际采样率需要采的帧率.
        rsmp->frames_needed = (framesRq * rsmp->in_sample_rate) / rsmp->out_sample_rate + 1;
        rsmp->frames_rq = framesRq;
    }

    size_t framesWr = 0;
    spx_uint32_t inFrames = 0;
    while (framesWr < framesRq) {
        if (rsmp->frames_in < rsmp->frames_needed) {
            // make sure that the number of frames present in rsmp->in_buf (rsmp->frames_in) is at
            // least the number of frames needed to produce the number of frames requested at
            // the output sampling rate
            if (rsmp->in_buf_size < rsmp->frames_needed) {
                //更新buffer size
                rsmp->in_buf_size = rsmp->frames_needed;
                //分配buffer
                rsmp->in_buf = (int16_t *)realloc(rsmp->in_buf,
                                        rsmp->in_buf_size * rsmp->channel_count * sizeof(int16_t));
            }
            struct resampler_buffer buf;
            //每次想获取的frame count.
            buf.frame_count = rsmp->frames_needed - rsmp->frames_in;
            //获取buffer的核心函数
            rsmp->provider->get_next_buffer(rsmp->provider, &buf);
            if (buf.raw == NULL) {
                break;
            }
            //拷贝buf.frame_count大小(这个值可能在get_next_buffer()中被修改)到rsmp->in_buf,
            //偏移没* sizeof(int16_t)是因为in_buf是int16类型.
            memcpy(rsmp->in_buf + rsmp->frames_in * rsmp->channel_count,
                    buf.raw,
                    buf.frame_count * rsmp->channel_count * sizeof(int16_t));
            //记录总共读取的帧数
            rsmp->frames_in += buf.frame_count;
            //用好就释放掉,实际只是更新了in->frames_in,这样前面拿过的数据不会再会重复拿了.
            rsmp->provider->release_buffer(rsmp->provider, &buf);
        }
        //
        spx_uint32_t outFrames = framesRq - framesWr;
        //一次要处理的帧数
        inFrames = rsmp->frames_in;
        if (rsmp->channel_count == 1) {
......
        } else {
            //inFrames会被改成实际能处理的帧数
            //outFrames返回世界写到out buffer中的帧数
            speex_resampler_process_interleaved_int(rsmp->speex_resampler,
                                        rsmp->in_buf,
                                        &inFrames,
                                        out + framesWr * rsmp->channel_count,
                                        &outFrames);
        }
        //累计更新实际处理帧数
        framesWr += outFrames;
        //如果输入帧数全部处理完,那么rsmp->frames_in和inFrames的值应该是是一样.
        rsmp->frames_in -= inFrames;
        //当上面说到的两个值都不一致,也就是输入和输出的实际值都不是我们想要达到的值时
        //就会提示警告信息.
        ALOGW_IF((framesWr != framesRq) && (rsmp->frames_in != 0),
                "ReSampler::resample() remaining %zu frames in and %zu frames out",
                rsmp->frames_in, (framesRq - framesWr));
    }
    //最后把未能处理的帧数直接copy到in_buf开头,等到下一次再处理.
    if (rsmp->frames_in) {
        memmove(rsmp->in_buf,
                rsmp->in_buf + inFrames * rsmp->channel_count,
                rsmp->frames_in * rsmp->channel_count * sizeof(int16_t));
    }
    //更新处理掉的帧
    *outFrameCount = framesWr;

    return 0;
}
get_next_buffer():
static int get_next_buffer(struct resampler_buffer_provider *buffer_provider,
                                   struct resampler_buffer* buffer)
{
    struct stream_in *in;
    size_t i,size;
......
    in = (struct stream_in *)((char *)buffer_provider -
                                   offsetof(struct stream_in, buf_provider));
......
    //start_input_stream()中设置为0,第一次进来
    if (in->frames_in == 0) {
        //size好像没用到???
        size = pcm_frames_to_bytes(in->pcm,pcm_get_buffer_size(in->pcm));
        //调用tinyalsa接口,从kernel读取录音数据.
        in->read_status = pcm_read(in->pcm,
                                    //放在之前adev_open_input_stream()中申请的in->buffer中,
                                    //之前的疑问是in->buffer申请多乘了一个channel,这里应证了,因为
                                    //pcm_frames_to_bytes()就是period_size*channel*format
                                   (void*)in->buffer,pcm_frames_to_bytes(in->pcm, in->config->period_size));
......
        //看这个参数貌似用来保存帧大小
        in->frames_in = in->config->period_size;
......
    }

    //buffer->frame_count为要获取的帧数,非resample时就是上层一次要读取的总frame
    //resample时会经过一个sample rate的比例转换. 得到的结果表明实际需要读取的字节数,
    //如果in->frames_in比buffer->frame_count,那么我们只需要buffer->frame_count大小就够了.
    buffer->frame_count = (buffer->frame_count > in->frames_in) ?
                                in->frames_in : buffer->frame_count;
    //调试结果是in->config->period_size 和in->frames_in一直一样,因此上面if语句里已经赋值了,
    //那就一直是从buffer开头存放没有再次利用了. 当in->frames_in比buffer->frame_count大的时候
    //release_buffer()会改变in->frames_in的值,偏移段前面的内容表示已经释放掉了.
    buffer->i16 = in->buffer +
            (in->config->period_size - in->frames_in) *
                audio_channel_count_from_in_mask(in->channel_mask);

    return in->read_status;
}

你可能感兴趣的:(子类__Audio)