Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9be07ef6 authored by Haynes Mathew George's avatar Haynes Mathew George Committed by Steve Kondik
Browse files

libstagefright: Squashed commit of LPA/tunnel updates from CAF

libstagefright: Exceptions in using Tunnel mode decode

- Accumulate all known exceptions to a separate function

Change-Id: I61bbc288c9a087559db210e76141b8c57e67fff0
CRs-Fixed: 432080

libstagefright : Stability fixes for Tunnel Player (part 2)

- Synchronize b/w reset() and onPauseTimeout
- Synchronize b/w seekTo() and onPauseTimeout

Change-Id: Ia5cfc6b4dcc326ead440fba35d809d4f3f1b5a81
CRs-Fixed: 449122

Revert "Revert "libstagefright: Convert mono to stereo for LPA clips""

This reverts commit 0db8a19f.

libstagefright: Port Tunnel mode fixes to LPA

- Miscellaneous fixes for seek, pause/resume, EOS handling
- Miscellaneous fixes for synchronization between the decoder thread,
  TimedEventQueue and the player thread.
- This change is a port of a similar set of changes made for
  TunnelPlayer

Change-Id: I82c2904f7aedfb9c4f03200419fcba8b038e3d54

libstagefright: Avoid use of extra bytes to signal seek processed

- A few bytes were reserved in the buffer sent by Tunnel/LPA
  player to audio HAL to indicate a seek has been processed and
  there is no need to skip it.
- We won't need this method anymore as this can be fixed instead
  by synchronizing seekTo() and the extractor/decoder threads.

Change-Id: Ic02ae1699bb59e2f6b8d9fb599d0fa43fd3f19e3

libstagefright: LPAPlayer synchronization fixes

- synchronize b/w seekTo() and onPauseTimeout()
- synchronize b/w reset() and onPauseTimeout()

Change-Id: I29a4ccf02e28fe7b7c00e35a679ff2b5271ffb6f

libstagefright: TunnelPlayer performance tweaks

Some tweaks when TunnelPlayer is used for audio/video playback

- Keep the extractor thread at ANDROID_PRIORITY_NORMAL
- sched_yield() after reading a frame to give the video thread(s)
  (CallbackDispatcher and/or TimedEventQueue) to be scheduled

Change-Id: If0d86d629fd0e15aff917af8589472578cd28bf4
CRs-Fixed: 444041
parent 1bf291a7
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -93,6 +93,8 @@ private:
    bool mA2DPEnabled;
    int32_t mChannelMask;
    int32_t numChannels;
    int32_t mNumOutputChannels;
    int32_t mNumInputChannels;
    int32_t mSampleRate;
    int64_t mLatencyUs;
    size_t mFrameSize;
@@ -258,6 +260,9 @@ private:
        MediaPlayerBase::AudioSink *audioSink,
        void *buffer, size_t size, void *cookie);
    size_t AudioCallback(void *cookie, void *data, size_t size);
    int64_t getMediaTimeUs_l();

    void convertMonoToStereo(int16_t *data, size_t size);

    LPAPlayer(const LPAPlayer &);
    LPAPlayer &operator=(const LPAPlayer &);
