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 <cutils/bitops.h>
     28 
     29 #include <media/Visualizer.h>
     30 
     31 extern void fixed_fft_real(int n, int32_t *v);
     32 
     33 namespace android {
     34 
     35 // ---------------------------------------------------------------------------
     36 
     37 Visualizer::Visualizer (int32_t priority,
     38          effect_callback_t cbf,
     39          void* user,
     40          int sessionId)
     41     :   AudioEffect(SL_IID_VISUALIZATION, NULL, priority, cbf, user, sessionId),
     42         mCaptureRate(CAPTURE_RATE_DEF),
     43         mCaptureSize(CAPTURE_SIZE_DEF),
     44         mSampleRate(44100000),
     45         mCaptureCallBack(NULL),
     46         mCaptureCbkUser(NULL)
     47 {
     48     initCaptureSize();
     49 }
     50 
     51 Visualizer::~Visualizer()
     52 {
     53 }
     54 
     55 status_t Visualizer::setEnabled(bool enabled)
     56 {
     57     Mutex::Autolock _l(mLock);
     58 
     59     sp<CaptureThread> t = mCaptureThread;
     60     if (t != 0) {
     61         if (enabled) {
     62             if (t->exitPending()) {
     63                 if (t->requestExitAndWait() == WOULD_BLOCK) {
     64                     LOGE("Visualizer::enable() called from thread");
     65                     return INVALID_OPERATION;
     66                 }
     67             }
     68         }
     69         t->mLock.lock();
     70      }
     71 
     72     status_t status = AudioEffect::setEnabled(enabled);
     73 
     74     if (status == NO_ERROR) {
     75         if (t != 0) {
     76             if (enabled) {
     77                 t->run("AudioTrackThread");
     78             } else {
     79                 t->requestExit();
     80             }
     81         }
     82     }
     83 
     84     if (t != 0) {
     85         t->mLock.unlock();
     86     }
     87 
     88     return status;
     89 }
     90 
     91 status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate)
     92 {
     93     if (rate > CAPTURE_RATE_MAX) {
     94         return BAD_VALUE;
     95     }
     96     Mutex::Autolock _l(mLock);
     97 
     98     if (mEnabled) {
     99         return INVALID_OPERATION;
    100     }
    101 
    102     sp<CaptureThread> t = mCaptureThread;
    103     if (t != 0) {
    104         t->mLock.lock();
    105     }
    106     mCaptureThread.clear();
    107     mCaptureCallBack = cbk;
    108     mCaptureCbkUser = user;
    109     mCaptureFlags = flags;
    110     mCaptureRate = rate;
    111 
    112     if (t != 0) {
    113         t->mLock.unlock();
    114     }
    115 
    116     if (cbk != NULL) {
    117         mCaptureThread = new CaptureThread(*this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
    118         if (mCaptureThread == 0) {
    119             LOGE("Could not create callback thread");
    120             return NO_INIT;
    121         }
    122     }
    123     LOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
    124             rate, mCaptureThread.get(), mCaptureFlags);
    125     return NO_ERROR;
    126 }
    127 
    128 status_t Visualizer::setCaptureSize(uint32_t size)
    129 {
    130     if (size > VISUALIZER_CAPTURE_SIZE_MAX ||
    131         size < VISUALIZER_CAPTURE_SIZE_MIN ||
    132         popcount(size) != 1) {
    133         return BAD_VALUE;
    134     }
    135 
    136     Mutex::Autolock _l(mLock);
    137     if (mEnabled) {
    138         return INVALID_OPERATION;
    139     }
    140 
    141     uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
    142     effect_param_t *p = (effect_param_t *)buf32;
    143 
    144     p->psize = sizeof(uint32_t);
    145     p->vsize = sizeof(uint32_t);
    146     *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
    147     *((int32_t *)p->data + 1)= size;
    148     status_t status = setParameter(p);
    149 
    150     LOGV("setCaptureSize size %d  status %d p->status %d", size, status, p->status);
    151 
    152     if (status == NO_ERROR) {
    153         status = p->status;
    154     }
    155     if (status == NO_ERROR) {
    156         mCaptureSize = size;
    157     }
    158 
    159     return status;
    160 }
    161 
    162 status_t Visualizer::getWaveForm(uint8_t *waveform)
    163 {
    164     if (waveform == NULL) {
    165         return BAD_VALUE;
    166     }
    167     if (mCaptureSize == 0) {
    168         return NO_INIT;
    169     }
    170 
    171     status_t status = NO_ERROR;
    172     if (mEnabled) {
    173         uint32_t replySize = mCaptureSize;
    174         status = command(VISUALIZER_CMD_CAPTURE, 0, NULL, &replySize, waveform);
    175         LOGV("getWaveForm() command returned %d", status);
    176         if (replySize == 0) {
    177             status = NOT_ENOUGH_DATA;
    178         }
    179     } else {
    180         LOGV("getWaveForm() disabled");
    181         memset(waveform, 0x80, mCaptureSize);
    182     }
    183     return status;
    184 }
    185 
    186 status_t Visualizer::getFft(uint8_t *fft)
    187 {
    188     if (fft == NULL) {
    189         return BAD_VALUE;
    190     }
    191     if (mCaptureSize == 0) {
    192         return NO_INIT;
    193     }
    194 
    195     status_t status = NO_ERROR;
    196     if (mEnabled) {
    197         uint8_t buf[mCaptureSize];
    198         status = getWaveForm(buf);
    199         if (status == NO_ERROR) {
    200             status = doFft(fft, buf);
    201         }
    202     } else {
    203         memset(fft, 0, mCaptureSize);
    204     }
    205     return status;
    206 }
    207 
    208 status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
    209 {
    210     int32_t workspace[mCaptureSize >> 1];
    211     int32_t nonzero = 0;
    212 
    213     for (uint32_t i = 0; i < mCaptureSize; i += 2) {
    214         workspace[i >> 1] =
    215                 ((waveform[i] ^ 0x80) << 24) | ((waveform[i + 1] ^ 0x80) << 8);
    216         nonzero |= workspace[i >> 1];
    217     }
    218 
    219     if (nonzero) {
    220         fixed_fft_real(mCaptureSize >> 1, workspace);
    221     }
    222 
    223     for (uint32_t i = 0; i < mCaptureSize; i += 2) {
    224         short tmp = workspace[i >> 1] >> 21;
    225         while (tmp > 127 || tmp < -128) tmp >>= 1;
    226         fft[i] = tmp;
    227         tmp = workspace[i >> 1];
    228         tmp >>= 5;
    229         while (tmp > 127 || tmp < -128) tmp >>= 1;
    230         fft[i + 1] = tmp;
    231     }
    232 
    233     return NO_ERROR;
    234 }
    235 
    236 void Visualizer::periodicCapture()
    237 {
    238     Mutex::Autolock _l(mLock);
    239     LOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x",
    240             this, mCaptureCallBack, mCaptureFlags);
    241     if (mCaptureCallBack != NULL &&
    242         (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) &&
    243         mCaptureSize != 0) {
    244         uint8_t waveform[mCaptureSize];
    245         status_t status = getWaveForm(waveform);
    246         if (status != NO_ERROR) {
    247             return;
    248         }
    249         uint8_t fft[mCaptureSize];
    250         if (mCaptureFlags & CAPTURE_FFT) {
    251             status = doFft(fft, waveform);
    252         }
    253         if (status != NO_ERROR) {
    254             return;
    255         }
    256         uint8_t *wavePtr = NULL;
    257         uint8_t *fftPtr = NULL;
    258         uint32_t waveSize = 0;
    259         uint32_t fftSize = 0;
    260         if (mCaptureFlags & CAPTURE_WAVEFORM) {
    261             wavePtr = waveform;
    262             waveSize = mCaptureSize;
    263         }
    264         if (mCaptureFlags & CAPTURE_FFT) {
    265             fftPtr = fft;
    266             fftSize = mCaptureSize;
    267         }
    268         mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate);
    269     }
    270 }
    271 
    272 uint32_t Visualizer::initCaptureSize()
    273 {
    274     uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
    275     effect_param_t *p = (effect_param_t *)buf32;
    276 
    277     p->psize = sizeof(uint32_t);
    278     p->vsize = sizeof(uint32_t);
    279     *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
    280     status_t status = getParameter(p);
    281 
    282     if (status == NO_ERROR) {
    283         status = p->status;
    284     }
    285 
    286     uint32_t size = 0;
    287     if (status == NO_ERROR) {
    288         size = *((int32_t *)p->data + 1);
    289     }
    290     mCaptureSize = size;
    291 
    292     LOGV("initCaptureSize size %d status %d", mCaptureSize, status);
    293 
    294     return size;
    295 }
    296 
    297 //-------------------------------------------------------------------------
    298 
    299 Visualizer::CaptureThread::CaptureThread(Visualizer& receiver, uint32_t captureRate, bool bCanCallJava)
    300     : Thread(bCanCallJava), mReceiver(receiver)
    301 {
    302     mSleepTimeUs = 1000000000 / captureRate;
    303     LOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs);
    304 }
    305 
    306 bool Visualizer::CaptureThread::threadLoop()
    307 {
    308     LOGV("CaptureThread %p enter", this);
    309     while (!exitPending())
    310     {
    311         usleep(mSleepTimeUs);
    312         mReceiver.periodicCapture();
    313     }
    314     LOGV("CaptureThread %p exiting", this);
    315     return false;
    316 }
    317 
    318 status_t Visualizer::CaptureThread::readyToRun()
    319 {
    320     return NO_ERROR;
    321 }
    322 
    323 void Visualizer::CaptureThread::onFirstRef()
    324 {
    325 }
    326 
    327 }; // namespace android
    328 
    329