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 #include <audio_utils/fixedfft.h>
     31 
     32 namespace android {
     33 
     34 // ---------------------------------------------------------------------------
     35 
     36 Visualizer::Visualizer (int32_t priority,
     37          effect_callback_t cbf,
     38          void* user,
     39          int sessionId)
     40     :   AudioEffect(SL_IID_VISUALIZATION, NULL, priority, cbf, user, sessionId),
     41         mCaptureRate(CAPTURE_RATE_DEF),
     42         mCaptureSize(CAPTURE_SIZE_DEF),
     43         mSampleRate(44100000),
     44         mScalingMode(VISUALIZER_SCALING_MODE_NORMALIZED),
     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(mCaptureLock);
     58 
     59     sp<CaptureThread> t = mCaptureThread;
     60     if (t != 0) {
     61         if (enabled) {
     62             if (t->exitPending()) {
     63                 if (t->requestExitAndWait() == WOULD_BLOCK) {
     64                     ALOGE("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("Visualizer");
     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,
     92         uint32_t rate)
     93 {
     94     if (rate > CAPTURE_RATE_MAX) {
     95         return BAD_VALUE;
     96     }
     97     Mutex::Autolock _l(mCaptureLock);
     98 
     99     if (mEnabled) {
    100         return INVALID_OPERATION;
    101     }
    102 
    103     sp<CaptureThread> t = mCaptureThread;
    104     if (t != 0) {
    105         t->mLock.lock();
    106     }
    107     mCaptureThread.clear();
    108     mCaptureCallBack = cbk;
    109     mCaptureCbkUser = user;
    110     mCaptureFlags = flags;
    111     mCaptureRate = rate;
    112 
    113     if (t != 0) {
    114         t->mLock.unlock();
    115     }
    116 
    117     if (cbk != NULL) {
    118         mCaptureThread = new CaptureThread(*this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
    119     }
    120     ALOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
    121             rate, mCaptureThread.get(), mCaptureFlags);
    122     return NO_ERROR;
    123 }
    124 
    125 status_t Visualizer::setCaptureSize(uint32_t size)
    126 {
    127     if (size > VISUALIZER_CAPTURE_SIZE_MAX ||
    128         size < VISUALIZER_CAPTURE_SIZE_MIN ||
    129         popcount(size) != 1) {
    130         return BAD_VALUE;
    131     }
    132 
    133     Mutex::Autolock _l(mCaptureLock);
    134     if (mEnabled) {
    135         return INVALID_OPERATION;
    136     }
    137 
    138     uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
    139     effect_param_t *p = (effect_param_t *)buf32;
    140 
    141     p->psize = sizeof(uint32_t);
    142     p->vsize = sizeof(uint32_t);
    143     *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
    144     *((int32_t *)p->data + 1)= size;
    145     status_t status = setParameter(p);
    146 
    147     ALOGV("setCaptureSize size %d  status %d p->status %d", size, status, p->status);
    148 
    149     if (status == NO_ERROR) {
    150         status = p->status;
    151         if (status == NO_ERROR) {
    152             mCaptureSize = size;
    153         }
    154     }
    155 
    156     return status;
    157 }
    158 
    159 status_t Visualizer::setScalingMode(uint32_t mode) {
    160     if ((mode != VISUALIZER_SCALING_MODE_NORMALIZED)
    161             && (mode != VISUALIZER_SCALING_MODE_AS_PLAYED)) {
    162         return BAD_VALUE;
    163     }
    164 
    165     Mutex::Autolock _l(mCaptureLock);
    166 
    167     uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
    168     effect_param_t *p = (effect_param_t *)buf32;
    169 
    170     p->psize = sizeof(uint32_t);
    171     p->vsize = sizeof(uint32_t);
    172     *(int32_t *)p->data = VISUALIZER_PARAM_SCALING_MODE;
    173     *((int32_t *)p->data + 1)= mode;
    174     status_t status = setParameter(p);
    175 
    176     ALOGV("setScalingMode mode %d  status %d p->status %d", mode, status, p->status);
    177 
    178     if (status == NO_ERROR) {
    179         status = p->status;
    180         if (status == NO_ERROR) {
    181             mScalingMode = mode;
    182         }
    183     }
    184 
    185     return status;
    186 }
    187 
    188 status_t Visualizer::getWaveForm(uint8_t *waveform)
    189 {
    190     if (waveform == NULL) {
    191         return BAD_VALUE;
    192     }
    193     if (mCaptureSize == 0) {
    194         return NO_INIT;
    195     }
    196 
    197     status_t status = NO_ERROR;
    198     if (mEnabled) {
    199         uint32_t replySize = mCaptureSize;
    200         status = command(VISUALIZER_CMD_CAPTURE, 0, NULL, &replySize, waveform);
    201         ALOGV("getWaveForm() command returned %d", status);
    202         if ((status == NO_ERROR) && (replySize == 0)) {
    203             status = NOT_ENOUGH_DATA;
    204         }
    205     } else {
    206         ALOGV("getWaveForm() disabled");
    207         memset(waveform, 0x80, mCaptureSize);
    208     }
    209     return status;
    210 }
    211 
    212 status_t Visualizer::getFft(uint8_t *fft)
    213 {
    214     if (fft == NULL) {
    215         return BAD_VALUE;
    216     }
    217     if (mCaptureSize == 0) {
    218         return NO_INIT;
    219     }
    220 
    221     status_t status = NO_ERROR;
    222     if (mEnabled) {
    223         uint8_t buf[mCaptureSize];
    224         status = getWaveForm(buf);
    225         if (status == NO_ERROR) {
    226             status = doFft(fft, buf);
    227         }
    228     } else {
    229         memset(fft, 0, mCaptureSize);
    230     }
    231     return status;
    232 }
    233 
    234 status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
    235 {
    236     int32_t workspace[mCaptureSize >> 1];
    237     int32_t nonzero = 0;
    238 
    239     for (uint32_t i = 0; i < mCaptureSize; i += 2) {
    240         workspace[i >> 1] =
    241                 ((waveform[i] ^ 0x80) << 24) | ((waveform[i + 1] ^ 0x80) << 8);
    242         nonzero |= workspace[i >> 1];
    243     }
    244 
    245     if (nonzero) {
    246         fixed_fft_real(mCaptureSize >> 1, workspace);
    247     }
    248 
    249     for (uint32_t i = 0; i < mCaptureSize; i += 2) {
    250         short tmp = workspace[i >> 1] >> 21;
    251         while (tmp > 127 || tmp < -128) tmp >>= 1;
    252         fft[i] = tmp;
    253         tmp = workspace[i >> 1];
    254         tmp >>= 5;
    255         while (tmp > 127 || tmp < -128) tmp >>= 1;
    256         fft[i + 1] = tmp;
    257     }
    258 
    259     return NO_ERROR;
    260 }
    261 
    262 void Visualizer::periodicCapture()
    263 {
    264     Mutex::Autolock _l(mCaptureLock);
    265     ALOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x",
    266             this, mCaptureCallBack, mCaptureFlags);
    267     if (mCaptureCallBack != NULL &&
    268         (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) &&
    269         mCaptureSize != 0) {
    270         uint8_t waveform[mCaptureSize];
    271         status_t status = getWaveForm(waveform);
    272         if (status != NO_ERROR) {
    273             return;
    274         }
    275         uint8_t fft[mCaptureSize];
    276         if (mCaptureFlags & CAPTURE_FFT) {
    277             status = doFft(fft, waveform);
    278         }
    279         if (status != NO_ERROR) {
    280             return;
    281         }
    282         uint8_t *wavePtr = NULL;
    283         uint8_t *fftPtr = NULL;
    284         uint32_t waveSize = 0;
    285         uint32_t fftSize = 0;
    286         if (mCaptureFlags & CAPTURE_WAVEFORM) {
    287             wavePtr = waveform;
    288             waveSize = mCaptureSize;
    289         }
    290         if (mCaptureFlags & CAPTURE_FFT) {
    291             fftPtr = fft;
    292             fftSize = mCaptureSize;
    293         }
    294         mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate);
    295     }
    296 }
    297 
    298 uint32_t Visualizer::initCaptureSize()
    299 {
    300     uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
    301     effect_param_t *p = (effect_param_t *)buf32;
    302 
    303     p->psize = sizeof(uint32_t);
    304     p->vsize = sizeof(uint32_t);
    305     *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
    306     status_t status = getParameter(p);
    307 
    308     if (status == NO_ERROR) {
    309         status = p->status;
    310     }
    311 
    312     uint32_t size = 0;
    313     if (status == NO_ERROR) {
    314         size = *((int32_t *)p->data + 1);
    315     }
    316     mCaptureSize = size;
    317 
    318     ALOGV("initCaptureSize size %d status %d", mCaptureSize, status);
    319 
    320     return size;
    321 }
    322 
    323 void Visualizer::controlStatusChanged(bool controlGranted) {
    324     if (controlGranted) {
    325         // this Visualizer instance regained control of the effect, reset the scaling mode
    326         //   and capture size as has been cached through it.
    327         ALOGV("controlStatusChanged(true) causes effect parameter reset:");
    328         ALOGV("    scaling mode reset to %d", mScalingMode);
    329         setScalingMode(mScalingMode);
    330         ALOGV("    capture size reset to %d", mCaptureSize);
    331         setCaptureSize(mCaptureSize);
    332     }
    333     AudioEffect::controlStatusChanged(controlGranted);
    334 }
    335 
    336 //-------------------------------------------------------------------------
    337 
    338 Visualizer::CaptureThread::CaptureThread(Visualizer& receiver, uint32_t captureRate,
    339         bool bCanCallJava)
    340     : Thread(bCanCallJava), mReceiver(receiver)
    341 {
    342     mSleepTimeUs = 1000000000 / captureRate;
    343     ALOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs);
    344 }
    345 
    346 bool Visualizer::CaptureThread::threadLoop()
    347 {
    348     ALOGV("CaptureThread %p enter", this);
    349     while (!exitPending())
    350     {
    351         usleep(mSleepTimeUs);
    352         mReceiver.periodicCapture();
    353     }
    354     ALOGV("CaptureThread %p exiting", this);
    355     return false;
    356 }
    357 
    358 }; // namespace android
    359