am 34161132: am 7070b365: Added support for auxiliary audio effects to AudioTrack and MediaPlayer.

Merge commit '34161132030254bac7dd64c9713832e2f961a061'

* commit '34161132030254bac7dd64c9713832e2f961a061':
  Added support for auxiliary audio effects to AudioTrack and MediaPlayer.
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index ce43e73..c559670 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -360,6 +360,7 @@
     if (lpTrack == NULL ) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for start()");
+        return;
     }
 
     lpTrack->start();
@@ -375,6 +376,7 @@
     if (lpTrack == NULL ) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for stop()");
+        return;
     }
 
     lpTrack->stop();
@@ -390,6 +392,7 @@
     if (lpTrack == NULL ) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for pause()");
+        return;
     }
 
     lpTrack->pause();
@@ -405,6 +408,7 @@
     if (lpTrack == NULL ) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for flush()");
+        return;
     }
 
     lpTrack->flush();
@@ -419,6 +423,7 @@
     if (lpTrack == NULL ) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for setVolume()");
+        return;
     }
 
     lpTrack->setVolume(leftVol, rightVol);
@@ -515,6 +520,7 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for write()");
+        return 0;
     }
 
     // get the pointer for the audio data from the java array
@@ -801,6 +807,36 @@
     return minBuffSize;
 }
 
+// ----------------------------------------------------------------------------
+static void
+android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )
+{
+    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+        thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+    if (lpTrack == NULL ) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");
+        return;
+    }
+
+    lpTrack->setAuxEffectSendLevel(level);
+}
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_attachAuxEffect(JNIEnv *env,  jobject thiz,
+        jint effectId) {
+
+    AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+                thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+
+    if (lpTrack) {
+        return android_media_translateErrorCode( lpTrack->attachAuxEffect(effectId) );
+    } else {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for attachAuxEffect()");
+        return AUDIOTRACK_ERROR;
+    }
+}
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
@@ -837,6 +873,10 @@
                              "(I)I",      (void *)android_media_AudioTrack_get_output_sample_rate},
     {"native_get_min_buff_size",
                              "(III)I",   (void *)android_media_AudioTrack_get_min_buff_size},
+    {"native_setAuxEffectSendLevel",
+                             "(F)V",     (void *)android_media_AudioTrack_setAuxEffectSendLevel},
+    {"native_attachAuxEffect",
+                             "(I)I",     (void *)android_media_AudioTrack_attachAuxEffect},
 };
 
 
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index ef537f4..4475d4a 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -261,8 +261,8 @@
     /* set the send level for this track. An auxiliary effect should be attached
      * to the track with attachEffect(). Level must be <= 1.0.
      */
-            status_t    setSendLevel(float level);
-            void        getSendLevel(float* level);
+            status_t    setAuxEffectSendLevel(float level);
+            void        getAuxEffectSendLevel(float* level);
 
     /* set sample rate for this track, mostly used for games' sound effects
      */
@@ -479,6 +479,7 @@
     uint32_t                mUpdatePeriod;
     uint32_t                mFlags;
     int                     mSessionId;
+    int                     mAuxEffectId;
 };
 
 
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index 2619691..af9a7ed 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -48,6 +48,8 @@
     virtual status_t        setVolume(float leftVolume, float rightVolume) = 0;
     virtual status_t        suspend() = 0;
     virtual status_t        resume() = 0;
+    virtual status_t        setAuxEffectSendLevel(float level) = 0;
+    virtual status_t        attachAuxEffect(int effectId) = 0;
 
     // Invoke a generic method on the player by using opaque parcels
     // for the request and reply.
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 4963f73..207191d 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -173,6 +173,8 @@
             status_t        resume();
             status_t        setAudioSessionId(int sessionId);
             int             getAudioSessionId();
+            status_t        setAuxEffectSendLevel(float level);
+            status_t        attachAuxEffect(int effectId);
 private:
             void            clear_l();
             status_t        seekTo_l(int msec);
@@ -200,6 +202,7 @@
     int                         mVideoWidth;
     int                         mVideoHeight;
     int                         mAudioSessionId;
