huangcm
2025-02-28 c32b2f9505927d6bf06b1d06d5ddd3cd1d245faf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/*
 * 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 {
 
// abstract base class
class GenericPlayer : public AHandler
{
public:
 
    enum {
        kEventPrepared                = 0,
        kEventHasVideoSize            = 1,
        kEventPrefetchStatusChange    = 2,
        kEventPrefetchFillLevelUpdate = 3,
        kEventEndOfStream             = 4,
        kEventChannelCount            = 5,
        kEventPlay                    = 6, // SL_PLAYEVENT_*
        kEventErrorAfterPrepare       = 7, // error after successful prepare
    };
 
 
    explicit GenericPlayer(const AudioPlayback_Parameters* params);
    virtual ~GenericPlayer();
 
    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();
    void pause();
    void stop();
    // timeMsec must be >= 0 or == ANDROID_UNKNOWN_TIME (used by StreamPlayer after discontinuity)
    void seek(int64_t timeMsec);
    void loop(bool loop);
    void setBufferingUpdateThreshold(int16_t thresholdPercent);
 
    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<IGraphicBufferProducer> &bufferProducer __unused)
            { }
 
    void setVolume(float leftVol, float rightVol);
    void attachAuxEffect(int32_t effectId);
    void setAuxEffectSendLevel(float level);
 
    virtual void setPlaybackRate(int32_t ratePermille);
 
    // 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         = 0,  // start preparation
        kWhatNotif           = 1,  // send a notification to client
        kWhatPlay            = 2,  // start player
        kWhatPause           = 3,  // pause or stop player
        kWhatSeek            = 4,  // request a seek to specified position
        kWhatSeekComplete    = 5,  // seek request has completed
        kWhatLoop            = 6,  // set the player's looping status
        kWhatVolumeUpdate    = 7,  // set the channel gains to specified values
        kWhatBufferingUpdate = 8,
        kWhatBuffUpdateThres = 9,
        kWhatAttachAuxEffect = 10,
        kWhatSetAuxEffectSendLevel = 11,
        kWhatSetPlayEvents   = 12,  // process new IPlay settings related to SL_PLAYEVENT_*
        kWhatOneShot         = 13,  // 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,
    };
 
    // Only accessed from event loop, does not need a mutex
    uint32_t mStateFlags;
 
    sp<ALooper> mLooper;
 
    const AudioPlayback_Parameters mPlaybackParams;
 
    // protected by mSettingsLock after construction
    AndroidAudioLevels mAndroidAudioLevels;
 
    // protected by mSettingsLock
    int32_t mDurationMsec;
    int16_t mPlaybackRatePermille;
 
    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);
 
    // players that "render" data to present it to the user (a music player, a video player),
    // should return true, while players that only decode (hopefully faster than "real time")
    // should return false.
    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__ */