Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2d2bd6af authored by Andy Hung's avatar Andy Hung Committed by Android (Google) Code Review
Browse files

Merge "Allow duplicating thread to use native mixing audio format"

parents 50870c98 c25b84ab
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -255,7 +255,7 @@ public:

    class Buffer : public AudioBufferProvider::Buffer {
    public:
        int16_t *mBuffer;
        void *mBuffer;
    };

                        OutputTrack(PlaybackThread *thread,
@@ -271,7 +271,7 @@ public:
                                    AudioSystem::SYNC_EVENT_NONE,
                             int triggerSession = 0);
    virtual void        stop();
            bool        write(int16_t* data, uint32_t frames);
            bool        write(void* data, uint32_t frames);
            bool        bufferQueueEmpty() const { return mBufferQueue.size() == 0; }
            bool        isActive() const { return mActive; }
    const wp<ThreadBase>& thread() const { return mThread; }
+26 −22
Original line number Diff line number Diff line
@@ -172,6 +172,18 @@ static int sFastTrackMultiplier = kFastTrackMultiplier;
// and that all "fast" AudioRecord clients read from.  In either case, the size can be small.
static const size_t kRecordThreadReadOnlyHeapSize = 0x2000;

// Returns the source frames needed to resample to destination frames.  This is not a precise
// value and depends on the resampler (and possibly how it handles rounding internally).
// If srcSampleRate and dstSampleRate are equal, then it returns destination frames, which
// may not be a true if the resampler is asynchronous.
static inline size_t sourceFramesNeeded(
        uint32_t srcSampleRate, size_t dstFramesRequired, uint32_t dstSampleRate) {
    // +1 for rounding - always do this even if matched ratio
    // +1 for additional sample needed for interpolation
    return srcSampleRate == dstSampleRate ? dstFramesRequired :
            size_t((uint64_t)dstFramesRequired * srcSampleRate / dstSampleRate + 1 + 1);
}

// ----------------------------------------------------------------------------

