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