+    float                       mSendLevel;
 };
 
 }; // namespace android
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 079c41f..6360541 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -963,6 +963,65 @@
         return native_reload_static();
     }
 
+    //--------------------------------------------------------------------------
+    // Audio effects management
+    //--------------------
+
+    /**
+     * Attaches an auxiliary effect to the audio track. A typical auxiliary effect is a
+     * reverberation effect which can be applied on any sound source that directs a certain
+     * amount of its energy to this effect. This amount is defined by setAuxEffectSendLevel().
+     * {@see #setAuxEffectSendLevel(float)}.
+     // TODO when AudioEffect are unhidden
+     * <p>After creating an auxiliary effect (e.g. {_at_link android.media.EnvironmentalReverb}),
+     * retrieve its ID with {_at_link android.media.AudioEffect#getId()} and use it when calling
+     * this method to attach the audio track to the effect.
+     * <p>To detach the effect from the audio track, call this method with a null effect id.
+     *
+     * @param effectId system wide unique id of the effect to attach
+     * @return error code or success, see {@link #SUCCESS},
+     *    {@link #ERROR_INVALID_OPERATION}, {@link #ERROR_BAD_VALUE}
+     // FIXME: unhide.
+     * @hide
+     */
+    public int attachAuxEffect(int effectId) {
+        if (mState != STATE_INITIALIZED) {
+            return ERROR_INVALID_OPERATION;
+        }
+        return native_attachAuxEffect(effectId);
+    }
+
+    /**
+     * Sets the send level of the audio track to the attached auxiliary effect
+     * {@see #attachAuxEffect(int)}. The level value range is 0 to 1.0.
+     * <p>By default the send level is 0, so even if an effect is attached to the player
+     * this method must be called for the effect to be applied.
+     * <p>Note that the passed level value is a raw scalar. UI controls should be scaled
+     * logarithmically: the gain applied by audio framework ranges from -72dB to 0dB,
+     * so an appropriate conversion from linear UI input x to level is:
+     * x == 0 -> level = 0
+     * 0 < x <= R -> level = 10^(72*(x-R)/20/R)
+     *
+     * @param level send level scalar
+     * @return error code or success, see {@link #SUCCESS},
+     *    {@link #ERROR_INVALID_OPERATION}
+     // FIXME: unhide.
+     * @hide
+     */
+    public int setAuxEffectSendLevel(float level) {
+        if (mState != STATE_INITIALIZED) {
+            return ERROR_INVALID_OPERATION;
+        }
+        // clamp the level
+        if (level < getMinVolume()) {
+            level = getMinVolume();
+        }
+        if (level > getMaxVolume()) {
+            level = getMaxVolume();
+        }
+        native_setAuxEffectSendLevel(level);
+        return SUCCESS;
+    }
 
     //---------------------------------------------------------
     // Interface definitions
@@ -1123,6 +1182,9 @@
 
     private native final int native_get_session_id();
 
+    private native final int native_attachAuxEffect(int effectId);
+    private native final void native_setAuxEffectSendLevel(float level);
+
     //---------------------------------------------------------
     // Utility methods
     //------------------
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 8caa07a..e1f95b2 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -423,7 +423,7 @@
  *     <td>Successful invoke of this method in a valid state transfers the
  *         object to the <em>Stopped</em> state. Calling this method in an
  *         invalid state transfers the object to the <em>Error</em> state.</p></td></tr>
-  * <tr><td>setAudioSessionId </p></td>
+ * <tr><td>setAudioSessionId </p></td>
  *     <td>{Idle} </p></td>
  *     <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted,
  *          Error} </p></td>
@@ -434,6 +434,15 @@
  *     <td>{} </p></td>
  *     <td>This method can be called in any state and calling it does not change
  *         the object state. </p></td></tr>
+ * <tr><td>attachAuxEffect </p></td>
+ *     <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted} </p></td>
+ *     <td>{Idle, Error} </p></td>
+ *     <td>This method must be called after setDataSource.
+ *     Calling it does not change the object state. </p></td></tr>
+ * <tr><td>setAuxEffectSendLevel </p></td>
+ *     <td>any</p></td>
+ *     <td>{} </p></td>
+ *     <td>Calling this method does not change the object state. </p></td></tr>
  *
  * </table>
  *