static pthread_once_t sFastTrackMultiplierOnce = PTHREAD_ONCE_INIT;
@@ -3453,8 +3465,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
        if (sr == mSampleRate) {
            desiredFrames = mNormalFrameCount;
        } else {
            // +1 for rounding and +1 for additional sample needed for interpolation
            desiredFrames = (mNormalFrameCount * sr) / mSampleRate + 1 + 1;
            desiredFrames = sourceFramesNeeded(sr, mNormalFrameCount, mSampleRate);
            // add frames already consumed but not yet released by the resampler
            // because mAudioTrackServerProxy->framesReady() will include these frames
            desiredFrames += mAudioMixer->getUnreleasedFrames(track->name());
@@ -4881,16 +4892,8 @@ void AudioFlinger::DuplicatingThread::threadLoop_sleepTime()

ssize_t AudioFlinger::DuplicatingThread::threadLoop_write()
{
    // We convert the duplicating thread format to AUDIO_FORMAT_PCM_16_BIT
    // for delivery downstream as needed. This in-place conversion is safe as
    // AUDIO_FORMAT_PCM_16_BIT is smaller than any other supported format
    // (AUDIO_FORMAT_PCM_8_BIT is not allowed here).
    if (mFormat != AUDIO_FORMAT_PCM_16_BIT) {
        memcpy_by_audio_format(mSinkBuffer, AUDIO_FORMAT_PCM_16_BIT,
                               mSinkBuffer, mFormat, writeFrames * mChannelCount);
    }
    for (size_t i = 0; i < outputTracks.size(); i++) {
        outputTracks[i]->write(reinterpret_cast<int16_t*>(mSinkBuffer), writeFrames);
        outputTracks[i]->write(mSinkBuffer, writeFrames);
    }
    mStandby = false;
    return (ssize_t)mSinkBufferSize;
@@ -4917,25 +4920,26 @@ void AudioFlinger::DuplicatingThread::clearOutputTracks()
void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread)
{
    Mutex::Autolock _l(mLock);
    // FIXME explain this formula
    size_t frameCount = (3 * mNormalFrameCount * mSampleRate) / thread->sampleRate();
    // OutputTrack is forced to AUDIO_FORMAT_PCM_16_BIT regardless of mFormat
    // due to current usage case and restrictions on the AudioBufferProvider.
    // Actual buffer conversion is done in threadLoop_write().
    //
    // TODO: This may change in the future, depending on multichannel
    // (and non int16_t*) support on AF::PlaybackThread::OutputTrack
    OutputTrack *outputTrack = new OutputTrack(thread,
    // The downstream MixerThread consumes thread->frameCount() amount of frames per mix pass.
    // Adjust for thread->sampleRate() to determine minimum buffer frame count.
    // Then triple buffer because Threads do not run synchronously and may not be clock locked.
    const size_t frameCount =
            3 * sourceFramesNeeded(mSampleRate, thread->frameCount(), thread->sampleRate());
    // TODO: Consider asynchronous sample rate conversion to handle clock disparity
    // from different OutputTracks and their associated MixerThreads (e.g. one may
    // nearly empty and the other may be dropping data).

    sp<OutputTrack> outputTrack = new OutputTrack(thread,
                                            this,
                                            mSampleRate,
                                            AUDIO_FORMAT_PCM_16_BIT,
                                            mFormat,
                                            mChannelMask,
                                            frameCount,
                                            IPCThreadState::self()->getCallingUid());
    if (outputTrack->cblk() != NULL) {
        thread->setStreamVolume(AUDIO_STREAM_PATCH, 1.0f);
        mOutputTracks.add(outputTrack);
        ALOGV("addOutputTrack() track %p, on thread %p", outputTrack, thread);
        ALOGV("addOutputTrack() track %p, on thread %p", outputTrack.get(), thread);
        updateWaitTime_l();
    }
}
+21 −32
Original line number Diff line number Diff line
@@ -1710,14 +1710,13 @@ void AudioFlinger::PlaybackThread::OutputTrack::stop()
    mActive = false;
}

bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t frames)
bool AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frames)
{
    Buffer *pInBuffer;
    Buffer inBuffer;
    uint32_t channelCount = mChannelCount;
    bool outputBufferFull = false;
    inBuffer.frameCount = frames;
    inBuffer.i16 = data;
    inBuffer.raw = data;

    uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs();

@@ -1727,13 +1726,17 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr
        if (thread != 0) {
            MixerThread *mixerThread = (MixerThread *)thread.get();
            if (mFrameCount > frames) {
                // For the first write after being inactive, ensure that we have
                // enough frames to fill mFrameCount (which should be multiples of
                // the minimum buffer requirements of the downstream MixerThread).
                // This provides enough frames for the downstream mixer to begin
                // (see AudioFlinger::PlaybackThread::Track::isReady()).
                if (mBufferQueue.size() < kMaxOverFlowBuffers) {
                    uint32_t startFrames = (mFrameCount - frames);
                    pInBuffer = new Buffer;
                    pInBuffer->mBuffer = new int16_t[startFrames * channelCount];
                    pInBuffer->mBuffer = calloc(1, startFrames * mFrameSize);
                    pInBuffer->frameCount = startFrames;
                    pInBuffer->i16 = pInBuffer->mBuffer;
                    memset(pInBuffer->raw, 0, startFrames * channelCount * sizeof(int16_t));
                    pInBuffer->raw = pInBuffer->mBuffer;
                    mBufferQueue.add(pInBuffer);
                } else {
                    ALOGW("OutputTrack::write() %p no more buffers in queue", this);
@@ -1774,20 +1777,20 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr

        uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount :
                pInBuffer->frameCount;
        memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channelCount * sizeof(int16_t));
        memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * mFrameSize);
        Proxy::Buffer buf;
        buf.mFrameCount = outFrames;
        buf.mRaw = NULL;
        mClientProxy->releaseBuffer(&buf);
        pInBuffer->frameCount -= outFrames;
        pInBuffer->i16 += outFrames * channelCount;
        pInBuffer->raw = (int8_t *)pInBuffer->raw + outFrames * mFrameSize;
        mOutBuffer.frameCount -= outFrames;
        mOutBuffer.i16 += outFrames * channelCount;
        mOutBuffer.raw = (int8_t *)mOutBuffer.raw + outFrames * mFrameSize;

        if (pInBuffer->frameCount == 0) {
            if (mBufferQueue.size()) {
                mBufferQueue.removeAt(0);
                delete [] pInBuffer->mBuffer;
                free(pInBuffer->mBuffer);
                delete pInBuffer;
                ALOGV("OutputTrack::write() %p thread %p released overflow buffer %d", this,
                        mThread.unsafe_get(), mBufferQueue.size());
@@ -1803,11 +1806,10 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr
        if (thread != 0 && !thread->standby()) {
            if (mBufferQueue.size() < kMaxOverFlowBuffers) {
                pInBuffer = new Buffer;
                pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channelCount];
                pInBuffer->mBuffer = malloc(inBuffer.frameCount * mFrameSize);
                pInBuffer->frameCount = inBuffer.frameCount;
                pInBuffer->i16 = pInBuffer->mBuffer;
                memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channelCount *
                        sizeof(int16_t));
                pInBuffer->raw = pInBuffer->mBuffer;
                memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * mFrameSize);
                mBufferQueue.add(pInBuffer);
                ALOGV("OutputTrack::write() %p thread %p adding overflow buffer %d", this,
                        mThread.unsafe_get(), mBufferQueue.size());
@@ -1818,24 +1820,11 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr
        }
    }

    // Calling write() with a 0 length buffer, means that no more data will be written:
    // If no more buffers are pending, fill output track buffer to make sure it is started
    // by output mixer.
    if (frames == 0 && mBufferQueue.size() == 0) {
        // FIXME borken, replace by getting framesReady() from proxy
        size_t user = 0;    // was mCblk->user
        if (user < mFrameCount) {
            frames = mFrameCount - user;
            pInBuffer = new Buffer;
            pInBuffer->mBuffer = new int16_t[frames * channelCount];
            pInBuffer->frameCount = frames;
            pInBuffer->i16 = pInBuffer->mBuffer;
            memset(pInBuffer->raw, 0, frames * channelCount * sizeof(int16_t));
            mBufferQueue.add(pInBuffer);
        } else if (mActive) {
    // Calling write() with a 0 length buffer means that no more data will be written:
    // We rely on stop() to set the appropriate flags to allow the remaining frames to play out.
    if (frames == 0 && mBufferQueue.size() == 0 && mActive) {
        stop();
    }
    }

    return outputBufferFull;
}
@@ -1860,7 +1849,7 @@ void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue()

    for (size_t i = 0; i < size; i++) {
        Buffer *pBuffer = mBufferQueue.itemAt(i);
        delete [] pBuffer->mBuffer;
        free(pBuffer->mBuffer);
        delete pBuffer;
    }
    mBufferQueue.clear();