summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/media/AudioEffect.h70
-rw-r--r--include/media/EffectVisualizerApi.h55
-rw-r--r--include/media/IMediaPlayerService.h4
-rw-r--r--include/media/Visualizer.h160
-rw-r--r--include/media/mediaplayer.h1
-rw-r--r--libs/audioflinger/AudioFlinger.cpp40
-rw-r--r--libs/audioflinger/AudioFlinger.h6
-rw-r--r--media/java/android/media/AudioEffect.java713
-rwxr-xr-xmedia/java/android/media/Visualizer.java510
-rw-r--r--media/jni/android_media_MediaPlayer.cpp13
-rw-r--r--media/jni/audioeffect/Android.mk3
-rw-r--r--media/jni/audioeffect/android_media_AudioEffect.cpp41
-rw-r--r--media/jni/audioeffect/android_media_Visualizer.cpp507
-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
22 files changed, 2499 insertions, 623 deletions
diff --git a/include/media/AudioEffect.h b/include/media/AudioEffect.h
index 66670f3..e9ff8a3 100644
--- a/include/media/AudioEffect.h
+++ b/include/media/AudioEffect.h
@@ -307,29 +307,18 @@ public:
int32_t priority() const { return mPriority; }
- /* Enables the effect engine.
+ /* Enables or disables the effect engine.
*
* Parameters:
- * None.
+ * enabled: requested enable state.
*
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful operation
- * - INVALID_OPERATION: the application does not have control of the effect engine
+ * - INVALID_OPERATION: the application does not have control of the effect engine or the
+ * effect is already in the requested state.
*/
- status_t enable();
-
- /* Disables the effect engine.
- *
- * Parameters:
- * None.
- *
- * Returned status (from utils/Errors.h) can be:
- * - NO_ERROR: successful operation
- * - INVALID_OPERATION: the application does not have control of the effect engine
- */
- status_t disable();
-
- bool isEnabled() const;
+ virtual status_t setEnabled(bool enabled);
+ bool getEnabled() const;
/* Sets a parameter value.
*
@@ -342,7 +331,7 @@ public:
* - BAD_VALUE: invalid parameter identifier or value.
* - DEAD_OBJECT: the effect engine has been deleted.
*/
- status_t setParameter(effect_param_t *param);
+ virtual status_t setParameter(effect_param_t *param);
/* Prepare a new parameter value that will be set by next call to
* setParameterCommit(). This method can be used to set multiple parameters
@@ -359,7 +348,7 @@ public:
* - NO_MEMORY: no more space available in shared memory used for deferred parameter
* setting.
*/
- status_t setParameterDeferred(effect_param_t *param);
+ virtual status_t setParameterDeferred(effect_param_t *param);
/* Commit all parameter values previously prepared by setParameterDeferred().
*
@@ -373,7 +362,7 @@ public:
* as to which of the parameters caused this error.
* - DEAD_OBJECT: the effect engine has been deleted.
*/
- status_t setParameterCommit();
+ virtual status_t setParameterCommit();
/* Gets a parameter value.
*
@@ -387,13 +376,17 @@ public:
* - BAD_VALUE: invalid parameter identifier.
* - DEAD_OBJECT: the effect engine has been deleted.
*/
- status_t getParameter(effect_param_t *param);
+ virtual status_t getParameter(effect_param_t *param);
/* Sends a command and receives a response to/from effect engine.
* See EffectApi.h for details on effect command() function, valid command codes
* and formats.
*/
- status_t command(int32_t cmdCode, int32_t cmdSize, void *cmdData, int32_t *replySize, void *replyData);
+ virtual status_t command(int32_t cmdCode,
+ int32_t cmdSize,
+ void *cmdData,
+ int32_t *replySize,
+ void *replyData);
/*
@@ -409,6 +402,17 @@ public:
*/
static status_t guidToString(const effect_uuid_t *guid, char *str, size_t maxLen);
+protected:
+ volatile int32_t mEnabled; // enable state
+ int32_t mSessionId; // audio session ID
+ int32_t mPriority; // priority for effect control
+ status_t mStatus; // effect status
+ effect_callback_t mCbf; // callback function for status, control and
+ // parameter changes notifications
+ void* mUserData; // client context for callback function
+ effect_descriptor_t mDescriptor; // effect descriptor
+ int32_t mId; // system wide unique effect engine instance ID
+
private:
// Implements the IEffectClient interface
@@ -419,9 +423,17 @@ private:
EffectClient(AudioEffect *effect) : mEffect(effect){}
// IEffectClient
- virtual void controlStatusChanged(bool controlGranted) {mEffect->controlStatusChanged(controlGranted);}
- virtual void enableStatusChanged(bool enabled) {mEffect->enableStatusChanged(enabled);}
- virtual void commandExecuted(int cmdCode, int cmdSize, void *pCmdData, int replySize, void *pReplyData) {
+ virtual void controlStatusChanged(bool controlGranted) {
+ mEffect->controlStatusChanged(controlGranted);
+ }
+ virtual void enableStatusChanged(bool enabled) {
+ mEffect->enableStatusChanged(enabled);
+ }
+ virtual void commandExecuted(int cmdCode,
+ int cmdSize,
+ void *pCmdData,
+ int replySize,
+ void *pReplyData) {
mEffect->commandExecuted(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
}
@@ -446,14 +458,6 @@ private:
sp<EffectClient> mIEffectClient; // IEffectClient implementation
sp<IMemory> mCblkMemory; // shared memory for deferred parameter setting
effect_param_cblk_t* mCblk; // control block for deferred parameter setting
- int32_t mPriority; // priority for effect control
- status_t mStatus; // effect status
- volatile int32_t mEnabled; // enable state
- effect_callback_t mCbf; // callback function for status, control, parameter changes notifications
- void* mUserData; // client context for callback function
- effect_descriptor_t mDescriptor; // effect descriptor
- int32_t mId; // system wide unique effect engine instance identifier
- int32_t mSessionId; // audio session ID
};
diff --git a/include/media/EffectVisualizerApi.h b/include/media/EffectVisualizerApi.h
new file mode 100644
index 0000000..1155db8
--- /dev/null
+++ b/include/media/EffectVisualizerApi.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_EFFECTVISUALIZERAPI_H_
+#define ANDROID_EFFECTVISUALIZERAPI_H_
+
+#include <media/EffectApi.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+//TODO replace by openSL ES include when available
+static const effect_uuid_t SL_IID_VISUALIZATION_ =
+ { 0xe46b26a0, 0xdddd, 0x11db, 0x8afd, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_VISUALIZATION = &SL_IID_VISUALIZATION_;
+
+#define VISUALIZER_CAPTURE_SIZE_MAX 1024 // maximum capture size in samples
+#define VISUALIZER_CAPTURE_SIZE_MIN 128 // minimum capture size in samples
+
+/* enumerated parameters for Visualizer effect */
+typedef enum
+{
+ VISU_PARAM_CAPTURE_SIZE, // Sets the number PCM samples in the capture.
+} t_visualizer_params;
+
+/* commands */
+typedef enum
+{
+ VISU_CMD_CAPTURE = EFFECT_CMD_FIRST_PROPRIETARY, // Gets the latest PCM capture.
+}t_visualizer_cmds;
+
+// VISU_CMD_CAPTURE retrieves the latest PCM snapshot captured by the visualizer engine.
+// It returns the number of samples specified by VISU_PARAM_CAPTURE_SIZE
+// in 8 bit unsigned format (0 = 0x80)
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECTVISUALIZERAPI_H_*/
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index e892875..9416ca1 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -48,10 +48,6 @@ public:
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
virtual sp<IOMX> getOMX() = 0;
-
- // Take a peek at currently playing audio, for visualization purposes.
- // This returns a buffer of 16 bit mono PCM data, or NULL if no visualization buffer is currently available.
- virtual sp<IMemory> snoop() = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/media/Visualizer.h b/include/media/Visualizer.h
new file mode 100644
index 0000000..5d51de8
--- /dev/null
+++ b/include/media/Visualizer.h
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEDIA_VISUALIZER_H
+#define ANDROID_MEDIA_VISUALIZER_H
+
+#include <media/AudioEffect.h>
+#include <media/EffectVisualizerApi.h>
+#include <string.h>
+
+/**
+ * The Visualizer class enables application to retrieve part of the currently playing audio for
+ * visualization purpose. It is not an audio recording interface and only returns partial and low
+ * quality audio content. However, to protect privacy of certain audio data (e.g voice mail) the use
+ * of the visualizer requires the permission android.permission.RECORD_AUDIO.
+ * The audio session ID passed to the constructor indicates which audio content should be
+ * visualized:
+ * - If the session is 0, the audio output mix is visualized
+ * - If the session is not 0, the audio from a particular MediaPlayer or AudioTrack
+ * using this audio session is visualized
+ * Two types of representation of audio content can be captured:
+ * - Waveform data: consecutive 8-bit (unsigned) mono samples by using the getWaveForm() method
+ * - Frequency data: 8-bit magnitude FFT by using the getFft() method
+ *
+ * The length of the capture can be retrieved or specified by calling respectively
+ * getCaptureSize() and setCaptureSize() methods. Note that the size of the FFT
+ * is half of the specified capture size but both sides of the spectrum are returned yielding in a
+ * number of bytes equal to the capture size. The capture size must be a power of 2 in the range
+ * returned by getMinCaptureSize() and getMaxCaptureSize().
+ * In addition to the polling capture mode, a callback mode is also available by installing a
+ * callback function by use of the setCaptureCallBack() method. The rate at which the callback
+ * is called as well as the type of data returned is specified.
+ * Before capturing data, the Visualizer must be enabled by calling the setEnabled() method.
+ * When data capture is not needed any more, the Visualizer should be disabled.
+ */
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class Visualizer: public AudioEffect {
+public:
+
+ enum callback_flags {
+ CAPTURE_WAVEFORM = 0x00000001, // capture callback returns a PCM wave form
+ CAPTURE_FFT = 0x00000002, // apture callback returns a frequency representation
+ CAPTURE_CALL_JAVA = 0x00000004 // the callback thread can call java
+ };
+
+
+ /* Constructor.
+ * See AudioEffect constructor for details on parameters.
+ */
+ Visualizer(int32_t priority = 0,
+ effect_callback_t cbf = 0,
+ void* user = 0,
+ int sessionId = 0);
+
+ ~Visualizer();
+
+ virtual status_t setEnabled(bool enabled);
+
+ // maximum capture size in samples
+ static uint32_t getMaxCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MAX; }
+ // minimum capture size in samples
+ static uint32_t getMinCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MIN; }
+ // maximum capture rate in millihertz
+ static uint32_t getMaxCaptureRate() { return CAPTURE_RATE_MAX; }
+
+ // callback used to return periodic PCM or FFT captures to the application. Either one or both
+ // types of data are returned (PCM and FFT) according to flags indicated when installing the
+ // callback. When a type of data is not present, the corresponding size (waveformSize or
+ // fftSize) is 0.
+ typedef void (*capture_cbk_t)(void* user,
+ uint32_t waveformSize,
+ uint8_t *waveform,
+ uint32_t fftSize,
+ uint8_t *fft,
+ uint32_t samplingrate);
+
+ // install a callback to receive periodic captures. The capture rate is specified in milliHertz
+ // and the capture format is according to flags (see callback_flags).
+ status_t setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate);
+
+ // set the capture size capture size must be a power of two in the range
+ // [VISUALIZER_CAPTURE_SIZE_MAX. VISUALIZER_CAPTURE_SIZE_MIN]
+ // must be called when the visualizer is not enabled
+ status_t setCaptureSize(uint32_t size);
+ uint32_t getCaptureSize() { return mCaptureSize; }
+
+ // returns the capture rate indicated when installing the callback
+ uint32_t getCaptureRate() { return mCaptureRate; }
+
+ // returns the sampling rate of the audio being captured
+ uint32_t getSamplingRate() { return mSampleRate; }
+
+ // return a capture in PCM 8 bit unsigned format. The size of the capture is equal to
+ // getCaptureSize()
+ status_t getWaveForm(uint8_t *waveform);
+
+ // return a capture in FFT 8 bit signed format. The size of the capture is equal to
+ // getCaptureSize() but the length of the FFT is half of the size (both parts of the spectrum
+ // are returned
+ status_t getFft(uint8_t *fft);
+
+private:
+
+ static const uint32_t CAPTURE_RATE_MAX = 20000;
+ static const uint32_t CAPTURE_RATE_DEF = 10000;
+ static const uint32_t CAPTURE_SIZE_DEF = VISUALIZER_CAPTURE_SIZE_MAX;
+
+ /* internal class to handle the callback */
+ class CaptureThread : public Thread
+ {
+ public:
+ CaptureThread(Visualizer& receiver, uint32_t captureRate, bool bCanCallJava = false);
+
+ private:
+ friend class Visualizer;
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+ Visualizer& mReceiver;
+ Mutex mLock;
+ uint32_t mSleepTimeUs;
+ };
+
+ status_t doFft(uint8_t *fft, uint8_t *waveform);
+ void periodicCapture();
+ uint32_t initCaptureSize();
+
+ Mutex mLock;
+ uint32_t mCaptureRate;
+ uint32_t mCaptureSize;
+ uint32_t mSampleRate;
+ capture_cbk_t mCaptureCallBack;
+ void *mCaptureCbkUser;
+ sp<CaptureThread> mCaptureThread;
+ uint32_t mCaptureFlags;
+ void *mFftTable;
+};
+
+
+}; // namespace android
+
+#endif // ANDROID_MEDIA_VISUALIZER_H
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 62a4e50..4963f73 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -166,7 +166,6 @@ public:
void notify(int msg, int ext1, int ext2);
static sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
static sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
- static int snoop(short *data, int len, int kind);
status_t invoke(const Parcel& request, Parcel *reply);
status_t setMetadataFilter(const Parcel& filter);
status_t getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 48c04a6..e6f46ce 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -17,7 +17,8 @@
#define LOG_TAG "AudioFlinger"
-//#define LOG_NDEBUG 0
+//
+#define LOG_NDEBUG 0
#include <math.h>
#include <signal.h>
@@ -52,6 +53,7 @@
#endif
#include <media/EffectsFactoryApi.h>
+#include <media/EffectVisualizerApi.h>
// ----------------------------------------------------------------------------
// the sim build doesn't have gettid
@@ -4498,6 +4500,11 @@ status_t AudioFlinger::getEffectDescriptor(effect_uuid_t *pUuid, effect_descript
return EffectGetDescriptor(pUuid, descriptor);
}
+
+// this UUID must match the one defined in media/libeffects/EffectVisualizer.cpp
+static const effect_uuid_t VISUALIZATION_UUID_ =
+ {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+
sp<IEffect> AudioFlinger::createEffect(pid_t pid,
effect_descriptor_t *pDesc,
const sp<IEffectClient>& effectClient,
@@ -4525,6 +4532,15 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
{
Mutex::Autolock _l(mLock);
+ // check recording permission for visualizer
+ if (memcmp(&pDesc->type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0 ||
+ memcmp(&pDesc->uuid, &VISUALIZATION_UUID_, sizeof(effect_uuid_t)) == 0) {
+ if (!recordingAllowed()) {
+ lStatus = PERMISSION_DENIED;
+ goto Exit;
+ }
+ }
+
if (!EffectIsNullUuid(&pDesc->uuid)) {
// if uuid is specified, request effect descriptor
lStatus = EffectGetDescriptor(&pDesc->uuid, &desc);
@@ -5089,7 +5105,7 @@ void AudioFlinger::EffectModule::process()
if (mState != ACTIVE) {
switch (mState) {
case RESET:
- reset();
+ reset_l();
mState = STARTING;
// clear auxiliary effect input buffer for next accumulation
if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
@@ -5097,14 +5113,14 @@ void AudioFlinger::EffectModule::process()
}
return;
case STARTING:
- start();
+ start_l();
mState = ACTIVE;
break;
case STOPPING:
mState = STOPPED;
break;
case STOPPED:
- stop();
+ stop_l();
mState = IDLE;
return;
}
@@ -5132,7 +5148,7 @@ void AudioFlinger::EffectModule::process()
}
}
-void AudioFlinger::EffectModule::reset()
+void AudioFlinger::EffectModule::reset_l()
{
if (mEffectInterface == NULL) {
return;
@@ -5205,6 +5221,7 @@ status_t AudioFlinger::EffectModule::configure()
status_t AudioFlinger::EffectModule::init()
{
+ Mutex::Autolock _l(mLock);
if (mEffectInterface == NULL) {
return NO_INIT;
}
@@ -5217,7 +5234,7 @@ status_t AudioFlinger::EffectModule::init()
return status;
}
-status_t AudioFlinger::EffectModule::start()
+status_t AudioFlinger::EffectModule::start_l()
{
if (mEffectInterface == NULL) {
return NO_INIT;
@@ -5231,7 +5248,7 @@ status_t AudioFlinger::EffectModule::start()
return status;
}
-status_t AudioFlinger::EffectModule::stop()
+status_t AudioFlinger::EffectModule::stop_l()
{
if (mEffectInterface == NULL) {
return NO_INIT;
@@ -5247,7 +5264,8 @@ status_t AudioFlinger::EffectModule::stop()
status_t AudioFlinger::EffectModule::command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData)
{
- LOGV("command(), cmdCode: %d, mEffectInterface: %p", cmdCode, mEffectInterface);
+ Mutex::Autolock _l(mLock);
+// LOGV("command(), cmdCode: %d, mEffectInterface: %p", cmdCode, mEffectInterface);
if (mEffectInterface == NULL) {
return NO_INIT;
@@ -5255,7 +5273,6 @@ status_t AudioFlinger::EffectModule::command(int cmdCode, int cmdSize, void *pCm
status_t status = (*mEffectInterface)->command(mEffectInterface, cmdCode, cmdSize, pCmdData, replySize, pReplyData);
if (cmdCode != EFFECT_CMD_GET_PARAM && status == NO_ERROR) {
int size = (replySize == NULL) ? 0 : *replySize;
- Mutex::Autolock _l(mLock);
for (size_t i = 1; i < mHandles.size(); i++) {
sp<EffectHandle> h = mHandles[i].promote();
if (h != 0) {
@@ -5322,6 +5339,7 @@ bool AudioFlinger::EffectModule::isEnabled()
status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, bool controller)
{
+ Mutex::Autolock _l(mLock);
status_t status = NO_ERROR;
// Send volume indication if EFFECT_FLAG_VOLUME_IND is set and read back altered volume
@@ -5347,6 +5365,7 @@ status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right,
status_t AudioFlinger::EffectModule::setDevice(uint32_t device)
{
+ Mutex::Autolock _l(mLock);
status_t status = NO_ERROR;
if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) {
// convert device bit field from AudioSystem to EffectApi format.
@@ -5366,6 +5385,7 @@ status_t AudioFlinger::EffectModule::setDevice(uint32_t device)
status_t AudioFlinger::EffectModule::setMode(uint32_t mode)
{
+ Mutex::Autolock _l(mLock);
status_t status = NO_ERROR;
if ((mDescriptor.flags & EFFECT_FLAG_AUDIO_MODE_MASK) == EFFECT_FLAG_AUDIO_MODE_IND) {
// convert audio mode from AudioSystem to EffectApi format.
@@ -5586,7 +5606,7 @@ void AudioFlinger::EffectHandle::disconnect()
status_t AudioFlinger::EffectHandle::command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData)
{
- LOGV("command(), cmdCode: %d, mHasControl: %d, mEffect: %p", cmdCode, mHasControl, (mEffect == 0) ? 0 : mEffect.get());
+// LOGV("command(), cmdCode: %d, mHasControl: %d, mEffect: %p", cmdCode, mHasControl, (mEffect == 0) ? 0 : mEffect.get());
// only get parameter command is permitted for applications not controlling the effect
if (!mHasControl && cmdCode != EFFECT_CMD_GET_PARAM) {
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 42dca4c..ec3d7f1 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -916,7 +916,7 @@ private:
void process();
status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData);
- void reset();
+ void reset_l();
status_t configure();
status_t init();
uint32_t state() {
@@ -951,8 +951,8 @@ private:
EffectModule(const EffectModule&);
EffectModule& operator = (const EffectModule&);
- status_t start();
- status_t stop();
+ status_t start_l();
+ status_t stop_l();
// update this table when AudioSystem::audio_devices or audio_device_e (in EffectApi.h) are modified
static const uint32_t sDeviceConvTable[];
diff --git a/media/java/android/media/AudioEffect.java b/media/java/android/media/AudioEffect.java
index b1b7fed..053cc22 100644
--- a/media/java/android/media/AudioEffect.java
+++ b/media/java/android/media/AudioEffect.java
@@ -27,22 +27,25 @@ import java.nio.ByteBuffer;
import java.util.UUID;
/**
- * AudioEffect is the base class for implementing audio effect control in Java applications.
- * Creating an AudioEffect object will create the effect engine in audio framework if no
- * instance of the same effect type exists in the specified audio session.
- * If one exists, this instance will be used. The application creating the AudioEffect object
- * (or a derived class) will either receive control of the effect engine or not depending
- * on the priority parameter. If priority is higher than the priority used by the current
- * effect engine owner, the control will be transfered to the new object. Otherwise
- * control will remain with the previous object. In this case, the new application will be
- * notified of changes in effect engine state or control ownership by the appropiate listener.
- * If the effect is to be applied to a specific AudioTrack or MediaPlayer instance,
- * the application must specify the audio session ID of that instance.
+ * AudioEffect is the base class for implementing audio effect control in Java
+ * applications.
+ * <p>Creating an AudioEffect object will create the effect engine in
+ * audio framework if no instance of the same effect type exists in the
+ * specified audio session. If one exists, this instance will be used.
+ * <p>The application creating the AudioEffect object (or a derived class) will either
+ * receive control of the effect engine or not depending on the priority
+ * parameter. If priority is higher than the priority used by the current effect
+ * engine owner, the control will be transfered to the new object. Otherwise
+ * control will remain with the previous object. In this case, the new
+ * application will be notified of changes in effect engine state or control
+ * ownership by the appropiate listener.
+ * <p>If the effect is to be applied to a specific AudioTrack or MediaPlayer instance,
+ * the application must specify the audio session ID of that instance when calling the AudioEffect
+ * constructor.
*
- * {@hide Pending API council review}
+ * { @hide Pending API council review }
*/
-public class AudioEffect
-{
+public class AudioEffect {
static {
System.loadLibrary("audioeffect_jni");
native_init();
@@ -51,31 +54,60 @@ public class AudioEffect
private final static String TAG = "AudioEffect-JAVA";
/**
- * The following UUIDs define effect types corresponding to standard audio effects
- * whose implementation and interface conform to the OpenSL ES specification.
- * The definitions match the corresponding interface IDs in OpenSLES_IID.h
+ * The following UUIDs define effect types corresponding to standard audio
+ * effects whose implementation and interface conform to the OpenSL ES
+ * specification. The definitions match the corresponding interface IDs in
+ * OpenSLES_IID.h
*/
- public static final UUID EFFECT_TYPE_ENV_REVERB = UUID.fromString("c2e5d5f0-94bd-4763-9cac-4e234d06839e");
- public static final UUID EFFECT_TYPE_PRESET_REVERB = UUID.fromString("47382d60-ddd8-11db-bf3a-0002a5d5c51b");
- public static final UUID EFFECT_TYPE_EQUALIZER = UUID.fromString("0bed4300-ddd6-11db-8f34-0002a5d5c51b");
- public static final UUID EFFECT_TYPE_BASS_BOOST = UUID.fromString("0634f220-ddd4-11db-a0fc-0002a5d5c51b");
- public static final UUID EFFECT_TYPE_VIRTUALIZER = UUID.fromString("37cc2c00-dddd-11db-8577-0002a5d5c51b");
- public static final UUID EFFECT_TYPE_INVALID = UUID.fromString("ec7178ec-e5e1-4432-a3f4-4657e6795210");
+ /**
+ * UUID for environmental reverb effect
+ */
+ public static final UUID EFFECT_TYPE_ENV_REVERB = UUID
+ .fromString("c2e5d5f0-94bd-4763-9cac-4e234d06839e");
+ /**
+ * UUID for preset reverb effect
+ */
+ public static final UUID EFFECT_TYPE_PRESET_REVERB = UUID
+ .fromString("47382d60-ddd8-11db-bf3a-0002a5d5c51b");
+ /**
+ * UUID for equalizer effect
+ */
+ public static final UUID EFFECT_TYPE_EQUALIZER = UUID
+ .fromString("0bed4300-ddd6-11db-8f34-0002a5d5c51b");
+ /**
+ * UUID for bass boost effect
+ */
+ public static final UUID EFFECT_TYPE_BASS_BOOST = UUID
+ .fromString("0634f220-ddd4-11db-a0fc-0002a5d5c51b");
+ /**
+ * UUID for virtualizer effect
+ */
+ public static final UUID EFFECT_TYPE_VIRTUALIZER = UUID
+ .fromString("37cc2c00-dddd-11db-8577-0002a5d5c51b");
/**
- * State of an AudioEffect object that was not successfully initialized upon creation
+ * Null effect UUID. Used when the UUID for effect type of
+ */
+ public static final UUID EFFECT_TYPE_NULL = UUID
+ .fromString("ec7178ec-e5e1-4432-a3f4-4657e6795210");
+
+ /**
+ * State of an AudioEffect object that was not successfully initialized upon
+ * creation
*/
public static final int STATE_UNINITIALIZED = 0;
/**
* State of an AudioEffect object that is ready to be used.
*/
- public static final int STATE_INITIALIZED = 1;
+ public static final int STATE_INITIALIZED = 1;
+ // to keep in sync with
+ // frameworks/base/media/jni/audioeffect/android_media_AudioEffect.cpp
/**
* Event id for engine state change notification.
*/
- protected static final int NATIVE_EVENT_ENABLED_STATUS = 0;
+ protected static final int NATIVE_EVENT_ENABLED_STATUS = 0;
/**
* Event id for engine control ownership change notification.
*/
@@ -85,56 +117,89 @@ public class AudioEffect
*/
protected static final int NATIVE_EVENT_PARAMETER_CHANGED = 2;
+ /**
+ * Successful operation.
+ */
+ public static final int SUCCESS = 0;
+ /**
+ * Unspecified error.
+ */
+ public static final int ERROR = -1;
+ /**
+ * Internal opreation status. Not returned by any method.
+ */
+ public static final int ALREADY_EXISTS = -2;
+ /**
+ * Operation failed due to bad object initialization.
+ */
+ public static final int ERROR_NO_INIT = -3;
+ /**
+ * Operation failed due to bad parameter value.
+ */
+ public static final int ERROR_BAD_VALUE = -4;
+ /**
+ * Operation failed because it was requested in wrong state.
+ */
+ public static final int ERROR_INVALID_OPERATION = -5;
+ /**
+ * Operation failed due to lack of memory.
+ */
+ public static final int ERROR_NO_MEMORY = -6;
+ /**
+ * Operation failed due to dead remote object.
+ */
+ public static final int ERROR_DEAD_OBJECT = -7;
+
+ /**
+ * The effect descriptor contains necessary information to facilitate
+ * effects enumeration:<br>
+ * <ul>
+ * <li>mType: UUID corresponding to the OpenSL ES interface implemented by this effect</li>
+ * <li>mUuid: UUID for this particular implementation</li>
+ * <li>mConnectMode: {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}</li>
+ * <li>mName: human readable effect name</li>
+ * <li>mImplementor: human readable effect implementor name</li>
+ * </ul>
+ */
+ public static class Descriptor {
+
+ public Descriptor() {
+ }
+
+ public Descriptor(String type, String uuid, String connectMode,
+ String name, String implementor) {
+ mType = UUID.fromString(type);
+ mUuid = UUID.fromString(uuid);
+ mConnectMode = connectMode;
+ mName = name;
+ mImplementor = implementor;
+ }
+
+ public UUID mType;
+ public UUID mUuid;
+ public String mConnectMode;
+ public String mName;
+ public String mImplementor;
+ };
+
+ /**
+ * Effect connection mode is insert. Specifying an audio session ID when creating the effect
+ * will insert this effect after all players in the same audio session.
+ */
+ public static final String EFFECT_INSERT = "Insert";
+ /**
+ * Effect connection mode is auxiliary.
+ * <p>Auxiliary effects must be created on session 0 (global output mix). In order for a
+ * MediaPlayer or AudioTrack to be fed into this effect, they must be explicitely attached to
+ * this effect and a send level must be specified.
+ * <p>Use the effect ID returned by {@link #getId()} to designate this particular effect when
+ * attaching it to the MediaPlayer or AudioTrack.
+ */
+ public static final String EFFECT_AUXILIARY = "Auxiliary";
- // to keep in sync with frameworks/base/media/jni/audioeffect/android_media_AudioEffect.cpp
- public static final int SUCCESS = 0;
- public static final int ERROR = -1;
- public static final int ALREADY_EXISTS = -2;
- public static final int NO_INIT = -3;
- public static final int BAD_VALUE = -4;
- public static final int INVALID_OPERATION = -5;
- public static final int NO_MEMORY = -6;
- public static final int DEAD_OBJECT = -7;
-
-
- /**
- * The effect descriptor contains necessary information to facilitate
- * effects enumeration:
- * mType: UUID corresponding to the OpenSL ES interface implemented by this effect
- * mUuid: UUID for this particular implementation
- * mConnectMode: {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}
- * mName: human readable effect name
- * mImplementor: human readable effect implementor name
- */
- public static class Descriptor {
-
- public Descriptor() {
- }
- public Descriptor(String type,
- String uuid,
- String connectMode,
- String name,
- String implementor) {
- mType = UUID.fromString(type);
- mUuid = UUID.fromString(uuid);
- mConnectMode = connectMode;
- mName = name;
- mImplementor = implementor;
- }
-
- public UUID mType;
- public UUID mUuid;
- public String mConnectMode;
- public String mName;
- public String mImplementor;
- };
-
- public static final String EFFECT_INSERT = "Insert";
- public static final String EFFECT_AUXILIARY = "Auxiliary";
-
- //--------------------------------------------------------------------------
+ // --------------------------------------------------------------------------
// Member variables
- //--------------------
+ // --------------------
/**
* Indicates the state of the AudioEffect instance
*/
@@ -159,17 +224,20 @@ public class AudioEffect
/**
* Listener for effect engine state change notifications.
- * @see #setEnableStatusListener(OnEnableStatusChangeListener)
+ *
+ * @see #setEnableStatusListener(OnEnableStatusChangeListener)
*/
protected OnEnableStatusChangeListener mEnableStatusChangeListener = null;
/**
* Listener for effect engine control ownership change notifications.
- * @see #setControlStatusListener(OnControlStatusChangeListener)
+ *
+ * @see #setControlStatusListener(OnControlStatusChangeListener)
*/
protected OnControlStatusChangeListener mControlChangeStatusListener = null;
/**
* Listener for effect engine control ownership change notifications.
- * @see #setParameterListener(OnParameterChangeListener)
+ *
+ * @see #setParameterListener(OnParameterChangeListener)
*/
protected OnParameterChangeListener mParameterChangeListener = null;
/**
@@ -181,32 +249,36 @@ public class AudioEffect
*/
protected NativeEventHandler mNativeEventHandler = null;
-
-
- //--------------------------------------------------------------------------
+ // --------------------------------------------------------------------------
// Constructor, Finalize
- //--------------------
+ // --------------------
/**
* Class constructor.
- * @param type: type of effect engine created. See
- * {@link #EFFECT_TYPE_ENV_REVERB}, {@link #EFFECT_TYPE_EQUALIZER} ...
- * Types corresponding to built-in effects are defined by AudioEffect class.
- * Other types can be specified provided they correspond an existing OpenSL ES
- * interface ID and the corresponsing effect is available on the platform.
- * If an unspecified effect type is requested, the constructor with throw the
- * IllegalArgumentException.
- * @param uuid: unique identifier of a particular effect implementation. Must be
- * specified if the caller wants to use a particular implementation of an effect type.
- * This parameter can be set to null in which case only the type will be used to select
- * the effect.
- * @param priority: the priority level requested by the application for controlling
- * the effect engine. As the same effect engine can be shared by several applications,
- * this parameter indicates how much the requesting application needs control of
- * effect parameters. The normal priority is 0, above normal is a positive number,
- * below normal a negative number.
- * @param audioSession: System wide unique audio session identifier. If audioSession
- * is not 0, the effect will be attached to the MediaPlayer or AudioTrack in the
- * same audio session. Otherwise, the effect will apply to the output mix.
+ *
+ * @param type type of effect engine created. See {@link #EFFECT_TYPE_ENV_REVERB},
+ * {@link #EFFECT_TYPE_EQUALIZER} ... Types corresponding to
+ * built-in effects are defined by AudioEffect class. Other types
+ * can be specified provided they correspond an existing OpenSL
+ * ES interface ID and the corresponsing effect is available on
+ * the platform. If an unspecified effect type is requested, the
+ * constructor with throw the IllegalArgumentException. This
+ * parameter can be set to {@link #EFFECT_TYPE_NULL} in which
+ * case only the uuid will be used to select the effect.
+ * @param uuid unique identifier of a particular effect implementation.
+ * Must be specified if the caller wants to use a particular
+ * implementation of an effect type. This parameter can be set to
+ * {@link #EFFECT_TYPE_NULL} in which case only the type will
+ * be used to select the effect.
+ * @param priority the priority level requested by the application for
+ * controlling the effect engine. As the same effect engine can
+ * be shared by several applications, this parameter indicates
+ * how much the requesting application needs control of effect
+ * parameters. The normal priority is 0, above normal is a
+ * positive number, below normal a negative number.
+ * @param audioSession System wide unique audio session identifier. If audioSession
+ * is not 0, the effect will be attached to the MediaPlayer or
+ * AudioTrack in the same audio session. Otherwise, the effect
+ * will apply to the output mix.
*
* @throws java.lang.IllegalArgumentException
* @throws java.lang.UnsupportedOperationException
@@ -214,22 +286,28 @@ public class AudioEffect
*/
public AudioEffect(UUID type, UUID uuid, int priority, int audioSession)
- throws IllegalArgumentException, UnsupportedOperationException, RuntimeException {
+ throws IllegalArgumentException, UnsupportedOperationException,
+ RuntimeException {
int[] id = new int[1];
Descriptor[] desc = new Descriptor[1];
// native initialization
int initResult = native_setup(new WeakReference<AudioEffect>(this),
- type.toString(), uuid.toString(), priority, audioSession, id, desc);
+ type.toString(), uuid.toString(), priority, audioSession, id,
+ desc);
if (initResult != SUCCESS && initResult != ALREADY_EXISTS) {
- Log.e(TAG, "Error code "+initResult+" when initializing AudioEffect.");
+ Log.e(TAG, "Error code " + initResult
+ + " when initializing AudioEffect.");
switch (initResult) {
- case BAD_VALUE:
- throw (new IllegalArgumentException("Effect type: "+type+ " not supported."));
- case INVALID_OPERATION:
- throw (new UnsupportedOperationException("Effect library not loaded"));
+ case ERROR_BAD_VALUE:
+ throw (new IllegalArgumentException("Effect type: " + type
+ + " not supported."));
+ case ERROR_INVALID_OPERATION:
+ throw (new UnsupportedOperationException(
+ "Effect library not loaded"));
default:
- throw (new RuntimeException("Cannot initialize effect engine for type: "+type+
- "Error: "+ initResult));
+ throw (new RuntimeException(
+ "Cannot initialize effect engine for type: " + type
+ + "Error: " + initResult));
}
}
mId = id[0];
@@ -240,9 +318,9 @@ public class AudioEffect
}
/**
- * Releases the native AudioEffect resources. It is a good practice to release the
- * effect engine when not in use as control can be returned to other applications
- * or the native resources released.
+ * Releases the native AudioEffect resources. It is a good practice to
+ * release the effect engine when not in use as control can be returned to
+ * other applications or the native resources released.
*/
public void release() {
synchronized (mStateLock) {
@@ -258,119 +336,115 @@ public class AudioEffect
/**
* Get the effect descriptor.
- * {@see #Descriptor}.
+ *
+ //TODO when AudioEffect class is unhidden @ see android.media.AudioEffect.Descriptor
* @throws IllegalStateException
*/
- public Descriptor getDescriptor()
- throws IllegalStateException {
+ public Descriptor getDescriptor() throws IllegalStateException {
checkState("getDescriptor()");
return mDescriptor;
}
- //--------------------------------------------------------------------------
+ // --------------------------------------------------------------------------
// Effects Enumeration
- //--------------------
+ // --------------------
/**
* Query all effects available on the platform. Returns an array of
- * {@link #Descriptor} objects
+ //TODO when AudioEffect class is unhidden: {@ link android.media.AudioEffect.Descriptor} objects
*
* @throws IllegalStateException
*/
static public Descriptor[] queryEffects() {
- return (Descriptor[])native_query_effects();
+ return (Descriptor[]) native_query_effects();
}
- //--------------------------------------------------------------------------
+ // --------------------------------------------------------------------------
// Control methods
- //--------------------
-
- /**
- * Enable effect engine.
- * @return {@link #NO_ERROR} in case of success,
- * {@link #INVALID_OPERATION} or {@link #DEAD_OBJECT} in case of failure.
- * @throws IllegalStateException
- */
- public int enable()
- throws IllegalStateException {
- checkState("enable()");
- return native_enable();
- }
+ // --------------------
/**
- * Disable effect engine.
- * @return NO_ERROR in case of success,
- * INVALID_OPERATION or DEAD_OBJECT in case of failure.
+ * Enable or disable effect engine.
+ *
+ * @param enabled the requested enable state
+ * @return {@link #SUCCESS} in case of success, {@link #ERROR_INVALID_OPERATION}
+ * or {@link #ERROR_DEAD_OBJECT} in case of failure.
* @throws IllegalStateException
*/
- public int disable()
- throws IllegalStateException {
- checkState("disable()");
- return native_disable();
+ public int setEnabled(boolean enabled) throws IllegalStateException {
+ checkState("setEnabled()");
+ return native_setEnabled(enabled);
}
/**
* Set effect parameter. The setParameter method is provided in several
- * forms addressing most common parameter formats. This form is the
- * most generic one where the parameter and its value are both specified
- * as an array of bytes. The parameter and value type and length are therefore
- * totally free. For standard effect defined by OpenSL ES, the parameter format
- * and values must match the definitions in the corresponding OpenSL ES interface.
+ * forms addressing most common parameter formats. This form is the most
+ * generic one where the parameter and its value are both specified as an
+ * array of bytes. The parameter and value type and length are therefore
+ * totally free. For standard effect defined by OpenSL ES, the parameter
+ * format and values must match the definitions in the corresponding OpenSL
+ * ES interface.
*
- * @param param: the identifier of the parameter to set
- * @param value: the new value for the specified parameter
- * @return NO_ERROR in case of success,
- * {@link #BAD_VALUE}, {@link #NO_MEMORY}, {@link #INVALID_OPERATION} or {@link DEAD_OBJECT} in case of failure
+ * @param param the identifier of the parameter to set
+ * @param value the new value for the specified parameter
+ * @return {@link #SUCCESS} in case of success, {@link #ERROR_BAD_VALUE},
+ * {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or
+ * {@link #ERROR_DEAD_OBJECT} in case of failure
* @throws IllegalStateException
*/
public int setParameter(byte[] param, byte[] value)
- throws IllegalStateException {
+ throws IllegalStateException {
checkState("setParameter()");
return native_setParameter(param.length, param, value.length, value);
}
/**
* Set effect parameter. The parameter and its value are integers.
- * @see #setParameter(byte[], byte[])
+ *
+ * @see #setParameter(byte[], byte[])
*/
- public int setParameter(int param, int value)
- throws IllegalStateException {
+ public int setParameter(int param, int value) throws IllegalStateException {
byte[] p = intToByteArray(param);
byte[] v = intToByteArray(value);
return setParameter(p, v);
}
/**
- * Set effect parameter. The parameter is an integer and the value is a short integer.
- * @see #setParameter(byte[], byte[])
+ * Set effect parameter. The parameter is an integer and the value is a
+ * short integer.
+ *
+ * @see #setParameter(byte[], byte[])
*/
public int setParameter(int param, short value)
- throws IllegalStateException {
+ throws IllegalStateException {
byte[] p = intToByteArray(param);
byte[] v = shortToByteArray(value);
return setParameter(p, v);
}
/**
- * Set effect parameter. The parameter is an integer and the value is an array of bytes.
- * @see #setParameter(byte[], byte[])
+ * Set effect parameter. The parameter is an integer and the value is an
+ * array of bytes.
+ *
+ * @see #setParameter(byte[], byte[])
*/
public int setParameter(int param, byte[] value)
- throws IllegalStateException {
+ throws IllegalStateException {
byte[] p = intToByteArray(param);
return setParameter(p, value);
}
/**
- * Set effect parameter. The parameter is an array of 1 or 2 integers and the value
- * is also an array of 1 or 2 integers
- * @see #setParameter(byte[], byte[])
+ * Set effect parameter. The parameter is an array of 1 or 2 integers and
+ * the value is also an array of 1 or 2 integers
+ *
+ * @see #setParameter(byte[], byte[])
*/
public int setParameter(int[] param, int[] value)
- throws IllegalStateException {
+ throws IllegalStateException {
if (param.length > 2 || value.length > 2) {
- return BAD_VALUE;
+ return ERROR_BAD_VALUE;
}
byte[] p = intToByteArray(param[0]);
if (param.length > 1) {
@@ -386,14 +460,15 @@ public class AudioEffect
}
/**
- * Set effect parameter. The parameter is an array of 1 or 2 integers and the value
- * is an array of 1 or 2 short integers
- * @see #setParameter(byte[], byte[])
+ * Set effect parameter. The parameter is an array of 1 or 2 integers and
+ * the value is an array of 1 or 2 short integers
+ *
+ * @see #setParameter(byte[], byte[])
*/
public int setParameter(int[] param, short[] value)
- throws IllegalStateException {
+ throws IllegalStateException {
if (param.length > 2 || value.length > 2) {
- return BAD_VALUE;
+ return ERROR_BAD_VALUE;
}
byte[] p = intToByteArray(param[0]);
if (param.length > 1) {
@@ -410,14 +485,15 @@ public class AudioEffect
}
/**
- * Set effect parameter. The parameter is an array of 1 or 2 integers and the value
- * is an array of bytes
- * @see #setParameter(byte[], byte[])
+ * Set effect parameter. The parameter is an array of 1 or 2 integers and
+ * the value is an array of bytes
+ *
+ * @see #setParameter(byte[], byte[])
*/
public int setParameter(int[] param, byte[] value)
- throws IllegalStateException {
+ throws IllegalStateException {
if (param.length > 2) {
- return BAD_VALUE;
+ return ERROR_BAD_VALUE;
}
byte[] p = intToByteArray(param[0]);
if (param.length > 1) {
@@ -429,20 +505,23 @@ public class AudioEffect
/**
* Get effect parameter. The getParameter method is provided in several
- * forms addressing most common parameter formats. This form is the
- * most generic one where the parameter and its value are both specified
- * as an array of bytes. The parameter and value type and length are therefore
+ * forms addressing most common parameter formats. This form is the most
+ * generic one where the parameter and its value are both specified as an
+ * array of bytes. The parameter and value type and length are therefore
* totally free.
- * @param param: the identifier of the parameter to set
- * @param value: the new value for the specified parameter
- * @return NO_ERROR in case of success,
- * {@link #BAD_VALUE}, {@link #NO_MEMORY}, {@link #INVALID_OPERATION} or {@link DEAD_OBJECT} in case of failure
- * When called, value.length indicates the maximum size of the returned parameters value.
- * When returning, value.length is updated with the actual size of the returned value.
+ *
+ * @param param the identifier of the parameter to set
+ * @param value the new value for the specified parameter
+ * @return {@link #SUCCESS} in case of success, {@link #ERROR_BAD_VALUE},
+ * {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or
+ * {@link #ERROR_DEAD_OBJECT} in case of failure When called, value.length
+ * indicates the maximum size of the returned parameters value. When
+ * returning, value.length is updated with the actual size of the
+ * returned value.
* @throws IllegalStateException
*/
public int getParameter(byte[] param, byte[] value)
- throws IllegalStateException {
+ throws IllegalStateException {
checkState("getParameter()");
int[] vSize = new int[1];
vSize[0] = value.length;
@@ -456,25 +535,28 @@ public class AudioEffect
}
/**
- * Get effect parameter. The parameter is an integer and the value is an array of bytes.
- * @see #getParameter(byte[], byte[])
+ * Get effect parameter. The parameter is an integer and the value is an
+ * array of bytes.
+ *
+ * @see #getParameter(byte[], byte[])
*/
public int getParameter(int param, byte[] value)
- throws IllegalStateException {
+ throws IllegalStateException {
byte[] p = intToByteArray(param);
return getParameter(p, value);
}
/**
- * Get effect parameter. The parameter is an integer and the value
- * is an array of 1 or 2 integers
- * @see #getParameter(byte[], byte[])
+ * Get effect parameter. The parameter is an integer and the value is an
+ * array of 1 or 2 integers
+ *
+ * @see #getParameter(byte[], byte[])
*/
public int getParameter(int param, int[] value)
- throws IllegalStateException {
+ throws IllegalStateException {
if (value.length > 2) {
- return BAD_VALUE;
+ return ERROR_BAD_VALUE;
}
byte[] p = intToByteArray(param);
@@ -490,14 +572,15 @@ public class AudioEffect
}
/**
- * Get effect parameter. The parameter is an integer and the value
- * is an array of 1 or 2 short integers
- * @see #getParameter(byte[], byte[])
+ * Get effect parameter. The parameter is an integer and the value is an
+ * array of 1 or 2 short integers
+ *
+ * @see #getParameter(byte[], byte[])
*/
public int getParameter(int param, short[] value)
- throws IllegalStateException {
+ throws IllegalStateException {
if (value.length > 2) {
- return BAD_VALUE;
+ return ERROR_BAD_VALUE;
}
byte[] p = intToByteArray(param);
@@ -513,14 +596,15 @@ public class AudioEffect
}
/**
- * Get effect parameter. The parameter is an array of 1 or 2 integers and the value
- * is also an array of 1 or 2 integers
- * @see #getParameter(byte[], byte[])
+ * Get effect parameter. The parameter is an array of 1 or 2 integers and
+ * the value is also an array of 1 or 2 integers
+ *
+ * @see #getParameter(byte[], byte[])
*/
public int getParameter(int[] param, int[] value)
- throws IllegalStateException {
+ throws IllegalStateException {
if (param.length > 2 || value.length > 2) {
- return BAD_VALUE;
+ return ERROR_BAD_VALUE;
}
byte[] p = intToByteArray(param[0]);
if (param.length > 1) {
@@ -539,14 +623,15 @@ public class AudioEffect
}
/**
- * Get effect parameter. The parameter is an array of 1 or 2 integers and the value
- * is an array of 1 or 2 short integers
- * @see #getParameter(byte[], byte[])
+ * Get effect parameter. The parameter is an array of 1 or 2 integers and
+ * the value is an array of 1 or 2 short integers
+ *
+ * @see #getParameter(byte[], byte[])
*/
public int getParameter(int[] param, short[] value)
- throws IllegalStateException {
+ throws IllegalStateException {
if (param.length > 2 || value.length > 2) {
- return BAD_VALUE;
+ return ERROR_BAD_VALUE;
}
byte[] p = intToByteArray(param[0]);
if (param.length > 1) {
@@ -565,14 +650,15 @@ public class AudioEffect
}
/**
- * Get effect parameter. The parameter is an array of 1 or 2 integers and the value
- * is an array of bytes
- * @see #getParameter(byte[], byte[])
+ * Get effect parameter. The parameter is an array of 1 or 2 integers and
+ * the value is an array of bytes
+ *
+ * @see #getParameter(byte[], byte[])
*/
public int getParameter(int[] param, byte[] value)
- throws IllegalStateException {
+ throws IllegalStateException {
if (param.length > 2) {
- return BAD_VALUE;
+ return ERROR_BAD_VALUE;
}
byte[] p = intToByteArray(param[0]);
if (param.length > 1) {
@@ -583,19 +669,19 @@ public class AudioEffect
return getParameter(p, value);
}
-
/**
- * Send a command to the effect engine. This method is intended to send proprietary
- * commands to a particular effect implementation.
+ * Send a command to the effect engine. This method is intended to send
+ * proprietary commands to a particular effect implementation.
*
*/
public int command(int cmdCode, byte[] command, byte[] reply)
- throws IllegalStateException {
+ throws IllegalStateException {
checkState("command()");
int[] replySize = new int[1];
replySize[0] = reply.length;
- int status = native_command(cmdCode, command.length, command, replySize, reply);
+ int status = native_command(cmdCode, command.length, command,
+ replySize, reply);
if (reply.length > replySize[0]) {
byte[] resizedReply = new byte[replySize[0]];
@@ -605,51 +691,53 @@ public class AudioEffect
return status;
}
- //--------------------------------------------------------------------------
+ // --------------------------------------------------------------------------
// Getters
- //--------------------
+ // --------------------
/**
- * Returns effect unique identifier. This system wide unique identifier
- * can be used to attach this effect to a MediaPlayer or an AudioTrack
- * when the effect is an auxiliary effect (Reverb)
+ * Returns effect unique identifier. This system wide unique identifier can
+ * be used to attach this effect to a MediaPlayer or an AudioTrack when the
+ * effect is an auxiliary effect (Reverb)
+ *
* @return the effect identifier.
* @throws IllegalStateException
*/
- public int getId()
- throws IllegalStateException {
+ public int getId() throws IllegalStateException {
checkState("getId()");
return mId;
}
/**
* Returns effect engine enable state
+ *
* @return true if the effect is enabled, false otherwise.
* @throws IllegalStateException
*/
- public boolean getEnable()
- throws IllegalStateException {
- checkState("getEnable()");
- return native_getEnable();
+ public boolean getEnabled() throws IllegalStateException {
+ checkState("getEnabled()");
+ return native_getEnabled();
}
/**
* Checks if this AudioEffect object is controlling the effect engine.
- * @return true if this instance has control of effect engine, false otherwise.
+ *
+ * @return true if this instance has control of effect engine, false
+ * otherwise.
* @throws IllegalStateException
*/
- public boolean hasControl()
- throws IllegalStateException {
+ public boolean hasControl() throws IllegalStateException {
checkState("hasControl()");
return native_hasControl();
}
- //--------------------------------------------------------------------------
+ // --------------------------------------------------------------------------
// Initialization / configuration
- //--------------------
+ // --------------------
/**
* Sets the listener AudioEffect notifies when the effect engine is enabled
* or disabled.
+ *
* @param listener
*/
public void setEnableStatusListener(OnEnableStatusChangeListener listener) {
@@ -662,8 +750,9 @@ public class AudioEffect
}
/**
- * Sets the listener AudioEffect notifies when the effect engine control
- * is taken or returned.
+ * Sets the listener AudioEffect notifies when the effect engine control is
+ * taken or returned.
+ *
* @param listener
*/
public void setControlStatusListener(OnControlStatusChangeListener listener) {
@@ -677,6 +766,7 @@ public class AudioEffect
/**
* Sets the listener AudioEffect notifies when a parameter is changed.
+ *
* @param listener
*/
public void setParameterListener(OnParameterChangeListener listener) {
@@ -691,7 +781,7 @@ public class AudioEffect
// Convenience method for the creation of the native event handler
// It is called only when a non-null event listener is set.
// precondition:
- // mNativeEventHandler is null
+ // mNativeEventHandler is null
private void createNativeEventHandler() {
Looper looper;
if ((looper = Looper.myLooper()) != null) {
@@ -703,52 +793,62 @@ public class AudioEffect
}
}
- //---------------------------------------------------------
+ // ---------------------------------------------------------
// Interface definitions
- //--------------------
+ // --------------------
/**
- * Interface definition for a callback to be invoked when the
- * effect engine is enabled or disabled.
+ * The OnParameterChangeListener interface defines a method called by the AudioEffect
+ * when a the enabled state of the effect engine was changed by the controlling application.
*/
- public interface OnEnableStatusChangeListener {
+ public interface OnEnableStatusChangeListener {
/**
- * Called on the listener to notify it that the effect engine
- * has been enabled or disabled.
+ * Called on the listener to notify it that the effect engine has been
+ * enabled or disabled.
+ * @param effect the effect on which the interface is registered.
+ * @param enabled new effect state.
*/
void onEnableStatusChange(AudioEffect effect, boolean enabled);
}
/**
- * Interface definition for a callback to be invoked when the
- * effect engine control is taken or returned.
+ * The OnControlStatusChangeListener interface defines a method called by the AudioEffect
+ * when a the control of the effect engine is gained or lost by the application
*/
- public interface OnControlStatusChangeListener {
+ public interface OnControlStatusChangeListener {
/**
- * Called on the listener to notify it that the effect engine
- * control has been taken or returned.
+ * Called on the listener to notify it that the effect engine control
+ * has been taken or returned.
+ * @param effect the effect on which the interface is registered.
+ * @param controlGranted true if the application has been granted control of the effect
+ * engine, false otherwise.
*/
void onControlStatusChange(AudioEffect effect, boolean controlGranted);
}
/**
- * Interface definition for a callback to be invoked when a
- * parameter value has changed.
+ * The OnParameterChangeListener interface defines a method called by the AudioEffect
+ * when a parameter is changed in the effect engine by the controlling application.
*/
- public interface OnParameterChangeListener {
+ public interface OnParameterChangeListener {
/**
* Called on the listener to notify it that a parameter value has changed.
+ * @param effect the effect on which the interface is registered.
+ * @param status status of the set parameter operation.
+ * @param param ID of the modified parameter.
+ * @param value the new parameter value.
*/
- void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value);
+ void onParameterChange(AudioEffect effect, int status, byte[] param,
+ byte[] value);
}
- //---------------------------------------------------------
+ // ---------------------------------------------------------
// Inner classes
- //--------------------
+ // --------------------
/**
- * Helper class to handle the forwarding of native events to the appropriate listeners
+ * Helper class to handle the forwarding of native events to the appropriate
+ * listeners
*/
- private class NativeEventHandler extends Handler
- {
+ private class NativeEventHandler extends Handler {
private AudioEffect mAudioEffect;
public NativeEventHandler(AudioEffect ae, Looper looper) {
@@ -761,14 +861,15 @@ public class AudioEffect
if (mAudioEffect == null) {
return;
}
- switch(msg.what) {
+ switch (msg.what) {
case NATIVE_EVENT_ENABLED_STATUS:
OnEnableStatusChangeListener enableStatusChangeListener = null;
synchronized (mListenerLock) {
enableStatusChangeListener = mAudioEffect.mEnableStatusChangeListener;
}
if (enableStatusChangeListener != null) {
- enableStatusChangeListener.onEnableStatusChange(mAudioEffect, (boolean)(msg.arg1 != 0));
+ enableStatusChangeListener.onEnableStatusChange(
+ mAudioEffect, (boolean) (msg.arg1 != 0));
}
break;
case NATIVE_EVENT_CONTROL_STATUS:
@@ -777,7 +878,8 @@ public class AudioEffect
controlStatusChangeListener = mAudioEffect.mControlChangeStatusListener;
}
if (controlStatusChangeListener != null) {
- controlStatusChangeListener.onControlStatusChange(mAudioEffect, (boolean)(msg.arg1 != 0));
+ controlStatusChangeListener.onControlStatusChange(
+ mAudioEffect, (boolean) (msg.arg1 != 0));
}
break;
case NATIVE_EVENT_PARAMETER_CHANGED:
@@ -786,10 +888,12 @@ public class AudioEffect
parameterChangeListener = mAudioEffect.mParameterChangeListener;
}
if (parameterChangeListener != null) {
- // arg1 contains offset of parameter value from start of byte array
+ // arg1 contains offset of parameter value from start of
+ // byte array
int vOffset = msg.arg1;
- byte[] p = (byte[])msg.obj;
- // See effect_param_t in EffectApi.h for psize and vsize fields offsets
+ byte[] p = (byte[]) msg.obj;
+ // See effect_param_t in EffectApi.h for psize and vsize
+ // fields offsets
int status = byteArrayToInt(p, 0);
int psize = byteArrayToInt(p, 4);
int vsize = byteArrayToInt(p, 8);
@@ -798,90 +902,76 @@ public class AudioEffect
System.arraycopy(p, 12, param, 0, psize);
System.arraycopy(p, vOffset, value, 0, vsize);
- parameterChangeListener.onParameterChange(mAudioEffect, status, param, value);
+ parameterChangeListener.onParameterChange(mAudioEffect,
+ status, param, value);
}
break;
- default:
+ default:
Log.e(TAG, "handleMessage() Unknown event type: " + msg.what);
break;
}
}
}
-
- //---------------------------------------------------------
+ // ---------------------------------------------------------
// Java methods called from the native side
- //--------------------
+ // --------------------
@SuppressWarnings("unused")
- private static void postEventFromNative(Object effect_ref,
- int what, int arg1, int arg2, Object obj) {
- AudioEffect effect = (AudioEffect)((WeakReference)effect_ref).get();
+ private static void postEventFromNative(Object effect_ref, int what,
+ int arg1, int arg2, Object obj) {
+ AudioEffect effect = (AudioEffect) ((WeakReference) effect_ref).get();
if (effect == null) {
return;
}
if (effect.mNativeEventHandler != null) {
- Message m = effect.mNativeEventHandler.obtainMessage(what, arg1, arg2, obj);
+ Message m = effect.mNativeEventHandler.obtainMessage(what, arg1,
+ arg2, obj);
effect.mNativeEventHandler.sendMessage(m);
}
}
-
- //---------------------------------------------------------
+ // ---------------------------------------------------------
// Native methods called from the Java side
- //--------------------
+ // --------------------
private static native final void native_init();
- private native final int native_setup(Object audioeffect_this,
- String type,
- String uuid,
- int priority,
- int audioSession,
- int[] id,
- Object[] desc);
+ private native final int native_setup(Object audioeffect_this, String type,
+ String uuid, int priority, int audioSession, int[] id, Object[] desc);
private native final void native_finalize();
private native final void native_release();
- private native final int native_enable();
+ private native final int native_setEnabled(boolean enabled);
- private native final int native_disable();
-
- private native final boolean native_getEnable();
+ private native final boolean native_getEnabled();
private native final boolean native_hasControl();
- private native final int native_setParameter(int psize,
- byte[] param,
- int vsize,
- byte[] value);
+ private native final int native_setParameter(int psize, byte[] param,
+ int vsize, byte[] value);
- private native final int native_getParameter(int psize,
- byte[] param,
- int[] vsize,
- byte[] value);
+ private native final int native_getParameter(int psize, byte[] param,
+ int[] vsize, byte[] value);
- private native final int native_command(int cmdCode,
- int cmdSize,
- byte[] cmdData,
- int[] repSize,
- byte[] repData);
+ private native final int native_command(int cmdCode, int cmdSize,
+ byte[] cmdData, int[] repSize, byte[] repData);
private static native Object[] native_query_effects();
- //---------------------------------------------------------
+ // ---------------------------------------------------------
// Utility methods
- //------------------
+ // ------------------
- protected void checkState(String methodName)
- throws IllegalStateException {
+ protected void checkState(String methodName) throws IllegalStateException {
synchronized (mStateLock) {
if (mState != STATE_INITIALIZED) {
- throw(new IllegalStateException(methodName+" called on uninitialized AudioEffect."));
+ throw (new IllegalStateException(methodName
+ + " called on uninitialized AudioEffect."));
}
}
}
@@ -890,10 +980,12 @@ public class AudioEffect
switch (status) {
case AudioEffect.SUCCESS:
break;
- case AudioEffect.BAD_VALUE:
- throw (new IllegalArgumentException("AudioEffect: bad parameter value"));
- case AudioEffect.INVALID_OPERATION:
- throw (new UnsupportedOperationException("AudioEffect: invalid parameter operation"));
+ case AudioEffect.ERROR_BAD_VALUE:
+ throw (new IllegalArgumentException(
+ "AudioEffect: bad parameter value"));
+ case AudioEffect.ERROR_INVALID_OPERATION:
+ throw (new UnsupportedOperationException(
+ "AudioEffect: invalid parameter operation"));
default:
throw (new RuntimeException("AudioEffect: set/get parameter error"));
}
@@ -903,6 +995,7 @@ public class AudioEffect
return byteArrayToInt(valueBuf, 0);
}
+
protected int byteArrayToInt(byte[] valueBuf, int offset) {
ByteBuffer converter = ByteBuffer.wrap(valueBuf);
converter.order(ByteOrder.nativeOrder());
@@ -931,12 +1024,12 @@ public class AudioEffect
protected byte[] shortToByteArray(short value) {
ByteBuffer converter = ByteBuffer.allocate(2);
converter.order(ByteOrder.nativeOrder());
- short sValue = (short)value;
+ short sValue = (short) value;
converter.putShort(sValue);
return converter.array();
}
- protected byte[] concatArrays(byte[] ...arrays) {
+ protected byte[] concatArrays(byte[]... arrays) {
int len = 0;
for (byte[] a : arrays) {
len += a.length;
diff --git a/media/java/android/media/Visualizer.java b/media/java/android/media/Visualizer.java
new file mode 100755
index 0000000..cdd3cdf
--- /dev/null
+++ b/media/java/android/media/Visualizer.java
@@ -0,0 +1,510 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+import android.util.Log;
+import java.lang.ref.WeakReference;
+import java.io.IOException;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+/**
+ * The Visualizer class enables application to retrieve part of the currently playing audio for
+ * visualization purpose. It is not an audio recording interface and only returns partial and low
+ * quality audio content. However, to protect privacy of certain audio data (e.g voice mail) the use
+ * of the visualizer requires the permission android.permission.RECORD_AUDIO.
+ * <p>The audio session ID passed to the constructor indicates which audio content should be
+ * visualized:<br>
+ * <ul>
+ * <li>If the session is 0, the audio output mix is visualized</li>
+ * <li>If the session is not 0, the audio from a particular {@link MediaPlayer} or
+ * {@link AudioTrack}
+ * using this audio session is visualized </li>
+ * </ul>
+ * <p>Two types of representation of audio content can be captured: <br>
+ * <ul>
+ * <li>Waveform data: consecutive 8-bit (unsigned) mono samples by using the
+ * {@link #getWaveForm(byte[])} method</li>
+ * <li>Frequency data: 8-bit magnitude FFT by using the {@link #getFft(byte[])} method</li>
+ * </ul>
+ * <p>The length of the capture can be retrieved or specified by calling respectively
+ * {@link #getCaptureSize()} and {@link #setCaptureSize(int)} methods. Note that the size of the FFT
+ * is half of the specified capture size but both sides of the spectrum are returned yielding in a
+ * number of bytes equal to the capture size. The capture size must be a power of 2 in the range
+ * returned by {@link #getCaptureSizeRange()}.
+ * <p>In addition to the polling capture mode described above with {@link #getWaveForm(byte[])} and
+ * {@link #getFft(byte[])} methods, a callback mode is also available by installing a listener by
+ * use of the {@link #setDataCaptureListener(OnDataCaptureListener, int, boolean, boolean)} method.
+ * The rate at which the listener capture method is called as well as the type of data returned is
+ * specified.
+ * <p>Before capturing data, the Visualizer must be enabled by calling the
+ * {@link #setEnabled(boolean)} method.
+ * When data capture is not needed any more, the Visualizer should be disabled.
+ * <p>It is good practice to call the {@link #release()} method when the Visualizer is not used
+ * anymore to free up native resources associated to the Visualizer instance.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class Visualizer {
+
+ static {
+ System.loadLibrary("audioeffect_jni");
+ native_init();
+ }
+
+ private final static String TAG = "Visualizer-JAVA";
+
+ /**
+ * State of a Visualizer object that was not successfully initialized upon creation
+ */
+ public static final int STATE_UNINITIALIZED = 0;
+ /**
+ * State of a Visualizer object that is ready to be used.
+ */
+ public static final int STATE_INITIALIZED = 1;
+ /**
+ * State of a Visualizer object that is active.
+ */
+ public static final int STATE_ENABLED = 2;
+
+ // to keep in sync with frameworks/base/media/jni/audioeffect/android_media_Visualizer.cpp
+ protected static final int NATIVE_EVENT_PCM_CAPTURE = 0;
+ protected static final int NATIVE_EVENT_FFT_CAPTURE = 1;
+
+ // Error codes:
+ /**
+ * Successful operation.
+ */
+ public static final int SUCCESS = 0;
+ /**
+ * Unspecified error.
+ */
+ public static final int ERROR = -1;
+ /**
+ * Internal opreation status. Not returned by any method.
+ */
+ public static final int ALREADY_EXISTS = -2;
+ /**
+ * Operation failed due to bad object initialization.
+ */
+ public static final int ERROR_NO_INIT = -3;
+ /**
+ * Operation failed due to bad parameter value.
+ */
+ public static final int ERROR_BAD_VALUE = -4;
+ /**
+ * Operation failed because it was requested in wrong state.
+ */
+ public static final int ERROR_INVALID_OPERATION = -5;
+ /**
+ * Operation failed due to lack of memory.
+ */
+ public static final int ERROR_NO_MEMORY = -6;
+ /**
+ * Operation failed due to dead remote object.
+ */
+ public static final int ERROR_DEAD_OBJECT = -7;
+
+ //--------------------------------------------------------------------------
+ // Member variables
+ //--------------------
+ /**
+ * Indicates the state of the Visualizer instance
+ */
+ protected int mState = STATE_UNINITIALIZED;
+ /**
+ * Lock to synchronize access to mState
+ */
+ protected final Object mStateLock = new Object();
+ /**
+ * System wide unique Identifier of the visualizer engine used by this Visualizer instance
+ */
+ protected int mId;
+
+ /**
+ * Lock to protect listeners updates against event notifications
+ */
+ protected final Object mListenerLock = new Object();
+ /**
+ * Handler for events coming from the native code
+ */
+ protected NativeEventHandler mNativeEventHandler = null;
+ /**
+ * PCM and FFT capture listener registered by client
+ */
+ protected OnDataCaptureListener mCaptureListener = null;
+
+ // accessed by native methods
+ private int mNativeVisualizer;
+ private int mJniData;
+
+ //--------------------------------------------------------------------------
+ // Constructor, Finalize
+ //--------------------
+ /**
+ * Class constructor.
+ * @param audioSession System wide unique audio session identifier. If audioSession
+ * is not 0, the visualizer will be attached to the MediaPlayer or AudioTrack in the
+ * same audio session. Otherwise, the Visualizer will apply to the output mix.
+ *
+ * @throws java.lang.UnsupportedOperationException
+ * @throws java.lang.RuntimeException
+ */
+
+ public Visualizer(int audioSession)
+ throws UnsupportedOperationException, RuntimeException {
+ int[] id = new int[1];
+
+ synchronized (mStateLock) {
+ mState = STATE_UNINITIALIZED;
+ // native initialization
+ int result = native_setup(new WeakReference<Visualizer>(this), audioSession, id);
+ if (result != SUCCESS && result != ALREADY_EXISTS) {
+ Log.e(TAG, "Error code "+result+" when initializing Visualizer.");
+ switch (result) {
+ case ERROR_INVALID_OPERATION:
+ throw (new UnsupportedOperationException("Effect library not loaded"));
+ default:
+ throw (new RuntimeException("Cannot initialize Visualizer engine, error: "
+ +result));
+ }
+ }
+ mId = id[0];
+ if (native_getEnabled()) {
+ mState = STATE_ENABLED;
+ } else {
+ mState = STATE_INITIALIZED;
+ }
+ }
+ }
+
+ /**
+ * Releases the native Visualizer resources. It is a good practice to release the
+ * visualization engine when not in use.
+ */
+ public void release() {
+ synchronized (mStateLock) {
+ native_release();
+ mState = STATE_UNINITIALIZED;
+ }
+ }
+
+ @Override
+ protected void finalize() {
+ native_finalize();
+ }
+
+ /**
+ * Enable or disable the visualization engine.
+ * @param enabled requested enable state
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+ * @throws IllegalStateException
+ */
+ public int setEnabled(boolean enabled)
+ throws IllegalStateException {
+ synchronized (mStateLock) {
+ if ((enabled && mState != STATE_INITIALIZED) ||
+ (!enabled && mState != STATE_ENABLED)) {
+ throw(new IllegalStateException("setEnabled() called in wrong state: "+mState));
+ }
+ int status = native_setEnabled(enabled);
+ if (status == SUCCESS) {
+ mState = enabled ? STATE_ENABLED : STATE_INITIALIZED;
+ }
+ return status;
+ }
+ }
+
+ /**
+ * Get current activation state of the visualizer.
+ * @return true if the visualizer is active, false otherwise
+ */
+ public boolean getEnabled()
+ {
+ synchronized (mStateLock) {
+ if (mState == STATE_UNINITIALIZED) {
+ throw(new IllegalStateException("getEnabled() called in wrong state: "+mState));
+ }
+ return native_getEnabled();
+ }
+ }
+
+ /**
+ * Returns the capture size range.
+ * @return the mininum capture size is returned in first array element and the maximum in second
+ * array element.
+ */
+ public static native int[] getCaptureSizeRange();
+
+ /**
+ * Returns the maximum capture rate for the callback capture method. This is the maximum value
+ * for the rate parameter of the
+ * {@link #setDataCaptureListener(OnDataCaptureListener, int, boolean, boolean)} method.
+ * @return the maximum capture rate expressed in milliHertz
+ */
+ public static native int getMaxCaptureRate();
+
+ /**
+ * Sets the capture size, i.e. the number of bytes returned by {@link #getWaveForm(byte[])} and
+ * {@link #getFft(byte[])} methods. The capture size must be a power of 2 in the range returned
+ * by {@link #getCaptureSizeRange()}.
+ * This method must not be called when the Visualizer is enabled.
+ * @param size requested capture size
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR_BAD_VALUE} in case of failure.
+ * @throws IllegalStateException
+ */
+ public int setCaptureSize(int size)
+ throws IllegalStateException {
+ synchronized (mStateLock) {
+ if (mState != STATE_INITIALIZED) {
+ throw(new IllegalStateException("setCaptureSize() called in wrong state: "+mState));
+ }
+ return native_setCaptureSize(size);
+ }
+ }
+
+ /**
+ * Returns current capture size.
+ * @return the capture size in bytes.
+ */
+ public int getCaptureSize()
+ throws IllegalStateException {
+ synchronized (mStateLock) {
+ if (mState == STATE_UNINITIALIZED) {
+ throw(new IllegalStateException("getCaptureSize() called in wrong state: "+mState));
+ }
+ return native_getCaptureSize();
+ }
+ }
+
+ /**
+ * Returns the sampling rate of the captured audio.
+ * @return the sampling rate in milliHertz.
+ */
+ public int getSamplingRate()
+ throws IllegalStateException {
+ synchronized (mStateLock) {
+ if (mState == STATE_UNINITIALIZED) {
+ throw(new IllegalStateException("getSamplingRate() called in wrong state: "+mState));
+ }
+ return native_getSamplingRate();
+ }
+ }
+
+ /**
+ * Returns a waveform capture of currently playing audio content. The capture consists in
+ * a number of consecutive 8-bit (unsigned) mono PCM samples equal to the capture size returned
+ * by {@link #getCaptureSize()}.
+ * <p>This method must be called when the Visualizer is enabled.
+ * @param waveform array of bytes where the waveform should be returned
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT}
+ * in case of failure.
+ * @throws IllegalStateException
+ */
+ public int getWaveForm(byte[] waveform)
+ throws IllegalStateException {
+ synchronized (mStateLock) {
+ if (mState != STATE_ENABLED) {
+ throw(new IllegalStateException("getWaveForm() called in wrong state: "+mState));
+ }
+ return native_getWaveForm(waveform);
+ }
+ }
+ /**
+ * Returns a frequency capture of currently playing audio content. The capture is a 8-bit
+ * magnitude FFT. Note that the size of the FFT is half of the specified capture size but both
+ * sides of the spectrum are returned yielding in a number of bytes equal to the capture size.
+ * {@see #getCaptureSize()}.
+ * <p>This method must be called when the Visualizer is enabled.
+ * @param fft array of bytes where the FFT should be returned
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT}
+ * in case of failure.
+ * @throws IllegalStateException
+ */
+ public int getFft(byte[] fft)
+ throws IllegalStateException {
+ synchronized (mStateLock) {
+ if (mState != STATE_ENABLED) {
+ throw(new IllegalStateException("getFft() called in wrong state: "+mState));
+ }
+ return native_getFft(fft);
+ }
+ }
+
+ //---------------------------------------------------------
+ // Interface definitions
+ //--------------------
+ /**
+ * The OnDataCaptureListener interface defines methods called by the Visualizer to periodically
+ * update the audio visualization capture.
+ * The client application can implement this interface and register the listener with the
+ * {@link #setDataCaptureListener(OnDataCaptureListener, int, boolean, boolean)} method.
+ */
+ public interface OnDataCaptureListener {
+ /**
+ * Method called when a new waveform capture is available.
+ * @param visualizer Visualizer object on which the listener is registered.
+ * @param waveform array of bytes containing the waveform representation.
+ * @param samplingRate sampling rate of the audio visualized.
+ */
+ void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate);
+
+ /**
+ * Method called when a new frequency capture is available.
+ * @param visualizer Visualizer object on which the listener is registered.
+ * @param fft array of bytes containing the frequency representation.
+ * @param samplingRate sampling rate of the audio visualized.
+ */
+ void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate);
+ }
+
+ /**
+ * Registers an OnDataCaptureListener interface and specifies the rate at which the capture
+ * should be updated as well as the type of capture requested.
+ * <p>Call this method with a null listener to stop receiving the capture updates.
+ * @param listener OnDataCaptureListener registered
+ * @param rate rate in milliHertz at which the capture should be updated
+ * @param waveform true if a waveform capture is requested: the onWaveFormDataCapture()
+ * method will be called on the OnDataCaptureListener interface.
+ * @param fft true if a frequency capture is requested: the onFftDataCapture() method will be
+ * called on the OnDataCaptureListener interface.
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR_NO_INIT} or {@link #ERROR_BAD_VALUE} in case of failure.
+ */
+ public int setDataCaptureListener(OnDataCaptureListener listener,
+ int rate, boolean waveform, boolean fft) {
+ synchronized (mListenerLock) {
+ mCaptureListener = listener;
+ }
+ if (listener == null) {
+ // make sure capture callback is stopped in native code
+ waveform = false;
+ fft = false;
+ }
+ int status = native_setPeriodicCapture(rate, waveform, fft);
+ if (status == SUCCESS) {
+ if ((listener != null) && (mNativeEventHandler == null)) {
+ Looper looper;
+ if ((looper = Looper.myLooper()) != null) {
+ mNativeEventHandler = new NativeEventHandler(this, looper);
+ } else if ((looper = Looper.getMainLooper()) != null) {
+ mNativeEventHandler = new NativeEventHandler(this, looper);
+ } else {
+ mNativeEventHandler = null;
+ status = ERROR_NO_INIT;
+ }
+ }
+ }
+ return status;
+ }
+
+ /**
+ * Helper class to handle the forwarding of native events to the appropriate listeners
+ */
+ private class NativeEventHandler extends Handler
+ {
+ private Visualizer mVisualizer;
+
+ public NativeEventHandler(Visualizer v, Looper looper) {
+ super(looper);
+ mVisualizer = v;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (mVisualizer == null) {
+ return;
+ }
+ OnDataCaptureListener l = null;
+ synchronized (mListenerLock) {
+ l = mVisualizer.mCaptureListener;
+ }
+
+ if (l != null) {
+ byte[] data = (byte[])msg.obj;
+ int samplingRate = msg.arg1;
+ switch(msg.what) {
+ case NATIVE_EVENT_PCM_CAPTURE:
+ l.onWaveFormDataCapture(mVisualizer, data, samplingRate);
+ break;
+ case NATIVE_EVENT_FFT_CAPTURE:
+ l.onFftDataCapture(mVisualizer, data, samplingRate);
+ break;
+ default:
+ Log.e(TAG,"Unknown native event: "+msg.what);
+ break;
+ }
+ }
+ }
+ }
+
+ //---------------------------------------------------------
+ // Interface definitions
+ //--------------------
+
+ private static native final void native_init();
+
+ private native final int native_setup(Object audioeffect_this,
+ int audioSession,
+ int[] id);
+
+ private native final void native_finalize();
+
+ private native final void native_release();
+
+ private native final int native_setEnabled(boolean enabled);
+
+ private native final boolean native_getEnabled();
+
+ private native final int native_setCaptureSize(int size);
+
+ private native final int native_getCaptureSize();
+
+ private native final int native_getSamplingRate();
+
+ private native final int native_getWaveForm(byte[] waveform);
+
+ private native final int native_getFft(byte[] fft);
+
+ private native final int native_setPeriodicCapture(int rate, boolean waveForm, boolean fft);
+
+ //---------------------------------------------------------
+ // Java methods called from the native side
+ //--------------------
+ @SuppressWarnings("unused")
+ private static void postEventFromNative(Object effect_ref,
+ int what, int arg1, int arg2, Object obj) {
+ Visualizer visu = (Visualizer)((WeakReference)effect_ref).get();
+ if (visu == null) {
+ return;
+ }
+
+ if (visu.mNativeEventHandler != null) {
+ Message m = visu.mNativeEventHandler.obtainMessage(what, arg1, arg2, obj);
+ visu.mNativeEventHandler.sendMessage(m);
+ }
+
+ }
+
+}
+
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index c5250d7..aedb54a 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -681,18 +681,6 @@ android_media_MediaPlayer_native_finalize(JNIEnv *env, jobject thiz)
}
static jint
-android_media_MediaPlayer_snoop(JNIEnv* env, jobject thiz, jobject data, jint kind) {
- jshort* ar = (jshort*)env->GetPrimitiveArrayCritical((jarray)data, 0);
- jsize len = env->GetArrayLength((jarray)data);
- int ret = 0;
- if (ar) {
- ret = MediaPlayer::snoop(ar, len, kind);
- env->ReleasePrimitiveArrayCritical((jarray)data, ar, 0);
- }
- return ret;
-}
-
-static jint
android_media_MediaPlayer_native_suspend_resume(
JNIEnv *env, jobject thiz, jboolean isSuspend) {
LOGV("suspend_resume(%d)", isSuspend);
@@ -757,7 +745,6 @@ static JNINativeMethod gMethods[] = {
{"native_init", "()V", (void *)android_media_MediaPlayer_native_init},
{"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup},
{"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize},
- {"snoop", "([SI)I", (void *)android_media_MediaPlayer_snoop},
{"native_suspend_resume", "(Z)I", (void *)android_media_MediaPlayer_native_suspend_resume},
{"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id},
{"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id},
diff --git a/media/jni/audioeffect/Android.mk b/media/jni/audioeffect/Android.mk
index d03b63b..4c5cf71 100644
--- a/media/jni/audioeffect/Android.mk
+++ b/media/jni/audioeffect/Android.mk
@@ -2,7 +2,8 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- android_media_AudioEffect.cpp
+ android_media_AudioEffect.cpp \
+ android_media_Visualizer.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index 17f2d8f..02474a4 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -455,9 +455,8 @@ static void android_media_AudioEffect_native_release(JNIEnv *env, jobject thiz)
env->SetIntField(thiz, fields.fidJniData, 0);
}
-
static jint
-android_media_AudioEffect_native_enable(JNIEnv *env, jobject thiz)
+android_media_AudioEffect_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
{
// retrieve the AudioEffect object
AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
@@ -469,29 +468,11 @@ android_media_AudioEffect_native_enable(JNIEnv *env, jobject thiz)
return AUDIOEFFECT_ERROR_NO_INIT;
}
- return translateError(lpAudioEffect->enable());
+ return translateError(lpAudioEffect->setEnabled(enabled));
}
-
-static jint
-android_media_AudioEffect_native_disable(JNIEnv *env, jobject thiz)
-{
- // retrieve the AudioEffect object
- AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
- thiz, fields.fidNativeAudioEffect);
-
- if (lpAudioEffect == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "Unable to retrieve AudioEffect pointer for disable()");
- return AUDIOEFFECT_ERROR_NO_INIT;
- }
-
- return translateError(lpAudioEffect->disable());
-}
-
-
static jboolean
-android_media_AudioEffect_native_getEnable(JNIEnv *env, jobject thiz)
+android_media_AudioEffect_native_getEnabled(JNIEnv *env, jobject thiz)
{
// retrieve the AudioEffect object
AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
@@ -503,7 +484,7 @@ android_media_AudioEffect_native_getEnable(JNIEnv *env, jobject thiz)
return false;
}
- return (jboolean)lpAudioEffect->isEnabled();
+ return (jboolean)lpAudioEffect->getEnabled();
}
@@ -516,7 +497,7 @@ android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz)
if (lpAudioEffect == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
- "Unable to retrieve AudioEffect pointer for getEnabled()");
+ "Unable to retrieve AudioEffect pointer for hasControl()");
return false;
}
@@ -817,9 +798,8 @@ static JNINativeMethod gMethods[] = {
(void *)android_media_AudioEffect_native_setup},
{"native_finalize", "()V", (void *)android_media_AudioEffect_native_finalize},
{"native_release", "()V", (void *)android_media_AudioEffect_native_release},
- {"native_enable", "()I", (void *)android_media_AudioEffect_native_enable},
- {"native_disable", "()I", (void *)android_media_AudioEffect_native_disable},
- {"native_getEnable", "()Z", (void *)android_media_AudioEffect_native_getEnable},
+ {"native_setEnabled", "(Z)I", (void *)android_media_AudioEffect_native_setEnabled},
+ {"native_getEnabled", "()Z", (void *)android_media_AudioEffect_native_getEnabled},
{"native_hasControl", "()Z", (void *)android_media_AudioEffect_native_hasControl},
{"native_setParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_setParameter},
{"native_getParameter", "(I[B[I[B)I", (void *)android_media_AudioEffect_native_getParameter},
@@ -830,6 +810,8 @@ static JNINativeMethod gMethods[] = {
// ----------------------------------------------------------------------------
+extern int register_android_media_visualizer(JNIEnv *env);
+
int register_android_media_AudioEffect(JNIEnv *env)
{
return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
@@ -852,6 +834,11 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved)
goto bail;
}
+ if (register_android_media_visualizer(env) < 0) {
+ LOGE("ERROR: Visualizer native registration failed\n");
+ goto bail;
+ }
+
/* success -- return valid version number */
result = JNI_VERSION_1_4;
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
new file mode 100644
index 0000000..31119f8
--- /dev/null
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -0,0 +1,507 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "visualizers-JNI"
+
+#include <utils/Log.h>
+#include <nativehelper/jni.h>
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+#include "media/Visualizer.h"
+
+using namespace android;
+
+#define VISUALIZER_SUCCESS 0
+#define VISUALIZER_ERROR -1
+#define VISUALIZER_ERROR_ALREADY_EXISTS -2
+#define VISUALIZER_ERROR_NO_INIT -3
+#define VISUALIZER_ERROR_BAD_VALUE -4
+#define VISUALIZER_ERROR_INVALID_OPERATION -5
+#define VISUALIZER_ERROR_NO_MEMORY -6
+#define VISUALIZER_ERROR_DEAD_OBJECT -7
+
+#define NATIVE_EVENT_PCM_CAPTURE 0
+#define NATIVE_EVENT_FFT_CAPTURE 1
+
+// ----------------------------------------------------------------------------
+static const char* const kClassPathName = "android/media/Visualizer";
+
+struct fields_t {
+ // these fields provide access from C++ to the...
+ jclass clazzEffect; // Visualizer class
+ jmethodID midPostNativeEvent; // event post callback method
+ jfieldID fidNativeVisualizer; // stores in Java the native Visualizer object
+ jfieldID fidJniData; // stores in Java additional resources used by the native Visualizer
+};
+static fields_t fields;
+
+struct visualizer_callback_cookie {
+ jclass visualizer_class; // Visualizer class
+ jobject visualizer_ref; // Visualizer object instance
+ };
+
+// ----------------------------------------------------------------------------
+class visualizerJniStorage {
+ public:
+ visualizer_callback_cookie mCallbackData;
+
+ visualizerJniStorage() {
+ }
+
+ ~visualizerJniStorage() {
+ }
+
+};
+
+
+static jint translateError(int code) {
+ switch(code) {
+ case NO_ERROR:
+ return VISUALIZER_SUCCESS;
+ case ALREADY_EXISTS:
+ return VISUALIZER_ERROR_ALREADY_EXISTS;
+ case NO_INIT:
+ return VISUALIZER_ERROR_NO_INIT;
+ case BAD_VALUE:
+ return VISUALIZER_ERROR_BAD_VALUE;
+ case INVALID_OPERATION:
+ return VISUALIZER_ERROR_INVALID_OPERATION;
+ case NO_MEMORY:
+ return VISUALIZER_ERROR_NO_MEMORY;
+ case DEAD_OBJECT:
+ return VISUALIZER_ERROR_DEAD_OBJECT;
+ default:
+ return VISUALIZER_ERROR;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static void captureCallback(void* user,
+ uint32_t waveformSize,
+ uint8_t *waveform,
+ uint32_t fftSize,
+ uint8_t *fft,
+ uint32_t samplingrate) {
+
+ int arg1 = 0;
+ int arg2 = 0;
+ size_t size;
+
+ visualizer_callback_cookie *callbackInfo = (visualizer_callback_cookie *)user;
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ LOGV("captureCallback: callbackInfo %p, visualizer_ref %p visualizer_class %p",
+ callbackInfo,
+ callbackInfo->visualizer_ref,
+ callbackInfo->visualizer_class);
+
+ if (!user || !env) {
+ LOGW("captureCallback error user %p, env %p", user, env);
+ return;
+ }
+
+ if (waveformSize != 0 && waveform != NULL) {
+ jbyteArray jArray = env->NewByteArray(waveformSize);
+ if (jArray != NULL) {
+ jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
+ memcpy(nArray, waveform, waveformSize);
+ env->ReleaseByteArrayElements(jArray, nArray, 0);
+ env->CallStaticVoidMethod(
+ callbackInfo->visualizer_class,
+ fields.midPostNativeEvent,
+ callbackInfo->visualizer_ref,
+ NATIVE_EVENT_PCM_CAPTURE,
+ samplingrate,
+ 0,
+ jArray);
+ }
+ }
+
+ if (fftSize != 0 && fft != NULL) {
+ jbyteArray jArray = env->NewByteArray(fftSize);
+ if (jArray != NULL) {
+ jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
+ memcpy(nArray, fft, fftSize);
+ env->ReleaseByteArrayElements(jArray, nArray, 0);
+ env->CallStaticVoidMethod(
+ callbackInfo->visualizer_class,
+ fields.midPostNativeEvent,
+ callbackInfo->visualizer_ref,
+ NATIVE_EVENT_FFT_CAPTURE,
+ samplingrate,
+ 0,
+ jArray);
+ env->DeleteLocalRef(jArray);
+ }
+ }
+
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+}
+
+static Visualizer *getVisualizer(JNIEnv* env, jobject thiz)
+{
+ Visualizer *v = (Visualizer *)env->GetIntField(
+ thiz, fields.fidNativeVisualizer);
+ if (v == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve Visualizer pointer");
+ }
+ return v;
+}
+
+// ----------------------------------------------------------------------------
+// This function gets some field IDs, which in turn causes class initialization.
+// It is called from a static block in Visualizer, which won't run until the
+// first time an instance of this class is used.
+static void
+android_media_visualizer_native_init(JNIEnv *env)
+{
+
+ LOGV("android_media_visualizer_native_init");
+
+ fields.clazzEffect = NULL;
+
+ // Get the Visualizer class
+ jclass clazz = env->FindClass(kClassPathName);
+ if (clazz == NULL) {
+ LOGE("Can't find %s", kClassPathName);
+ return;
+ }
+
+ fields.clazzEffect = (jclass)env->NewGlobalRef(clazz);
+
+ // Get the postEvent method
+ fields.midPostNativeEvent = env->GetStaticMethodID(
+ fields.clazzEffect,
+ "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+ if (fields.midPostNativeEvent == NULL) {
+ LOGE("Can't find Visualizer.%s", "postEventFromNative");
+ return;
+ }
+
+ // Get the variables fields
+ // nativeTrackInJavaObj
+ fields.fidNativeVisualizer = env->GetFieldID(
+ fields.clazzEffect,
+ "mNativeVisualizer", "I");
+ if (fields.fidNativeVisualizer == NULL) {
+ LOGE("Can't find Visualizer.%s", "mNativeVisualizer");
+ return;
+ }
+ // fidJniData;
+ fields.fidJniData = env->GetFieldID(
+ fields.clazzEffect,
+ "mJniData", "I");
+ if (fields.fidJniData == NULL) {
+ LOGE("Can't find Visualizer.%s", "mJniData");
+ return;
+ }
+
+}
+
+
+static jint
+android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
+ jint sessionId, jintArray jId)
+{
+ LOGV("android_media_visualizer_native_setup");
+ visualizerJniStorage* lpJniStorage = NULL;
+ int lStatus = VISUALIZER_ERROR_NO_MEMORY;
+ Visualizer* lpVisualizer = NULL;
+ jint* nId = NULL;
+
+ lpJniStorage = new visualizerJniStorage();
+ if (lpJniStorage == NULL) {
+ LOGE("setup: Error creating JNI Storage");
+ goto setup_failure;
+ }
+
+ lpJniStorage->mCallbackData.visualizer_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
+ // we use a weak reference so the Visualizer object can be garbage collected.
+ lpJniStorage->mCallbackData.visualizer_ref = env->NewGlobalRef(weak_this);
+
+ LOGV("setup: lpJniStorage: %p visualizer_ref %p visualizer_class %p, &mCallbackData %p",
+ lpJniStorage,
+ lpJniStorage->mCallbackData.visualizer_ref,
+ lpJniStorage->mCallbackData.visualizer_class,
+ &lpJniStorage->mCallbackData);
+
+ if (jId) {
+ nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
+ if (nId == NULL) {
+ LOGE("setup: Error retrieving id pointer");
+ lStatus = VISUALIZER_ERROR_BAD_VALUE;
+ goto setup_failure;
+ }
+ } else {
+ LOGE("setup: NULL java array for id pointer");
+ lStatus = VISUALIZER_ERROR_BAD_VALUE;
+ goto setup_failure;
+ }
+
+ // create the native Visualizer object
+ lpVisualizer = new Visualizer(0,
+ NULL,
+ NULL,
+ sessionId);
+ if (lpVisualizer == NULL) {
+ LOGE("Error creating Visualizer");
+ goto setup_failure;
+ }
+
+ lStatus = translateError(lpVisualizer->initCheck());
+ if (lStatus != VISUALIZER_SUCCESS && lStatus != VISUALIZER_ERROR_ALREADY_EXISTS) {
+ LOGE("Visualizer initCheck failed %d", lStatus);
+ goto setup_failure;
+ }
+
+ nId[0] = lpVisualizer->id();
+
+ env->ReleasePrimitiveArrayCritical(jId, nId, 0);
+ nId = NULL;
+
+ env->SetIntField(thiz, fields.fidNativeVisualizer, (int)lpVisualizer);
+
+ env->SetIntField(thiz, fields.fidJniData, (int)lpJniStorage);
+
+ return VISUALIZER_SUCCESS;
+
+ // failures:
+setup_failure:
+
+ if (nId != NULL) {
+ env->ReleasePrimitiveArrayCritical(jId, nId, 0);
+ }
+
+ if (lpVisualizer) {
+ delete lpVisualizer;
+ }
+ env->SetIntField(thiz, fields.fidNativeVisualizer, 0);
+
+ if (lpJniStorage) {
+ delete lpJniStorage;
+ }
+ env->SetIntField(thiz, fields.fidJniData, 0);
+
+ return lStatus;
+}
+
+// ----------------------------------------------------------------------------
+static void android_media_visualizer_native_finalize(JNIEnv *env, jobject thiz) {
+ LOGV("android_media_visualizer_native_finalize jobject: %x\n", (int)thiz);
+
+ // delete the Visualizer object
+ Visualizer* lpVisualizer = (Visualizer *)env->GetIntField(
+ thiz, fields.fidNativeVisualizer);
+ if (lpVisualizer) {
+ LOGV("deleting Visualizer: %x\n", (int)lpVisualizer);
+ delete lpVisualizer;
+ }
+
+ // delete the JNI data
+ visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetIntField(
+ thiz, fields.fidJniData);
+ if (lpJniStorage) {
+ LOGV("deleting pJniStorage: %x\n", (int)lpJniStorage);
+ delete lpJniStorage;
+ }
+}
+
+// ----------------------------------------------------------------------------
+static void android_media_visualizer_native_release(JNIEnv *env, jobject thiz) {
+
+ // do everything a call to finalize would
+ android_media_visualizer_native_finalize(env, thiz);
+ // + reset the native resources in the Java object so any attempt to access
+ // them after a call to release fails.
+ env->SetIntField(thiz, fields.fidNativeVisualizer, 0);
+ env->SetIntField(thiz, fields.fidJniData, 0);
+}
+
+static jint
+android_media_visualizer_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
+{
+ Visualizer* lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == NULL) {
+ return VISUALIZER_ERROR_NO_INIT;
+ }
+
+ return translateError(lpVisualizer->setEnabled(enabled));
+}
+
+static jboolean
+android_media_visualizer_native_getEnabled(JNIEnv *env, jobject thiz)
+{
+ Visualizer* lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == NULL) {
+ return false;
+ }
+
+ return (jboolean)lpVisualizer->getEnabled();
+}
+
+static jintArray
+android_media_visualizer_native_getCaptureSizeRange(JNIEnv *env, jobject thiz)
+{
+ jintArray jRange = env->NewIntArray(2);
+ jint *nRange = env->GetIntArrayElements(jRange, NULL);
+ nRange[0] = Visualizer::getMinCaptureSize();
+ nRange[1] = Visualizer::getMaxCaptureSize();
+ LOGV("getCaptureSizeRange() min %d max %d", nRange[0], nRange[1]);
+ env->ReleaseIntArrayElements(jRange, nRange, 0);
+ return jRange;
+}
+
+static jint
+android_media_visualizer_native_getMaxCaptureRate(JNIEnv *env, jobject thiz)
+{
+ return Visualizer::getMaxCaptureRate();
+}
+
+static jint
+android_media_visualizer_native_setCaptureSize(JNIEnv *env, jobject thiz, jint size)
+{
+ Visualizer* lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == NULL) {
+ return VISUALIZER_ERROR_NO_INIT;
+ }
+
+ return translateError(lpVisualizer->setCaptureSize(size));
+}
+
+static jint
+android_media_visualizer_native_getCaptureSize(JNIEnv *env, jobject thiz)
+{
+ Visualizer* lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == NULL) {
+ return -1;
+ }
+ return lpVisualizer->getCaptureSize();
+}
+
+static jint
+android_media_visualizer_native_getSamplingRate(JNIEnv *env, jobject thiz)
+{
+ Visualizer* lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == NULL) {
+ return -1;
+ }
+ return lpVisualizer->getSamplingRate();
+}
+
+static jint
+android_media_visualizer_native_getWaveForm(JNIEnv *env, jobject thiz, jbyteArray jWaveform)
+{
+ Visualizer* lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == NULL) {
+ return VISUALIZER_ERROR_NO_INIT;
+ }
+
+ jbyte* nWaveform = (jbyte *) env->GetPrimitiveArrayCritical(jWaveform, NULL);
+ if (nWaveform == NULL) {
+ return VISUALIZER_ERROR_NO_MEMORY;
+ }
+ jint status = translateError(lpVisualizer->getWaveForm((uint8_t *)nWaveform));
+
+ env->ReleasePrimitiveArrayCritical(jWaveform, nWaveform, 0);
+
+ return status;
+}
+
+static jint
+android_media_visualizer_native_getFft(JNIEnv *env, jobject thiz, jbyteArray jFft)
+{
+ Visualizer* lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == NULL) {
+ return VISUALIZER_ERROR_NO_INIT;
+ }
+
+ jbyte* nFft = (jbyte *) env->GetPrimitiveArrayCritical(jFft, NULL);
+ if (nFft == NULL) {
+ return VISUALIZER_ERROR_NO_MEMORY;
+ }
+ jint status = translateError(lpVisualizer->getFft((uint8_t *)nFft));
+
+ env->ReleasePrimitiveArrayCritical(jFft, nFft, 0);
+
+ return status;
+}
+
+static jint
+android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean jWaveform, jboolean jFft)
+{
+ Visualizer* lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == NULL) {
+ return VISUALIZER_ERROR_NO_INIT;
+ }
+ visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetIntField(thiz,
+ fields.fidJniData);
+ if (lpJniStorage == NULL) {
+ return VISUALIZER_ERROR_NO_INIT;
+ }
+
+ LOGV("setPeriodicCapture: rate %d, jWaveform %d jFft %d",
+ rate,
+ jWaveform,
+ jFft);
+
+ uint32_t flags = Visualizer::CAPTURE_CALL_JAVA;
+ if (jWaveform) flags |= Visualizer::CAPTURE_WAVEFORM;
+ if (jFft) flags |= Visualizer::CAPTURE_FFT;
+ Visualizer::capture_cbk_t cbk = captureCallback;
+ if (!jWaveform && !jFft) cbk = NULL;
+
+ return translateError(lpVisualizer->setCaptureCallBack(cbk,
+ &lpJniStorage->mCallbackData,
+ flags,
+ rate));
+}
+
+// ----------------------------------------------------------------------------
+
+// Dalvik VM type signatures
+static JNINativeMethod gMethods[] = {
+ {"native_init", "()V", (void *)android_media_visualizer_native_init},
+ {"native_setup", "(Ljava/lang/Object;I[I)I",
+ (void *)android_media_visualizer_native_setup},
+ {"native_finalize", "()V", (void *)android_media_visualizer_native_finalize},
+ {"native_release", "()V", (void *)android_media_visualizer_native_release},
+ {"native_setEnabled", "(Z)I", (void *)android_media_visualizer_native_setEnabled},
+ {"native_getEnabled", "()Z", (void *)android_media_visualizer_native_getEnabled},
+ {"getCaptureSizeRange", "()[I", (void *)android_media_visualizer_native_getCaptureSizeRange},
+ {"getMaxCaptureRate", "()I", (void *)android_media_visualizer_native_getMaxCaptureRate},
+ {"native_setCaptureSize", "(I)I", (void *)android_media_visualizer_native_setCaptureSize},
+ {"native_getCaptureSize", "()I", (void *)android_media_visualizer_native_getCaptureSize},
+ {"native_getSamplingRate", "()I", (void *)android_media_visualizer_native_getSamplingRate},
+ {"native_getWaveForm", "([B)I", (void *)android_media_visualizer_native_getWaveForm},
+ {"native_getFft", "([B)I", (void *)android_media_visualizer_native_getFft},
+ {"native_setPeriodicCapture","(IZZ)I",(void *)android_media_setPeriodicCapture},
+};
+
+// ----------------------------------------------------------------------------
+
+int register_android_media_visualizer(JNIEnv *env)
+{
+ return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
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);