Function getminframecount (Java side: getminbuffersize) of the audiotrack class)

Source: Internet
Author: User

When I used to look at this function, I was not very familiar with how min frame was computed.

I looked at it again today and finally got a clue.

status_t AudioTrack::getMinFrameCount(        int* frameCount,        int streamType,        uint32_t sampleRate){    int afSampleRate;    if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {        return NO_INIT;    }    int afFrameCount;    if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {        return NO_INIT;    }    uint32_t afLatency;    if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {        return NO_INIT;    }    // Ensure that buffer depth covers at least audio hardware latency    uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate);    if (minBufCount < 2) minBufCount = 2;    *frameCount = (sampleRate == 0) ? afFrameCount * minBufCount :              afFrameCount * minBufCount * sampleRate / afSampleRate;    return NO_ERROR;}

Let's take a look at the following code:

    int afSampleRate;    if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {        return NO_INIT;    }

Basically, it can be seen from the literal meaning that the sampling rate of the output device is obtained.
How can we get it?
Step by step.

In the audiosystem: getoutputsamplingrate function, the corresponding output is obtained based on stream type, and the output description is obtained.
If the result is obtained successfully, take the samplerate described in output:

        *samplingRate = outputDesc->samplingRate;

Otherwise, take the sample rate of audioflinger:

        *samplingRate = af->sampleRate(output);

First, let's look at how the sample rate of audio flinger is obtained.

In the audioflinger: samplerate function, find the thread corresponding to the output and obtain the sample rate of the corresponding thread.

The member variable msamplerate is directly returned in the function audioflinger: threadbase: samplerate.

Msamplerate is assigned a value in the audioflinger: playbackthread: readoutputparameters function:

    mSampleRate = mOutput->sampleRate();

Moutput-> samplerate, which calls the functions of the audiostreamoutalsa object.
The function is defined in its parent class alsastreamops:

uint32_t ALSAStreamOps::sampleRate() const{    return mHandle->sampleRate;}

The mhandle value is assigned to the constructor of alsastreamops. The constructor parameter handle is used.
In the audiostreamoutalsa object, the function audiohardwarealsa: openoutputstream is created:

            out = new AudioStreamOutALSA(this, &(*it));

It is the constructor parameter handle.
It assignment:

ALSAHandleList::iterator it = mDeviceList.begin();

The mdevicelist value is assigned to the constructor audiohardwarealsa:

            mALSADevice->init(mALSADevice, mDeviceList);

The init function is actually the s_init function:

static status_t s_init(alsa_device_t *module, ALSAHandleList &list){    LOGD("Initializing devices for IMX51 ALSA module");    list.clear();    for (size_t i = 0; i < ARRAY_SIZE(_defaults); i++) {        _defaults[i].module = module;        list.push_back(_defaults[i]);    }    return NO_ERROR;}

_ Defaults definition:

static alsa_handle_t _defaults[] = {    {        module      : 0,        devices     : IMX51_OUT_DEFAULT,        curDev      : 0,        curMode     : 0,        handle      : 0,        format      : SND_PCM_FORMAT_S16_LE, // AudioSystem::PCM_16_BIT        channels    : 2,        sampleRate  : DEFAULT_SAMPLE_RATE,        latency     : 200000, // Desired Delay in usec        bufferSize  : 6144, // Desired Number of samples        modPrivate  : (void *)&setDefaultControls,    },    {        module      : 0,        devices     : IMX51_IN_DEFAULT,        curDev      : 0,        curMode     : 0,        handle      : 0,        format      : SND_PCM_FORMAT_S16_LE, // AudioSystem::PCM_16_BIT        channels    : 2,        sampleRate  : DEFAULT_SAMPLE_RATE,        latency     : 250000, // Desired Delay in usec        bufferSize  : 6144, // Desired Number of samples        modPrivate  : (void *)&setDefaultControls,    },};

Samplerate was originally specified here:

        sampleRate  : DEFAULT_SAMPLE_RATE,

The value of default_sample_rate is 44100.

Therefore, the value of afsamplerate is 44100.

Let's look back. What if we find the output description in the audiosystem: getoutputsamplingrate function?

The output description is created in the constructor of audiopolicymanagerbase.
Among them, latency is obtained by calling the function mpclientinterface-> openoutput:

    mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,                                    &outputDesc->mSamplingRate,                                    &outputDesc->mFormat,                                    &outputDesc->mChannels,                                    &outputDesc->mLatency,                                    outputDesc->mFlags);

Actually, the audioflinger: openoutput function is called.
Here, the value of samplingrate is:

        if (pSamplingRate) *pSamplingRate = samplingRate;

Why samplingrate:

    AudioStreamOut *output = mAudioHardware->openOutputStream(*pDevices,                                                             (int *)&format,                                                             &channels,                                                             &samplingRate,                                                             &status);

Function audiohardwarealsa: value assigned to samplingrate in openoutputstream:

            err = out->set(format, channels, sampleRate);

Processing samplerate in the alsastreamops: Set function:

    if (rate && *rate > 0) {        if (mHandle->sampleRate != *rate)            return BAD_VALUE;    } else if (rate)        *rate = mHandle->sampleRate;

It joins the river above.

The process of framecount is similar to that of samplerate. The following is only a difference.
In the audioflinger: playbackthread: readoutputparameters function:

    mFrameSize = (uint16_t)mOutput->frameSize();    mFrameCount = mOutput->bufferSize() / mFrameSize;

The function framesize comes from the audiostreamout class:

    /**     * return the frame size (number of bytes per sample).     */    uint32_t    frameSize() const { return AudioSystem::popCount(channels())*((format()==AudioSystem::PCM_16_BIT)?sizeof(int16_t):sizeof(int8_t)); }

Implementation of the function alsastreamops: channels:

uint32_t ALSAStreamOps::channels() const{    unsigned int count = mHandle->channels;    uint32_t channels = 0;    if (mHandle->curDev & AudioSystem::DEVICE_OUT_ALL)        switch(count) {            case 4:                channels |= AudioSystem::CHANNEL_OUT_BACK_LEFT;                channels |= AudioSystem::CHANNEL_OUT_BACK_RIGHT;                // Fall through...            default:            case 2:                channels |= AudioSystem::CHANNEL_OUT_FRONT_RIGHT;                // Fall through...            case 1:                channels |= AudioSystem::CHANNEL_OUT_FRONT_LEFT;                break;        }    else        switch(count) {            default:            case 2:                channels |= AudioSystem::CHANNEL_IN_RIGHT;                // Fall through...            case 1:                channels |= AudioSystem::CHANNEL_IN_LEFT;                break;        }    return channels;}

Let's take a look at the definition of channels in _ defaults:

        channels    : 2,

Function alsastreamops: Format implementation:

int ALSAStreamOps::format() const{    int pcmFormatBitWidth;    int audioSystemFormat;    snd_pcm_format_t ALSAFormat = mHandle->format;    pcmFormatBitWidth = snd_pcm_format_physical_width(ALSAFormat);    switch(pcmFormatBitWidth) {        case 8:            audioSystemFormat = AudioSystem::PCM_8_BIT;            break;        default:            LOG_FATAL("Unknown AudioSystem bit width %i!", pcmFormatBitWidth);        case 16:            audioSystemFormat = AudioSystem::PCM_16_BIT;            break;    }    return audioSystemFormat;}

Let's look at the definition of format in _ defaults:

        format      : SND_PCM_FORMAT_S16_LE, // AudioSystem::PCM_16_BIT

Definitions of pcm_8_bit and pcm_16_bit:

    // Audio sub formats (see AudioSystem::audio_format).    enum pcm_sub_format {        PCM_SUB_16_BIT          = 0x1, // must be 1 for backward compatibility        PCM_SUB_8_BIT           = 0x2, // must be 2 for backward compatibility    };

So,

    mFrameSize = (uint16_t)mOutput->frameSize();

The result is actually 4.

Implementation of the function alsastreamops: buffersize:

Size_t alsastreamops: buffersize () const {bytes buffersize = mhandle-> buffersize; snd_pcm_uframes_t periodsize; // falls into the difficult ALSA Lib. Snd_pcm_get_params (mhandle-> handle, & buffersize, & periodsize); size_t bytes = static_cast <size_t> (handler (mhandle-> handle, buffersize )); // not sure when this happened, but unfortunately it now // appears that the buffersize must be reported as a // power of 2. this might be for OSS compatibility. for (size_t I = 1; (Bytes &~ I )! = 0; I <= 1) bytes & = ~ I; return bytes ;}

Let's look at the definition of buffersize in _ defaults:

        bufferSize  : 6144, // Desired Number of samples

Therefore, ALSA Lib is not considered. below:

    mFrameCount = mOutput->bufferSize() / mFrameSize;

Result: 6144/4 = 1536
That is, afframecount is 1536.

The latency process is no longer read.
In _ defaults, latency is defined:

        latency     : 200000, // Desired Delay in usec

The calculation formula is as follows:

#define USEC_TO_MSEC(x) ((x + 999) / 1000)

The result of aflatency is 200.

The value of the variable is known, so minbufcount can be calculated as follows:

    // Ensure that buffer depth covers at least audio hardware latency    uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate);

Minbufcount = 200/(1000x1536)/44100) = 5.

Digest.
Afframecount indicates the number of frames in the hardware buffer. afframecount/afsamplerate indicates the amount of time required to play data in the hardware buffer. The unit is seconds.
Multiply by 1000 to convert the second to milliseconds.
This is consistent with the unit of aflatency.
The result is that the buffer size on the software side is only several times the buffer size on the hardware side to meet the hardware latency.

I still don't feel completely digested.
What is hardware latency? Why does the buffer size on the software side require this multiple?
Hardware delay means that the hardware side may be delayed for so long, that is, the hardware may not retrieve data from the software side for such a long time.
The software side is still writing data. To ensure that the data on the software side is not lost, the buffer on the software side is large enough.
What is big enough?
That is, when the maximum time allowed by the hardware and no data is obtained, the buffer on the software side will not burst into a warehouse.
This basically completely digested the problem.

The Calculation of framecount is related to the input parameter samplerate:

    *frameCount = (sampleRate == 0) ? afFrameCount * minBufCount :              afFrameCount * minBufCount * sampleRate / afSampleRate;

If samplerate is 0, framecount is 7680.
If samplerate is not 0, framecount is 7680 × samplerate/44100.

Digest it.
Since the buffer size of the software has been calculated as multiple times the size of the hardware, and the number of frames contained in the hardware buffer is known as afframecount,
It is no longer difficult to calculate the number of frames contained in the software buffer.
If the data on the software side is not specified as the sampling rate on the hardware side, or is the same as that on the hardware side, the number of frames that the buffer on the software side can hold is afframecount * minbufcount.
If the sampling rate on the software side is different from that on the hardware side, multiply the above result by samplerate/afsamplerate.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.