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 #include <utils/Thread.h>
     32 
     33 namespace android {
     34 
     35 // ---------------------------------------------------------------------------
     36 
     37 Visualizer::Visualizer (const String16& opPackageName,
     38          int32_t priority,
     39          effect_callback_t cbf,
     40          void* user,
     41          int sessionId)
     42     :   AudioEffect(SL_IID_VISUALIZATION, opPackageName, NULL, priority, cbf, user, sessionId),
     43         mCaptureRate(CAPTURE_RATE_DEF),
     44         mCaptureSize(CAPTURE_SIZE_DEF),
     45         mSampleRate(44100000),
     46         mScalingMode(VISUALIZER_SCALING_MODE_NORMALIZED),
     47         mMeasurementMode(MEASUREMENT_MODE_NONE),
     48         mCaptureCallBack(NULL),
     49         mCaptureCbkUser(NULL)
     50 {
     51     initCaptureSize();
     52 }
     53 
     54 Visualizer::~Visualizer()
     55 {
     56     ALOGV("Visualizer::~Visualizer()");
     57     setEnabled(false);
     58     setCaptureCallBack(NULL, NULL, 0, 0, true);
     59 }
     60 
     61 status_t Visualizer::setEnabled(bool enabled)
     62 {
     63     Mutex::Autolock _l(mCaptureLock);
     64 
     65     sp<CaptureThread> t = mCaptureThread;
     66     if (t != 0) {
     67         if (enabled) {
     68             if (t->exitPending()) {
     69                 if (t->requestExitAndWait() == WOULD_BLOCK) {
     70                     ALOGE("Visualizer::enable() called from thread");
     71                     return INVALID_OPERATION;
     72                 }
     73             }
     74         }
     75         t->mLock.lock();
     76     }
     77 
     78     status_t status = AudioEffect::setEnabled(enabled);
     79 
     80     if (status == NO_ERROR) {
     81         if (t != 0) {
     82             if (enabled) {
     83                 t->run("Visualizer");
     84             } else {
     85                 t->requestExit();
     86             }
     87         }
     88     }
     89 
     90     if (t != 0) {
     91         t->mLock.unlock();
     92     }
     93 
     94     return status;
     95 }
     96 
     97 status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags,
     98         uint32_t rate, bool force)
     99 {
    100     if (rate > CAPTURE_RATE_MAX) {
    101         return BAD_VALUE;
    102     }
    103     Mutex::Autolock _l(mCaptureLock);
    104 
    105     if (force || mEnabled) {
    106         return INVALID_OPERATION;
    107     }
    108 
    109     if (mCaptureThread != 0) {
    110         mCaptureLock.unlock();
    111         mCaptureThread->requestExitAndWait();
    112         mCaptureLock.lock();
    113     }
    114 
    115     mCaptureThread.clear();
    116     mCaptureCallBack = cbk;
    117     mCaptureCbkUser = user;
    118     mCaptureFlags = flags;
    119     mCaptureRate = rate;
    120 
    121     if (cbk != NULL) {
    122         mCaptureThread = new CaptureThread(*this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
    123     }
    124     ALOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
    125             rate, mCaptureThread.get(), mCaptureFlags);
    126     return NO_ERROR;
    127 }
    128 
    129 status_t Visualizer::setCaptureSize(uint32_t size)
    130 {
    131     if (size > VISUALIZER_CAPTURE_SIZE_MAX ||
    132         size < VISUALIZER_CAPTURE_SIZE_MIN ||
    133         popcount(size) != 1) {
    134         return BAD_VALUE;
    135     }
    136 
    137     Mutex::Autolock _l(mCaptureLock);
    138     if (mEnabled) {
    139         return INVALID_OPERATION;
    140     }
    141 
    142     uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
    143     effect_param_t *p = (effect_param_t *)buf32;
    144 
    145     p->psize = sizeof(uint32_t);
    146     p->vsize = sizeof(uint32_t);
    147     *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
    148     *((int32_t *)p->data + 1)= size;
    149     status_t status = setParameter(p);
    150 
    151     ALOGV("setCaptureSize size %d  status %d p->status %d", size, status, p->status);
    152 
    153     if (status == NO_ERROR) {
    154         status = p->status;
    155         if (status == NO_ERROR) {
    156             mCaptureSize = size;
    157         }
    158     }
    159 
    160     return status;
    161 }
    162 
    163 status_t Visualizer::setScalingMode(uint32_t mode) {
    164     if ((mode != VISUALIZER_SCALING_MODE_NORMALIZED)
    165             && (mode != VISUALIZER_SCALING_MODE_AS_PLAYED)) {
    166         return BAD_VALUE;
    167     }
    168 
    169     Mutex::Autolock _l(mCaptureLock);
    170 
    171     uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
    172     effect_param_t *p = (effect_param_t *)buf32;
    173 
    174     p->psize = sizeof(uint32_t);
    175     p->vsize = sizeof(uint32_t);
    176     *(int32_t *)p->data = VISUALIZER_PARAM_SCALING_MODE;
    177     *((int32_t *)p->data + 1)= mode;
    178     status_t status = setParameter(p);
    179 
    180     ALOGV("setScalingMode mode %d  status %d p->status %d", mode, status, p->status);
    181 
    182     if (status == NO_ERROR) {
    183         status = p->status;
    184         if (status == NO_ERROR) {
    185             mScalingMode = mode;
    186         }
    187     }
    188 
    189     return status;
    190 }
    191 
    192 status_t Visualizer::setMeasurementMode(uint32_t mode) {
    193     if ((mode != MEASUREMENT_MODE_NONE)
    194             //Note: needs to be handled as a mask when more measurement modes are added
    195             && ((mode & MEASUREMENT_MODE_PEAK_RMS) != mode)) {
    196         return BAD_VALUE;
    197     }
    198 
    199     Mutex::Autolock _l(mCaptureLock);
    200 
    201     uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
    202     effect_param_t *p = (effect_param_t *)buf32;
    203 
    204     p->psize = sizeof(uint32_t);
    205     p->vsize = sizeof(uint32_t);
    206     *(int32_t *)p->data = VISUALIZER_PARAM_MEASUREMENT_MODE;
    207     *((int32_t *)p->data + 1)= mode;
    208     status_t status = setParameter(p);
    209 
    210     ALOGV("setMeasurementMode mode %d  status %d p->status %d", mode, status, p->status);
    211 
    212     if (status == NO_ERROR) {
    213         status = p->status;
    214         if (status == NO_ERROR) {
    215             mMeasurementMode = mode;
    216         }
    217     }
    218     return status;
    219 }
    220 
    221 status_t Visualizer::getIntMeasurements(uint32_t type, uint32_t number, int32_t *measurements) {
    222     if (mMeasurementMode == MEASUREMENT_MODE_NONE) {
    223         ALOGE("Cannot retrieve int measurements, no measurement mode set");
    224         return INVALID_OPERATION;
    225     }
    226     if (!(mMeasurementMode & type)) {
    227         // measurement type has not been set on this Visualizer
    228         ALOGE("Cannot retrieve int measurements, requested measurement mode 0x%x not set(0x%x)",
    229                 type, mMeasurementMode);
    230         return INVALID_OPERATION;
    231     }
    232     // only peak+RMS measurement supported
    233     if ((type != MEASUREMENT_MODE_PEAK_RMS)
    234             // for peak+RMS measurement, the results are 2 int32_t values
    235             || (number != 2)) {
    236         ALOGE("Cannot retrieve int measurements, MEASUREMENT_MODE_PEAK_RMS returns 2 ints, not %d",
    237                         number);
    238         return BAD_VALUE;
    239     }
    240 
    241     status_t status = NO_ERROR;
    242     if (mEnabled) {
    243         uint32_t replySize = number * sizeof(int32_t);
    244         status = command(VISUALIZER_CMD_MEASURE,
    245                 sizeof(uint32_t)  /*cmdSize*/,
    246                 &type /*cmdData*/,
    247                 &replySize, measurements);
    248         ALOGV("getMeasurements() command returned %d", status);
    249         if ((status == NO_ERROR) && (replySize == 0)) {
    250             status = NOT_ENOUGH_DATA;
    251         }
    252     } else {
    253         ALOGV("getMeasurements() disabled");
    254         return INVALID_OPERATION;
    255     }
    256     return status;
    257 }
    258 
    259 status_t Visualizer::getWaveForm(uint8_t *waveform)
    260 {
    261     if (waveform == NULL) {
    262         return BAD_VALUE;
    263     }
    264     if (mCaptureSize == 0) {
    265         return NO_INIT;
    266     }
    267 
    268     status_t status = NO_ERROR;
    269     if (mEnabled) {
    270         uint32_t replySize = mCaptureSize;
    271         status = command(VISUALIZER_CMD_CAPTURE, 0, NULL, &replySize, waveform);
    272         ALOGV("getWaveForm() command returned %d", status);
    273         if ((status == NO_ERROR) && (replySize == 0)) {
    274             status = NOT_ENOUGH_DATA;
    275         }
    276     } else {
    277         ALOGV("getWaveForm() disabled");
    278         memset(waveform, 0x80, mCaptureSize);
    279     }
    280     return status;
    281 }
    282 
    283 status_t Visualizer::getFft(uint8_t *fft)
    284 {
    285     if (fft == NULL) {
    286         return BAD_VALUE;
    287     }
    288     if (mCaptureSize == 0) {
    289         return NO_INIT;
    290     }
    291 
    292     status_t status = NO_ERROR;
    293     if (mEnabled) {
    294         uint8_t buf[mCaptureSize];
    295         status = getWaveForm(buf);
    296         if (status == NO_ERROR) {
    297             status = doFft(fft, buf);
    298         }
    299     } else {
    300         memset(fft, 0, mCaptureSize);
    301     }
    302     return status;
    303 }
    304 
    305 status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
    306 {
    307     int32_t workspace[mCaptureSize >> 1];
    308     int32_t nonzero = 0;
    309 
    310     for (uint32_t i = 0; i < mCaptureSize; i += 2) {
    311         workspace[i >> 1] =
    312                 ((waveform[i] ^ 0x80) << 24) | ((waveform[i + 1] ^ 0x80) << 8);
    313         nonzero |= workspace[i >> 1];
    314     }
    315 
    316     if (nonzero) {
    317         fixed_fft_real(mCaptureSize >> 1, workspace);
    318     }
    319 
    320     for (uint32_t i = 0; i < mCaptureSize; i += 2) {
    321         short tmp = workspace[i >> 1] >> 21;
    322         while (tmp > 127 || tmp < -128) tmp >>= 1;
    323         fft[i] = tmp;
    324         tmp = workspace[i >> 1];
    325         tmp >>= 5;
    326         while (tmp > 127 || tmp < -128) tmp >>= 1;
    327         fft[i + 1] = tmp;
    328     }
    329 
    330     return NO_ERROR;
    331 }
    332 
    333 void Visualizer::periodicCapture()
    334 {
    335     Mutex::Autolock _l(mCaptureLock);
    336     ALOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x",
    337             this, mCaptureCallBack, mCaptureFlags);
    338     if (mCaptureCallBack != NULL &&
    339         (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) &&
    340         mCaptureSize != 0) {
    341         uint8_t waveform[mCaptureSize];
    342         status_t status = getWaveForm(waveform);
    343         if (status != NO_ERROR) {
    344             return;
    345         }
    346         uint8_t fft[mCaptureSize];
    347         if (mCaptureFlags & CAPTURE_FFT) {
    348             status = doFft(fft, waveform);
    349         }
    350         if (status != NO_ERROR) {
    351             return;
    352         }
    353         uint8_t *wavePtr = NULL;
    354         uint8_t *fftPtr = NULL;
    355         uint32_t waveSize = 0;
    356         uint32_t fftSize = 0;
    357         if (mCaptureFlags & CAPTURE_WAVEFORM) {
    358             wavePtr = waveform;
    359             waveSize = mCaptureSize;
    360         }
    361         if (mCaptureFlags & CAPTURE_FFT) {
    362             fftPtr = fft;
    363             fftSize = mCaptureSize;
    364         }
    365         mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate);
    366     }
    367 }
    368 
    369 uint32_t Visualizer::initCaptureSize()
    370 {
    371     uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
    372     effect_param_t *p = (effect_param_t *)buf32;
    373 
    374     p->psize = sizeof(uint32_t);
    375     p->vsize = sizeof(uint32_t);
    376     *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
    377     status_t status = getParameter(p);
    378 
    379     if (status == NO_ERROR) {
    380         status = p->status;
    381     }
    382 
    383     uint32_t size = 0;
    384     if (status == NO_ERROR) {
    385         size = *((int32_t *)p->data + 1);
    386     }
    387     mCaptureSize = size;
    388 
    389     ALOGV("initCaptureSize size %d status %d", mCaptureSize, status);
    390 
    391     return size;
    392 }
    393 
    394 void Visualizer::controlStatusChanged(bool controlGranted) {
    395     if (controlGranted) {
    396         // this Visualizer instance regained control of the effect, reset the scaling mode
    397         //   and capture size as has been cached through it.
    398         ALOGV("controlStatusChanged(true) causes effect parameter reset:");
    399         ALOGV("    scaling mode reset to %d", mScalingMode);
    400         setScalingMode(mScalingMode);
    401         ALOGV("    capture size reset to %d", mCaptureSize);
    402         setCaptureSize(mCaptureSize);
    403     }
    404     AudioEffect::controlStatusChanged(controlGranted);
    405 }
    406 
    407 //-------------------------------------------------------------------------
    408 
    409 Visualizer::CaptureThread::CaptureThread(Visualizer& receiver, uint32_t captureRate,
    410         bool bCanCallJava)
    411     : Thread(bCanCallJava), mReceiver(receiver)
    412 {
    413     mSleepTimeUs = 1000000000 / captureRate;
    414     ALOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs);
    415 }
    416 
    417 bool Visualizer::CaptureThread::threadLoop()
    418 {
    419     ALOGV("CaptureThread %p enter", this);
    420     while (!exitPending())
    421     {
    422         usleep(mSleepTimeUs);
    423         mReceiver.periodicCapture();
    424     }
    425     ALOGV("CaptureThread %p exiting", this);
    426     return false;
    427 }
    428 
    429 } // namespace android
    430