AudioTrack中write函數size疑問

AudioTrack中write函數size疑問

最近在看《深入理解Android》中Audio相關部分時,看到AudioTrack::write函數的實現時,對其中操作的size有些疑問。
函數完整代碼如下:
ssize_t AudioTrack::write(const void* buffer, size_t userSize)
{

    if (mSharedBuffer != 0) return INVALID_OPERATION;
    if (mIsTimed) return INVALID_OPERATION;

    if (ssize_t(userSize) < 0) {
        // Sanity-check: user is most-likely passing an error code, and it would
        // make the return value ambiguous (actualSize vs error).
        ALOGE("AudioTrack::write(buffer=%p, size=%u (%d)",
                buffer, userSize, userSize);
        return BAD_VALUE;
    }

    ALOGV("write %p: %d bytes, mActive=%d", this, userSize, mActive);

    if (userSize == 0) {
        return 0;
    }

    // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed
    // while we are accessing the cblk
    mLock.lock();
    sp<IAudioTrack> audioTrack = mAudioTrack;
    sp<IMemory> iMem = mCblkMemory;
    mLock.unlock();

    ssize_t written = 0;
    const int8_t *src = (const int8_t *)buffer;
    Buffer audioBuffer;
    size_t frameSz = frameSize();

    do {
        audioBuffer.frameCount = userSize/frameSz;

        status_t err = obtainBuffer(&audioBuffer, -1);
        if (err < 0) {
            // out of buffers, return #bytes written
            if (err == status_t(NO_MORE_BUFFERS))
                break;
            return ssize_t(err);
        }

        size_t toWrite;

        if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
            // Divide capacity by 2 to take expansion into account
            toWrite = audioBuffer.size>>1;
            memcpy_to_i16_from_u8(audioBuffer.i16, (const uint8_t *) src, toWrite);
        } else {
   // !!!疑問點!!!
            toWrite = audioBuffer.size;
            memcpy(audioBuffer.i8, src, toWrite);
            src += toWrite;
        }
        userSize -= toWrite;
        written += toWrite;

        releaseBuffer(&audioBuffer);
    } while (userSize >= frameSz);

    return written;
}

疑問點就是上面代碼中標識出的疑問點。
因為audioBuffer是調用obtainBuffer獲取的,此處copy數據時隻考慮到瞭audioBuffer的size,而沒考慮源數據src的size,如果audioBuffer的size大於src的size,豈不是會copy到無效數據?
除非audioBuffer的size與src的size有一定關系。
看看obtainBuffer的實現(隻列出相關部分):

status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
{
    AutoMutex lock(mLock);
 …
    audio_track_cblk_t* cblk = mCblk;
 // 關註點 1
    uint32_t framesReq = audioBuffer->frameCount;
 …

    audioBuffer->frameCount  = 0;
    audioBuffer->size = 0;

    uint32_t framesAvail = cblk->framesAvailable();

    …
 
    cblk->lock.unlock();

    if (framesAvail == 0) {
        cblk->lock.lock();
        goto start_loop_here;
        while (framesAvail == 0) {
            // 循環嘗試獲取可寫的空間
   …
            // read the server count again
        start_loop_here:
            framesAvail = cblk->framesAvailable_l();
        }
        cblk->lock.unlock();
    }

    cblk->waitTimeMs = 0;

 // 關註點 2
    if (framesReq > framesAvail) {
        framesReq = framesAvail;
    }

    uint32_t u = cblk->user;
    uint32_t bufferEnd = cblk->userBase + cblk->frameCount;

 // 關註點 3
    if (framesReq > bufferEnd – u) {
        framesReq = bufferEnd – u;
    }

    audioBuffer->flags = mMuted ? Buffer::MUTE : 0;
    audioBuffer->channelCount = mChannelCount;
    audioBuffer->frameCount = framesReq;
 // 關註點 4
    audioBuffer->size = framesReq * cblk->frameSize;
    if (audio_is_linear_pcm(mFormat)) {
        audioBuffer->format = AUDIO_FORMAT_PCM_16_BIT;
    } else {
        audioBuffer->format = mFormat;
    }
    audioBuffer->raw = (int8_t *)cblk->buffer(u);
    active = mActive;
    return active ? status_t(NO_ERROR) : status_t(STOPPED);
}

從上面的4個關註點可知,audioBuffer的size來源於framesReq,即audioBuffer->frameCount,當然中間設計到比較適配處理。
從函數AudioTrack::write的實現可知,audioBuffer->frameCount是根據src的size計算得來:
audioBuffer.frameCount = userSize/frameSz;
也就是說,audioBuffer的size最終來源於src的size。
並且根據上述關註點2、3的處理可知,audioBuffer的size小於或等於src的size。
因此之前的擔心點也就不用擔心瞭。

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *