Home | History | Annotate | Download | only in libmedia
      1 /*
      2 **
      3 ** Copyright 2010, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 
     19 //#define LOG_NDEBUG 0
     20 #define LOG_TAG "Visualizer"
     21 #include <utils/Log.h>
     22 
     23 #include <stdint.h>
     24 #include <sys/types.h>
     25 #include <limits.h>
     26 
     27 #include <media/Visualizer.h>
     28 
     29 extern void fixed_fft_real(int n, int32_t *v);
     30 
     31 namespace android {
     32 
     33 // ---------------------------------------------------------------------------
     34 
     35 Visualizer::Visualizer (int32_t priority,
     36          effect_callback_t cbf,
     37          void* user,
     38          int sessionId)
     39     :   AudioEffect(SL_IID_VISUALIZATION, NULL, priority, cbf, user, sessionId),
     40         mCaptureRate(CAPTURE_RATE_DEF),
     41         mCaptureSize(CAPTURE_SIZE_DEF),
     42         mSampleRate(44100000),
     43         mCaptureCallBack(NULL),
     44         mCaptureCbkUser(NULL)
     45 {
     46     initCaptureSize();
     47 }
     48 
     49 Visualizer::~Visualizer()
     50 {
     51 }
     52 
     53 status_t Visualizer::setEnabled(bool enabled)
     54 {
     55     Mutex::Autolock _l(mLock);
     56 
     57     sp<CaptureThread> t = mCaptureThread;
     58     if (t != 0) {
     59         if (enabled) {
     60             if (t->exitPending()) {
     61                 if (t->requestExitAndWait() == WOULD_BLOCK) {
     62                     LOGE("Visualizer::enable() called from thread");
     63                     return INVALID_OPERATION;
     64                 }
     65             }
     66         }
     67         t->mLock.lock();
     68      }
     69 
     70     status_t status = AudioEffect::setEnabled(enabled);
     71 
     72     if (status == NO_ERROR) {
     73         if (t != 0) {
     74             if (enabled) {
     75                 t->run("AudioTrackThread");
     76             } else {
     77                 t->requestExit();
     78             }
     79         }
     80     }
     81 
     82     if (t != 0) {
     83         t->mLock.unlock();
     84     }
     85 
     86     return status;
     87 }
     88 
     89 status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate)
     90 {
     91     if (rate > CAPTURE_RATE_MAX) {
     92         return BAD_VALUE;
     93     }
     94     Mutex::Autolock _l(mLock);
     95 
     96     if (mEnabled) {
     97         return INVALID_OPERATION;
     98     }
     99 
    100     sp<CaptureThread> t = mCaptureThread;
    101     if (t != 0) {
    102         t->mLock.lock();
    103     }
    104     mCaptureThread.clear();
    105     mCaptureCallBack = cbk;
    106     mCaptureCbkUser = user;
    107     mCaptureFlags = flags;
    108     mCaptureRate = rate;
    109 
    110     if (t != 0) {
    111         t->mLock.unlock();
    112     }
    113 
    114     if (cbk != NULL) {
    115         mCaptureThread = new CaptureThread(*this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
    116         if (mCaptureThread == 0) {
    117             LOGE("Could not create callback thread");
    118             return NO_INIT;
    119         }
    120     }
    121     LOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
    122             rate, mCaptureThread.get(), mCaptureFlags);
    123     return NO_ERROR;
    124 }
    125 
    126 status_t Visualizer::setCaptureSize(uint32_t size)
    127 {
    128     if (size > VISUALIZER_CAPTURE_SIZE_MAX ||
    129         size < VISUALIZER_CAPTURE_SIZE_MIN ||
    130         AudioSystem::popCount(size) != 1) {
    131         return BAD_VALUE;
    132     }
    133 
    134     Mutex::Autolock _l(mLock);
    135     if (mEnabled) {
    136         return INVALID_OPERATION;
    137     }
    138 
    139     uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
    140     effect_param_t *p = (effect_param_t *)buf32;
    141 
    142     p->psize = sizeof(uint32_t);
    143     p->vsize = sizeof(uint32_t);
    144     *(int32_t *)p->data = VISU_PARAM_CAPTURE_SIZE;
    145     *((int32_t *)p->data + 1)= size;
    146     status_t status = setParameter(p);
    147 
    148     LOGV("setCaptureSize size %d  status %d p->status %d", size, status, p->status);
    149 
    150     if (status == NO_ERROR) {
    151         status = p->status;
    152     }
    153     if (status == NO_ERROR) {
    154         mCaptureSize = size;
    155     }
    156 
    157     return status;
    158 }
    159 
    160 status_t Visualizer::getWaveForm(uint8_t *waveform)
    161 {
    162     if (waveform == NULL) {
    163         return BAD_VALUE;
    164     }
    165     if (mCaptureSize == 0) {
    166         return NO_INIT;
    167     }
    168 
    169     status_t status = NO_ERROR;
    170     if (mEnabled) {
    171         uint32_t replySize = mCaptureSize;
    172         status = command(VISU_CMD_CAPTURE, 0, NULL, &replySize, waveform);
    173         LOGV("getWaveForm() command returned %d", status);
    174         if (replySize == 0) {
    175             status = NOT_ENOUGH_DATA;
    176         }
    177     } else {
    178         LOGV("getWaveForm() disabled");
    179         memset(waveform, 0x80, mCaptureSize);
    180     }
    181     return status;
    182 }
    183 
    184 status_t Visualizer::getFft(uint8_t *fft)
    185 {
    186     if (fft == NULL) {
    187         return BAD_VALUE;
    188     }
    189     if (mCaptureSize == 0) {
    190         return NO_INIT;
    191     }
    192 
    193     status_t status = NO_ERROR;
    194     if (mEnabled) {
    195         uint8_t buf[mCaptureSize];
    196         status = getWaveForm(buf);
    197         if (status == NO_ERROR) {
    198             status = doFft(fft, buf);
    199         }
    200     } else {
    201         memset(fft, 0, mCaptureSize);
    202     }
    203     return status;
    204 }
    205 
    206 status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
    207 {
    208     int32_t workspace[mCaptureSize >> 1];
    209     int32_t nonzero = 0;
    210 
    211     for (uint32_t i = 0; i < mCaptureSize; i += 2) {
    212         workspace[i >> 1] = (waveform[i] ^ 0x80) << 23;
    213         workspace[i >> 1] |= (waveform[i + 1] ^ 0x80) << 7;
    214         nonzero |= workspace[i >> 1];
    215     }
    216 
    217     if (nonzero) {
    218         fixed_fft_real(mCaptureSize >> 1, workspace);
    219     }
    220 
    221     for (uint32_t i = 0; i < mCaptureSize; i += 2) {
    222         fft[i] = workspace[i >> 1] >> 23;
    223         fft[i + 1] = workspace[i >> 1] >> 7;
    224     }
    225 
    226     return NO_ERROR;
    227 }
    228 
    229 void Visualizer::periodicCapture()
    230 {
    231     Mutex::Autolock _l(mLock);
    232     LOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x",
    233             this, mCaptureCallBack, mCaptureFlags);
    234     if (mCaptureCallBack != NULL &&
    235         (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) &&
    236         mCaptureSize != 0) {
    237         uint8_t waveform[mCaptureSize];
    238         status_t status = getWaveForm(waveform);
    239         if (status != NO_ERROR) {
    240             return;
    241         }
    242         uint8_t fft[mCaptureSize];
    243         if (mCaptureFlags & CAPTURE_FFT) {
    244             status = doFft(fft, waveform);
    245         }
    246         if (status != NO_ERROR) {
    247             return;
    248         }
    249         uint8_t *wavePtr = NULL;
    250         uint8_t *fftPtr = NULL;
    251         uint32_t waveSize = 0;
    252         uint32_t fftSize = 0;
    253         if (mCaptureFlags & CAPTURE_WAVEFORM) {
    254             wavePtr = waveform;
    255             waveSize = mCaptureSize;
    256         }
    257         if (mCaptureFlags & CAPTURE_FFT) {
    258             fftPtr = fft;
    259             fftSize = mCaptureSize;
    260         }
    261         mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate);
    262     }
    263 }
    264 
    265 uint32_t Visualizer::initCaptureSize()
    266 {
    267     uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
    268     effect_param_t *p = (effect_param_t *)buf32;
    269 
    270     p->psize = sizeof(uint32_t);
    271     p->vsize = sizeof(uint32_t);
    272     *(int32_t *)p->data = VISU_PARAM_CAPTURE_SIZE;
    273     status_t status = getParameter(p);
    274 
    275     if (status == NO_ERROR) {
    276         status = p->status;
    277     }
    278 
    279     uint32_t size = 0;
    280     if (status == NO_ERROR) {
    281         size = *((int32_t *)p->data + 1);
    282     }
    283     mCaptureSize = size;
    284 
    285     LOGV("initCaptureSize size %d status %d", mCaptureSize, status);
    286 
    287     return size;
    288 }
    289 
    290 //-------------------------------------------------------------------------
    291 
    292 Visualizer::CaptureThread::CaptureThread(Visualizer& receiver, uint32_t captureRate, bool bCanCallJava)
    293     : Thread(bCanCallJava), mReceiver(receiver)
    294 {
    295     mSleepTimeUs = 1000000000 / captureRate;
    296     LOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs);
    297 }
    298 
    299 bool Visualizer::CaptureThread::threadLoop()
    300 {
    301     LOGV("CaptureThread %p enter", this);
    302     while (!exitPending())
    303     {
    304         usleep(mSleepTimeUs);
    305         mReceiver.periodicCapture();
    306     }
    307     LOGV("CaptureThread %p exiting", this);
    308     return false;
    309 }
    310 
    311 status_t Visualizer::CaptureThread::readyToRun()
    312 {
    313     return NO_ERROR;
    314 }
    315 
    316 void Visualizer::CaptureThread::onFirstRef()
    317 {
    318 }
    319 
    320 }; // namespace android
    321 
    322