@@ -1187,7 +1196,7 @@
      * @throws IllegalStateException if it is called in an invalid state
      *
      // FIXME: unhide.
-     // FIXME: link to AudioEffect class when public.
+     // TODO when AudioEffect is unhidden
      * @hide
      */
     public native void setAudioSessionId(int sessionId)  throws IllegalArgumentException, IllegalStateException;
@@ -1203,6 +1212,41 @@
     public native int getAudioSessionId();
 
     /**
+     * Attaches an auxiliary effect to the player. A typical auxiliary effect is a reverberation
+     * effect which can be applied on any sound source that directs a certain amount of its
+     * energy to this effect. This amount is defined by setAuxEffectSendLevel().
+     * {@see #setAuxEffectSendLevel(float)}.
+     // TODO when AudioEffect is unhidden
+     * <p>After creating an auxiliary effect (e.g. {_at_link android.media.EnvironmentalReverb}),
+     * retrieve its ID with {_at_link android.media.AudioEffect#getId()} and use it when calling
+     * this method to attach the player to the effect.
+     * <p>To detach the effect from the player, call this method with a null effect id.
+     * <p>This method must be called after one of the overloaded <code> setDataSource </code>
+     * methods.
+     *
+     * @param effectId system wide unique id of the effect to attach
+     // FIXME: unhide.
+     * @hide
+     */
+    public native void attachAuxEffect(int effectId);
+
+    /**
+     * Sets the send level of the player to the attached auxiliary effect
+     * {@see #attachAuxEffect(int)}. The level value range is 0 to 1.0.
+     * <p>By default the send level is 0, so even if an effect is attached to the player
+     * this method must be called for the effect to be applied.
+     * <p>Note that the passed level value is a raw scalar. UI controls should be scaled
+     * logarithmically: the gain applied by audio framework ranges from -72dB to 0dB,
+     * so an appropriate conversion from linear UI input x to level is:
+     * x == 0 -> level = 0
+     * 0 < x <= R -> level = 10^(72*(x-R)/20/R)
+     * @param level send level scalar
+     // FIXME: unhide.
+     * @hide
+     */
+    public native void setAuxEffectSendLevel(float level);
+
+    /**
      * @param request Parcel destinated to the media player. The
      *                Interface token must be set to the IMediaPlayer
      *                one to be routed correctly through the system.
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 5c2ec00..6710db0 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -714,6 +714,28 @@
     return mp->getAudioSessionId();
 }
 
+static void
+android_media_MediaPlayer_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level)
+{
+    LOGV("setAuxEffectSendLevel: level %f", level);
+    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+    if (mp == NULL ) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+    process_media_player_call( env, thiz, mp->setAuxEffectSendLevel(level), NULL, NULL );
+}
+
+static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env,  jobject thiz, jint effectId) {
+    LOGV("attachAuxEffect(): %d", sessionId);
+    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+    if (mp == NULL ) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+    process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL );
+}
+
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
@@ -748,6 +770,8 @@
     {"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},
+    {"setAuxEffectSendLevel", "(F)V",                           (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
+    {"attachAuxEffect",     "(I)V",                             (void *)android_media_MediaPlayer_attachAuxEffect},
 };
 
 static const char* const kClassPathName = "android/media/MediaPlayer";
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 0f2093a..890786e 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -209,6 +209,7 @@
     mFrameCount = frameCount;
     mNotificationFramesReq = notificationFrames;
     mSessionId = sessionId;
+    mAuxEffectId = 0;
 
     // create the IAudioTrack
     status_t status = createTrack(streamType, sampleRate, format, channelCount,
@@ -458,8 +459,9 @@
     }
 }
 
-status_t AudioTrack::setSendLevel(float level)
+status_t AudioTrack::setAuxEffectSendLevel(float level)
 {
+    LOGV("setAuxEffectSendLevel(%f)", level);
     if (level > 1.0f) {
         return BAD_VALUE;
     }
@@ -471,7 +473,7 @@
     return NO_ERROR;
 }
 
-void AudioTrack::getSendLevel(float* level)
+void AudioTrack::getAuxEffectSendLevel(float* level)
 {
     if (level != NULL) {
         *level  = mSendLevel;
@@ -637,7 +639,12 @@
 
 status_t AudioTrack::attachAuxEffect(int effectId)
 {
-    return mAudioTrack->attachAuxEffect(effectId);
+    LOGV("attachAuxEffect(%d)", effectId);
+    status_t status = mAudioTrack->attachAuxEffect(effectId);
+    if (status == NO_ERROR) {
+        mAuxEffectId = effectId;
+    }
+    return status;
 }
 
 // -------------------------------------------------------------------------
@@ -752,6 +759,7 @@
 
     mCblk->volumeLR = (uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) | uint16_t(mVolume[LEFT] * 0x1000);
     mCblk->sendLevel = uint16_t(mSendLevel * 0x1000);
+    mAudioTrack->attachAuxEffect(mAuxEffectId);
     mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
     mCblk->waitTimeMs = 0;
     mRemainingFrames = mNotificationFramesAct;
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index ed792b3..0f55b19d 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -45,6 +45,8 @@
     GET_METADATA,
     SUSPEND,
     RESUME,
+    SET_AUX_EFFECT_SEND_LEVEL,
+    ATTACH_AUX_EFFECT
 };
 
 class BpMediaPlayer: public BpInterface<IMediaPlayer>
@@ -221,6 +223,24 @@
 
         return reply.readInt32();
     }
+
+    status_t setAuxEffectSendLevel(float level)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        data.writeFloat(level);
+        remote()->transact(SET_AUX_EFFECT_SEND_LEVEL, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t attachAuxEffect(int effectId)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        data.writeInt32(effectId);
+        remote()->transact(ATTACH_AUX_EFFECT, data, &reply);
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
@@ -339,6 +359,16 @@
             reply->setDataPosition(0);
             return NO_ERROR;
         } break;
+        case SET_AUX_EFFECT_SEND_LEVEL: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            reply->writeInt32(setAuxEffectSendLevel(data.readFloat()));
+            return NO_ERROR;
+        } break;
+        case ATTACH_AUX_EFFECT: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            reply->writeInt32(attachAuxEffect(data.readInt32()));
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index b43f75f..1c99ae5 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -270,6 +270,7 @@
                     MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
         mPlayer->setLooping(mLoop);
         mPlayer->setVolume(mLeftVolume, mRightVolume);
+        mPlayer->setAuxEffectSendLevel(mSendLevel);
         mCurrentState = MEDIA_PLAYER_STARTED;
         status_t ret = mPlayer->start();
         if (ret != NO_ERROR) {
@@ -523,6 +524,31 @@
     return mAudioSessionId;
 }
 
+status_t MediaPlayer::setAuxEffectSendLevel(float level)
+{
+    LOGV("MediaPlayer::setAuxEffectSendLevel(%f)", level);
+    Mutex::Autolock _l(mLock);
+    mSendLevel = level;
+    if (mPlayer != 0) {
+        return mPlayer->setAuxEffectSendLevel(level);
+    }
+    return OK;
+}
+
+status_t MediaPlayer::attachAuxEffect(int effectId)
+{
+    LOGV("MediaPlayer::attachAuxEffect(%d)", effectId);
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == 0 ||
+        (mCurrentState & MEDIA_PLAYER_IDLE) ||
+        (mCurrentState == MEDIA_PLAYER_STATE_ERROR )) {
+        LOGE("attachAuxEffect called in state %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    return mPlayer->attachAuxEffect(effectId);
+}
+
 void MediaPlayer::notify(int msg, int ext1, int ext2)
 {
     LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 5401ec0..b5972e7 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -329,6 +329,10 @@
     snprintf(buffer, 255, "  msec per frame(%f), latency (%d)\n",
             mMsecsPerFrame, mLatency);
     result.append(buffer);
+    snprintf(buffer, 255, "  aux effect id(%d), send level (%f)\n",
+            mAuxEffectId, mSendLevel);
+    result.append(buffer);
+
     ::write(fd, result.string(), result.size());
     if (mTrack != 0) {
         mTrack->dump(fd, args);
@@ -1093,6 +1097,21 @@
     return NO_ERROR;
 }
 
+status_t MediaPlayerService::Client::setAuxEffectSendLevel(float level)
+{
+    LOGV("[%d] setAuxEffectSendLevel(%f)", mConnId, level);
+    Mutex::Autolock l(mLock);
+    if (mAudioOutput != 0) return mAudioOutput->setAuxEffectSendLevel(level);
+    return NO_ERROR;
+}
+
+status_t MediaPlayerService::Client::attachAuxEffect(int effectId)
+{
+    LOGV("[%d] attachAuxEffect(%d)", mConnId, effectId);
+    Mutex::Autolock l(mLock);
+    if (mAudioOutput != 0) return mAudioOutput->attachAuxEffect(effectId);
+    return NO_ERROR;
+}
 
 void MediaPlayerService::Client::notify(void* cookie, int msg, int ext1, int ext2)
 {
@@ -1285,6 +1304,8 @@
     mRightVolume = 1.0;
     mLatency = 0;
     mMsecsPerFrame = 0;
+    mAuxEffectId = 0;
+    mSendLevel = 0.0;
     setMinBufferCount();
 }
 
@@ -1417,10 +1438,13 @@
 
     LOGV("setVolume");
     t->setVolume(mLeftVolume, mRightVolume);
+
     mMsecsPerFrame = 1.e3 / (float) sampleRate;
     mLatency = t->latency();
     mTrack = t;
-    return NO_ERROR;
+
+    t->setAuxEffectSendLevel(mSendLevel);
+    return t->attachAuxEffect(mAuxEffectId);;
 }
 
 void MediaPlayerService::AudioOutput::start()
@@ -1428,6 +1452,7 @@
     LOGV("start");
     if (mTrack) {
         mTrack->setVolume(mLeftVolume, mRightVolume);
+        mTrack->setAuxEffectSendLevel(mSendLevel);
         mTrack->start();
     }
 }
@@ -1481,6 +1506,26 @@
     }
 }
 
+status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level)
+{
+    LOGV("setAuxEffectSendLevel(%f)", level);
+    mSendLevel = level;
+    if (mTrack) {
+        return mTrack->setAuxEffectSendLevel(level);
+    }
+    return NO_ERROR;
+}
+
+status_t MediaPlayerService::AudioOutput::attachAuxEffect(int effectId)
+{
+    LOGV("attachAuxEffect(%d)", effectId);
+    mAuxEffectId = effectId;
+    if (mTrack) {
+        return mTrack->attachAuxEffect(effectId);
+    }
+    return NO_ERROR;
+}
+
 // static
 void MediaPlayerService::AudioOutput::CallbackWrapper(
         int event, void *cookie, void *info) {
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 39f525e..a967ee2 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -91,6 +91,8 @@
         virtual void            close();
                 void            setAudioStreamType(int streamType) { mStreamType = streamType; }
                 void            setVolume(float left, float right);
+                status_t        setAuxEffectSendLevel(float level);
+                status_t        attachAuxEffect(int effectId);
         virtual status_t        dump(int fd, const Vector<String16>& args) const;
 
         static bool             isOnEmulator();
@@ -109,7 +111,8 @@
         float                   mMsecsPerFrame;
         uint32_t                mLatency;
         int                     mSessionId;
-
+        float                   mSendLevel;
+        int                     mAuxEffectId;
         static bool             mIsOnEmulator;
         static int              mMinBufferCount;  // 12 for emulator; otherwise 4
 
@@ -221,6 +224,8 @@
                                             Parcel *reply);
         virtual status_t        suspend();
         virtual status_t        resume();
+        virtual status_t        setAuxEffectSendLevel(float level);
+        virtual status_t        attachAuxEffect(int effectId);
 
         sp<MediaPlayerBase>     createPlayer(player_type playerType);