A truth table is listed to illustrate all conditions of length/offset/reopen.
The original code doesn't handle the following cases correctly:
1. length == offset == 0, shouldn't reopen the channel for there is no data to download.
2. length == -1 && offset > 0, should reopen the channel if seekable.
MozReview-Commit-ID: IisnrA8hK4M
--HG--
extra : rebase_source : c5826f314b09b2ae9c3e7f2cc1f6ce285fc612df
The server might send us fewer bytes than requested. So we also need
"reopen on error" in this case as well.
MozReview-Commit-ID: Fi82x4h1TZ0
--HG--
extra : rebase_source : 3a19838de9c11545f00778623735c7e9a5cb1439
NotifyDataEnded() runs off the main thread which might set mChannelEnded
wrongly after NotifyChannelRecreated reset it on the main thread.
We should reset the flags in NotifyDataStarted() which indicate a new load has begun.
MozReview-Commit-ID: Gi6PFXwMJqc
--HG--
extra : rebase_source : 85bb2c25a55cce4b3c3f023bf4c02fe5d1de7552
extra : source : 2f8c5518bf615f9190f87032568fc53037bc6fc1
There are some works to do when we allow a stream whose download ends abnormally
to continue sharing the resource:
1. Abort Read() when download error happens. We might still have a chance to
get all the data successfully. However, it doesn't really matter since
the stream data is incomplete and we will encounter decode errors sooner
or later.
2. Update() needs to check mChannelEnded since an ended stream will not
download data needed by other streams.
MozReview-Commit-ID: LGCecQ5rpzq
--HG--
extra : rebase_source : 17a91a1cfd145344c3c0a29b80665cb99ce20746
extra : source : 0947c12b035acc9fba02e89dc87b3a17f84cf2e5
Since NotifyDataEnded() run its code asynchronously, it is possible that a new
channel is created and NotifyDataStarted() is called before NotifyDataEndedInternal()
has a chance to run. We check the load ID to exit the function if necessary.
We also need to fix data races when running NotifyDataEndedInternal() off the
main thread in next patches.
MozReview-Commit-ID: IIAc7dxHike
--HG--
extra : rebase_source : 58e45f924058a986b8d86bfaeff2791ee8a5f4bc
extra : intermediate-source : b2a7fa7514723e214b8da40cfc0ec40b1de9a345
extra : source : 1ff93dc8f8c451b804133c780cedef2ee3d348e5
We will need to modify these members off the main thead while IsAvailableForSharing()
is a main thread only function.
InitAsClone() will return an error if the original stream ends abnormally.
MozReview-Commit-ID: 1qRyboca2YZ
--HG--
extra : rebase_source : 4617a911a1de052833bd0085b883a8ae4d639c7d
This will remove the need to retry reading for the callers.
Note since data is usually downloaded faster than being consumed, we don't
benefit much in reading data from a partial block in the memory. Chances are
we still need to wait for the block to commit to the cache so the reader can
continue. So we change the code to always read data from the cache or from
the last block when it is completed (reaching EOS).
This change allows up to somewhat optimize NotifyDataReceived() which won't
have to wake up readers if no blocks are committed to the cache.
MozReview-Commit-ID: KwgNSOawuAE
--HG--
extra : rebase_source : af29b9f5d8b7ee1ed41bda5d23e1e94209e323b7
extra : intermediate-source : 863cb113d20b9cc1222de001bacbefa7eb8ac5c1
extra : source : 09683d9ffe477c27164769dc93e9eb9ee0af21bd
So it doesn't need to call mCacheStream.IsTransportSeekable() which needs to
take the lock and might block the main thread.
MozReview-Commit-ID: 99QVcSxzjCz
--HG--
extra : rebase_source : be71b065ce0334987efbfb67a5cf010ab0373d80
extra : source : 2de3f0baf1475e8ae3228a33cf4cf139cf923c37
Per P2 changes, a reader will always read data from the cache or from the last
block in the memory. NotifyDataReceived() will be slightly more efficient
if we don't wake up readers unnecessarily when there are no new blocks committed
to the cache.
MozReview-Commit-ID: 3UWHbvtEUmu
--HG--
extra : rebase_source : d8c97d275ca5df7deb56447ef55092ac3d110e7f
extra : source : 8acc253fb322c4b6defb03bbc5489b5b1877f375
This will remove the need to retry reading for the callers.
Note since data is usually downloaded faster than being consumed, we don't
benefit much in reading data from a partial block in the memory. Chances are
we still need to wait for the block to commit to the cache so the reader can
continue. So we change the code to always read data from the cache or from
the last block when it is completed (reaching EOS).
This change allows up to somewhat optimize NotifyDataReceived() which won't
have to wake up readers if no blocks are committed to the cache.
MozReview-Commit-ID: KwgNSOawuAE
--HG--
extra : rebase_source : dcf61b2c43a7c030a0265979d75d18c63a3c41d0
extra : intermediate-source : 62e5895d3684b6fd00df7703156af5ea1f08bef3
extra : source : 09683d9ffe477c27164769dc93e9eb9ee0af21bd
Evicting the block will result in a gap in the current cached range starting
from mStreamOffset to mChannelOffset. Then we have
|GetCachedDataEndInternal(mStreamOffset) < mChannelOffset| and MediaCache
will open a new channel to fill the gap which is bad.
This is exactly the issue described in bug 1347174 where we limit the readahead
size to prevent the problem above from happening.
However bug 1347174 is indeed a workaround instead of a fix. It works around
the issue by suspending the download before the cache is full and has to evict
some blocks to allow new data to come in.
We should let MediaCache suspend the channel if it is full or evict played
blocks if possible.
MozReview-Commit-ID: HuUsZLdHGuh
--HG--
extra : rebase_source : cdd9bdb5bc63589550bafd49f6e313244037d8dd
extra : intermediate-source : 90aaf942dfbfdff98ef3df412ed49141f3f50e55
extra : source : fc8bc1c456677b92884c80ecfe4d5074a610f81a
We don't want MediaCache to use a half-initialized stream.
MozReview-Commit-ID: LjPLOYwy0Wd
--HG--
extra : rebase_source : a52a23fc6dce2a87ef2829254dcabe8176b2c28c
extra : intermediate-source : eb9c3d068ff4c3496831d80398012daebe8a5d52
extra : source : d980eb79f7a5219651ef710630cdf6dc3bd96195
By mirroring the suspend status of the client, Update() is able to make
decisions on reading streams without calling mClient->IsSuspended().
MozReview-Commit-ID: G4gS2VGiMjj
--HG--
extra : rebase_source : bcdc1010fce47965c999df61666983c87e189670
extra : intermediate-source : 9dd8cfb80e29677e8cae866b2326dfb0aec5b6ae
extra : source : d20f640bf99478c9ba581e4979ec8091ef94e0f3
Note we will fix bugs required to run Update() off the main thread
in the following patches.
MozReview-Commit-ID: CYwT5kDjD9R
--HG--
extra : rebase_source : edef59353b5f56d5aecb6d58f5cc2a8dfb09c317
extra : intermediate-source : 995a34fb6af54d3f4ad2de479d7777860a957f98
extra : source : 8d86a14f877cf83584cf1e57020568037a35154a
MediaCache::Update() depends on mStreamOffset to make decision whether to
read streams or not. It is important to update mStreamOffset before releasing
the monitor so Update() won't make wrong decisions based on the stale value.
MozReview-Commit-ID: 40jUk5xd6GR
--HG--
extra : rebase_source : 40f4a64d0b66886b3a12c374f1bda874f8853750
extra : intermediate-source : 20ad1ad39a1e0c128ffd16e3fa669c9db1bb9c98
extra : source : 04f82ee89d93d5c008e51746c9686b4298e5f44f
This is a fix to P3.
Since seek is performed asynchronously by CacheClientSeek(), it is possible
for OnStopRequest() to come before Seek(). Changing mChannelOffset will
cause MediaCacheStream::NotifyDataEnded() to update mStreamLength incorrectly.
mChannelOffset should only be changed in response to channel activities such
as NotifyDataStarted() and NotifyDataReceived().
However, if MediaCache::Update() calls CacheClientSeek() without updating
mChannelOffset, next Update() might make a wrong decision and call CacheClientSeek()
again which is bad. So we add a member mSeekTarget to track if there is a pending
seek on which the stream reading decisions will be made.
MozReview-Commit-ID: VWP0vdlEYM
--HG--
extra : rebase_source : ea0d85bcbcc5d14f1554ebff3d10981a5b17e18a
extra : source : 339b9323b583849ac88e39da19670f6b26772877
For it is not safe to access mStreams without the lock off the main thread.
MozReview-Commit-ID: DjVlhxgjVj5
--HG--
extra : rebase_source : b584fe59712430acd4528e6b6cd01ae86dc5761f
extra : source : d7fd550934bfe6967638e42acb076882611792dd
SetTransportSeekable() is always called after NotifyDataStarted().
This is slightly more efficient for we don't acquire the lock twice.
MozReview-Commit-ID: 9myolomriIQ
--HG--
extra : rebase_source : f33c3be978edacf45d8144af43f45c8ad5e7b53e
extra : source : 2cefaeb1adae7238b77d5e2d1287ae0d96d9f671
To avoid leaks caused by Dispatch() failures. See comment 0 for the detail.
MozReview-Commit-ID: 3lYxQNj1GPl
--HG--
extra : rebase_source : 8df990476a49544b475df39be789e3cb27853609
extra : intermediate-source : 012f42a1a9d46b0dafa31ca03da1c2bc4fc76d2e
extra : source : c6acb9362de9ab8d130104aaf102de2ecb27dc8f
To avoid leaks caused by Dispatch() failures. See comment 0 for the detail.
MozReview-Commit-ID: 3lYxQNj1GPl
--HG--
extra : rebase_source : 3ea4958ba21e691f83dbdf36fd820e597d6c5d68
extra : intermediate-source : 012f42a1a9d46b0dafa31ca03da1c2bc4fc76d2e
extra : source : c6acb9362de9ab8d130104aaf102de2ecb27dc8f
It's only used in MediaCache.cpp, so it may as well be defined there.
MozReview-Commit-ID: HcA499xFOUg
--HG--
extra : rebase_source : f25c30d6e9be10549af80d5dfa963ef66abac576