summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/libeffects/Android.mk30
-rw-r--r--media/libeffects/EffectVisualizer.cpp401
-rw-r--r--media/libmedia/Android.mk3
-rw-r--r--media/libmedia/AudioEffect.cpp36
-rw-r--r--media/libmedia/IMediaPlayerService.cpp17
-rw-r--r--media/libmedia/Visualizer.cpp330
-rw-r--r--media/libmedia/mediaplayer.cpp57
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp121
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h4
9 files changed, 778 insertions, 221 deletions
diff --git a/media/libeffects/Android.mk b/media/libeffects/Android.mk
index b5f1d42..54e87f3 100644
--- a/media/libeffects/Android.mk
+++ b/media/libeffects/Android.mk
@@ -94,3 +94,33 @@ LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)
endif
+
+
+# Visualizer library
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ EffectVisualizer.cpp
+
+LOCAL_CFLAGS+= -O2
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
+LOCAL_MODULE:= libvisualizer
+
+ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
+LOCAL_LDLIBS += -ldl
+endif
+
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, graphics corecg)
+
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/EffectVisualizer.cpp b/media/libeffects/EffectVisualizer.cpp
new file mode 100644
index 0000000..f27e296
--- /dev/null
+++ b/media/libeffects/EffectVisualizer.cpp
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Visualizer"
+//#define LOG_NDEBUG 0
+#include <cutils/log.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <new>
+#include <media/EffectVisualizerApi.h>
+
+namespace android {
+
+// effect_interface_t interface implementation for visualizer effect
+extern "C" const struct effect_interface_s gVisualizerInterface;
+
+// Google Visualizer UUID: d069d9e0-8329-11df-9168-0002a5d5c51b
+const effect_descriptor_t gVisualizerDescriptor = {
+ {0xe46b26a0, 0xdddd, 0x11db, 0x8afd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type
+ {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
+ EFFECT_API_VERSION,
+ (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST),
+ 0, // TODO
+ 1,
+ "Visualizer",
+ "Google Inc.",
+};
+
+enum visualizer_state_e {
+ VISUALIZER_STATE_UNINITIALIZED,
+ VISUALIZER_STATE_INITIALIZED,
+ VISUALIZER_STATE_ACTIVE,
+};
+
+struct VisualizerContext {
+ const struct effect_interface_s *mItfe;
+ effect_config_t mConfig;
+ uint32_t mState;
+ uint32_t mCaptureIdx;
+ uint32_t mCaptureSize;
+ uint32_t mCurrentBuf;
+ uint8_t mCaptureBuf[2][VISUALIZER_CAPTURE_SIZE_MAX];
+};
+
+
+//
+//--- Local functions
+//
+
+void Visualizer_reset(VisualizerContext *pContext)
+{
+ pContext->mCaptureIdx = 0;
+ pContext->mCurrentBuf = 0;
+ memset(pContext->mCaptureBuf[0], 0, VISUALIZER_CAPTURE_SIZE_MAX);
+ memset(pContext->mCaptureBuf[1], 0, VISUALIZER_CAPTURE_SIZE_MAX);
+}
+
+//----------------------------------------------------------------------------
+// Visualizer_configure()
+//----------------------------------------------------------------------------
+// Purpose: Set input and output audio configuration.
+//
+// Inputs:
+// pContext: effect engine context
+// pConfig: pointer to effect_config_t structure holding input and output
+// configuration parameters
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+int Visualizer_configure(VisualizerContext *pContext, effect_config_t *pConfig)
+{
+ LOGV("Visualizer_configure start");
+
+ if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL;
+ if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL;
+ if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL;
+ if (pConfig->inputCfg.channels != CHANNEL_STEREO) return -EINVAL;
+ if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
+ pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
+ if (pConfig->inputCfg.format != SAMPLE_FORMAT_PCM_S15) return -EINVAL;
+
+ memcpy(&pContext->mConfig, pConfig, sizeof(effect_config_t));
+
+ Visualizer_reset(pContext);
+
+ return 0;
+}
+
+
+//----------------------------------------------------------------------------
+// Visualizer_init()
+//----------------------------------------------------------------------------
+// Purpose: Initialize engine with default configuration.
+//
+// Inputs:
+// pContext: effect engine context
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+int Visualizer_init(VisualizerContext *pContext)
+{
+ pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+ pContext->mConfig.inputCfg.channels = CHANNEL_STEREO;
+ pContext->mConfig.inputCfg.format = SAMPLE_FORMAT_PCM_S15;
+ pContext->mConfig.inputCfg.samplingRate = 44100;
+ pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
+ pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
+ pContext->mConfig.inputCfg.bufferProvider.cookie = NULL;
+ pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
+ pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+ pContext->mConfig.outputCfg.channels = CHANNEL_STEREO;
+ pContext->mConfig.outputCfg.format = SAMPLE_FORMAT_PCM_S15;
+ pContext->mConfig.outputCfg.samplingRate = 44100;
+ pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
+ pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
+ pContext->mConfig.outputCfg.bufferProvider.cookie = NULL;
+ pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+ pContext->mCaptureSize = VISUALIZER_CAPTURE_SIZE_MAX;
+
+ Visualizer_configure(pContext, &pContext->mConfig);
+
+ return 0;
+}
+
+//
+//--- Effect Library Interface Implementation
+//
+
+extern "C" int EffectQueryNumberEffects(uint32_t *pNumEffects) {
+ *pNumEffects = 1;
+ return 0;
+}
+
+extern "C" int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor) {
+ if (pDescriptor == NULL) {
+ return -EINVAL;
+ }
+ if (index > 0) {
+ return -EINVAL;
+ }
+ memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
+ return 0;
+}
+
+extern "C" int EffectCreate(effect_uuid_t *uuid,
+ int32_t sessionId,
+ int32_t ioId,
+ effect_interface_t *pInterface) {
+ int ret;
+ int i;
+
+ if (pInterface == NULL || uuid == NULL) {
+ return -EINVAL;
+ }
+
+ if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) != 0) {
+ return -EINVAL;
+ }
+
+ VisualizerContext *pContext = new VisualizerContext;
+
+ pContext->mItfe = &gVisualizerInterface;
+ pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
+
+ ret = Visualizer_init(pContext);
+ if (ret < 0) {
+ LOGW("EffectCreate() init failed");
+ delete pContext;
+ return ret;
+ }
+
+ *pInterface = (effect_interface_t)pContext;
+
+ pContext->mState = VISUALIZER_STATE_INITIALIZED;
+
+ LOGV("EffectCreate %p", pContext);
+
+ return 0;
+
+}
+
+extern "C" int EffectRelease(effect_interface_t interface) {
+ VisualizerContext * pContext = (VisualizerContext *)interface;
+
+ LOGV("EffectRelease %p", interface);
+ if (pContext == NULL) {
+ return -EINVAL;
+ }
+ pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
+ delete pContext;
+
+ return 0;
+}
+
+//
+//--- Effect Control Interface Implementation
+//
+
+static inline int16_t clamp16(int32_t sample)
+{
+ if ((sample>>15) ^ (sample>>31))
+ sample = 0x7FFF ^ (sample>>31);
+ return sample;
+}
+
+extern "C" int Visualizer_process(
+ effect_interface_t self,audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
+{
+ android::VisualizerContext * pContext = (android::VisualizerContext *)self;
+
+ if (pContext == NULL) {
+ return -EINVAL;
+ }
+ if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
+ return -ENOSYS;
+ }
+
+ if (inBuffer == NULL || inBuffer->raw == NULL ||
+ outBuffer == NULL || outBuffer->raw == NULL ||
+ inBuffer->frameCount != outBuffer->frameCount ||
+ inBuffer->frameCount == 0) {
+ return -EINVAL;
+ }
+
+ // all code below assumes stereo 16 bit PCM output and input
+ uint32_t captIdx;
+ uint32_t inIdx;
+ uint8_t *buf = pContext->mCaptureBuf[pContext->mCurrentBuf];
+ for (inIdx = 0, captIdx = pContext->mCaptureIdx;
+ inIdx < inBuffer->frameCount && captIdx < pContext->mCaptureSize;
+ inIdx++, captIdx++) {
+ int32_t smp = inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1];
+ smp = (smp + (1 << 8)) >> 9;
+ buf[captIdx] = ((uint8_t)smp)^0x80;
+ }
+ pContext->mCaptureIdx = captIdx;
+
+ // go to next buffer when buffer full
+ if (pContext->mCaptureIdx == pContext->mCaptureSize) {
+ pContext->mCurrentBuf ^= 1;
+ pContext->mCaptureIdx = 0;
+ }
+
+ if (inBuffer->raw != outBuffer->raw) {
+ if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+ for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
+ outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
+ }
+ } else {
+ memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
+ }
+ }
+ return 0;
+} // end Visualizer_process
+
+extern "C" int Visualizer_command(effect_interface_t self, int cmdCode, int cmdSize,
+ void *pCmdData, int *replySize, void *pReplyData) {
+
+ android::VisualizerContext * pContext = (android::VisualizerContext *)self;
+ int retsize;
+
+ if (pContext == NULL || pContext->mState == VISUALIZER_STATE_UNINITIALIZED) {
+ return -EINVAL;
+ }
+
+// LOGV("Visualizer_command command %d cmdSize %d",cmdCode, cmdSize);
+
+ switch (cmdCode) {
+ case EFFECT_CMD_INIT:
+ if (pReplyData == NULL || *replySize != sizeof(int)) {
+ return -EINVAL;
+ }
+ *(int *) pReplyData = Visualizer_init(pContext);
+ break;
+ case EFFECT_CMD_CONFIGURE:
+ if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
+ || pReplyData == NULL || *replySize != sizeof(int)) {
+ return -EINVAL;
+ }
+ *(int *) pReplyData = Visualizer_configure(pContext,
+ (effect_config_t *) pCmdData);
+ break;
+ case EFFECT_CMD_RESET:
+ Visualizer_reset(pContext);
+ break;
+ case EFFECT_CMD_ENABLE:
+ if (pReplyData == NULL || *replySize != sizeof(int)) {
+ return -EINVAL;
+ }
+ if (pContext->mState != VISUALIZER_STATE_INITIALIZED) {
+ return -ENOSYS;
+ }
+ pContext->mState = VISUALIZER_STATE_ACTIVE;
+ LOGV("EFFECT_CMD_ENABLE() OK");
+ *(int *)pReplyData = 0;
+ break;
+ case EFFECT_CMD_DISABLE:
+ if (pReplyData == NULL || *replySize != sizeof(int)) {
+ return -EINVAL;
+ }
+ if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
+ return -ENOSYS;
+ }
+ pContext->mState = VISUALIZER_STATE_INITIALIZED;
+ LOGV("EFFECT_CMD_DISABLE() OK");
+ *(int *)pReplyData = 0;
+ break;
+ case EFFECT_CMD_GET_PARAM: {
+ if (pCmdData == NULL ||
+ cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
+ pReplyData == NULL ||
+ *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) {
+ return -EINVAL;
+ }
+ memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t));
+ effect_param_t *p = (effect_param_t *)pReplyData;
+ p->status = 0;
+ *replySize = sizeof(effect_param_t) + sizeof(uint32_t);
+ if (p->psize != sizeof(uint32_t) ||
+ *(uint32_t *)p->data != VISU_PARAM_CAPTURE_SIZE) {
+ p->status = -EINVAL;
+ break;
+ }
+ LOGV("get mCaptureSize = %d", pContext->mCaptureSize);
+ *((uint32_t *)p->data + 1) = pContext->mCaptureSize;
+ p->vsize = sizeof(uint32_t);
+ *replySize += sizeof(uint32_t);
+ } break;
+ case EFFECT_CMD_SET_PARAM: {
+ if (pCmdData == NULL ||
+ cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) ||
+ pReplyData == NULL || *replySize != sizeof(int32_t)) {
+ return -EINVAL;
+ }
+ *(int32_t *)pReplyData = 0;
+ effect_param_t *p = (effect_param_t *)pCmdData;
+ if (p->psize != sizeof(uint32_t) ||
+ p->vsize != sizeof(uint32_t) ||
+ *(uint32_t *)p->data != VISU_PARAM_CAPTURE_SIZE) {
+ *(int32_t *)pReplyData = -EINVAL;
+ break;;
+ }
+ pContext->mCaptureSize = *((uint32_t *)p->data + 1);
+ LOGV("set mCaptureSize = %d", pContext->mCaptureSize);
+ } break;
+ case EFFECT_CMD_SET_DEVICE:
+ case EFFECT_CMD_SET_VOLUME:
+ case EFFECT_CMD_SET_AUDIO_MODE:
+ break;
+
+
+ case VISU_CMD_CAPTURE:
+ if (pReplyData == NULL || *replySize != (int)pContext->mCaptureSize) {
+ LOGV("VISU_CMD_CAPTURE() error *replySize %d pContext->mCaptureSize %d",
+ *replySize, pContext->mCaptureSize);
+ return -EINVAL;
+ }
+ if (pContext->mState == VISUALIZER_STATE_ACTIVE) {
+ memcpy(pReplyData,
+ pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
+ pContext->mCaptureSize);
+ } else {
+ memset(pReplyData, 0x80, pContext->mCaptureSize);
+ }
+ break;
+
+ default:
+ LOGW("Visualizer_command invalid command %d",cmdCode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+// effect_interface_t interface implementation for visualizer effect
+const struct effect_interface_s gVisualizerInterface = {
+ Visualizer_process,
+ Visualizer_command
+};
+
+} // namespace
+
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index de9e51d..977e6be 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -30,7 +30,8 @@ LOCAL_SRC_FILES:= \
MediaProfiles.cpp \
IEffect.cpp \
IEffectClient.cpp \
- AudioEffect.cpp
+ AudioEffect.cpp \
+ Visualizer.cpp
LOCAL_SHARED_LIBRARIES := \
libui libcutils libutils libbinder libsonivox libicuuc libexpat libsurfaceflinger_client libcamera_client
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index 4afa2dc..783249d 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -171,7 +171,7 @@ AudioEffect::~AudioEffect()
LOGV("Destructor %p", this);
if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) {
- disable();
+ setEnabled(false);
if (mIEffect != NULL) {
mIEffect->disconnect();
mIEffect->asBinder()->unlinkToDeath(mIEffectClient);
@@ -196,36 +196,28 @@ effect_descriptor_t AudioEffect::descriptor() const
return mDescriptor;
}
-bool AudioEffect::isEnabled() const
+bool AudioEffect::getEnabled() const
{
return (mEnabled != 0);
}
-status_t AudioEffect::enable()
+status_t AudioEffect::setEnabled(bool enabled)
{
if (mStatus != NO_ERROR) {
return INVALID_OPERATION;
}
- LOGV("enable %p", this);
- if (android_atomic_or(1, &mEnabled) == 0) {
- return mIEffect->enable();
- }
-
- return INVALID_OPERATION;
-}
-
-status_t AudioEffect::disable()
-{
- if (mStatus != NO_ERROR) {
- return INVALID_OPERATION;
- }
- LOGV("disable %p", this);
-
- if (android_atomic_and(~1, &mEnabled) == 1) {
- return mIEffect->disable();
+ if (enabled) {
+ LOGV("enable %p", this);
+ if (android_atomic_or(1, &mEnabled) == 0) {
+ return mIEffect->enable();
+ }
+ } else {
+ LOGV("disable %p", this);
+ if (android_atomic_and(~1, &mEnabled) == 1) {
+ return mIEffect->disable();
+ }
}
-
return INVALID_OPERATION;
}
@@ -349,7 +341,7 @@ void AudioEffect::controlStatusChanged(bool controlGranted)
void AudioEffect::enableStatusChanged(bool enabled)
{
- LOGV("enableStatusChanged %p enabled %d", this, enabled);
+ LOGV("enableStatusChanged %p enabled %d mCbf %p", this, enabled, mCbf);
if (mStatus == ALREADY_EXISTS) {
mEnabled = enabled;
if (mCbf) {
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 1ae222e..4abfa75 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -35,8 +35,7 @@ enum {
DECODE_FD,
CREATE_MEDIA_RECORDER,
CREATE_METADATA_RETRIEVER,
- GET_OMX,
- SNOOP
+ GET_OMX
};
class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
@@ -134,14 +133,6 @@ public:
return interface_cast<IMemory>(reply.readStrongBinder());
}
- virtual sp<IMemory> snoop()
- {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
- remote()->transact(SNOOP, data, &reply);
- return interface_cast<IMemory>(reply.readStrongBinder());
- }
-
virtual sp<IOMX> getOMX() {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
@@ -221,12 +212,6 @@ status_t BnMediaPlayerService::onTransact(
reply->writeStrongBinder(player->asBinder());
return NO_ERROR;
} break;
- case SNOOP: {
- CHECK_INTERFACE(IMediaPlayerService, data, reply);
- sp<IMemory> snooped_audio = snoop();
- reply->writeStrongBinder(snooped_audio->asBinder());
- return NO_ERROR;
- } break;
case CREATE_MEDIA_RECORDER: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
pid_t pid = data.readInt32();
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
new file mode 100644
index 0000000..47e96e5
--- /dev/null
+++ b/media/libmedia/Visualizer.cpp
@@ -0,0 +1,330 @@
+/*
+**
+** Copyright 2010, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Visualizer"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include <media/Visualizer.h>
+
+extern "C" {
+#define FLOATING_POINT 1
+#include "fftwrap.h"
+}
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+Visualizer::Visualizer (int32_t priority,
+ effect_callback_t cbf,
+ void* user,
+ int sessionId)
+ : AudioEffect(SL_IID_VISUALIZATION, NULL, priority, cbf, user, sessionId),
+ mCaptureRate(CAPTURE_RATE_DEF),
+ mCaptureSize(CAPTURE_SIZE_DEF),
+ mSampleRate(44100000),
+ mCaptureCallBack(NULL),
+ mCaptureCbkUser(NULL)
+{
+ initCaptureSize();
+ if (mCaptureSize != 0) {
+ mFftTable = spx_fft_init(mCaptureSize);
+ } else {
+ mFftTable = NULL;
+ }
+}
+
+Visualizer::~Visualizer()
+{
+ if (mFftTable != NULL) {
+ spx_fft_destroy(mFftTable);
+ }
+}
+
+status_t Visualizer::setEnabled(bool enabled)
+{
+ Mutex::Autolock _l(mLock);
+
+ sp<CaptureThread> t = mCaptureThread;
+ if (t != 0) {
+ if (enabled) {
+ if (t->exitPending()) {
+ if (t->requestExitAndWait() == WOULD_BLOCK) {
+ LOGE("Visualizer::enable() called from thread");
+ return INVALID_OPERATION;
+ }
+ }
+ }
+ t->mLock.lock();
+ }
+
+ status_t status = AudioEffect::setEnabled(enabled);
+
+ if (status == NO_ERROR) {
+ if (t != 0) {
+ if (enabled) {
+ t->run("AudioTrackThread");
+ } else {
+ t->requestExit();
+ }
+ }
+ }
+
+ if (t != 0) {
+ t->mLock.unlock();
+ }
+
+ return status;
+}
+
+status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate)
+{
+ if (rate > CAPTURE_RATE_MAX) {
+ return BAD_VALUE;
+ }
+ Mutex::Autolock _l(mLock);
+
+ if (mEnabled) {
+ return INVALID_OPERATION;
+ }
+
+ sp<CaptureThread> t = mCaptureThread;
+ if (t != 0) {
+ t->mLock.lock();
+ }
+ mCaptureThread.clear();
+ mCaptureCallBack = cbk;
+ mCaptureCbkUser = user;
+ mCaptureFlags = flags;
+ mCaptureRate = rate;
+
+ if (t != 0) {
+ t->mLock.unlock();
+ }
+
+ if (cbk != NULL) {
+ mCaptureThread = new CaptureThread(*this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
+ if (mCaptureThread == 0) {
+ LOGE("Could not create callback thread");
+ return NO_INIT;
+ }
+ }
+ LOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
+ rate, mCaptureThread.get(), mCaptureFlags);
+ return NO_ERROR;
+}
+
+status_t Visualizer::setCaptureSize(uint32_t size)
+{
+ if (size > VISUALIZER_CAPTURE_SIZE_MAX ||
+ size < VISUALIZER_CAPTURE_SIZE_MIN ||
+ AudioSystem::popCount(size) != 1) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock _l(mLock);
+ if (mEnabled) {
+ return INVALID_OPERATION;
+ }
+
+ uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
+ effect_param_t *p = (effect_param_t *)buf32;
+
+ p->psize = sizeof(uint32_t);
+ p->vsize = sizeof(uint32_t);
+ *(int32_t *)p->data = VISU_PARAM_CAPTURE_SIZE;
+ *((int32_t *)p->data + 1)= size;
+ status_t status = setParameter(p);
+
+ LOGV("setCaptureSize size %d status %d p->status %d", size, status, p->status);
+
+ if (status == NO_ERROR) {
+ status = p->status;
+ }
+ if (status == NO_ERROR) {
+ mCaptureSize = size;
+ if (mFftTable != NULL) {
+ spx_fft_destroy(mFftTable);
+ }
+ mFftTable = spx_fft_init(mCaptureSize);
+ LOGV("setCaptureSize size %d mFftTable %p", mCaptureSize, mFftTable);
+ }
+
+ return status;
+}
+
+status_t Visualizer::getWaveForm(uint8_t *waveform)
+{
+ if (waveform == NULL) {
+ return BAD_VALUE;
+ }
+ if (mCaptureSize == 0) {
+ return NO_INIT;
+ }
+
+ status_t status = NO_ERROR;
+ if (mEnabled) {
+ int32_t replySize = mCaptureSize;
+ status_t status = command(VISU_CMD_CAPTURE, 0, NULL, &replySize, waveform);
+ if (replySize == 0) {
+ status = NOT_ENOUGH_DATA;
+ }
+ } else {
+ memset(waveform, 0x80, mCaptureSize);
+ }
+ return status;
+}
+
+status_t Visualizer::getFft(uint8_t *fft)
+{
+ if (fft == NULL) {
+ return BAD_VALUE;
+ }
+ if (mCaptureSize == 0) {
+ return NO_INIT;
+ }
+
+ status_t status = NO_ERROR;
+ if (mEnabled) {
+ uint8_t buf[mCaptureSize];
+ status_t status = getWaveForm(buf);
+ if (status == NO_ERROR) {
+ status = doFft(fft, buf);
+ }
+ } else {
+ memset(fft, 0, mCaptureSize);
+ }
+ return status;
+}
+
+status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
+{
+ if (mFftTable == NULL) {
+ return NO_INIT;
+ }
+
+ float fsrc[mCaptureSize];
+ for (uint32_t i = 0; i < mCaptureSize; i++) {
+ fsrc[i] = (int16_t)(waveform[i] ^ 0x80) << 8;
+ }
+ float fdst[mCaptureSize];
+ spx_fft_float(mFftTable, fsrc, fdst);
+ for (uint32_t i = 0; i < mCaptureSize; i++) {
+ fft[i] = (uint8_t)((int32_t)fdst[i] >> 8);
+ }
+ return NO_ERROR;
+}
+
+void Visualizer::periodicCapture()
+{
+ Mutex::Autolock _l(mLock);
+ LOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x",
+ this, mCaptureCallBack, mCaptureFlags);
+ if (mCaptureCallBack != NULL &&
+ (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) &&
+ mCaptureSize != 0) {
+ uint8_t waveform[mCaptureSize];
+ status_t status = getWaveForm(waveform);
+ if (status != NO_ERROR) {
+ return;
+ }
+ uint8_t fft[mCaptureSize];
+ if (mCaptureFlags & CAPTURE_FFT) {
+ status = doFft(fft, waveform);
+ }
+ if (status != NO_ERROR) {
+ return;
+ }
+ uint8_t *wavePtr = NULL;
+ uint8_t *fftPtr = NULL;
+ uint32_t waveSize = 0;
+ uint32_t fftSize = 0;
+ if (mCaptureFlags & CAPTURE_WAVEFORM) {
+ wavePtr = waveform;
+ waveSize = mCaptureSize;
+ }
+ if (mCaptureFlags & CAPTURE_FFT) {
+ fftPtr = fft;
+ fftSize = mCaptureSize;
+ }
+ mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate);
+ }
+}
+
+uint32_t Visualizer::initCaptureSize()
+{
+ uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
+ effect_param_t *p = (effect_param_t *)buf32;
+
+ p->psize = sizeof(uint32_t);
+ p->vsize = sizeof(uint32_t);
+ *(int32_t *)p->data = VISU_PARAM_CAPTURE_SIZE;
+ status_t status = getParameter(p);
+
+ if (status == NO_ERROR) {
+ status = p->status;
+ }
+
+ uint32_t size = 0;
+ if (status == NO_ERROR) {
+ size = *((int32_t *)p->data + 1);
+ }
+ mCaptureSize = size;
+
+ LOGV("initCaptureSize size %d status %d", mCaptureSize, status);
+
+ return size;
+}
+
+//-------------------------------------------------------------------------
+
+Visualizer::CaptureThread::CaptureThread(Visualizer& receiver, uint32_t captureRate, bool bCanCallJava)
+ : Thread(bCanCallJava), mReceiver(receiver)
+{
+ mSleepTimeUs = 1000000000 / captureRate;
+ LOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs);
+}
+
+bool Visualizer::CaptureThread::threadLoop()
+{
+ LOGV("CaptureThread %p enter", this);
+ while (!exitPending())
+ {
+ usleep(mSleepTimeUs);
+ mReceiver.periodicCapture();
+ }
+ LOGV("CaptureThread %p exiting", this);
+ return false;
+}
+
+status_t Visualizer::CaptureThread::readyToRun()
+{
+ return NO_ERROR;
+}
+
+void Visualizer::CaptureThread::onFirstRef()
+{
+}
+
+}; // namespace android
+
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index d5a3c13..b43f75f 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -658,61 +658,4 @@ void MediaPlayer::died()
}
-extern "C" {
-#define FLOATING_POINT 1
-#include "fftwrap.h"
-}
-
-static void *ffttable = NULL;
-
-// peeks at the audio data and fills 'data' with the requested kind
-// (currently kind=0 returns mono 16 bit PCM data, and kind=1 returns
-// 256 point FFT data). Return value is number of samples returned,
-// which may be 0.
-/*static*/ int MediaPlayer::snoop(short* data, int len, int kind) {
-
- sp<IMemory> p;
- const sp<IMediaPlayerService>& service = getMediaPlayerService();
- if (service != 0) {
- // Take a peek at the waveform. The returned data consists of 16 bit mono PCM data.
- p = service->snoop();
-
- if (p == NULL) {
- return 0;
- }
-
- if (kind == 0) { // return waveform data
- int plen = p->size();
- len *= 2; // number of shorts -> number of bytes
- short *src = (short*) p->pointer();
- if (plen > len) {
- plen = len;
- }
- memcpy(data, src, plen);
- return plen / sizeof(short); // return number of samples
- } else if (kind == 1) {
- // TODO: use a more efficient FFT
- // Right now this uses the speex library, which is compiled to do a float FFT
- if (!ffttable) ffttable = spx_fft_init(512);
- short *usrc = (short*) p->pointer();
- float fsrc[512];
- for (int i=0;i<512;i++)
- fsrc[i] = usrc[i];
- float fdst[512];
- spx_fft_float(ffttable, fsrc, fdst);
- if (len > 512) {
- len = 512;
- }
- len /= 2; // only half the output data is valid
- for (int i=0; i < len; i++)
- data[i] = fdst[i];
- return len;
- }
-
- } else {
- LOGE("Unable to locate media service");
- }
- return 0;
-}
-
}; // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 82d5c14..4872047 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1265,98 +1265,6 @@ Exit:
return mem;
}
-/*
- * Avert your eyes, ugly hack ahead.
- * The following is to support music visualizations.
- */
-
-static const int NUMVIZBUF = 32;
-static const int VIZBUFFRAMES = 1024;
-static const int BUFTIMEMSEC = NUMVIZBUF * VIZBUFFRAMES * 1000 / 44100;
-static const int TOTALBUFTIMEMSEC = NUMVIZBUF * BUFTIMEMSEC;
-
-static bool gotMem = false;
-static sp<MemoryHeapBase> heap;
-static sp<MemoryBase> mem[NUMVIZBUF];
-static uint64_t endTime;
-static uint64_t lastReadTime;
-static uint64_t lastWriteTime;
-static int writeIdx = 0;
-
-static void allocVizBufs() {
- if (!gotMem) {
- heap = new MemoryHeapBase(NUMVIZBUF * VIZBUFFRAMES * 2, 0, "snooper");
- for (int i=0;i<NUMVIZBUF;i++) {
- mem[i] = new MemoryBase(heap, VIZBUFFRAMES * 2 * i, VIZBUFFRAMES * 2);
- }
- endTime = 0;
- gotMem = true;
- }
-}
-
-
-/*
- * Get a buffer of audio data that is about to be played.
- * We don't synchronize this because in practice the writer
- * is ahead of the reader, and even if we did happen to catch
- * a buffer while it's being written, it's just a visualization,
- * so no harm done.
- */
-static sp<MemoryBase> getVizBuffer() {
-
- allocVizBufs();
-
- lastReadTime = uptimeMillis();
-
- // if there is no recent buffer (yet), just return empty handed
- if (lastWriteTime + TOTALBUFTIMEMSEC < lastReadTime) {
- //LOGI("@@@@ no audio data to look at yet: %d + %d < %d", (int)lastWriteTime, TOTALBUFTIMEMSEC, (int)lastReadTime);
- return NULL;
- }
-
- int timedelta = endTime - lastReadTime;
- if (timedelta < 0) timedelta = 0;
- int framedelta = timedelta * 44100 / 1000;
- int headIdx = (writeIdx - framedelta) / VIZBUFFRAMES - 1;
- while (headIdx < 0) {
- headIdx += NUMVIZBUF;
- }
- return mem[headIdx];
-}
-
-// Append the data to the vizualization buffer
-static void makeVizBuffers(const char *data, int len, uint64_t time) {
-
- allocVizBufs();
-
- uint64_t startTime = time;
- const int frameSize = 4; // 16 bit stereo sample is 4 bytes
- int offset = writeIdx;
- int maxoff = heap->getSize() / 2; // in shorts
- short *base = (short*)heap->getBase();
- short *src = (short*)data;
- while (len > 0) {
-
- // Degrade quality by mixing to mono and clearing the lowest 3 bits.
- // This should still be good enough for a visualization
- base[offset++] = ((int(src[0]) + int(src[1])) >> 1) & ~0x7;
- src += 2;
- len -= frameSize;
- if (offset >= maxoff) {
- offset = 0;
- }
- }
- writeIdx = offset;
- endTime = time + (len / frameSize) / 44;
- //LOGI("@@@ stored buffers from %d to %d", uint32_t(startTime), uint32_t(time));
-}
-
-sp<IMemory> MediaPlayerService::snoop()
-{
- sp<MemoryBase> mem = getVizBuffer();
- return mem;
-}
-
#undef LOG_TAG
#define LOG_TAG "AudioSink"
@@ -1371,7 +1279,6 @@ MediaPlayerService::AudioOutput::AudioOutput(int sessionId)
mRightVolume = 1.0;
mLatency = 0;
mMsecsPerFrame = 0;
- mNumFramesWritten = 0;
setMinBufferCount();
}
@@ -1516,30 +1423,9 @@ void MediaPlayerService::AudioOutput::start()
if (mTrack) {
mTrack->setVolume(mLeftVolume, mRightVolume);
mTrack->start();
- mTrack->getPosition(&mNumFramesWritten);
}
}
-void MediaPlayerService::AudioOutput::snoopWrite(const void* buffer, size_t size) {
- // Only make visualization buffers if anyone recently requested visualization data
- uint64_t now = uptimeMillis();
- if (lastReadTime + TOTALBUFTIMEMSEC >= now) {
- // Based on the current play counter, the number of frames written and
- // the current real time we can calculate the approximate real start
- // time of the buffer we're about to write.
- uint32_t pos;
- mTrack->getPosition(&pos);
-
- // we're writing ahead by this many frames:
- int ahead = mNumFramesWritten - pos;
- //LOGI("@@@ written: %d, playpos: %d, latency: %d", mNumFramesWritten, pos, mTrack->latency());
- // which is this many milliseconds, assuming 44100 Hz:
- ahead /= 44;
-
- makeVizBuffers((const char*)buffer, size, now + ahead + mTrack->latency());
- lastWriteTime = now;
- }
-}
ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
@@ -1548,9 +1434,7 @@ ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
//LOGV("write(%p, %u)", buffer, size);
if (mTrack) {
- snoopWrite(buffer, size);
ssize_t ret = mTrack->write(buffer, size);
- mNumFramesWritten += ret / 4; // assume 16 bit stereo
return ret;
}
return NO_INIT;
@@ -1560,7 +1444,6 @@ void MediaPlayerService::AudioOutput::stop()
{
LOGV("stop");
if (mTrack) mTrack->stop();
- lastWriteTime = 0;
}
void MediaPlayerService::AudioOutput::flush()
@@ -1573,7 +1456,6 @@ void MediaPlayerService::AudioOutput::pause()
{
LOGV("pause");
if (mTrack) mTrack->pause();
- lastWriteTime = 0;
}
void MediaPlayerService::AudioOutput::close()
@@ -1609,9 +1491,6 @@ void MediaPlayerService::AudioOutput::CallbackWrapper(
buffer->size = actualSize;
- if (actualSize > 0) {
- me->snoopWrite(buffer->raw, actualSize);
- }
}
#undef LOG_TAG
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 60b91c6..39f525e 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -113,9 +113,6 @@ class MediaPlayerService : public BnMediaPlayerService
static bool mIsOnEmulator;
static int mMinBufferCount; // 12 for emulator; otherwise 4
- public: // visualization hack support
- uint32_t mNumFramesWritten;
- void snoopWrite(const void*, size_t);
};
class AudioCache : public MediaPlayerBase::AudioSink
@@ -191,7 +188,6 @@ public:
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length, int audioSessionId);
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
- virtual sp<IMemory> snoop();
virtual sp<IOMX> getOMX();
virtual status_t dump(int fd, const Vector<String16>& args);