+45 −8
Original line number Diff line number Diff line
@@ -1540,6 +1540,7 @@ status_t AwesomePlayer::initAudioDecoder() {
    if (isADTS == 1) {
        ALOGV("Widevine content\n");
    }

    ALOGV("nchannels %d;LPA will be skipped if nchannels is > 2 or nchannels == 0",
           nchannels);
#endif
@@ -1555,7 +1556,7 @@ status_t AwesomePlayer::initAudioDecoder() {

    //widevine will fallback to software decoder
    if (sys_prop_enabled && (TunnelPlayer::mTunnelObjectsAlive == 0) &&
        mTunnelAliveAP == 0 && (isADTS == 0) &&
       (mTunnelAliveAP == 0) && (isADTS == 0) &&
        mAudioSink->realtime() &&
        inSupportedTunnelFormats(mime)) {

@@ -1576,10 +1577,7 @@ status_t AwesomePlayer::initAudioDecoder() {
    else
       ALOGD("Normal Audio Playback");

    if (isStreamingHTTP()) {
      ALOGV("Streaming, force disable tunnel mode playback");
      mIsTunnelAudio = false;
    }
    checkTunnelExceptions();

    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW) ||
             (mIsTunnelAudio && (mTunnelAliveAP == 0))) {
@@ -2050,8 +2048,8 @@ void AwesomePlayer::onVideoEvent() {

        if (latenessUs > 40000) {
            // We're more than 40ms late.
            ALOGV("we're late by %lld us (%.2f secs)",
                 latenessUs, latenessUs / 1E6);
            ALOGE("we're late by %lld us nowUs %lld, timeUs %lld",
                  latenessUs, nowUs, timeUs);

            if (!(mFlags & SLOW_DECODER_HACK)
                    || mSinceLastDropped > FRAME_DROP_FREQ)
@@ -3056,6 +3054,45 @@ bool AwesomePlayer::inSupportedTunnelFormats(const char * mime) {
    ALOGW("Tunnel playback unsupported for %s", mime);
    return false;
}

void AwesomePlayer::checkTunnelExceptions()
{
    /* exception 1: No streaming */
    if (isStreamingHTTP()) {
        ALOGV("Streaming, force disable tunnel mode playback");
        mIsTunnelAudio = false;
        return;
    }

    /* below exceptions are only for av content */
    if (mVideoTrack == NULL) return;

    /* exception 2: No avi having video + mp3 */
    if (mExtractor == NULL) return;

    sp<MetaData> metaData = mExtractor->getMetaData();
    const char * container;

    /*only proceed for avi content.*/
    if (!metaData->findCString(kKeyMIMEType, &container) ||
        strcmp(container, MEDIA_MIMETYPE_CONTAINER_AVI)) {
        return;
    }

    CHECK(mAudioTrack != NULL);

    const char * mime;
    metaData = mAudioTrack->getFormat();
    /*disable for av content having mp3*/
    if (metaData->findCString(kKeyMIMEType, &mime) &&
        !strcmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
        ALOGV("Clip has AVI extractor and mp3 content, disable tunnel mode");
        mIsTunnelAudio = false;
        return;
    }

    return;
}
#endif

}  // namespace android
+191 −76
Original line number Diff line number Diff line
/*
 * Copyright (C) 2009 The Android Open Source Project
 * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
 * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
 * Not a Contribution, Apache license notifications and license are retained
 * for attribution purposes only.
 *
@@ -51,11 +51,14 @@

static const char   mName[] = "LPAPlayer";

#define MEM_BUFFER_SIZE 262144
#define MEM_PADDING 64
#define MEM_BUFFER_SIZE (256*1024)
#define MEM_BUFFER_COUNT 4

#define PCM_FORMAT 2
#define NUM_FDS 2
#define LPA_BUFFER_TIME 1500000

namespace android {
int LPAPlayer::objectsAlive = 0;

@@ -87,7 +90,8 @@ mAudioSink(audioSink),
mObserver(observer) {
    ALOGV("LPAPlayer::LPAPlayer() ctor");
    objectsAlive++;
    numChannels =0;
    mNumOutputChannels =0;
    mNumInputChannels = 0;
    mPaused = false;
    mIsA2DPEnabled = false;
    mAudioFlinger = NULL;
@@ -256,20 +260,24 @@ status_t LPAPlayer::start(bool sourceAlreadyStarted) {
    success = format->findInt32(kKeySampleRate, &mSampleRate);
    CHECK(success);

    success = format->findInt32(kKeyChannelCount, &numChannels);
    success = format->findInt32(kKeyChannelCount, &mNumInputChannels);
    CHECK(success);

    // Always produce stereo output
    mNumOutputChannels = 2;

    if(!format->findInt32(kKeyChannelMask, &mChannelMask)) {
        // log only when there's a risk of ambiguity of channel mask selection
        ALOGI_IF(numChannels > 2,
                "source format didn't specify channel mask, using (%d) channel order", numChannels);
        ALOGI_IF(mNumInputChannels > 2,
                "source format didn't specify channel mask, using (%d) channel order", mNumInputChannels);
        mChannelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
    }
    audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_LPA |
                                                         AUDIO_OUTPUT_FLAG_DIRECT);
    ALOGV("mAudiosink->open() mSampleRate %d, numChannels %d, mChannelMask %d, flags %d",mSampleRate, numChannels, mChannelMask, flags);
    ALOGV("mAudiosink->open() mSampleRate %d, numOutputChannels %d, mChannelMask %d, flags %d",mSampleRate,
          mNumOutputChannels, mChannelMask, flags);
    err = mAudioSink->open(
        mSampleRate, numChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
        mSampleRate, mNumOutputChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
        DEFAULT_AUDIOSINK_BUFFERCOUNT,
        &LPAPlayer::AudioSinkCallback,
        this,
@@ -301,16 +309,40 @@ status_t LPAPlayer::start(bool sourceAlreadyStarted) {
status_t LPAPlayer::seekTo(int64_t time_us) {
    Mutex::Autolock autoLock(mLock);
    ALOGV("seekTo: time_us %lld", time_us);
    if ( mReachedEOS ) {
        mReachedEOS = false;
        mReachedOutputEOS = false;

    int64_t mediaTimeUs = getMediaTimeUs_l();

    if (mediaTimeUs != 0) {
      //check for return conditions only if seektime
      // is set
      int64_t diffUs = time_us - mediaTimeUs;

      if (labs(diffUs) < LPA_BUFFER_TIME) {
          ALOGV("In seekTo(), ignoring time_us %lld mSeekTimeUs %lld", time_us, mSeekTimeUs);
          mObserver->postAudioSeekComplete();
          return OK;
      }
    }

    mSeeking = true;
    mSeekTimeUs = time_us;
    mPauseTime = mSeekTimeUs;
    ALOGV("In seekTo(), mSeekTimeUs %lld",mSeekTimeUs);

    if (mIsAudioRouted) {
        mAudioSink->flush();
    }

    if (mReachedEOS) {
        mReachedEOS = false;
        mReachedOutputEOS = false;
        if(mPaused == false) {
            ALOGV("Going to signal decoder thread since playback is already going on ");
            pthread_cond_signal(&decoder_cv);
            ALOGV("Signalled extractor thread.");
        }
    }
    ALOGV("seek done.");
    return OK;
}

@@ -322,21 +354,6 @@ void LPAPlayer::pause(bool playPendingSamples) {
    ALOGV("pause: playPendingSamples %d", playPendingSamples);
    mPaused = true;
    A2DPState state;
    if (playPendingSamples) {
        if (!mIsA2DPEnabled) {
            if (!mPauseEventPending) {
                ALOGV("Posting an event for Pause timeout");
                mQueue.postEventWithDelay(mPauseEvent, LPA_PAUSE_TIMEOUT_USEC);
                mPauseEventPending = true;
            }
            mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_DISABLED);
        }
        else {
            mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_ENABLED);
        }
        if (mAudioSink.get() != NULL)
            mAudioSink->pause();
    } else {
    if (!mIsA2DPEnabled) {
       if (!mPauseEventPending) {
           ALOGV("Posting an event for Pause timeout");
@@ -347,16 +364,16 @@ void LPAPlayer::pause(bool playPendingSamples) {
    } else {
        mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_ENABLED);
    }

    if (mAudioSink.get() != NULL) {
        ALOGV("AudioSink pause");
        mAudioSink->pause();
    }
}
}

void LPAPlayer::resume() {
    ALOGV("resume: mPaused %d",mPaused);
    Mutex::Autolock autoLock(mResumeLock);
    Mutex::Autolock autoLock(mLock);
    if ( mPaused) {
        CHECK(mStarted);
        if (!mIsA2DPEnabled) {
@@ -372,7 +389,7 @@ void LPAPlayer::resume() {
            audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_LPA |
                                                                AUDIO_OUTPUT_FLAG_DIRECT);
            status_t err = mAudioSink->open(
                mSampleRate, numChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
                mSampleRate, mNumOutputChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
                DEFAULT_AUDIOSINK_BUFFERCOUNT,
                &LPAPlayer::AudioSinkCallback,
                this,
@@ -394,30 +411,42 @@ size_t LPAPlayer::AudioSinkCallback(
        void *buffer, size_t size, void *cookie) {
    if (buffer == NULL && size == AudioTrack::EVENT_UNDERRUN) {
        LPAPlayer *me = (LPAPlayer *)cookie;
        me->mReachedEOS = true;
        if(me->mReachedEOS == true) {
            //in the case of seek all these flags will be reset
            me->mReachedOutputEOS = true;
        ALOGV("postAudioEOS");
            ALOGV("postAudioEOS mSeeking %d", me->mSeeking);
            me->mObserver->postAudioEOS(0);
        }else {
            ALOGV("postAudioEOS ignored since %d", me->mSeeking);
        }
    }
    return 1;
}

void LPAPlayer::reset() {
    ALOGD("Reset");

    Mutex::Autolock _l(mLock); //to sync w/ onpausetimeout

    //cancel any pending onpause timeout events
    //doesnt matter if the event is really present or not
    mPauseEventPending = false;
    mQueue.cancelEvent(mPauseEvent->eventID());

    ALOGV("Reset");
    // Close the audiosink after all the threads exited to make sure
    mReachedEOS = true;

    // make sure Decoder thread has exited
    ALOGV("Closing all the threads");
    ALOGD("Closing all the threads");
    requestAndWaitForDecoderThreadExit();
    requestAndWaitForA2DPNotificationThreadExit();

    ALOGV("Close the Sink");
    ALOGD("Close the Sink");
    if (mIsAudioRouted) {
	    mAudioSink->stop();
        mAudioSink->close();
        mAudioSink.clear();
        mIsAudioRouted = false;
    }
    // Make sure to release any buffer we hold onto so that the
    // source is able to stop().
@@ -490,25 +519,80 @@ void LPAPlayer::decoderThreadEntry() {
        return;
    }
    void* local_buf = malloc(MEM_BUFFER_SIZE);
    if(local_buf == (void*) NULL) {
        killDecoderThread = true;
        ALOGE("Malloc failed");
        return;
    }
    int *lptr = ((int*)local_buf);
    int bytesWritten = 0;

    if (!local_buf) {
      ALOGE("Failed to allocate temporary buffer for decoderThread");
      return;
    }

    bool lSeeking = false;
    bool lPaused = false;

    while (!killDecoderThread) {

        if (mReachedEOS || mPaused || !mIsAudioRouted) {
            ALOGV("Going to sleep before write since "
                  "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
                  mReachedEOS, mPaused, mIsAudioRouted);
            pthread_mutex_lock(&decoder_mutex);
            pthread_cond_wait(&decoder_cv, &decoder_mutex);
            pthread_mutex_unlock(&decoder_mutex);
            ALOGV("Woke up from sleep before write since "
                  "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
                  mReachedEOS, mPaused, mIsAudioRouted);
            continue;
        }

        if (!mIsA2DPEnabled) {
            ALOGV("FillBuffer: MemBuffer size %d", MEM_BUFFER_SIZE);
            ALOGV("Fillbuffer started");
            //TODO: Add memset
            if (mNumInputChannels == 1) {
                bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE/2);
                CHECK(bytesWritten <= MEM_BUFFER_SIZE/2);

                convertMonoToStereo((int16_t*)local_buf, bytesWritten);
                bytesWritten *= 2;
            } else {
                bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE);
            ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten);
                CHECK(bytesWritten <= MEM_BUFFER_SIZE);
            }

            ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten);
            if(!killDecoderThread) {
                mAudioSink->write(local_buf, bytesWritten);
                mLock.lock();
                lPaused = mPaused;
                mLock.unlock();

                if(lPaused == true) {
                    //write only if player is not in paused state. Sleep on lock
                    // resume is called
                    ALOGV("Going to sleep in decodethreadiwrite since sink is paused");
                    pthread_mutex_lock(&decoder_mutex);
                    pthread_cond_wait(&decoder_cv, &decoder_mutex);
                    ALOGV("Going to unlock n decodethreadwrite since sink "
                          "resumed mPaused %d, mIsAudioRouted %d, mReachedEOS %d",
                          mPaused, mIsAudioRouted, mReachedEOS);
                    pthread_mutex_unlock(&decoder_mutex);
                }
                mLock.lock();
                lSeeking = mSeeking||mInternalSeeking;
                mLock.unlock();

                if(lSeeking == false && (killDecoderThread == false)){
                    //if we are seeking, ignore write, otherwise write
                    ALOGV("Fillbuffer before seeling flag %d", mSeeking);
                    int lWrittenBytes = mAudioSink->write(local_buf, bytesWritten);
                    ALOGV("Fillbuffer after write, written bytes %d and seek flag %d", lWrittenBytes, mSeeking);
                } else {
                    ALOGV("Fillbuffer ignored since we seeked after fillBuffer was set %d", mSeeking);
                }
            }
        }
    }
@@ -580,10 +664,17 @@ size_t LPAPlayer::fillBuffer(void *data, size_t size) {
        return 0;
    }

    if ((data == (void*) NULL) || size > MEM_BUFFER_SIZE) {
        ALOGE("fillBuffer given wrong buffer");
        return 0;
    }

    bool postSeekComplete = false;

    size_t size_done = 0;
    size_t size_remaining = size;
    ALOGV("fillBuffer: Clearing seek flag in fill buffer");

    while (size_remaining > 0) {
        MediaSource::ReadOptions options;

@@ -593,6 +684,7 @@ size_t LPAPlayer::fillBuffer(void *data, size_t size) {
            if(mSeeking) {
                mInternalSeeking = false;
            }

            if (mSeeking || mInternalSeeking) {
                if (mIsFirstBuffer) {
                    if (mFirstBuffer != NULL) {
@@ -609,8 +701,9 @@ size_t LPAPlayer::fillBuffer(void *data, size_t size) {
                    mInputBuffer = NULL;
                }

                size_remaining = size;
                // This is to ignore the data already filled in the output buffer
                size_done = 0;
                size_remaining = size;

                mSeeking = false;
                if (mObserver && !mInternalSeeking) {
@@ -618,6 +711,7 @@ size_t LPAPlayer::fillBuffer(void *data, size_t size) {
                    postSeekComplete = true;
                }
                mInternalSeeking = false;
                ALOGV("fillBuffer: Setting seek flag in fill buffer");
            }
        }

@@ -636,14 +730,16 @@ size_t LPAPlayer::fillBuffer(void *data, size_t size) {

            CHECK((err == OK && mInputBuffer != NULL)
                  || (err != OK && mInputBuffer == NULL));

            {
                Mutex::Autolock autoLock(mLock);

                if (err != OK) {
                    ALOGD("fill buffer - reached eos true");
                    mReachedEOS = true;
                    mFinalStatus = err;
                    break;
                }
            }

            CHECK(mInputBuffer->meta_data()->findInt64(
                        kKeyTime, &mPositionTimeMediaUs));
@@ -662,7 +758,7 @@ size_t LPAPlayer::fillBuffer(void *data, size_t size) {
        size_t copy = size_remaining;
        if (copy > mInputBuffer->range_length()) {
            copy = mInputBuffer->range_length();
        }
        } //is size_remaining < range_length impossible?

        memcpy((char *)data + size_done,
               (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
@@ -712,9 +808,7 @@ int64_t LPAPlayer::getTimeStamp(A2DPState state) {
    return timestamp;
}

int64_t LPAPlayer::getMediaTimeUs() {
    Mutex::Autolock autoLock(mLock);
    ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld mPauseTime %lld", mPaused, mSeekTimeUs, mPauseTime);
int64_t LPAPlayer::getMediaTimeUs_l() {
    if (mPaused) {
        return mPauseTime;
    } else {
@@ -723,16 +817,21 @@ int64_t LPAPlayer::getMediaTimeUs() {
    }
}

bool LPAPlayer::getMediaTimeMapping(
                                   int64_t *realtime_us, int64_t *mediatime_us) {
int64_t LPAPlayer::getMediaTimeUs() {
    Mutex::Autolock autoLock(mLock);
    ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld mPauseTime %lld", mPaused, mSeekTimeUs, mPauseTime);
    return getMediaTimeUs_l();
}

    *realtime_us = mPositionTimeRealUs;
    *mediatime_us = mPositionTimeMediaUs;

    return mPositionTimeRealUs != -1 && mPositionTimeMediaUs != -1;
bool LPAPlayer::getMediaTimeMapping(
                                   int64_t *realtime_us, int64_t *mediatime_us) {
    ALOGE("getMediaTimeMapping is invalid for LPA Player");
    *realtime_us = -1;
    *mediatime_us = -1;
    return false;
}

//lock taken in reset()
void LPAPlayer::requestAndWaitForDecoderThreadExit() {

    if (!decoderThreadAlive)
@@ -745,8 +844,10 @@ void LPAPlayer::requestAndWaitForDecoderThreadExit() {
        mAudioSink->flush();

    pthread_cond_signal(&decoder_cv);
    mLock.unlock();
    pthread_join(decoderThread,NULL);
    ALOGV("decoder thread killed");
    mLock.lock();
    ALOGD("decoder thread killed");

}

@@ -761,7 +862,7 @@ void LPAPlayer::requestAndWaitForA2DPNotificationThreadExit() {

void LPAPlayer::onPauseTimeOut() {
    ALOGV("onPauseTimeOut");
    Mutex::Autolock autoLock(mResumeLock);
    Mutex::Autolock autoLock(mLock);
    if (!mPauseEventPending) {
        return;
    }
@@ -790,4 +891,18 @@ void LPAPlayer::onPauseTimeOut() {

}

//dup each mono frame
void LPAPlayer::convertMonoToStereo(int16_t *data, size_t size)
{
    int i =0;
    int16_t *start_pointer = data;
    int monoFrameCount = (size) / (sizeof(int16_t));

    for (i = monoFrameCount; i > 0 ; i--) {
      int16_t temp_sample = *(start_pointer + i - 1);
      *(start_pointer + (i*2) - 1) = temp_sample;
      *(start_pointer + (i*2) - 2) = temp_sample;
    }
}

} //namespace android
+45 −14
Original line number Diff line number Diff line
@@ -51,6 +51,13 @@
static const char   mName[] = "TunnelPlayer";
#define MEM_METADATA_SIZE 64
#define MEM_PADDING 64
/*
 * We need to reserve some space in the
 * ion buffer (used in HAL) to save the
 * metadata. so read from the extractor
 * a somewhat smaller number of bytes.
 * ideally this number should be bufer_size - sizeof(struct output_metadata_t)
 */
#define MEM_BUFFER_SIZE (240*1024 - MEM_METADATA_SIZE)
#define MEM_BUFFER_COUNT 4
#define TUNNEL_BUFFER_TIME 1500000
@@ -374,7 +381,9 @@ status_t TunnelPlayer::start(bool sourceAlreadyStarted) {

status_t TunnelPlayer::seekTo(int64_t time_us) {

    ALOGV("seekTo: time_us %lld", time_us);
    ALOGD("seekTo: time_us %lld", time_us);

    Mutex::Autolock _l(mLock); //to sync w/ onpausetimeout

    //This can happen if the client calls seek
    //without ever calling getPosition
@@ -385,20 +394,27 @@ status_t TunnelPlayer::seekTo(int64_t time_us) {
    if (mPositionTimeRealUs > 0) {
      //check for return conditions only if seektime
      // is set
      bool postSeekComplete = false;

      if (time_us > mPositionTimeRealUs){
           if ((time_us - mPositionTimeRealUs) < TUNNEL_BUFFER_TIME){
             ALOGV("In seekTo(), ignoring time_us %lld mSeekTimeUs %lld", time_us, mSeekTimeUs);
             mObserver->postAudioSeekComplete();
             return OK;
             postSeekComplete = true;
           }
      } else {
           if ((mPositionTimeRealUs - time_us) < TUNNEL_BUFFER_TIME){
               ALOGV("In seekTo(), ignoring time_us %lld mSeekTimeUs %lld", time_us, mSeekTimeUs);
               postSeekComplete = true;
           }
      }

      if (postSeekComplete) {
          mLock.unlock(); //unlock and post
          mObserver->postAudioSeekComplete();
          mLock.lock();
          return OK;
      }
    }
    }

    mSeeking = true;
    mSeekTimeUs = time_us;
@@ -502,6 +518,13 @@ size_t TunnelPlayer::AudioSinkCallback(
void TunnelPlayer::reset() {
    ALOGV("Reset");

    Mutex::Autolock _l(mLock); //to sync w/ onpausetimeout

    //cancel any pending onpause timeout events
    //doesnt matter if the event is really present or not
    mPauseEventPending = false;
    mQueue.cancelEvent(mPauseEvent->eventID());

    mReachedEOS = true;

    // make sure Decoder thread has exited
@@ -568,7 +591,8 @@ void TunnelPlayer::extractorThreadEntry() {
    uint32_t BufferSizeToUse = MEM_BUFFER_SIZE;

    pid_t tid  = gettid();
    androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO);
    androidSetThreadPriority(tid, mHasVideo ? ANDROID_PRIORITY_NORMAL :
                                              ANDROID_PRIORITY_AUDIO);
    prctl(PR_SET_NAME, (unsigned long)"Extractor Thread", 0, 0, 0);

    ALOGV("extractorThreadEntry wait for signal \n");
@@ -585,7 +609,7 @@ void TunnelPlayer::extractorThreadEntry() {
        const char *mime;
        bool success = format->findCString(kKeyMIMEType, &mime);
    }
    void* local_buf = malloc(BufferSizeToUse + MEM_PADDING);
    void* local_buf = malloc(BufferSizeToUse);
    int *lptr = ((int*)local_buf);
    int bytesWritten = 0;
    bool lSeeking = false;
@@ -632,8 +656,7 @@ void TunnelPlayer::extractorThreadEntry() {

                if(lSeeking == false && (killExtractorThread == false)){
                    //if we are seeking, ignore write, otherwise write
                    ALOGV("Fillbuffer before write %d and seek flag %d", mSeeking,
                          lptr[MEM_BUFFER_SIZE/sizeof(int)]);
                  ALOGV("Fillbuffer before seek flag %d", mSeeking);
                    int lWrittenBytes = mAudioSink->write(local_buf, bytesWritten);
                    ALOGV("Fillbuffer after write, written bytes %d and seek flag %d", lWrittenBytes, mSeeking);
                    if(lWrittenBytes > 0) {
@@ -660,6 +683,7 @@ void TunnelPlayer::extractorThreadEntry() {
                }
            }
        }

    }

    free(local_buf);
@@ -696,11 +720,11 @@ size_t TunnelPlayer::fillBuffer(void *data, size_t size) {

    size_t size_done = 0;
    size_t size_remaining = size;
    int *ldataptr = (int*) data;
    //clear the flag since we dont know whether we are seeking or not, yet
    ldataptr[(MEM_BUFFER_SIZE/sizeof(int))] = 0;
    ALOGV("fillBuffer: Clearing seek flag in fill buffer");

    bool yield = !mIsFirstBuffer;

    while (size_remaining > 0) {
        MediaSource::ReadOptions options;
        {
@@ -738,7 +762,6 @@ size_t TunnelPlayer::fillBuffer(void *data, size_t size) {
                mInternalSeeking = false;
                ALOGV("fillBuffer: Setting seek flag in fill buffer");
                //set the flag since we know that this buffer is the new positions buffer
                ldataptr[(MEM_BUFFER_SIZE/sizeof(int))] = 1;
            }
        }
        if (mInputBuffer == NULL) {
@@ -787,6 +810,10 @@ size_t TunnelPlayer::fillBuffer(void *data, size_t size) {

        size_done += copy;
        size_remaining -= copy;

        if (mHasVideo && yield) {
            sched_yield();
        }
    }
    if(mReachedEOS)
        memset((char *)data + size_done, 0x0, size_remaining);
@@ -841,7 +868,9 @@ bool TunnelPlayer::getMediaTimeMapping(
    return mPositionTimeRealUs != -1 && mPositionTimeMediaUs != -1;
}

//lock has been taken in reset() to sync with onpausetimeout
void TunnelPlayer::requestAndWaitForExtractorThreadExit() {
    ALOGV("requestAndWaitForExtractorThreadExit -1");

    if (!extractorThreadAlive)
        return;
@@ -856,7 +885,9 @@ void TunnelPlayer::requestAndWaitForExtractorThreadExit() {
    ALOGV("requestAndWaitForExtractorThreadExit +1");
    pthread_cond_signal(&extractor_cv);
    ALOGV("requestAndWaitForExtractorThreadExit +2");
    mLock.unlock();
    pthread_join(extractorThread,NULL);
    mLock.lock();
    ALOGV("requestAndWaitForExtractorThreadExit +3");

    ALOGV("Extractor thread killed");
+3 −0
Original line number Diff line number Diff line
@@ -309,6 +309,9 @@ private:
    void logLate(int64_t ts, int64_t clock, int64_t delta);
    void logOnTime(int64_t ts, int64_t clock, int64_t delta);
    int64_t getTimeOfDayUs();
#ifdef QCOM_HARDWARE
    void checkTunnelExceptions();
#endif
    bool mStatistics;

    struct TrackStat {