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