[RK3288][Android6.0] Initialization process analysis of Audio recording HAL layer

Platform: Rockchip
OS: Android 6.0
Kernel: 3.10.92 Use

sample rate and buffer size as clues to track Audio Hal first initialization at boot:
AudioPolicyManager ->
    ConfigParsingUtils::loadAudioPolicyConfig -> AUDIO_POLICY_CONFIG_FILE is /system/etc/audio_policy.conf , corresponding to /device/rockchip/common/audio_policy_rk30board.conf
        loadHwModules ->
            loadHwModule ->
                config_find(root, INPUTS_TAG); //INPUTS_TAG is inputs, which can be found in audio_policy.conf.
                module->loadInput ->
                HwModule::loadInput ->
                    profile->loadSamplingRates -> find the content of SAMPLING_RATES_TAG, ie sampling_rates
                    mSamplingRates.add //All supported sampling rates are saved, others such as format and channel are also saved separately
                    mInputProfiles.add //An input node is saved as a profile
    new AudioInputDescriptor(inProfile); -> Create a profile based on the above
        profile->pickSamplingRate //Get the maximum sampling rate, here is 48kHz, and the channel is similar.
    mpClientInterface->openInput - > Pass the sample rate, channel and format obtained above to config to hal to see if it is really supported. If not, HAL will be reconfigured.
        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, //Maximum supported configuration from audio_policy.conf
                                  struct audio_stream_in **stream_in, // incoming is new
                                  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;
    //No matter what kind of it is passed in, it will be directly set to two channels.
    config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
#ifdef ALSA_IN_DEBUG
    //Used to debug and grab pcm data
    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;
......
    //The maximum sampling rate in audio_policy.conf is 48kHz
    in->requested_rate = config->sample_rate;
......
    in->channel_mask = config->channel_mask;
    ALOGE("in->channel_mask:%d", in->channel_mask);
......
    //The default is 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;
    // Calculated by the configuration of pcm_config_in, audio_stream_in_frame_size(&in->stream) is called
    //in_get_format(), fixed is AUDIO_FORMAT_PCM_16_BIT, audio_channel_count_from_out_mask() is used to convert
    //The channel macro is defined as the actual number. But the question here is that there is one more pcm_config->channels?
    //audio_stream_in_frame_size() already contains the channel, I think it is more application.
    in->buffer = malloc(pcm_config->period_size * pcm_config->channels
                                               * audio_stream_in_frame_size(&in->stream));
......
    //When the sampling rate of the upper layer and the sampling rate of the HAL configuration do not want to wait, resample is required. Of course, the data is finally obtained from the buffer after resample.
    if (in->requested_rate != pcm_config->rate) {
        //The same as the normal non-resample method to obtain the kernel recording data.
        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,
                               in->requested_rate,
                               audio_channel_count_from_in_mask(in->channel_mask),
                               RESAMPLER_QUALITY_DEFAULT,
                               &in->buf_provider,
                               &in->resampler);
        if (ret! = 0) {
            ret = -EINVAL;
            goto err_resampler;
        }
    }
......
    *stream_in = &in->stream;
    return 0;
......
}

The upper layer obtains the buffer size through in_get_buffer_size()
static size_t in_get_buffer_size(const struct audio_stream *stream)
{
    struct stream_in *in = (struct stream_in *)stream;
    ALOGE("in_get_buffer_size");
    //The same as before, the first request uses the value in audio_policy.conf.
    //in->requested_rate=48kHz
    //audio_channel_count_from_in_mask(in_get_channels(stream)) is fixed in front, so it is 2.
    return get_input_buffer_size(in->requested_rate,
                                 AUDIO_FORMAT_PCM_16_BIT,
                                 audio_channel_count_from_in_mask(in_get_channels(stream)),
                                 (in->flags & AUDIO_INPUT_FLAG_FAST) != 0);
}

static size_t get_input_buffer_size(unsigned int sample_rate,
                                    audio_format_t format,
                                    unsigned int channel_count,
                                    bool is_low_latency)
{
    const struct pcm_config *config = is_low_latency ?
            &pcm_config_in_low_latency : &pcm_config_in;
    size_t size;

    //Consider alignment and sampling rate inconsistencies.
    size = (config->period_size * sample_rate) / config->rate;
    size = ((size + 15) / 16) * 16;
    //The size of a sample is period size * channel * format.
    return size * channel_count * audio_bytes_per_sample(format);
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324818396&siteId=291194637