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

Commit 67e54402 authored by Glenn Kasten's avatar Glenn Kasten Committed by Android (Google) Code Review
Browse files

Merge "Keep a copy of most recent audio played" into jb-dev

parents a6490c65 fbae5dae
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -85,4 +85,8 @@ LOCAL_CFLAGS += -DHAVE_REQUEST_PRIORITY -UFAST_TRACKS_AT_NON_NATIVE_SAMPLE_RATE
# uncomment for systrace
# LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_AUDIO

# uncomment for dumpsys to write most recent audio output to .wav file
# 47.5 seconds at 44.1 kHz, 8 megabytes
# LOCAL_CFLAGS += -DTEE_SINK_FRAMES=0x200000

include $(BUILD_SHARED_LIBRARY)
+73 −0
Original line number Diff line number Diff line
@@ -79,6 +79,8 @@
#include "AudioStreamOutSink.h"
#include "MonoPipe.h"
#include "MonoPipeReader.h"
#include "Pipe.h"
#include "PipeReader.h"
#include "SourceAudioBufferProvider.h"

#ifdef HAVE_REQUEST_PRIORITY
@@ -2217,6 +2219,20 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud
        ALOG_ASSERT(index == 0);
        mPipeSink = monoPipe;

#ifdef TEE_SINK_FRAMES
        // create a Pipe to archive a copy of FastMixer's output for dumpsys
        Pipe *teeSink = new Pipe(TEE_SINK_FRAMES, format);
        numCounterOffers = 0;
        index = teeSink->negotiate(offers, 1, NULL, numCounterOffers);
        ALOG_ASSERT(index == 0);
        mTeeSink = teeSink;
        PipeReader *teeSource = new PipeReader(*teeSink);
        numCounterOffers = 0;
        index = teeSource->negotiate(offers, 1, NULL, numCounterOffers);
        ALOG_ASSERT(index == 0);
        mTeeSource = teeSource;
#endif

#ifdef SOAKER
        // create a soaker as workaround for governor issues
        mSoaker = new Soaker();
@@ -2245,6 +2261,7 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud
        state->mColdFutexAddr = &mFastMixerFutex;
        state->mColdGen++;
        state->mDumpState = &mFastMixerDumpState;
        state->mTeeSink = mTeeSink.get();
        sq->end();
        sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);

@@ -3440,6 +3457,62 @@ status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>
    FastMixerDumpState copy = mFastMixerDumpState;
    copy.dump(fd);

    // Write the tee output to a .wav file
    NBAIO_Source *teeSource = mTeeSource.get();
    if (teeSource != NULL) {
        char teePath[64];
        struct timeval tv;
        gettimeofday(&tv, NULL);
        struct tm tm;
        localtime_r(&tv.tv_sec, &tm);
        strftime(teePath, sizeof(teePath), "/data/misc/media/%T.wav", &tm);
        int teeFd = open(teePath, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
        if (teeFd >= 0) {
            char wavHeader[44];
            memcpy(wavHeader,
                "RIFF\0\0\0\0WAVEfmt \20\0\0\0\1\0\2\0\104\254\0\0\0\0\0\0\4\0\20\0data\0\0\0\0",
                sizeof(wavHeader));
            NBAIO_Format format = teeSource->format();
            unsigned channelCount = Format_channelCount(format);
            ALOG_ASSERT(channelCount <= FCC_2);
            unsigned sampleRate = Format_sampleRate(format);
            wavHeader[22] = channelCount;       // number of channels
            wavHeader[24] = sampleRate;         // sample rate
            wavHeader[25] = sampleRate >> 8;
            wavHeader[32] = channelCount * 2;   // block alignment
            write(teeFd, wavHeader, sizeof(wavHeader));
            size_t total = 0;
            bool firstRead = true;
            for (;;) {
#define TEE_SINK_READ 1024
                short buffer[TEE_SINK_READ * FCC_2];
                size_t count = TEE_SINK_READ;
                ssize_t actual = teeSource->read(buffer, count);
                bool wasFirstRead = firstRead;
                firstRead = false;
                if (actual <= 0) {
                    if (actual == (ssize_t) OVERRUN && wasFirstRead) {
                        continue;
                    }
                    break;
                }
                ALOG_ASSERT(actual <= count);
                write(teeFd, buffer, actual * channelCount * sizeof(short));
                total += actual;
            }
            lseek(teeFd, (off_t) 4, SEEK_SET);
            uint32_t temp = 44 + total * channelCount * sizeof(short) - 8;
            write(teeFd, &temp, sizeof(temp));
            lseek(teeFd, (off_t) 40, SEEK_SET);
            temp =  total * channelCount * sizeof(short);
            write(teeFd, &temp, sizeof(temp));
            close(teeFd);
            fdprintf(fd, "FastMixer tee copied to %s\n", teePath);
        } else {
            fdprintf(fd, "FastMixer unable to create tee %s: \n", strerror(errno));
        }
    }

    return NO_ERROR;
}

+3 −0
Original line number Diff line number Diff line
@@ -1111,6 +1111,9 @@ public:
        sp<NBAIO_Sink>          mPipeSink;
        // The current sink for the normal mixer to write it's (sub)mix, mOutputSink or mPipeSink
        sp<NBAIO_Sink>          mNormalSink;
        // For dumpsys
        sp<NBAIO_Sink>          mTeeSink;
        sp<NBAIO_Source>        mTeeSource;
    public:
        virtual     bool        hasFastMixer() const = 0;
        virtual     FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex) const
+5 −0
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ bool FastMixer::threadLoop()
    bool isWarm = false;    // true means ready to mix, false means wait for warmup before mixing
    struct timespec measuredWarmupTs = {0, 0};  // how long did it take for warmup to complete
    uint32_t warmupCycles = 0;  // counter of number of loop cycles required to warmup
    NBAIO_Sink* teeSink = NULL; // if non-NULL, then duplicate write() to this non-blocking sink

    for (;;) {

@@ -106,6 +107,7 @@ bool FastMixer::threadLoop()

            // As soon as possible of learning of a new dump area, start using it
            dumpState = next->mDumpState != NULL ? next->mDumpState : &dummyDumpState;
            teeSink = next->mTeeSink;

            // We want to always have a valid reference to the previous (non-idle) state.
            // However, the state queue only guarantees access to current and previous states.
@@ -398,6 +400,9 @@ bool FastMixer::threadLoop()
                memset(mixBuffer, 0, frameCount * 2 * sizeof(short));
                mixBufferState = ZEROED;
            }
            if (teeSink != NULL) {
                (void) teeSink->write(mixBuffer, frameCount);
            }
            // FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink,
            //       but this code should be modified to handle both non-blocking and blocking sinks
            dumpState->mWriteSequence++;
+2 −1
Original line number Diff line number Diff line
@@ -30,7 +30,8 @@ FastTrack::~FastTrack()

FastMixerState::FastMixerState() :
    mFastTracksGen(0), mTrackMask(0), mOutputSink(NULL), mOutputSinkGen(0),
    mFrameCount(0), mCommand(INITIAL), mColdFutexAddr(NULL), mColdGen(0), mDumpState(NULL)
    mFrameCount(0), mCommand(INITIAL), mColdFutexAddr(NULL), mColdGen(0),
    mDumpState(NULL), mTeeSink(NULL)
{
}

Loading