diff options
Diffstat (limited to 'media/libmedia/Visualizer.cpp')
| -rw-r--r-- | media/libmedia/Visualizer.cpp | 319 | 
1 files changed, 319 insertions, 0 deletions
| diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp new file mode 100644 index 000000000000..39552b64a85c --- /dev/null +++ b/media/libmedia/Visualizer.cpp @@ -0,0 +1,319 @@ +/* +** +** Copyright 2010, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +**     http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + + +//#define LOG_NDEBUG 0 +#define LOG_TAG "Visualizer" +#include <utils/Log.h> + +#include <stdint.h> +#include <sys/types.h> +#include <limits.h> + +#include <media/Visualizer.h> + +extern void fixed_fft_real(int n, int32_t *v); + +namespace android { + +// --------------------------------------------------------------------------- + +Visualizer::Visualizer (int32_t priority, +         effect_callback_t cbf, +         void* user, +         int sessionId) +    :   AudioEffect(SL_IID_VISUALIZATION, NULL, priority, cbf, user, sessionId), +        mCaptureRate(CAPTURE_RATE_DEF), +        mCaptureSize(CAPTURE_SIZE_DEF), +        mSampleRate(44100000), +        mCaptureCallBack(NULL), +        mCaptureCbkUser(NULL) +{ +    initCaptureSize(); +} + +Visualizer::~Visualizer() +{ +} + +status_t Visualizer::setEnabled(bool enabled) +{ +    Mutex::Autolock _l(mLock); + +    sp<CaptureThread> t = mCaptureThread; +    if (t != 0) { +        if (enabled) { +            if (t->exitPending()) { +                if (t->requestExitAndWait() == WOULD_BLOCK) { +                    LOGE("Visualizer::enable() called from thread"); +                    return INVALID_OPERATION; +                } +            } +        } +        t->mLock.lock(); +     } + +    status_t status = AudioEffect::setEnabled(enabled); + +    if (status == NO_ERROR) { +        if (t != 0) { +            if (enabled) { +                t->run("AudioTrackThread"); +            } else { +                t->requestExit(); +            } +        } +    } + +    if (t != 0) { +        t->mLock.unlock(); +    } + +    return status; +} + +status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate) +{ +    if (rate > CAPTURE_RATE_MAX) { +        return BAD_VALUE; +    } +    Mutex::Autolock _l(mLock); + +    if (mEnabled) { +        return INVALID_OPERATION; +    } + +    sp<CaptureThread> t = mCaptureThread; +    if (t != 0) { +        t->mLock.lock(); +    } +    mCaptureThread.clear(); +    mCaptureCallBack = cbk; +    mCaptureCbkUser = user; +    mCaptureFlags = flags; +    mCaptureRate = rate; + +    if (t != 0) { +        t->mLock.unlock(); +    } + +    if (cbk != NULL) { +        mCaptureThread = new CaptureThread(*this, rate, ((flags & CAPTURE_CALL_JAVA) != 0)); +        if (mCaptureThread == 0) { +            LOGE("Could not create callback thread"); +            return NO_INIT; +        } +    } +    LOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x", +            rate, mCaptureThread.get(), mCaptureFlags); +    return NO_ERROR; +} + +status_t Visualizer::setCaptureSize(uint32_t size) +{ +    if (size > VISUALIZER_CAPTURE_SIZE_MAX || +        size < VISUALIZER_CAPTURE_SIZE_MIN || +        AudioSystem::popCount(size) != 1) { +        return BAD_VALUE; +    } + +    Mutex::Autolock _l(mLock); +    if (mEnabled) { +        return INVALID_OPERATION; +    } + +    uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2]; +    effect_param_t *p = (effect_param_t *)buf32; + +    p->psize = sizeof(uint32_t); +    p->vsize = sizeof(uint32_t); +    *(int32_t *)p->data = VISU_PARAM_CAPTURE_SIZE; +    *((int32_t *)p->data + 1)= size; +    status_t status = setParameter(p); + +    LOGV("setCaptureSize size %d  status %d p->status %d", size, status, p->status); + +    if (status == NO_ERROR) { +        status = p->status; +    } +    if (status == NO_ERROR) { +        mCaptureSize = size; +    } + +    return status; +} + +status_t Visualizer::getWaveForm(uint8_t *waveform) +{ +    if (waveform == NULL) { +        return BAD_VALUE; +    } +    if (mCaptureSize == 0) { +        return NO_INIT; +    } + +    status_t status = NO_ERROR; +    if (mEnabled) { +        uint32_t replySize = mCaptureSize; +        status_t status = command(VISU_CMD_CAPTURE, 0, NULL, &replySize, waveform); +        if (replySize == 0) { +            status = NOT_ENOUGH_DATA; +        } +    } else { +        memset(waveform, 0x80, mCaptureSize); +    } +    return status; +} + +status_t Visualizer::getFft(uint8_t *fft) +{ +    if (fft == NULL) { +        return BAD_VALUE; +    } +    if (mCaptureSize == 0) { +        return NO_INIT; +    } + +    status_t status = NO_ERROR; +    if (mEnabled) { +        uint8_t buf[mCaptureSize]; +        status_t status = getWaveForm(buf); +        if (status == NO_ERROR) { +            status = doFft(fft, buf); +        } +    } else { +        memset(fft, 0, mCaptureSize); +    } +    return status; +} + +status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform) +{ +    int32_t workspace[mCaptureSize >> 1]; +    int32_t nonzero = 0; + +    for (uint32_t i = 0; i < mCaptureSize; i += 2) { +        workspace[i >> 1] = (waveform[i] ^ 0x80) << 23; +        workspace[i >> 1] |= (waveform[i + 1] ^ 0x80) << 7; +        nonzero |= workspace[i >> 1]; +    } + +    if (nonzero) { +        fixed_fft_real(mCaptureSize >> 1, workspace); +    } + +    for (uint32_t i = 0; i < mCaptureSize; i += 2) { +        fft[i] = workspace[i >> 1] >> 23; +        fft[i + 1] = workspace[i >> 1] >> 7; +    } + +    return NO_ERROR; +} + +void Visualizer::periodicCapture() +{ +    Mutex::Autolock _l(mLock); +    LOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x", +            this, mCaptureCallBack, mCaptureFlags); +    if (mCaptureCallBack != NULL && +        (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) && +        mCaptureSize != 0) { +        uint8_t waveform[mCaptureSize]; +        status_t status = getWaveForm(waveform); +        if (status != NO_ERROR) { +            return; +        } +        uint8_t fft[mCaptureSize]; +        if (mCaptureFlags & CAPTURE_FFT) { +            status = doFft(fft, waveform); +        } +        if (status != NO_ERROR) { +            return; +        } +        uint8_t *wavePtr = NULL; +        uint8_t *fftPtr = NULL; +        uint32_t waveSize = 0; +        uint32_t fftSize = 0; +        if (mCaptureFlags & CAPTURE_WAVEFORM) { +            wavePtr = waveform; +            waveSize = mCaptureSize; +        } +        if (mCaptureFlags & CAPTURE_FFT) { +            fftPtr = fft; +            fftSize = mCaptureSize; +        } +        mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate); +    } +} + +uint32_t Visualizer::initCaptureSize() +{ +    uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2]; +    effect_param_t *p = (effect_param_t *)buf32; + +    p->psize = sizeof(uint32_t); +    p->vsize = sizeof(uint32_t); +    *(int32_t *)p->data = VISU_PARAM_CAPTURE_SIZE; +    status_t status = getParameter(p); + +    if (status == NO_ERROR) { +        status = p->status; +    } + +    uint32_t size = 0; +    if (status == NO_ERROR) { +        size = *((int32_t *)p->data + 1); +    } +    mCaptureSize = size; + +    LOGV("initCaptureSize size %d status %d", mCaptureSize, status); + +    return size; +} + +//------------------------------------------------------------------------- + +Visualizer::CaptureThread::CaptureThread(Visualizer& receiver, uint32_t captureRate, bool bCanCallJava) +    : Thread(bCanCallJava), mReceiver(receiver) +{ +    mSleepTimeUs = 1000000000 / captureRate; +    LOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs); +} + +bool Visualizer::CaptureThread::threadLoop() +{ +    LOGV("CaptureThread %p enter", this); +    while (!exitPending()) +    { +        usleep(mSleepTimeUs); +        mReceiver.periodicCapture(); +    } +    LOGV("CaptureThread %p exiting", this); +    return false; +} + +status_t Visualizer::CaptureThread::readyToRun() +{ +    return NO_ERROR; +} + +void Visualizer::CaptureThread::onFirstRef() +{ +} + +}; // namespace android + | 
