This removes some boiler-plate code for compostite sources and will also
simplify resuing media source in the future (because this class can keep track
of child listeners).
Issue:#3498
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=183387123
So far this wasn't possible because Robolectric's Looper and MessageQueue
implementations have multiple shortcomings:
1. The message loop of new HandlerThreads is an not an actual loop and
scheduled messages are executed on the thread the message is enqueued
(not the handler thread).
2. The scheduler used to replace the message queue is synchronizing all its
methods. Thus, when a test attempts to add messages to a Handler from
two different threads, it may easily run into a deadlock.
3. The scheduler doesn't correctly emulate the order of messages as they
would be in an actual MessageQueue:
a. If the message is enqueued on the handler thread, it gets executed
immediately (and not after all other messages at the same time).
b. The list of messages is always re-sorted by time, meaning that the
order of execution for messages at the same time is indeterminate.
4. Robolectric's SystemClock implementation returns the current scheduler
time of the main UI thread. So, unless this scheduler is used to add
messages in the future, the SystemClock time never advances.
This CL adds two helper classes which extend and replace Robolectric's
ShadowLooper and ShadowMessageQueue.
1. We intercept messages being enqueued or deleted in the message queue.
Thus Robolectric's faulty scheduler gets never used. Instead, we keep
a blocking priority queue of messages, sorted first by execution time
and then by FIFO order to correctly emulate the real MessageQueue.
2. We also keep a list of deleted messages to know which messages to ignore
when they come up in the looper.
3. When a new Looper is started, we override the dummy loop to an actual
eternal while loop which waits for new messages, checks if they haven't
been deleted, and runs the messages (similar to what Robolectric's
MessageQueue would have done at this point).
Because we don't actually use the main UI thread in our tests, we can't rely
on the SystemClock to progress in any sensible manner. To overcome this issue,
we can use the auto-advancing FakeClock also used for the simulation tests.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=182912510
This achieves two things:
1. All our tests use the same type of assertions.
2. The tests currently run as instrumentation test can be moved to
Robolectric without changing the assertions.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=182910542
These were caused by two issues:
1. The FakeMediaSource can be updated with a new timeline. The setNewSourceInfo
is called from a different thread than prepareSource and both access local
variables without synchronization.
2. For multi-window playback, the FakeRenderer claims that isReady and isEnded
are both set to false if it read the end of the stream. However isReady should be
true because it is able to "render" its data until the end of the stream.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=182785169
This fixes a very specific case where the data read has non-cached gaps
and a read-only CDS switches to read from upstream in a gap then the
cached data is deleted. When the CDS reaches the end of the gap, it
tries to open the next source. As there is no cached data, it tries to
continue with the already opened upstream data source but as it reached
end of the gap range, the code starts looping.
Also fixes infinite lock which occurs when in the previous case CDS isn't
readonly. It locks the content while filling the gap in the cache. At the
end of the gap, as the following data is deleted it tries to lock the
content for writing but the content is already locked by itself.
The last fix is preventing removal of CachedContent entry from
CachedContentIndex while associated key is locked.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=182595426
Some tests in ExoPlayerTest issue commands to the player from the test thread
while the player is actively playing media (playWhenReady=true). Due to the
indeterminate time taken to enqueue the commands on the playback thread, they
may arrive when the player already proceeded to another window or finished
playback.
To ensure the tests are always deterministic, this change pauses playback in
the tests where this may happen before issuing the commands.
Also, for tests where we need to wait for a new window before issuing the
next command, a new action is added which allows to play until a specified
position.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=182535096
As soon as the seek gets acknowledged by EPII, EPI returns the actual position
from the playback info again which is set by EPII. Thus, EPII needs to update
the position to reflect the changes expected by EPI.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=182515106
Partial reads were performed once using a partial size of 1 byte.
This was not enough to detect problems which only occur in combination
with IOExceptions. Partial reads are now only applied when no exception
is thrown.
Moreover, the tests didn't check whether the total number of sampled bytes
is what it is supposed to be. Added a field to the data dumps checking
the total number of bytes in the sampled data.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=181296545
This adds options to ExoPlayer.sendMessages which allow to specify a window index
and position at which the message should be sent. Additionally, the options can be
configured to use a custom Handler for the messages and whether the message should
be repeated when playback reaches the same position again.
The internal player converts these window positions to period index and position
at the earliest possibility. The internal player also attempts to update these
when the source info is refreshed. A sorted list of pending posts is kept and the
player triggers these posts when the playback position moves over the specified
position.
Issue:#2189
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=179683841
*** Original change description ***
Add possiblity to send messages at playback position.
This adds options to ExoPlayer.sendMessages which allow to specify a window index
and position at which the message should be sent. Additionally, the options can be
configured to use a custom Handler for the messages and whether the message should
be repeated when playback reaches the same position again.
The internal player converts these window positions to period index and position
at the earliest possibility. The internal player also at...
***
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=179666357
This adds options to ExoPlayer.sendMessages which allow to specify a window index
and position at which the message should be sent. Additionally, the options can be
configured to use a custom Handler for the messages and whether the message should
be repeated when playback reaches the same position again.
The internal player converts these window positions to period index and position
at the earliest possibility. The internal player also attempts to update these
when the source info is refreshed. A sorted list of pending posts is kept and the
player triggers these posts when the playback position moves over the specified
position.
Issue:#2189
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=179563355
Skipping short periods in a while loop is conceptually a new operation
and thus we need to send out the updated playback info in between for
the listeners to receive multiple period transition discontinuities.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=179027334
This is a no-op change replacing the local variables in ExoPlayerImplInternal
with the new ones in PlaybackInfo.
***
Use playbackState, isLoading and trackSelectorResult from playbackInfo in ExoPlayerImpl.
***
Move duplicated listener notification in ExoPlayerImpl to new method.
Also split reset method in one parts which creates the new playback info
and one part which notifies the listeners. The increment of the pending
operation counter needs to happen in between.
***
Use only one pending operation counter in ExoPlayerImpl.
This also allows to move onSeekProcessed into the notification chain.
***
Replace playback info changing messages to ExoPlayerImpl by single message type.
As they are all handled in the same way, they can be summarized to one message.
***
Only send playback info change notifications once per playback thread message.
This ensures that all concurrent changes actually reach ExoPlayerImpl concurrently.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=178907165
1. The player doesn't acknowledge phantom stops when an exception is thrown anymore.
2. It also makes sure it doesn't reset the pendingPrepareCount unless it's actually
immediately acknowledging these prepares.
3. It ensures a seek is acknowledged even though an exception is thrown during seeking.
Added tests (which previously failed) for all three cases.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=178876362
Waiting for the timeline change didn't work correctly because the timeline was
already equal to Timeline.EMPTY (due to the masking). Now waiting explicitly
for the empty Timeline exposed by the source.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=177749292
- Remove skipping of the VBRI/XING frame before calculating position
offsets. This was incorrect. Instead, a constraint is used to ensure
we don't return positions within these frames, the difference being
that the constraint adjusts only positions that would fall within
the frames, where-as the previous approach shifted positions through
the whole stream.
- Excluded last entry in the VBRI table because it has an invalid
position (the length of the stream).
- Give variables in XingSeeker descriptive names.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=177451295
- This change snaps the seek position for constant bitrate MP3s
to the nearest frame boundary, avoiding the need to skip one
byte at a time to re-synchronize (this may still happen if the
MP3 does not really have fixed size frames).
- Tweaked both ConstantBitrateSeeker and WavHeader to ensure the
returned positions are valid.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=177441798
This allows to keep the state synced with ExoPlayerImpl after stopping the player,
but still releases the media source immediately as it needs to be reprepared.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=177167980
We can acknoledge seeks before preparation finished immediately now,
because ExoPlayerImpl won't leave the masking state until the first prepare
operation is processed.
As a side effect, it also cleans up the responsibility of the callbacks.
Prepares are always acknowledged with a SOURCE_INFO_REFRESHED, while seeks
are always acknowledged with a SEEK_ACK.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=177144089
The ExoPlayerImpl implementation forwards the stop request with this optional
parameter. To ensure correct masking (e.g. when timeline updates arrive after
calling reset in ExoPlayerImpl but before resetInternal in
ExoPlayerImplInternal), we use the existing prepareAck counter and extend it
also count stop operations. For this to work, we also return the updated
empty timeline after finishing the reset.
The CastPlayer doesn't support the two reset options so far.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=177132107
Unconditionally waiting for the action schedule to finish in ExoPlayerTestRunner
doesn't work if the action schedule is not intended to be finished.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=177024139
Fixed by explicitly waiting for the timeline update. This shouldn't be
necessary and will be removed as soon as the correct order of events
can be guaranteed (timeline change -> state change -> onSeekProcessed).
The waiting for the timeline update is implemented by introducing the
feature that the test runner also waits until the action schedule has
finished before stopping the test.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=176848540
This is mostly useful for suppressing the initial position
discontinuity reported by ClippingMediaPeriod.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=176758972
This brings ClippingMediaSource clip failures in line with
what MergingMediaSource does when it cannot merge.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=176660123
We (eventually - albeit possibly infinitely far in the future)
expect a timeline update with a window of known duration. This
also stops live radio stream playbacks transitioning to ended
state when their tracks are disabled.
As part of this fix, I found an issue where getPeriodPosition
could return null even when defaultPositionProjectionUs is 0,
which is not as documented.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=176492024
The ExoPlayerImplInternal.reset method now takes the same set of options
as the ExoPlayer.prepare method. This also allows to
- Remove some code duplication within ExoPlayerImplInternal
- Fix calls to prepare(sameSource, resetPosition=true, resetState=false)
with enabled shuffle mode where the position was not correctly reset to the
first period index.
- Keep the current timeline when calling stop (in line with ExoPlayerImpl).
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=176481878
Currently onTimelineChanged doesn't allow to distinguish easily between the
different reasons why it's being called. Especially, finding
out whether a new media source has been prepared or the current source
refreshed dynamically was impossible without tightly coupling the player
operations with the listener.
The new reasons provide this disdinction by either indicating a newly
initialized media source, a dynamic update to an existing timeline
or manifest, or a reset of the player (which usually results in an
empty timeline).
The original onTimelineChanged method without reason is kept in the
DefaultEventListener as deprecated to prevent the need to update all
existing listeners in one go.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=176478701
- Properly report internal discontinuities
- Add DISCONTINUITY_REASON_SEEK_ADJUSTMENT to distinguish
seek adjustments from other internal discontinuity events
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=176367365
- MediaSourceTestRunner aims to encapsulate some of the logic
currently used in DynamicConcatenatingMediaSourceTest, so it
can be re-used for testing other MediaSource implementations.
- The change also fixes DynamicConcatenatingMediaSourceTest to
execute calls on the correct threads, and to release handler
threads at the end of each test.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=176117535
This test seems to obtain a timeline from a prepared
FakeMediaSource, but that's identical to the timeline
passed into that source to start with :).
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=176117133
This is helpful for tests which don't care about detailled timeline set-ups
besides the number of windows.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=176097369
The purpose of this change isn't to fix anything. It's just to
simplify things a little bit. There will be following CLs that
make some changes to get things onto correct threads.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=175800354
This allows to remove the LazyMediaSource used within
DynamicConcatenatingMediaSourceTest and also allows to write test which
simulates dynamic timeline or manifest updates.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=175680371
Also added tests which verify the intended behaviour.
GitHub:#3452
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=175656478
Add onEnable() and onDisable() call-backs to TrackSelection. This allows
TrackSelection to perform interesting operations (like subscribe to
NetworkStatus) and clean up after itself.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=175558485
These callbacks are executed on the app thread after the corresponding
timeline update was triggered. This ensures that seek operations see the
updated timelines and are therefore valid, even if the seek is performed into a
window which didn't exist before.
GitHub:#3407
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=175136187