| /* |
| * Copyright (C) 2011 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_GENERICPLAYER_H__ |
| #define __ANDROID_GENERICPLAYER_H__ |
| |
| #include <media/stagefright/foundation/AHandler.h> |
| #include <media/stagefright/foundation/ALooper.h> |
| #include <media/stagefright/foundation/AMessage.h> |
| |
| //-------------------------------------------------------------------------------------------------- |
| /** |
| * Message parameters for AHandler messages, see list in GenericPlayer::kWhatxxx |
| */ |
| #define WHATPARAM_SEEK_SEEKTIME_MS "seekTimeMs" |
| #define WHATPARAM_LOOP_LOOPING "looping" |
| #define WHATPARAM_BUFFERING_UPDATE "bufferingUpdate" |
| #define WHATPARAM_BUFFERING_UPDATETHRESHOLD_PERCENT "buffUpdateThreshold" |
| #define WHATPARAM_ATTACHAUXEFFECT "attachAuxEffect" |
| #define WHATPARAM_SETAUXEFFECTSENDLEVEL "setAuxEffectSendLevel" |
| // Parameters for kWhatSetPlayEvents |
| #define WHATPARAM_SETPLAYEVENTS_FLAGS "setPlayEventsFlags" |
| #define WHATPARAM_SETPLAYEVENTS_MARKER "setPlayEventsMarker" |
| #define WHATPARAM_SETPLAYEVENTS_UPDATE "setPlayEventsUpdate" |
| // Parameters for kWhatOneShot (see explanation at definition of kWhatOneShot below) |
| #define WHATPARAM_ONESHOT_GENERATION "oneShotGeneration" |
| |
| namespace android { |
| |
| class GenericPlayer : public AHandler |
| { |
| public: |
| |
| enum { |
| kEventPrepared = 'prep', |
| kEventHasVideoSize = 'vsiz', |
| kEventPrefetchStatusChange = 'pfsc', |
| kEventPrefetchFillLevelUpdate = 'pflu', |
| kEventEndOfStream = 'eos', |
| kEventChannelCount = 'ccnt', |
| kEventPlay = 'play', // SL_PLAYEVENT_* |
| kEventErrorAfterPrepare = 'easp', // error after successful prepare |
| }; |
| |
| |
| GenericPlayer(const AudioPlayback_Parameters* params); |
| virtual ~GenericPlayer(); |
| |
| virtual void init(const notif_cbf_t cbf, void* notifUser); |
| virtual void preDestroy(); |
| |
| void setDataSource(const char *uri); |
| void setDataSource(int fd, int64_t offset, int64_t length, bool closeAfterUse = false); |
| |
| void prepare(); |
| virtual void play(); |
| virtual void pause(); |
| virtual void stop(); |
| // timeMsec must be >= 0 or == ANDROID_UNKNOWN_TIME (used by StreamPlayer after discontinuity) |
| virtual void seek(int64_t timeMsec); |
| virtual void loop(bool loop); |
| virtual void setBufferingUpdateThreshold(int16_t thresholdPercent); |
| |
| virtual void getDurationMsec(int* msec); //msec != NULL, ANDROID_UNKNOWN_TIME if unknown |
| virtual void getPositionMsec(int* msec) = 0; //msec != NULL, ANDROID_UNKNOWN_TIME if unknown |
| |
| virtual void setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {} |
| |
| void setVolume(float leftVol, float rightVol); |
| void attachAuxEffect(int32_t effectId); |
| void setAuxEffectSendLevel(float level); |
| |
| // Call after changing any of the IPlay settings related to SL_PLAYEVENT_* |
| void setPlayEvents(int32_t eventFlags, int32_t markerPosition, int32_t positionUpdatePeriod); |
| |
| protected: |
| // mutex used for set vs use of volume, duration, and cache (fill, threshold) settings |
| Mutex mSettingsLock; |
| |
| void resetDataLocator(); |
| DataLocator2 mDataLocator; |
| int mDataLocatorType; |
| |
| // Constants used to identify the messages in this player's AHandler message loop |
| // in onMessageReceived() |
| enum { |
| kWhatPrepare = 'prep', |
| kWhatNotif = 'noti', |
| kWhatPlay = 'play', |
| kWhatPause = 'paus', |
| kWhatSeek = 'seek', |
| kWhatSeekComplete = 'skcp', |
| kWhatLoop = 'loop', |
| kWhatVolumeUpdate = 'volu', |
| kWhatBufferingUpdate = 'bufu', |
| kWhatBuffUpdateThres = 'buut', |
| kWhatAttachAuxEffect = 'aaux', |
| kWhatSetAuxEffectSendLevel = 'saux', |
| kWhatSetPlayEvents = 'spev', // process new IPlay settings related to SL_PLAYEVENT_* |
| kWhatOneShot = 'ones', // deferred (non-0 timeout) handler for SL_PLAYEVENT_* |
| // As used here, "one-shot" is the software equivalent of a "retriggerable monostable |
| // multivibrator" from electronics. Briefly, a one-shot is a timer that can be triggered |
| // to fire at some point in the future. It is "retriggerable" because while the timer |
| // is active, it is possible to replace the current timeout value by a new value. |
| // This is done by cancelling the current timer (using a generation count), |
| // and then posting another timer with the new desired value. |
| }; |
| |
| // Send a notification to one of the event listeners |
| virtual void notify(const char* event, int data1, bool async); |
| virtual void notify(const char* event, int data1, int data2, bool async); |
| |
| // AHandler implementation |
| virtual void onMessageReceived(const sp<AMessage> &msg); |
| |
| // Async event handlers (called from GenericPlayer's event loop) |
| virtual void onPrepare(); |
| virtual void onNotify(const sp<AMessage> &msg); |
| virtual void onPlay(); |
| virtual void onPause(); |
| virtual void onSeek(const sp<AMessage> &msg); |
| virtual void onLoop(const sp<AMessage> &msg); |
| virtual void onVolumeUpdate(); |
| virtual void onSeekComplete(); |
| virtual void onBufferingUpdate(const sp<AMessage> &msg); |
| virtual void onSetBufferingUpdateThreshold(const sp<AMessage> &msg); |
| virtual void onAttachAuxEffect(const sp<AMessage> &msg); |
| virtual void onSetAuxEffectSendLevel(const sp<AMessage> &msg); |
| void onSetPlayEvents(const sp<AMessage> &msg); |
| void onOneShot(const sp<AMessage> &msg); |
| |
| // Convenience methods |
| // for async notifications of prefetch status and cache fill level, needs to be called |
| // with mSettingsLock locked |
| void notifyStatus(); |
| void notifyCacheFill(); |
| // for internal async notification to update state that the player is no longer seeking |
| void seekComplete(); |
| void bufferingUpdate(int16_t fillLevelPerMille); |
| |
| // Event notification from GenericPlayer to OpenSL ES / OpenMAX AL framework |
| notif_cbf_t mNotifyClient; |
| void* mNotifyUser; |
| // lock to protect mNotifyClient and mNotifyUser updates |
| Mutex mNotifyClientLock; |
| |
| // Bits for mStateFlags |
| enum { |
| kFlagPrepared = 1 << 0, // use only for successful preparation |
| kFlagPreparing = 1 << 1, |
| kFlagPlaying = 1 << 2, |
| kFlagBuffering = 1 << 3, |
| kFlagSeeking = 1 << 4, // set if we (not Stagefright) initiated a seek |
| kFlagLooping = 1 << 5, // set if looping is enabled |
| kFlagPreparedUnsuccessfully = 1 << 6, |
| }; |
| |
| uint32_t mStateFlags; |
| |
| sp<ALooper> mLooper; |
| |
| AudioPlayback_Parameters mPlaybackParams; |
| |
| AndroidAudioLevels mAndroidAudioLevels; |
| |
| // protected by mSettingsLock |
| int32_t mDurationMsec; |
| |
| CacheStatus_t mCacheStatus; |
| int16_t mCacheFill; // cache fill level + played back level in permille |
| int16_t mLastNotifiedCacheFill; // last cache fill level communicated to the listener |
| int16_t mCacheFillNotifThreshold; // threshold in cache fill level for cache fill to be reported |
| |
| // Call any time any of the IPlay copies, current position, or play state changes, and |
| // supply the latest known position or ANDROID_UNKNOWN_TIME if position is unknown to caller. |
| void updateOneShot(int positionMs = ANDROID_UNKNOWN_TIME); |
| |
| virtual bool advancesPositionInRealTime() const { return true; } |
| |
| private: |
| |
| // Our copy of some important IPlay member variables, except in Android units |
| int32_t mEventFlags; |
| int32_t mMarkerPositionMs; |
| int32_t mPositionUpdatePeriodMs; |
| |
| // We need to be able to cancel any pending one-shot event(s) prior to posting |
| // a new one-shot. As AMessage does not currently support cancellation by |
| // "what" category, we simulate this by keeping a generation counter for |
| // one-shots. When a one-shot event is delivered, it checks to see if it is |
| // still the current one-shot. If not, it returns immediately, thus |
| // effectively cancelling itself. Note that counter wrap-around is possible |
| // but unlikely and benign. |
| int32_t mOneShotGeneration; |
| |
| // Play position at time of the most recently delivered SL_PLAYEVENT_HEADATNEWPOS, |
| // or ANDROID_UNKNOWN_TIME if a SL_PLAYEVENT_HEADATNEWPOS has never been delivered. |
| int32_t mDeliveredNewPosMs; |
| |
| // Play position most recently observed by updateOneShot, or ANDROID_UNKNOWN_TIME |
| // if the play position has never been observed. |
| int32_t mObservedPositionMs; |
| |
| DISALLOW_EVIL_CONSTRUCTORS(GenericPlayer); |
| }; |
| |
| } // namespace android |
| |
| extern void android_player_volumeUpdate(float *pVolumes /*[2]*/, const IVolume *volumeItf, |
| unsigned channelCount, float amplFromDirectLevel, const bool *audibilityFactors /*[2]*/); |
| |
| #endif /* __ANDROID_GENERICPLAYER_H__ */ |