summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/libmedia/AudioSystem.cpp185
-rw-r--r--media/libmedia/AudioTrack.cpp5
-rw-r--r--media/libmedia/AudioTrackShared.cpp60
-rw-r--r--media/libmediaplayerservice/Drm.cpp6
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp1
-rw-r--r--media/libmediaplayerservice/nuplayer/GenericSource.cpp26
-rw-r--r--media/libmediaplayerservice/nuplayer/GenericSource.h4
-rw-r--r--media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp10
-rw-r--r--media/libmediaplayerservice/nuplayer/HTTPLiveSource.h3
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.cpp45
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.h2
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp17
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp19
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h3
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerSource.h2
-rw-r--r--media/libstagefright/ACodec.cpp18
-rw-r--r--media/libstagefright/AwesomePlayer.cpp10
-rw-r--r--media/libstagefright/httplive/LiveSession.cpp8
-rw-r--r--media/libstagefright/httplive/LiveSession.h2
-rw-r--r--media/libstagefright/httplive/M3UParser.cpp35
-rw-r--r--media/libstagefright/httplive/M3UParser.h2
-rw-r--r--media/libstagefright/httplive/PlaylistFetcher.cpp20
22 files changed, 362 insertions, 121 deletions
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index fce4389..1f8e9b6 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -32,6 +32,7 @@ namespace android {
// client singleton for AudioFlinger binder interface
Mutex AudioSystem::gLock;
+Mutex AudioSystem::gLockCache;
Mutex AudioSystem::gLockAPS;
Mutex AudioSystem::gLockAPC;
sp<IAudioFlinger> AudioSystem::gAudioFlinger;
@@ -50,33 +51,40 @@ size_t AudioSystem::gInBuffSize = 0; // zero indicates cache is invalid
sp<AudioSystem::AudioPortCallback> AudioSystem::gAudioPortCallback;
// establish binder interface to AudioFlinger service
-const sp<IAudioFlinger>& AudioSystem::get_audio_flinger()
+const sp<IAudioFlinger> AudioSystem::get_audio_flinger()
{
- Mutex::Autolock _l(gLock);
- if (gAudioFlinger == 0) {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder;
- do {
- binder = sm->getService(String16("media.audio_flinger"));
- if (binder != 0)
- break;
- ALOGW("AudioFlinger not published, waiting...");
- usleep(500000); // 0.5 s
- } while (true);
- if (gAudioFlingerClient == NULL) {
- gAudioFlingerClient = new AudioFlingerClient();
- } else {
- if (gAudioErrorCallback) {
- gAudioErrorCallback(NO_ERROR);
+ sp<IAudioFlinger> af;
+ sp<AudioFlingerClient> afc;
+ {
+ Mutex::Autolock _l(gLock);
+ if (gAudioFlinger == 0) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder;
+ do {
+ binder = sm->getService(String16("media.audio_flinger"));
+ if (binder != 0)
+ break;
+ ALOGW("AudioFlinger not published, waiting...");
+ usleep(500000); // 0.5 s
+ } while (true);
+ if (gAudioFlingerClient == NULL) {
+ gAudioFlingerClient = new AudioFlingerClient();
+ } else {
+ if (gAudioErrorCallback) {
+ gAudioErrorCallback(NO_ERROR);
+ }
}
+ binder->linkToDeath(gAudioFlingerClient);
+ gAudioFlinger = interface_cast<IAudioFlinger>(binder);
+ LOG_ALWAYS_FATAL_IF(gAudioFlinger == 0);
+ afc = gAudioFlingerClient;
}
- binder->linkToDeath(gAudioFlingerClient);
- gAudioFlinger = interface_cast<IAudioFlinger>(binder);
- LOG_ALWAYS_FATAL_IF(gAudioFlinger == 0);
- gAudioFlinger->registerClient(gAudioFlingerClient);
+ af = gAudioFlinger;
}
-
- return gAudioFlinger;
+ if (afc != 0) {
+ af->registerClient(afc);
+ }
+ return af;
}
/* static */ status_t AudioSystem::checkAudioFlinger()
@@ -250,20 +258,20 @@ status_t AudioSystem::getOutputSamplingRate(uint32_t* samplingRate, audio_stream
status_t AudioSystem::getSamplingRate(audio_io_handle_t output,
uint32_t* samplingRate)
{
- OutputDescriptor *outputDesc;
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+
+ Mutex::Autolock _l(gLockCache);
- gLock.lock();
- outputDesc = AudioSystem::gOutputs.valueFor(output);
+ OutputDescriptor *outputDesc = AudioSystem::gOutputs.valueFor(output);
if (outputDesc == NULL) {
ALOGV("getOutputSamplingRate() no output descriptor for output %d in gOutputs", output);
- gLock.unlock();
- const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ gLockCache.unlock();
*samplingRate = af->sampleRate(output);
+ gLockCache.lock();
} else {
ALOGV("getOutputSamplingRate() reading from output desc");
*samplingRate = outputDesc->samplingRate;
- gLock.unlock();
}
if (*samplingRate == 0) {
ALOGE("AudioSystem::getSamplingRate failed for output %d", output);
@@ -294,18 +302,18 @@ status_t AudioSystem::getOutputFrameCount(size_t* frameCount, audio_stream_type_
status_t AudioSystem::getFrameCount(audio_io_handle_t output,
size_t* frameCount)
{
- OutputDescriptor *outputDesc;
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
- gLock.lock();
- outputDesc = AudioSystem::gOutputs.valueFor(output);
+ Mutex::Autolock _l(gLockCache);
+
+ OutputDescriptor *outputDesc = AudioSystem::gOutputs.valueFor(output);
if (outputDesc == NULL) {
- gLock.unlock();
- const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ gLockCache.unlock();
*frameCount = af->frameCount(output);
+ gLockCache.lock();
} else {
*frameCount = outputDesc->frameCount;
- gLock.unlock();
}
if (*frameCount == 0) {
ALOGE("AudioSystem::getFrameCount failed for output %d", output);
@@ -336,18 +344,18 @@ status_t AudioSystem::getOutputLatency(uint32_t* latency, audio_stream_type_t st
status_t AudioSystem::getLatency(audio_io_handle_t output,
uint32_t* latency)
{
- OutputDescriptor *outputDesc;
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+
+ Mutex::Autolock _l(gLockCache);
- gLock.lock();
- outputDesc = AudioSystem::gOutputs.valueFor(output);
+ OutputDescriptor *outputDesc = AudioSystem::gOutputs.valueFor(output);
if (outputDesc == NULL) {
- gLock.unlock();
- const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
+ gLockCache.unlock();
*latency = af->latency(output);
+ gLockCache.lock();
} else {
*latency = outputDesc->latency;
- gLock.unlock();
}
ALOGV("getLatency() output %d, latency %d", output, *latency);
@@ -358,24 +366,24 @@ status_t AudioSystem::getLatency(audio_io_handle_t output,
status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t format,
audio_channel_mask_t channelMask, size_t* buffSize)
{
- gLock.lock();
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ return PERMISSION_DENIED;
+ }
+ Mutex::Autolock _l(gLockCache);
// Do we have a stale gInBufferSize or are we requesting the input buffer size for new values
size_t inBuffSize = gInBuffSize;
if ((inBuffSize == 0) || (sampleRate != gPrevInSamplingRate) || (format != gPrevInFormat)
|| (channelMask != gPrevInChannelMask)) {
- gLock.unlock();
- const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
- if (af == 0) {
- return PERMISSION_DENIED;
- }
+ gLockCache.unlock();
inBuffSize = af->getInputBufferSize(sampleRate, format, channelMask);
+ gLockCache.lock();
if (inBuffSize == 0) {
ALOGE("AudioSystem::getInputBufferSize failed sampleRate %d format %#x channelMask %x",
sampleRate, format, channelMask);
return BAD_VALUE;
}
// A benign race is possible here: we could overwrite a fresher cache entry
- gLock.lock();
// save the request params
gPrevInSamplingRate = sampleRate;
gPrevInFormat = format;
@@ -383,7 +391,6 @@ status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t for
gInBuffSize = inBuffSize;
}
- gLock.unlock();
*buffSize = inBuffSize;
return NO_ERROR;
@@ -450,14 +457,21 @@ audio_hw_sync_t AudioSystem::getAudioHwSyncForSession(audio_session_t sessionId)
void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who __unused)
{
- Mutex::Autolock _l(AudioSystem::gLock);
+ audio_error_callback cb = NULL;
+ {
+ Mutex::Autolock _l(AudioSystem::gLock);
+ AudioSystem::gAudioFlinger.clear();
+ cb = gAudioErrorCallback;
+ }
- AudioSystem::gAudioFlinger.clear();
- // clear output handles and stream to output map caches
- AudioSystem::gOutputs.clear();
+ {
+ // clear output handles and stream to output map caches
+ Mutex::Autolock _l(gLockCache);
+ AudioSystem::gOutputs.clear();
+ }
- if (gAudioErrorCallback) {
- gAudioErrorCallback(DEAD_OBJECT);
+ if (cb) {
+ cb(DEAD_OBJECT);
}
ALOGW("AudioFlinger server died!");
}
@@ -470,7 +484,7 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle
if (ioHandle == AUDIO_IO_HANDLE_NONE) return;
- Mutex::Autolock _l(AudioSystem::gLock);
+ Mutex::Autolock _l(AudioSystem::gLockCache);
switch (event) {
case STREAM_CONFIG_CHANGED:
@@ -539,29 +553,37 @@ sp<AudioSystem::AudioPolicyServiceClient> AudioSystem::gAudioPolicyServiceClient
// establish binder interface to AudioPolicy service
-const sp<IAudioPolicyService>& AudioSystem::get_audio_policy_service()
-{
- Mutex::Autolock _l(gLockAPS);
- if (gAudioPolicyService == 0) {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder;
- do {
- binder = sm->getService(String16("media.audio_policy"));
- if (binder != 0)
- break;
- ALOGW("AudioPolicyService not published, waiting...");
- usleep(500000); // 0.5 s
- } while (true);
- if (gAudioPolicyServiceClient == NULL) {
- gAudioPolicyServiceClient = new AudioPolicyServiceClient();
+const sp<IAudioPolicyService> AudioSystem::get_audio_policy_service()
+{
+ sp<IAudioPolicyService> ap;
+ sp<AudioPolicyServiceClient> apc;
+ {
+ Mutex::Autolock _l(gLockAPS);
+ if (gAudioPolicyService == 0) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder;
+ do {
+ binder = sm->getService(String16("media.audio_policy"));
+ if (binder != 0)
+ break;
+ ALOGW("AudioPolicyService not published, waiting...");
+ usleep(500000); // 0.5 s
+ } while (true);
+ if (gAudioPolicyServiceClient == NULL) {
+ gAudioPolicyServiceClient = new AudioPolicyServiceClient();
+ }
+ binder->linkToDeath(gAudioPolicyServiceClient);
+ gAudioPolicyService = interface_cast<IAudioPolicyService>(binder);
+ LOG_ALWAYS_FATAL_IF(gAudioPolicyService == 0);
+ apc = gAudioPolicyServiceClient;
}
- binder->linkToDeath(gAudioPolicyServiceClient);
- gAudioPolicyService = interface_cast<IAudioPolicyService>(binder);
- LOG_ALWAYS_FATAL_IF(gAudioPolicyService == 0);
- gAudioPolicyService->registerClient(gAudioPolicyServiceClient);
+ ap = gAudioPolicyService;
+ }
+ if (apc != 0) {
+ ap->registerClient(apc);
}
- return gAudioPolicyService;
+ return ap;
}
// ---------------------------------------------------------------------------
@@ -829,8 +851,11 @@ void AudioSystem::clearAudioConfigCache()
// called by restoreTrack_l(), which needs new IAudioFlinger and IAudioPolicyService instances
ALOGV("clearAudioConfigCache()");
{
- Mutex::Autolock _l(gLock);
+ Mutex::Autolock _l(gLockCache);
gOutputs.clear();
+ }
+ {
+ Mutex::Autolock _l(gLock);
gAudioFlinger.clear();
}
{
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 2f57b9d..c11050e 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -2149,6 +2149,11 @@ void AudioTrack::setStreamTypeFromAttributes(audio_attributes_t& aa) {
mStreamType = AUDIO_STREAM_ALARM;
break;
}
+ audio_mode_t phoneState = AudioSystem::getPhoneState();
+ if (phoneState == AUDIO_MODE_IN_CALL || phoneState == AUDIO_MODE_IN_COMMUNICATION) {
+ mStreamType = AUDIO_STREAM_VOICE_CALL;
+ break;
+ }
} /// FALL THROUGH
case AUDIO_USAGE_MEDIA:
case AUDIO_USAGE_GAME:
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 561cb24..62362da 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -25,6 +25,12 @@
namespace android {
+// used to clamp a value to size_t. TODO: move to another file.
+template <typename T>
+size_t clampToSize(T x) {
+ return x > SIZE_MAX ? SIZE_MAX : x < 0 ? 0 : (size_t) x;
+}
+
audio_track_cblk_t::audio_track_cblk_t()
: mServer(0), mFutex(0), mMinimum(0),
mVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY), mSampleRate(0), mSendLevel(0), mFlags(0)
@@ -728,7 +734,8 @@ StaticAudioTrackServerProxy::StaticAudioTrackServerProxy(audio_track_cblk_t* cbl
size_t frameCount, size_t frameSize)
: AudioTrackServerProxy(cblk, buffers, frameCount, frameSize),
mObserver(&cblk->u.mStatic.mSingleStateQueue), mPosition(0),
- mEnd(frameCount), mFramesReadyIsCalledByMultipleThreads(false)
+ mFramesReadySafe(frameCount), mFramesReady(frameCount),
+ mFramesReadyIsCalledByMultipleThreads(false)
{
mState.mLoopStart = 0;
mState.mLoopEnd = 0;
@@ -742,20 +749,11 @@ void StaticAudioTrackServerProxy::framesReadyIsCalledByMultipleThreads()
size_t StaticAudioTrackServerProxy::framesReady()
{
- // FIXME
- // This is racy if called by normal mixer thread,
- // as we're reading 2 independent variables without a lock.
- // Can't call mObserver.poll(), as we might be called from wrong thread.
- // If looping is enabled, should return a higher number (since includes non-contiguous).
- size_t position = mPosition;
+ // Can't call pollPosition() from multiple threads.
if (!mFramesReadyIsCalledByMultipleThreads) {
- ssize_t positionOrStatus = pollPosition();
- if (positionOrStatus >= 0) {
- position = (size_t) positionOrStatus;
- }
+ (void) pollPosition();
}
- size_t end = mEnd;
- return position < end ? end - position : 0;
+ return mFramesReadySafe;
}
ssize_t StaticAudioTrackServerProxy::pollPosition()
@@ -772,25 +770,35 @@ ssize_t StaticAudioTrackServerProxy::pollPosition()
}
// ignore loopEnd
mPosition = position = loopStart;
- mEnd = mFrameCount;
+ mFramesReady = mFrameCount - mPosition;
mState.mLoopCount = 0;
valid = true;
- } else {
+ } else if (state.mLoopCount >= -1) {
if (loopStart < loopEnd && loopEnd <= mFrameCount &&
loopEnd - loopStart >= MIN_LOOP) {
if (!(loopStart <= position && position < loopEnd)) {
mPosition = position = loopStart;
}
- mEnd = loopEnd;
+ if (state.mLoopCount == -1) {
+ mFramesReady = INT64_MAX;
+ } else {
+ // mFramesReady is 64 bits to handle the effective number of frames
+ // that the static audio track contains, including loops.
+ // TODO: Later consider fixing overflow, but does not seem needed now
+ // as will not overflow if loopStart and loopEnd are Java "ints".
+ mFramesReady = int64_t(state.mLoopCount) * (loopEnd - loopStart)
+ + mFrameCount - mPosition;
+ }
mState = state;
valid = true;
}
}
- if (!valid) {
+ if (!valid || mPosition > mFrameCount) {
ALOGE("%s client pushed an invalid state, shutting down", __func__);
mIsShutdown = true;
return (ssize_t) NO_INIT;
}
+ mFramesReadySafe = clampToSize(mFramesReady);
// This may overflow, but client is not supposed to rely on it
mCblk->u.mStatic.mBufferPosition = (uint32_t) position;
}
@@ -815,9 +823,10 @@ status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush
return (status_t) positionOrStatus;
}
size_t position = (size_t) positionOrStatus;
+ size_t end = mState.mLoopCount != 0 ? mState.mLoopEnd : mFrameCount;
size_t avail;
- if (position < mEnd) {
- avail = mEnd - position;
+ if (position < end) {
+ avail = end - position;
size_t wanted = buffer->mFrameCount;
if (avail < wanted) {
buffer->mFrameCount = avail;
@@ -830,7 +839,10 @@ status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush
buffer->mFrameCount = 0;
buffer->mRaw = NULL;
}
- buffer->mNonContig = 0; // FIXME should be > 0 for looping
+ // As mFramesReady is the total remaining frames in the static audio track,
+ // it is always larger or equal to avail.
+ LOG_ALWAYS_FATAL_IF(mFramesReady < avail);
+ buffer->mNonContig = mFramesReady == INT64_MAX ? SIZE_MAX : clampToSize(mFramesReady - avail);
mUnreleased = avail;
return NO_ERROR;
}
@@ -838,6 +850,7 @@ status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush
void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer)
{
size_t stepCount = buffer->mFrameCount;
+ LOG_ALWAYS_FATAL_IF(!(stepCount <= mFramesReady));
LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased));
if (stepCount == 0) {
// prevent accidental re-use of buffer
@@ -854,11 +867,10 @@ void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer)
ALOGW("%s newPosition %zu outside [%zu, %zu]", __func__, newPosition, position, mFrameCount);
newPosition = mFrameCount;
} else if (mState.mLoopCount != 0 && newPosition == mState.mLoopEnd) {
+ newPosition = mState.mLoopStart;
if (mState.mLoopCount == -1 || --mState.mLoopCount != 0) {
- newPosition = mState.mLoopStart;
setFlags = CBLK_LOOP_CYCLE;
} else {
- mEnd = mFrameCount; // this is what allows playback to continue after the loop
setFlags = CBLK_LOOP_FINAL;
}
}
@@ -866,6 +878,10 @@ void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer)
setFlags |= CBLK_BUFFER_END;
}
mPosition = newPosition;
+ if (mFramesReady != INT64_MAX) {
+ mFramesReady -= stepCount;
+ }
+ mFramesReadySafe = clampToSize(mFramesReady);
cblk->mServer += stepCount;
// This may overflow, but client is not supposed to rely on it
diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp
index 2a8b2c6..81dad41 100644
--- a/media/libmediaplayerservice/Drm.cpp
+++ b/media/libmediaplayerservice/Drm.cpp
@@ -674,10 +674,14 @@ status_t Drm::signRSA(Vector<uint8_t> const &sessionId,
void Drm::binderDied(const wp<IBinder> &the_late_who)
{
+ mEventLock.lock();
+ mListener.clear();
+ mEventLock.unlock();
+
+ Mutex::Autolock autoLock(mLock);
delete mPlugin;
mPlugin = NULL;
closeFactory();
- mListener.clear();
}
} // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index c120898..d461af3 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -2125,6 +2125,7 @@ ssize_t MediaPlayerService::AudioCache::write(const void* buffer, size_t size)
// immutable with respect to future writes.
//
// It is thus safe for another thread to read the AudioCache.
+ Mutex::Autolock lock(mLock);
mCommandComplete = true;
mSignal.signal();
}
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index eb10dda..e7a26b6 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -1005,11 +1005,12 @@ ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const
return -1;
}
-status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) {
+status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
sp<AMessage> msg = new AMessage(kWhatSelectTrack, id());
msg->setInt32("trackIndex", trackIndex);
msg->setInt32("select", select);
+ msg->setInt64("timeUs", timeUs);
sp<AMessage> response;
status_t err = msg->postAndAwaitResponse(&response);
@@ -1022,11 +1023,13 @@ status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) {
void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) {
int32_t trackIndex, select;
+ int64_t timeUs;
CHECK(msg->findInt32("trackIndex", &trackIndex));
CHECK(msg->findInt32("select", &select));
+ CHECK(msg->findInt64("timeUs", &timeUs));
sp<AMessage> response = new AMessage;
- status_t err = doSelectTrack(trackIndex, select);
+ status_t err = doSelectTrack(trackIndex, select, timeUs);
response->setInt32("err", err);
uint32_t replyID;
@@ -1034,7 +1037,7 @@ void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) {
response->postReply(replyID);
}
-status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select) {
+status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select, int64_t timeUs) {
if (trackIndex >= mSources.size()) {
return BAD_INDEX;
}
@@ -1087,6 +1090,23 @@ status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select)
mFetchTimedTextDataGeneration++;
}
+ status_t eosResult; // ignored
+ if (mSubtitleTrack.mSource != NULL
+ && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
+ sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
+ msg->setInt64("timeUs", timeUs);
+ msg->setInt32("generation", mFetchSubtitleDataGeneration);
+ msg->post();
+ }
+
+ if (mTimedTextTrack.mSource != NULL
+ && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
+ sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
+ msg->setInt64("timeUs", timeUs);
+ msg->setInt32("generation", mFetchTimedTextDataGeneration);
+ msg->post();
+ }
+
return OK;
} else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
bool audio = !strncasecmp(mime, "audio/", 6);
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 7a03df0..f2528a9 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -67,7 +67,7 @@ struct NuPlayer::GenericSource : public NuPlayer::Source {
virtual size_t getTrackCount() const;
virtual sp<AMessage> getTrackInfo(size_t trackIndex) const;
virtual ssize_t getSelectedTrack(media_track_type type) const;
- virtual status_t selectTrack(size_t trackIndex, bool select);
+ virtual status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs);
virtual status_t seekTo(int64_t seekTimeUs);
virtual status_t setBuffers(bool audio, Vector<MediaBuffer *> &buffers);
@@ -164,7 +164,7 @@ private:
ssize_t doGetSelectedTrack(media_track_type type) const;
void onSelectTrack(sp<AMessage> msg);
- status_t doSelectTrack(size_t trackIndex, bool select);
+ status_t doSelectTrack(size_t trackIndex, bool select, int64_t timeUs);
void onSeek(sp<AMessage> msg);
status_t doSeek(int64_t seekTimeUs);
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 02e9caf..a26ef9e 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -139,7 +139,15 @@ sp<AMessage> NuPlayer::HTTPLiveSource::getTrackInfo(size_t trackIndex) const {
return mLiveSession->getTrackInfo(trackIndex);
}
-status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select) {
+ssize_t NuPlayer::HTTPLiveSource::getSelectedTrack(media_track_type type) const {
+ if (mLiveSession == NULL) {
+ return -1;
+ } else {
+ return mLiveSession->getSelectedTrack(type);
+ }
+}
+
+status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select, int64_t /*timeUs*/) {
status_t err = mLiveSession->selectTrack(trackIndex, select);
if (err == OK) {
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
index 6b5f6af..bbb8981 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -42,7 +42,8 @@ struct NuPlayer::HTTPLiveSource : public NuPlayer::Source {
virtual status_t getDuration(int64_t *durationUs);
virtual size_t getTrackCount() const;
virtual sp<AMessage> getTrackInfo(size_t trackIndex) const;
- virtual status_t selectTrack(size_t trackIndex, bool select);
+ virtual ssize_t getSelectedTrack(media_track_type /* type */) const;
+ virtual status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs);
virtual status_t seekTo(int64_t seekTimeUs);
protected:
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 4f88f02..c01f16a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -33,6 +33,8 @@
#include "ATSParser.h"
+#include <cutils/properties.h>
+
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -453,8 +455,10 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
size_t trackIndex;
int32_t select;
+ int64_t timeUs;
CHECK(msg->findSize("trackIndex", &trackIndex));
CHECK(msg->findInt32("select", &select));
+ CHECK(msg->findInt64("timeUs", &timeUs));
status_t err = INVALID_OPERATION;
@@ -468,7 +472,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
}
if (trackIndex < inbandTracks) {
- err = mSource->selectTrack(trackIndex, select);
+ err = mSource->selectTrack(trackIndex, select, timeUs);
if (!select && err == OK) {
int32_t type;
@@ -604,8 +608,17 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
instantiateDecoder(false, &mVideoDecoder);
}
- if (mAudioSink != NULL) {
- if (mOffloadAudio) {
+ // Don't try to re-open audio sink if there's an existing decoder.
+ if (mAudioSink != NULL && mAudioDecoder == NULL) {
+ sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
+ sp<AMessage> videoFormat = mSource->getFormat(false /* audio */);
+ audio_stream_type_t streamType = mAudioSink->getAudioStreamType();
+ bool canOffload = canOffloadStream(audioMeta, (videoFormat != NULL),
+ true /* is_streaming */, streamType);
+ if (canOffload) {
+ if (!mOffloadAudio) {
+ mRenderer->signalEnableOffloadAudio();
+ }
// open audio sink early under offload mode.
sp<AMessage> format = mSource->getFormat(true /*audio*/);
openAudioSink(format, true /*offloadOnly*/);
@@ -839,7 +852,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
ALOGV("media rendering started");
notifyListener(MEDIA_STARTED, 0, 0);
} else if (what == Renderer::kWhatAudioOffloadTearDown) {
- ALOGV("Tear down audio offload, fall back to s/w path");
+ ALOGV("Tear down audio offload, fall back to s/w path if due to error.");
int64_t positionUs;
CHECK(msg->findInt64("positionUs", &positionUs));
int32_t reason;
@@ -851,11 +864,11 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
if (mVideoDecoder != NULL) {
mRenderer->flush(false /* audio */);
}
- mRenderer->signalDisableOffloadAudio();
- mOffloadAudio = false;
performSeek(positionUs, false /* needNotify */);
if (reason == Renderer::kDueToError) {
+ mRenderer->signalDisableOffloadAudio();
+ mOffloadAudio = false;
instantiateDecoder(true /* audio */, &mAudioDecoder);
}
}
@@ -1190,6 +1203,17 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) {
notify->setInt32("generation", mVideoDecoderGeneration);
*decoder = new Decoder(notify, mSource, mRenderer, mNativeWindow);
+
+ // enable FRC if high-quality AV sync is requested, even if not
+ // queuing to native window, as this will even improve textureview
+ // playback.
+ {
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("persist.sys.media.avsync", value, NULL) &&
+ (!strcmp("1", value) || !strcasecmp("true", value))) {
+ format->setInt32("auto-frc", 1);
+ }
+ }
}
(*decoder)->init();
(*decoder)->configure(format);
@@ -1321,6 +1345,12 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) {
// This stream is unaffected by the discontinuity
return -EWOULDBLOCK;
}
+ } else if (err == ERROR_END_OF_STREAM
+ && doBufferAggregation && (mAggregateBuffer != NULL)) {
+ // send out the last bit of aggregated data
+ reply->setBuffer("buffer", mAggregateBuffer);
+ mAggregateBuffer.clear();
+ err = OK;
}
reply->setInt32("err", err);
@@ -1624,10 +1654,11 @@ status_t NuPlayer::getSelectedTrack(int32_t type, Parcel* reply) const {
return err;
}
-status_t NuPlayer::selectTrack(size_t trackIndex, bool select) {
+status_t NuPlayer::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
sp<AMessage> msg = new AMessage(kWhatSelectTrack, id());
msg->setSize("trackIndex", trackIndex);
msg->setInt32("select", select);
+ msg->setInt64("timeUs", timeUs);
sp<AMessage> response;
status_t err = msg->postAndAwaitResponse(&response);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 5f6deee..901cfbd 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -65,7 +65,7 @@ struct NuPlayer : public AHandler {
status_t setVideoScalingMode(int32_t mode);
status_t getTrackInfo(Parcel* reply) const;
status_t getSelectedTrack(int32_t type, Parcel* reply) const;
- status_t selectTrack(size_t trackIndex, bool select);
+ status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs);
status_t getCurrentPosition(int64_t *mediaUs);
void getStats(int64_t *mNumFramesTotal, int64_t *mNumFramesDropped);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index b42b480..e09567a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -480,13 +480,16 @@ status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) {
case INVOKE_ID_SELECT_TRACK:
{
int trackIndex = request.readInt32();
- return mPlayer->selectTrack(trackIndex, true /* select */);
+ int msec = 0;
+ // getCurrentPosition should always return OK
+ getCurrentPosition(&msec);
+ return mPlayer->selectTrack(trackIndex, true /* select */, msec * 1000ll);
}
case INVOKE_ID_UNSELECT_TRACK:
{
int trackIndex = request.readInt32();
- return mPlayer->selectTrack(trackIndex, false /* select */);
+ return mPlayer->selectTrack(trackIndex, false /* select */, 0xdeadbeef /* not used */);
}
case INVOKE_ID_GET_SELECTED_TRACK:
@@ -625,6 +628,16 @@ void NuPlayerDriver::notifyListener_l(
case MEDIA_PLAYBACK_COMPLETE:
{
if (mState != STATE_RESET_IN_PROGRESS) {
+ if (mAutoLoop) {
+ audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
+ if (mAudioSink != NULL) {
+ streamType = mAudioSink->getAudioStreamType();
+ }
+ if (streamType == AUDIO_STREAM_NOTIFICATION) {
+ ALOGW("disabling auto-loop for notification");
+ mAutoLoop = false;
+ }
+ }
if (mLooping || (mAutoLoop
&& (mAudioSink == NULL || mAudioSink->realtime()))) {
mPlayer->seekToAsync(0);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 73bc829..42288a3 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -144,6 +144,10 @@ void NuPlayer::Renderer::signalDisableOffloadAudio() {
(new AMessage(kWhatDisableOffloadAudio, id()))->post();
}
+void NuPlayer::Renderer::signalEnableOffloadAudio() {
+ (new AMessage(kWhatEnableOffloadAudio, id()))->post();
+}
+
void NuPlayer::Renderer::pause() {
(new AMessage(kWhatPause, id()))->post();
}
@@ -407,6 +411,12 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
break;
}
+ case kWhatEnableOffloadAudio:
+ {
+ onEnableOffloadAudio();
+ break;
+ }
+
case kWhatPause:
{
onPause();
@@ -1133,6 +1143,12 @@ void NuPlayer::Renderer::onDisableOffloadAudio() {
++mAudioQueueGeneration;
}
+void NuPlayer::Renderer::onEnableOffloadAudio() {
+ Mutex::Autolock autoLock(mLock);
+ mFlags |= FLAG_OFFLOAD_AUDIO;
+ ++mAudioQueueGeneration;
+}
+
void NuPlayer::Renderer::onPause() {
if (mPaused) {
ALOGW("Renderer::onPause() called while already paused!");
@@ -1416,6 +1432,9 @@ bool NuPlayer::Renderer::onOpenAudioSink(
if (audioSinkChanged) {
onAudioSinkChanged();
}
+ if (offloadingAudio()) {
+ mAudioOffloadTornDown = false;
+ }
return offloadingAudio();
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 7b46a59..985ec49 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -53,6 +53,7 @@ struct NuPlayer::Renderer : public AHandler {
void signalAudioSinkChanged();
void signalDisableOffloadAudio();
+ void signalEnableOffloadAudio();
void pause();
void resume();
@@ -114,6 +115,7 @@ private:
kWhatCloseAudioSink = 'clsA',
kWhatStopAudioSink = 'stpA',
kWhatDisableOffloadAudio = 'noOA',
+ kWhatEnableOffloadAudio = 'enOA',
kWhatSetVideoFrameRate = 'sVFR',
};
@@ -200,6 +202,7 @@ private:
void onFlush(const sp<AMessage> &msg);
void onAudioSinkChanged();
void onDisableOffloadAudio();
+ void onEnableOffloadAudio();
void onPause();
void onResume();
void onSetVideoFrameRate(float fps);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 2f06c31..2b0ac47 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -97,7 +97,7 @@ struct NuPlayer::Source : public AHandler {
return INVALID_OPERATION;
}
- virtual status_t selectTrack(size_t /* trackIndex */, bool /* select */) {
+ virtual status_t selectTrack(size_t /* trackIndex */, bool /* select */, int64_t /* timeUs*/) {
return INVALID_OPERATION;
}
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 0e9d734..1413635 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1268,6 +1268,24 @@ status_t ACodec::configureCodec(
static_cast<NativeWindowWrapper *>(obj.get()));
sp<ANativeWindow> nativeWindow = windowWrapper->getNativeWindow();
+ // START of temporary support for automatic FRC - THIS WILL BE REMOVED
+ int32_t autoFrc;
+ if (msg->findInt32("auto-frc", &autoFrc)) {
+ bool enabled = autoFrc;
+ OMX_CONFIG_BOOLEANTYPE config;
+ InitOMXParams(&config);
+ config.bEnabled = (OMX_BOOL)enabled;
+ status_t temp = mOMX->setConfig(
+ mNode, (OMX_INDEXTYPE)OMX_IndexConfigAutoFramerateConversion,
+ &config, sizeof(config));
+ if (temp == OK) {
+ outputFormat->setInt32("auto-frc", enabled);
+ } else if (enabled) {
+ ALOGI("codec does not support requested auto-frc (err %d)", temp);
+ }
+ }
+ // END of temporary support for automatic FRC
+
int32_t tunneled;
if (msg->findInt32("feature-tunneled-playback", &tunneled) &&
tunneled != 0) {
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 6a56729..007c090 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -878,6 +878,16 @@ void AwesomePlayer::onStreamDone() {
return;
}
+ if (mFlags & AUTO_LOOPING) {
+ audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
+ if (mAudioSink != NULL) {
+ streamType = mAudioSink->getAudioStreamType();
+ }
+ if (streamType == AUDIO_STREAM_NOTIFICATION) {
+ ALOGW("disabling auto-loop for notification");
+ modifyFlags(AUTO_LOOPING, CLEAR);
+ }
+ }
if ((mFlags & LOOPING)
|| ((mFlags & AUTO_LOOPING)
&& (mAudioSink == NULL || mAudioSink->realtime()))) {
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 874c118..5eb4652 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -1164,6 +1164,14 @@ status_t LiveSession::selectTrack(size_t index, bool select) {
return err;
}
+ssize_t LiveSession::getSelectedTrack(media_track_type type) const {
+ if (mPlaylist == NULL) {
+ return -1;
+ } else {
+ return mPlaylist->getSelectedTrack(type);
+ }
+}
+
bool LiveSession::canSwitchUp() {
// Allow upwards bandwidth switch when a stream has buffered at least 10 seconds.
status_t err = OK;
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index 7aacca6..896a8fc 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -19,6 +19,7 @@
#define LIVE_SESSION_H_
#include <media/stagefright/foundation/AHandler.h>
+#include <media/mediaplayer.h>
#include <utils/String8.h>
@@ -73,6 +74,7 @@ struct LiveSession : public AHandler {
size_t getTrackCount() const;
sp<AMessage> getTrackInfo(size_t trackIndex) const;
status_t selectTrack(size_t index, bool select);
+ ssize_t getSelectedTrack(media_track_type /* type */) const;
bool isSeekable() const;
bool hasDynamicDuration() const;
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index 1651dee..eb62c7a 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -66,6 +66,9 @@ protected:
virtual ~MediaGroup();
private:
+
+ friend struct M3UParser;
+
struct Media {
AString mName;
AString mURI;
@@ -356,6 +359,38 @@ ssize_t M3UParser::getSelectedIndex() const {
return mSelectedIndex;
}
+ssize_t M3UParser::getSelectedTrack(media_track_type type) const {
+ MediaGroup::Type groupType;
+ switch (type) {
+ case MEDIA_TRACK_TYPE_VIDEO:
+ groupType = MediaGroup::TYPE_VIDEO;
+ break;
+
+ case MEDIA_TRACK_TYPE_AUDIO:
+ groupType = MediaGroup::TYPE_AUDIO;
+ break;
+
+ case MEDIA_TRACK_TYPE_SUBTITLE:
+ groupType = MediaGroup::TYPE_SUBS;
+ break;
+
+ default:
+ return -1;
+ }
+
+ for (size_t i = 0, ii = 0; i < mMediaGroups.size(); ++i) {
+ sp<MediaGroup> group = mMediaGroups.valueAt(i);
+ size_t tracks = group->countTracks();
+ if (groupType != group->mType) {
+ ii += tracks;
+ } else if (group->mSelectedIndex >= 0) {
+ return ii + group->mSelectedIndex;
+ }
+ }
+
+ return -1;
+}
+
bool M3UParser::getTypeURI(size_t index, const char *key, AString *uri) const {
if (!mIsVariantPlaylist) {
*uri = mBaseURI;
diff --git a/media/libstagefright/httplive/M3UParser.h b/media/libstagefright/httplive/M3UParser.h
index d588afe..1cad060 100644
--- a/media/libstagefright/httplive/M3UParser.h
+++ b/media/libstagefright/httplive/M3UParser.h
@@ -21,6 +21,7 @@
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AString.h>
+#include <media/mediaplayer.h>
#include <utils/Vector.h>
namespace android {
@@ -46,6 +47,7 @@ struct M3UParser : public RefBase {
size_t getTrackCount() const;
sp<AMessage> getTrackInfo(size_t index) const;
ssize_t getSelectedIndex() const;
+ ssize_t getSelectedTrack(media_track_type /* type */) const;
bool getTypeURI(size_t index, const char *key, AString *uri) const;
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index e247550..d8eed5b 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -826,6 +826,18 @@ void PlaylistFetcher::onDownloadNext() {
" mStartup=%d, was looking for %d in %d-%d",
mStartup, mSeqNumber, firstSeqNumberInPlaylist,
lastSeqNumberInPlaylist);
+ if (mStopParams != NULL) {
+ // we should have kept on fetching until we hit the boundaries in mStopParams,
+ // but since the segments we are supposed to fetch have already rolled off
+ // the playlist, i.e. we have already missed the boat, we inevitably have to
+ // skip.
+ for (size_t i = 0; i < mPacketSources.size(); i++) {
+ sp<ABuffer> formatChange = mSession->createFormatChangeBuffer();
+ mPacketSources.valueAt(i)->queueAccessUnit(formatChange);
+ }
+ stopAsync(/* clear = */ false);
+ return;
+ }
mSeqNumber = lastSeqNumberInPlaylist - 3;
if (mSeqNumber < firstSeqNumberInPlaylist) {
mSeqNumber = firstSeqNumberInPlaylist;
@@ -1266,6 +1278,11 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &bu
CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
if (mStartTimeUsNotify != NULL && timeUs > mStartTimeUs) {
+ int32_t firstSeqNumberInPlaylist;
+ if (mPlaylist->meta() == NULL || !mPlaylist->meta()->findInt32(
+ "media-sequence", &firstSeqNumberInPlaylist)) {
+ firstSeqNumberInPlaylist = 0;
+ }
int32_t targetDurationSecs;
CHECK(mPlaylist->meta()->findInt32("target-duration", &targetDurationSecs));
@@ -1276,6 +1293,8 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &bu
// mStartTimeUs.
// mSegmentStartTimeUs >= 0
// mSegmentStartTimeUs is non-negative when adapting or switching tracks
+ // mSeqNumber > firstSeqNumberInPlaylist
+ // don't decrement mSeqNumber if it already points to the 1st segment
// timeUs - mStartTimeUs > targetDurationUs:
// This and the 2 above conditions should only happen when adapting in a live
// stream; the old fetcher has already fetched to mStartTimeUs; the new fetcher
@@ -1285,6 +1304,7 @@ status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &bu
// stop as early as possible. The definition of being "too far ahead" is
// arbitrary; here we use targetDurationUs as threshold.
if (mStartup && mSegmentStartTimeUs >= 0
+ && mSeqNumber > firstSeqNumberInPlaylist
&& timeUs - mStartTimeUs > targetDurationUs) {
// we just guessed a starting timestamp that is too high when adapting in a
// live stream; re-adjust based on the actual timestamp extracted from the