android_GenericPlayer.cpp revision a9f22e6f5f53e90daa779e38b22f88e4faa35c95
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define USE_LOG SLAndroidLogLevel_Verbose
18
19#include "sles_allinclusive.h"
20
21#include <media/stagefright/foundation/ADebug.h>
22#include <sys/stat.h>
23
24namespace android {
25
26//--------------------------------------------------------------------------------------------------
27GenericPlayer::GenericPlayer(const AudioPlayback_Parameters* params) :
28        mDataLocatorType(kDataLocatorNone),
29        mNotifyClient(NULL),
30        mNotifyUser(NULL),
31        mStateFlags(0),
32        mPlaybackParams(*params),
33        mChannelCount(UNKNOWN_NUMCHANNELS),
34        mDurationMsec(ANDROID_UNKNOWN_TIME),
35        mSampleRateHz(UNKNOWN_SAMPLERATE),
36        mCacheStatus(kStatusEmpty),
37        mCacheFill(0),
38        mLastNotifiedCacheFill(0),
39        mCacheFillNotifThreshold(100),
40        mEventFlags(0),
41        mMarkerPositionMs(ANDROID_UNKNOWN_TIME),
42        mPositionUpdatePeriodMs(1000), // per spec
43        mOneShotGeneration(0),
44        mDeliveredNewPosMs(ANDROID_UNKNOWN_TIME),
45        mObservedPositionMs(ANDROID_UNKNOWN_TIME)
46{
47    SL_LOGD("GenericPlayer::GenericPlayer()");
48
49    mLooper = new android::ALooper();
50
51    mAndroidAudioLevels.mFinalVolume[0] = 1.0f;
52    mAndroidAudioLevels.mFinalVolume[1] = 1.0f;
53}
54
55
56GenericPlayer::~GenericPlayer() {
57    SL_LOGV("GenericPlayer::~GenericPlayer()");
58
59    resetDataLocator();
60}
61
62
63void GenericPlayer::init(const notif_cbf_t cbf, void* notifUser) {
64    SL_LOGD("GenericPlayer::init()");
65
66    {
67        android::Mutex::Autolock autoLock(mNotifyClientLock);
68        mNotifyClient = cbf;
69        mNotifyUser = notifUser;
70    }
71
72    mLooper->registerHandler(this);
73    mLooper->start(false /*runOnCallingThread*/, false /*canCallJava*/, PRIORITY_DEFAULT);
74}
75
76
77void GenericPlayer::preDestroy() {
78    SL_LOGD("GenericPlayer::preDestroy()");
79    {
80        android::Mutex::Autolock autoLock(mNotifyClientLock);
81        mNotifyClient = NULL;
82        mNotifyUser = NULL;
83    }
84
85    mLooper->stop();
86    mLooper->unregisterHandler(id());
87}
88
89
90void GenericPlayer::setDataSource(const char *uri) {
91    SL_LOGV("GenericPlayer::setDataSource(uri=%s)", uri);
92    resetDataLocator();
93
94    mDataLocator.uriRef = uri;
95
96    mDataLocatorType = kDataLocatorUri;
97}
98
99
100void GenericPlayer::setDataSource(int fd, int64_t offset, int64_t length, bool closeAfterUse) {
101    SL_LOGV("GenericPlayer::setDataSource(fd=%d, offset=%lld, length=%lld, closeAfterUse=%s)", fd,
102            offset, length, closeAfterUse ? "true" : "false");
103    resetDataLocator();
104
105    mDataLocator.fdi.fd = fd;
106
107    struct stat sb;
108    int ret = fstat(fd, &sb);
109    if (ret != 0) {
110        SL_LOGE("GenericPlayer::setDataSource: fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
111        return;
112    }
113
114    if (offset >= sb.st_size) {
115        SL_LOGE("SfPlayer::setDataSource: invalid offset");
116        return;
117    }
118    mDataLocator.fdi.offset = offset;
119
120    if (PLAYER_FD_FIND_FILE_SIZE == length) {
121        mDataLocator.fdi.length = sb.st_size;
122    } else if (offset + length > sb.st_size) {
123        mDataLocator.fdi.length = sb.st_size - offset;
124    } else {
125        mDataLocator.fdi.length = length;
126    }
127
128    mDataLocator.fdi.mCloseAfterUse = closeAfterUse;
129
130    mDataLocatorType = kDataLocatorFd;
131}
132
133
134void GenericPlayer::prepare() {
135    SL_LOGD("GenericPlayer::prepare()");
136    // do not attempt prepare more than once
137    if (!(mStateFlags & (kFlagPrepared | kFlagPreparedUnsuccessfully))) {
138        sp<AMessage> msg = new AMessage(kWhatPrepare, id());
139        msg->post();
140    }
141}
142
143
144void GenericPlayer::play() {
145    SL_LOGD("GenericPlayer::play()");
146    sp<AMessage> msg = new AMessage(kWhatPlay, id());
147    msg->post();
148}
149
150
151void GenericPlayer::pause() {
152    SL_LOGD("GenericPlayer::pause()");
153    sp<AMessage> msg = new AMessage(kWhatPause, id());
154    msg->post();
155}
156
157
158void GenericPlayer::stop() {
159    SL_LOGD("GenericPlayer::stop()");
160    (new AMessage(kWhatPause, id()))->post();
161
162    // after a stop, playback should resume from the start.
163    seek(0);
164}
165
166
167void GenericPlayer::seek(int64_t timeMsec) {
168    SL_LOGV("GenericPlayer::seek %lld", timeMsec);
169    if (timeMsec < 0 && timeMsec != ANDROID_UNKNOWN_TIME) {
170        SL_LOGE("GenericPlayer::seek error, can't seek to negative time %lldms", timeMsec);
171        return;
172    }
173    sp<AMessage> msg = new AMessage(kWhatSeek, id());
174    msg->setInt64(WHATPARAM_SEEK_SEEKTIME_MS, timeMsec);
175    msg->post();
176}
177
178
179void GenericPlayer::loop(bool loop) {
180    SL_LOGV("GenericPlayer::loop %s", loop ? "true" : "false");
181    sp<AMessage> msg = new AMessage(kWhatLoop, id());
182    msg->setInt32(WHATPARAM_LOOP_LOOPING, (int32_t)loop);
183    msg->post();
184}
185
186
187void GenericPlayer::setBufferingUpdateThreshold(int16_t thresholdPercent) {
188    SL_LOGV("GenericPlayer::setBufferingUpdateThreshold %d", thresholdPercent);
189    sp<AMessage> msg = new AMessage(kWhatBuffUpdateThres, id());
190    msg->setInt32(WHATPARAM_BUFFERING_UPDATETHRESHOLD_PERCENT, (int32_t)thresholdPercent);
191    msg->post();
192}
193
194
195//--------------------------------------------------
196void GenericPlayer::getDurationMsec(int* msec) {
197    *msec = mDurationMsec;
198}
199
200void GenericPlayer::getSampleRate(uint* hz) {
201    *hz = mSampleRateHz;
202}
203
204//--------------------------------------------------
205void GenericPlayer::setVolume(float leftVol, float rightVol)
206{
207    {
208        Mutex::Autolock _l(mSettingsLock);
209        mAndroidAudioLevels.mFinalVolume[0] = leftVol;
210        mAndroidAudioLevels.mFinalVolume[1] = rightVol;
211    }
212    // send a message for the volume to be updated by the object which implements the volume
213    (new AMessage(kWhatVolumeUpdate, id()))->post();
214}
215
216
217//--------------------------------------------------
218void GenericPlayer::attachAuxEffect(int32_t effectId)
219{
220    SL_LOGV("GenericPlayer::attachAuxEffect(id=%d)", effectId);
221    sp<AMessage> msg = new AMessage(kWhatAttachAuxEffect, id());
222    msg->setInt32(WHATPARAM_ATTACHAUXEFFECT, effectId);
223    msg->post();
224}
225
226
227//--------------------------------------------------
228void GenericPlayer::setAuxEffectSendLevel(float level)
229{
230    SL_LOGV("GenericPlayer::setAuxEffectSendLevel(level=%g)", level);
231    sp<AMessage> msg = new AMessage(kWhatSetAuxEffectSendLevel, id());
232    msg->setFloat(WHATPARAM_SETAUXEFFECTSENDLEVEL, level);
233    msg->post();
234}
235
236
237//--------------------------------------------------
238// Call after changing any of the IPlay settings related to SL_PLAYEVENT_*
239void GenericPlayer::setPlayEvents(int32_t eventFlags, int32_t markerPositionMs,
240        int32_t positionUpdatePeriodMs)
241{
242    // Normalize ms that are within the valid unsigned range, but not in the int32_t range
243    if (markerPositionMs < 0) {
244        markerPositionMs = ANDROID_UNKNOWN_TIME;
245    }
246    if (positionUpdatePeriodMs < 0) {
247        positionUpdatePeriodMs = ANDROID_UNKNOWN_TIME;
248    }
249    // markers are delivered accurately, but new position updates are limited to every 100 ms
250    if (positionUpdatePeriodMs < 100) {
251        positionUpdatePeriodMs = 100;
252    }
253    sp<AMessage> msg = new AMessage(kWhatSetPlayEvents, id());
254    msg->setInt32(WHATPARAM_SETPLAYEVENTS_FLAGS, eventFlags);
255    msg->setInt32(WHATPARAM_SETPLAYEVENTS_MARKER, markerPositionMs);
256    msg->setInt32(WHATPARAM_SETPLAYEVENTS_UPDATE, positionUpdatePeriodMs);
257    msg->post();
258}
259
260
261//--------------------------------------------------
262/*
263 * post-condition: mDataLocatorType == kDataLocatorNone
264 *
265 */
266void GenericPlayer::resetDataLocator() {
267    SL_LOGV("GenericPlayer::resetDataLocator()");
268    if (mDataLocatorType == kDataLocatorFd && mDataLocator.fdi.mCloseAfterUse) {
269        (void) ::close(mDataLocator.fdi.fd);
270        // would be redundant, as we're about to invalidate the union mDataLocator
271        //mDataLocator.fdi.fd = -1;
272        //mDataLocator.fdi.mCloseAfterUse = false;
273    }
274    mDataLocatorType = kDataLocatorNone;
275}
276
277
278void GenericPlayer::notify(const char* event, int data, bool async) {
279    SL_LOGV("GenericPlayer::notify(event=%s, data=%d, async=%s)", event, data,
280            async ? "true" : "false");
281    sp<AMessage> msg = new AMessage(kWhatNotif, id());
282    msg->setInt32(event, (int32_t)data);
283    if (async) {
284        msg->post();
285    } else {
286        this->onNotify(msg);
287    }
288}
289
290
291void GenericPlayer::notify(const char* event, int data1, int data2, bool async) {
292    SL_LOGV("GenericPlayer::notify(event=%s, data1=%d, data2=%d, async=%s)", event, data1, data2,
293            async ? "true" : "false");
294    sp<AMessage> msg = new AMessage(kWhatNotif, id());
295    msg->setRect(event, 0, 0, (int32_t)data1, (int32_t)data2);
296    if (async) {
297        msg->post();
298    } else {
299        this->onNotify(msg);
300    }
301}
302
303
304//--------------------------------------------------
305// AHandler implementation
306void GenericPlayer::onMessageReceived(const sp<AMessage> &msg) {
307    SL_LOGV("GenericPlayer::onMessageReceived()");
308    switch (msg->what()) {
309        case kWhatPrepare:
310            SL_LOGV("kWhatPrepare");
311            onPrepare();
312            break;
313
314        case kWhatNotif:
315            SL_LOGV("kWhatNotif");
316            onNotify(msg);
317            break;
318
319        case kWhatPlay:
320            SL_LOGV("kWhatPlay");
321            onPlay();
322            break;
323
324        case kWhatPause:
325            SL_LOGV("kWhatPause");
326            onPause();
327            break;
328
329        case kWhatSeek:
330            SL_LOGV("kWhatSeek");
331            onSeek(msg);
332            break;
333
334        case kWhatLoop:
335            SL_LOGV("kWhatLoop");
336            onLoop(msg);
337            break;
338
339        case kWhatVolumeUpdate:
340            SL_LOGV("kWhatVolumeUpdate");
341            onVolumeUpdate();
342            break;
343
344        case kWhatSeekComplete:
345            SL_LOGV("kWhatSeekComplete");
346            onSeekComplete();
347            break;
348
349        case kWhatBufferingUpdate:
350            SL_LOGV("kWhatBufferingUpdate");
351            onBufferingUpdate(msg);
352            break;
353
354        case kWhatBuffUpdateThres:
355            SL_LOGV("kWhatBuffUpdateThres");
356            onSetBufferingUpdateThreshold(msg);
357            break;
358
359        case kWhatAttachAuxEffect:
360            SL_LOGV("kWhatAttachAuxEffect");
361            onAttachAuxEffect(msg);
362            break;
363
364        case kWhatSetAuxEffectSendLevel:
365            SL_LOGV("kWhatSetAuxEffectSendLevel");
366            onSetAuxEffectSendLevel(msg);
367            break;
368
369        case kWhatSetPlayEvents:
370            SL_LOGV("kWhatSetPlayEvents");
371            onSetPlayEvents(msg);
372            break;
373
374        case kWhatOneShot:
375            SL_LOGV("kWhatOneShot");
376            onOneShot(msg);
377            break;
378
379        default:
380            SL_LOGE("GenericPlayer::onMessageReceived unknown message %d", msg->what());
381            TRESPASS();
382    }
383}
384
385
386//--------------------------------------------------
387// Event handlers
388//  it is strictly verboten to call those methods outside of the event loop
389
390void GenericPlayer::onPrepare() {
391    SL_LOGV("GenericPlayer::onPrepare()");
392    // Subclass is responsible for indicating whether prepare was successful or unsuccessful
393    // by updating mStateFlags accordingly.  It must set exactly one of these two flags.
394    assert(!(mStateFlags & kFlagPrepared) != !(mStateFlags & kFlagPreparedUnsuccessfully));
395    notify(PLAYEREVENT_PREPARED, mStateFlags & kFlagPrepared ? PLAYER_SUCCESS : PLAYER_FAILURE,
396            true /*async*/);
397    SL_LOGD("GenericPlayer::onPrepare() done, mStateFlags=0x%x", mStateFlags);
398}
399
400
401void GenericPlayer::onNotify(const sp<AMessage> &msg) {
402    SL_LOGV("GenericPlayer::onNotify()");
403    notif_cbf_t notifClient;
404    void*       notifUser;
405    {
406        android::Mutex::Autolock autoLock(mNotifyClientLock);
407        if (NULL == mNotifyClient) {
408            return;
409        } else {
410            notifClient = mNotifyClient;
411            notifUser   = mNotifyUser;
412        }
413    }
414
415    int32_t val1, val2;
416    if (msg->findInt32(PLAYEREVENT_PREFETCHSTATUSCHANGE, &val1)) {
417        SL_LOGV("GenericPlayer notifying %s = %d", PLAYEREVENT_PREFETCHSTATUSCHANGE, val1);
418        notifClient(kEventPrefetchStatusChange, val1, 0, notifUser);
419    } else if (msg->findInt32(PLAYEREVENT_PREFETCHFILLLEVELUPDATE, &val1)) {
420        SL_LOGV("GenericPlayer notifying %s = %d", PLAYEREVENT_PREFETCHFILLLEVELUPDATE, val1);
421        notifClient(kEventPrefetchFillLevelUpdate, val1, 0, notifUser);
422    } else if (msg->findInt32(PLAYEREVENT_ENDOFSTREAM, &val1)) {
423        SL_LOGV("GenericPlayer notifying %s = %d", PLAYEREVENT_ENDOFSTREAM, val1);
424        notifClient(kEventEndOfStream, val1, 0, notifUser);
425    } else if (msg->findInt32(PLAYEREVENT_PREPARED, &val1)) {
426        SL_LOGV("GenericPlayer notifying %s = %d", PLAYEREVENT_PREPARED, val1);
427        notifClient(kEventPrepared, val1, 0, notifUser);
428    } else if (msg->findInt32(PLAYEREVENT_CHANNEL_COUNT, &val1)) {
429        SL_LOGV("GenericPlayer notifying %s = %d", PLAYEREVENT_CHANNEL_COUNT, val1);
430        notifClient(kEventChannelCount, val1, 0, notifUser);
431    } else if (msg->findRect(PLAYEREVENT_VIDEO_SIZE_UPDATE, &val1, &val2, &val1, &val2)) {
432        SL_LOGV("GenericPlayer notifying %s = %d, %d", PLAYEREVENT_VIDEO_SIZE_UPDATE, val1, val2);
433        notifClient(kEventHasVideoSize, val1, val2, notifUser);
434    } else if (msg->findInt32(PLAYEREVENT_PLAY, &val1)) {
435        SL_LOGV("GenericPlayer notifying %s = %d", PLAYEREVENT_PLAY, val1);
436        notifClient(kEventPlay, val1, 0, notifUser);
437    } else {
438        SL_LOGV("GenericPlayer notifying unknown");
439    }
440}
441
442
443void GenericPlayer::onPlay() {
444    SL_LOGD("GenericPlayer::onPlay()");
445    if ((mStateFlags & (kFlagPrepared | kFlagPlaying)) == kFlagPrepared) {
446        SL_LOGD("starting player");
447        mStateFlags |= kFlagPlaying;
448        updateOneShot();
449    }
450}
451
452
453void GenericPlayer::onPause() {
454    SL_LOGD("GenericPlayer::onPause()");
455    if (!(~mStateFlags & (kFlagPrepared | kFlagPlaying))) {
456        SL_LOGV("pausing player");
457        mStateFlags &= ~kFlagPlaying;
458        updateOneShot();
459    }
460}
461
462
463void GenericPlayer::onSeek(const sp<AMessage> &msg) {
464    SL_LOGV("GenericPlayer::onSeek");
465}
466
467
468void GenericPlayer::onLoop(const sp<AMessage> &msg) {
469    SL_LOGV("GenericPlayer::onLoop");
470}
471
472
473void GenericPlayer::onVolumeUpdate() {
474    SL_LOGV("GenericPlayer::onVolumeUpdate");
475}
476
477
478void GenericPlayer::onSeekComplete() {
479    SL_LOGD("GenericPlayer::onSeekComplete()");
480    mStateFlags &= ~kFlagSeeking;
481    // avoid spurious or lost events caused by seeking past a marker
482    mDeliveredNewPosMs = ANDROID_UNKNOWN_TIME;
483    mObservedPositionMs = ANDROID_UNKNOWN_TIME;
484    updateOneShot();
485}
486
487
488void GenericPlayer::onBufferingUpdate(const sp<AMessage> &msg) {
489    SL_LOGV("GenericPlayer::onBufferingUpdate");
490}
491
492
493void GenericPlayer::onSetBufferingUpdateThreshold(const sp<AMessage> &msg) {
494    SL_LOGV("GenericPlayer::onSetBufferingUpdateThreshold");
495    int32_t thresholdPercent = 0;
496    if (msg->findInt32(WHATPARAM_BUFFERING_UPDATETHRESHOLD_PERCENT, &thresholdPercent)) {
497        Mutex::Autolock _l(mSettingsLock);
498        mCacheFillNotifThreshold = (int16_t)thresholdPercent;
499    }
500}
501
502
503void GenericPlayer::onAttachAuxEffect(const sp<AMessage> &msg) {
504    SL_LOGV("GenericPlayer::onAttachAuxEffect()");
505}
506
507
508void GenericPlayer::onSetAuxEffectSendLevel(const sp<AMessage> &msg) {
509    SL_LOGV("GenericPlayer::onSetAuxEffectSendLevel()");
510}
511
512
513void GenericPlayer::onSetPlayEvents(const sp<AMessage> &msg) {
514    SL_LOGV("GenericPlayer::onSetPlayEvents()");
515    int32_t eventFlags, markerPositionMs, positionUpdatePeriodMs;
516    if (msg->findInt32(WHATPARAM_SETPLAYEVENTS_FLAGS, &eventFlags) &&
517            msg->findInt32(WHATPARAM_SETPLAYEVENTS_MARKER, &markerPositionMs) &&
518            msg->findInt32(WHATPARAM_SETPLAYEVENTS_UPDATE, &positionUpdatePeriodMs)) {
519        mEventFlags = eventFlags;
520        mMarkerPositionMs = markerPositionMs;
521        mPositionUpdatePeriodMs = positionUpdatePeriodMs;
522        updateOneShot();
523    }
524}
525
526
527void GenericPlayer::onOneShot(const sp<AMessage> &msg) {
528    SL_LOGV("GenericPlayer::onOneShot()");
529    int32_t generation;
530    if (msg->findInt32(WHATPARAM_ONESHOT_GENERATION, &generation)) {
531        if (generation != mOneShotGeneration) {
532            SL_LOGV("GenericPlayer::onOneShot() generation %d cancelled; latest is %d",
533                    generation, mOneShotGeneration);
534            return;
535        }
536        updateOneShot();
537    }
538}
539
540
541//-------------------------------------------------
542void GenericPlayer::notifyStatus() {
543    SL_LOGV("GenericPlayer::notifyStatus");
544    notify(PLAYEREVENT_PREFETCHSTATUSCHANGE, (int32_t)mCacheStatus, true /*async*/);
545}
546
547
548void GenericPlayer::notifyCacheFill() {
549    SL_LOGV("GenericPlayer::notifyCacheFill");
550    mLastNotifiedCacheFill = mCacheFill;
551    notify(PLAYEREVENT_PREFETCHFILLLEVELUPDATE, (int32_t)mLastNotifiedCacheFill, true/*async*/);
552}
553
554
555void GenericPlayer::seekComplete() {
556    SL_LOGV("GenericPlayer::seekComplete");
557    sp<AMessage> msg = new AMessage(kWhatSeekComplete, id());
558    msg->post();
559}
560
561
562void GenericPlayer::bufferingUpdate(int16_t fillLevelPerMille) {
563    SL_LOGV("GenericPlayer::bufferingUpdate");
564    sp<AMessage> msg = new AMessage(kWhatBufferingUpdate, id());
565    msg->setInt32(WHATPARAM_BUFFERING_UPDATE, fillLevelPerMille);
566    msg->post();
567}
568
569
570// For the meaning of positionMs, see comment in declaration at android_GenericPlayer.h
571void GenericPlayer::updateOneShot(int positionMs)
572{
573    SL_LOGV("GenericPlayer::updateOneShot");
574
575    // nop until prepared
576    if (!(mStateFlags & kFlagPrepared)) {
577        return;
578    }
579
580    // cancel any pending one-shot(s)
581    ++mOneShotGeneration;
582
583    // don't restart one-shot if player is paused or stopped
584    if (!(mStateFlags & kFlagPlaying)) {
585        return;
586    }
587
588    // get current player position in milliseconds
589    if (positionMs < 0) {
590        positionMs = ANDROID_UNKNOWN_TIME;
591    }
592    if (positionMs == ANDROID_UNKNOWN_TIME) {
593        getPositionMsec(&positionMs);
594        // normalize it
595        if (positionMs < 0) {
596            positionMs = ANDROID_UNKNOWN_TIME;
597        }
598        if (ANDROID_UNKNOWN_TIME == positionMs) {
599            // getPositionMsec is not working for some reason, give up
600            //LOGV("Does anyone really know what time it is?");
601            return;
602        }
603    }
604
605    // delayUs is the expected delay between current position and marker;
606    // the default is infinity in case there are no upcoming marker(s)
607    int64_t delayUs = -1;
608
609    // is there a marker?
610    if ((mEventFlags & SL_PLAYEVENT_HEADATMARKER) && (mMarkerPositionMs != ANDROID_UNKNOWN_TIME)) {
611        // check to see if we have observed the position passing through the marker
612        if (mObservedPositionMs <= mMarkerPositionMs && mMarkerPositionMs <= positionMs) {
613            notify(PLAYEREVENT_PLAY, (int32_t) SL_PLAYEVENT_HEADATMARKER, true /*async*/);
614        } else if (positionMs < mMarkerPositionMs) {
615            delayUs = (mMarkerPositionMs - positionMs) * 1000LL;
616        }
617    }
618
619    // are periodic position updates needed?
620    if ((mEventFlags & SL_PLAYEVENT_HEADATNEWPOS) &&
621            (mPositionUpdatePeriodMs != ANDROID_UNKNOWN_TIME)) {
622        // check to see if we have observed the position passing through a virtual marker, where the
623        // virtual marker is at the previously delivered new position plus position update period
624        int32_t virtualMarkerMs;
625        if (mDeliveredNewPosMs != ANDROID_UNKNOWN_TIME) {
626            virtualMarkerMs = mDeliveredNewPosMs + mPositionUpdatePeriodMs;
627        } else if (mObservedPositionMs != ANDROID_UNKNOWN_TIME) {
628            virtualMarkerMs = mObservedPositionMs + mPositionUpdatePeriodMs;
629            // pretend there has been an update in the past
630            mDeliveredNewPosMs = mObservedPositionMs;
631        } else {
632            virtualMarkerMs = positionMs + mPositionUpdatePeriodMs;
633            // pretend there has been an update in the past
634            mDeliveredNewPosMs = positionMs;
635        }
636        // nextVirtualMarkerMs will be set to the position of the next upcoming virtual marker
637        int32_t nextVirtualMarkerMs;
638        if (mObservedPositionMs <= virtualMarkerMs && virtualMarkerMs <= positionMs) {
639            // we did pass through the virtual marker, now compute the next virtual marker
640            mDeliveredNewPosMs = virtualMarkerMs;
641            nextVirtualMarkerMs = virtualMarkerMs + mPositionUpdatePeriodMs;
642            // re-synchronize if we missed an update
643            if (nextVirtualMarkerMs <= positionMs) {
644                SL_LOGW("Missed SL_PLAYEVENT_HEADATNEWPOS for position %d; current position %d",
645                        nextVirtualMarkerMs, positionMs);
646                // try to catch up by setting next goal to current position plus update period
647                mDeliveredNewPosMs = positionMs;
648                nextVirtualMarkerMs = positionMs + mPositionUpdatePeriodMs;
649            }
650            notify(PLAYEREVENT_PLAY, (int32_t) SL_PLAYEVENT_HEADATNEWPOS, true /*async*/);
651        } else {
652            // we did not pass through the virtual marker yet, so use same marker again
653            nextVirtualMarkerMs = virtualMarkerMs;
654        }
655        // note that if arithmetic overflow occurred, nextVirtualMarkerMs will be negative
656        if (positionMs < nextVirtualMarkerMs) {
657            int64_t trialDelayUs;
658            trialDelayUs = (nextVirtualMarkerMs - positionMs) * 1000LL;
659            if (trialDelayUs > 0 && (delayUs == -1 || trialDelayUs < delayUs)) {
660                delayUs = trialDelayUs;
661            }
662        }
663    }
664
665    // we have a new observed position
666    mObservedPositionMs = positionMs;
667
668    // post the new one-shot message if needed
669    if (advancesPositionInRealTime() && delayUs >= 0) {
670        // 20 ms min delay to avoid near busy waiting
671        if (delayUs < 20000LL) {
672            delayUs = 20000LL;
673        }
674        // 1 minute max delay avoids indefinite memory leaks caused by cancelled one-shots
675        if (delayUs > 60000000LL) {
676            delayUs = 60000000LL;
677        }
678        //SL_LOGI("delayUs = %lld", delayUs);
679        sp<AMessage> msg = new AMessage(kWhatOneShot, id());
680        msg->setInt32(WHATPARAM_ONESHOT_GENERATION, mOneShotGeneration);
681        msg->post(delayUs);
682    }
683
684}
685
686} // namespace android
687