diff options
author | Eric Laurent <elaurent@google.com> | 2010-07-21 09:49:27 -0700 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2010-07-21 09:49:27 -0700 |
commit | 34161132030254bac7dd64c9713832e2f961a061 (patch) | |
tree | b52219e904ce95b10dc8a2d76ec18faa5078094e /media | |
parent | 42ef77f3603ae54990d6718db79afae61e91dc61 (diff) | |
parent | 7070b36549d511d6627538c73dfbab23fbae5b43 (diff) | |
download | frameworks_base-34161132030254bac7dd64c9713832e2f961a061.zip frameworks_base-34161132030254bac7dd64c9713832e2f961a061.tar.gz frameworks_base-34161132030254bac7dd64c9713832e2f961a061.tar.bz2 |
am 7070b365: Added support for auxiliary audio effects to AudioTrack and MediaPlayer.
Merge commit '7070b36549d511d6627538c73dfbab23fbae5b43' into gingerbread-plus-aosp
* commit '7070b36549d511d6627538c73dfbab23fbae5b43':
Added support for auxiliary audio effects to AudioTrack and MediaPlayer.
Diffstat (limited to 'media')
-rw-r--r-- | media/java/android/media/AudioTrack.java | 62 | ||||
-rw-r--r-- | media/java/android/media/MediaPlayer.java | 48 | ||||
-rw-r--r-- | media/jni/android_media_MediaPlayer.cpp | 24 | ||||
-rw-r--r-- | media/libmedia/AudioTrack.cpp | 14 | ||||
-rw-r--r-- | media/libmedia/IMediaPlayer.cpp | 30 | ||||
-rw-r--r-- | media/libmedia/mediaplayer.cpp | 26 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.cpp | 47 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.h | 7 |
8 files changed, 251 insertions, 7 deletions
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 @@ public class AudioTrack 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 @@ public class AudioTrack 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 @@ import java.lang.ref.WeakReference; * <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 @@ import java.lang.ref.WeakReference; * <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 @@ public class MediaPlayer * @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 class MediaPlayer 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 aedb54a..474a174 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -714,6 +714,28 @@ static jint android_media_MediaPlayer_get_audio_session_id(JNIEnv *env, jobject 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 @@ static JNINativeMethod gMethods[] = { {"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 @@ status_t AudioTrack::set( mFrameCount = frameCount; mNotificationFramesReq = notificationFrames; mSessionId = sessionId; + mAuxEffectId = 0; // create the IAudioTrack status_t status = createTrack(streamType, sampleRate, format, channelCount, @@ -458,8 +459,9 @@ void AudioTrack::getVolume(float* left, float* right) } } -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 @@ status_t AudioTrack::setSendLevel(float level) return NO_ERROR; } -void AudioTrack::getSendLevel(float* level) +void AudioTrack::getAuxEffectSendLevel(float* level) { if (level != NULL) { *level = mSendLevel; @@ -637,7 +639,12 @@ int AudioTrack::getSessionId() 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 @@ status_t AudioTrack::createTrack( 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 @@ enum { GET_METADATA, SUSPEND, RESUME, + SET_AUX_EFFECT_SEND_LEVEL, + ATTACH_AUX_EFFECT }; class BpMediaPlayer: public BpInterface<IMediaPlayer> @@ -221,6 +223,24 @@ public: 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 @@ status_t BnMediaPlayer::onTransact( 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 @@ status_t MediaPlayer::start() 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 @@ int MediaPlayer::getAudioSessionId() 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 @@ status_t MediaPlayerService::AudioOutput::dump(int fd, const Vector<String16>& a 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 @@ status_t MediaPlayerService::Client::setVolume(float leftVolume, float rightVolu 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 @@ MediaPlayerService::AudioOutput::AudioOutput(int sessionId) mRightVolume = 1.0; mLatency = 0; mMsecsPerFrame = 0; + mAuxEffectId = 0; + mSendLevel = 0.0; setMinBufferCount(); } @@ -1417,10 +1438,13 @@ status_t MediaPlayerService::AudioOutput::open( 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 @@ void MediaPlayerService::AudioOutput::start() LOGV("start"); if (mTrack) { mTrack->setVolume(mLeftVolume, mRightVolume); + mTrack->setAuxEffectSendLevel(mSendLevel); mTrack->start(); } } @@ -1481,6 +1506,26 @@ void MediaPlayerService::AudioOutput::setVolume(float left, float right) } } +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 @@ class MediaPlayerService : public BnMediaPlayerService 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 @@ class MediaPlayerService : public BnMediaPlayerService 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 @@ private: 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); |