示例#1
0
BOOL
MediaSourceImpl::NeedRestart(const MediaByteRange& request)
{
	OP_ASSERT(!request.IsEmpty());
	// Note: this function assumes that request is not in cache

	// If not loading we certainly need to start.
	if (m_state == NONE || m_state == IDLE)
		return TRUE;

	// Only restart resumable resources.
	if (!IsResumableURL(m_use_url))
		return FALSE;

	// Get the currently loading range.
	MediaByteRange loading;
	m_use_url->GetAttribute(URL::KHTTPRangeStart, &loading.start);
	m_use_url->GetAttribute(URL::KHTTPRangeEnd, &loading.end);
	OP_ASSERT(!loading.IsEmpty());

	// When streaming, adjust the loading range to not include what
	// has already been evicted from the cache. Note: This must not be
	// done for a request that was just started, as the cache can then
	// contain data from the previous request which is not relevant.
	if (m_state >= LOADING && IsStreaming())
	{
		BOOL available = FALSE;
		OpFileLength length = 0;
		GetPartialCoverage(loading.start, available, length);
		if (!available && (!loading.IsFinite() || length < loading.Length()))
			loading.start += length;
	}

	// Restart if request is before currently loading range.
	if (request.start < loading.start)
		return TRUE;

	// Restart if request is after currently loading range.
	if (loading.IsFinite() && request.start > loading.end)
		return TRUE;

	// request is now a subset of loading, check how much we have left
	// to load until request.start.
	BOOL available = FALSE;
	OpFileLength length = 0;
	GetPartialCoverage(loading.start, available, length);
	if (!available)
		length = 0;
	if (request.start > loading.start + length)
	{
		// FIXME: calculate download rate and time taken to reach offset (CORE-27952)
		OpFileLength remaining = request.start - (loading.start + length);
		if (remaining > MEDIA_SOURCE_MAX_WAIT)
			return TRUE;
	}

	return FALSE;
}
示例#2
0
MediaSourceImpl::State
MediaSourceImpl::EnsureBufferingInternal()
{
	MediaByteRange request;
	CalcRequest(request);

	if (!request.IsEmpty())
	{
		m_clamp_request = FALSE;

		if (NeedRestart(request))
		{
			StopBuffering();
			return StartBuffering(request);
		}

		// The request wasn't restarted, so it may need to be clamped
		// by aborting it once enough data has become available.
		if (request.IsFinite() && !IsStreaming())
		{
			OpFileLength loading_end = FILE_LENGTH_NONE;
			m_use_url->GetAttribute(URL::KHTTPRangeEnd, &loading_end);
			if (loading_end == FILE_LENGTH_NONE || request.end < loading_end)
				m_clamp_request = TRUE;
		}
	}
	else
	{
		// We have all the data we wanted, so stop buffering if possible.
		switch (m_state)
		{
		case NONE:
			// Already loaded (data: URL or in cache).
			return IDLE;

		case IDLE:
		case FAILED:
			// not loading
			break;

		case STARTED:
		case HEADERS:
		case LOADING:
		case PAUSED:
			// Only stop a load if it's in fact already complete or if
			// it's one that we can later resume. However, when using
			// the streaming cache, continue loading until either the
			// cache fills up and PauseBuffering() is called or (if
			// the request fits in cache) IsLoadedURL() is true.
			if (IsLoadedURL(m_use_url) || (IsResumableURL(m_use_url) && !IsStreaming()))
			{
				StopBuffering();
				return IDLE;
			}
			break;
		}
	}

	return NONE;
}
示例#3
0
void
MediaSourceImpl::CalcRequest(MediaByteRange& request)
{
	if (IsStreaming())
	{
		// When streaming we only consider the pending range (if any).
		// When there are no clients, request the entire resource.
		// To support preload together with streaming, care must be
		// taken to not restart a preload request [0,Inf] as soon as
		// data has been evicted and the cached range is e.g.
		// [500,1000499] if there is no pending request in that range.

		if (!m_clients.Empty())
		{
			MediaByteRange preload; // unused
			ReduceRanges(m_clients, request, preload);
			if (!request.IsEmpty())
			{
				request.SetLength(FILE_LENGTH_NONE);
				IntersectWithUnavailable(request, m_use_url);
				if (!request.IsEmpty())
					request.SetLength(FILE_LENGTH_NONE);
			}
		}
		else
		{
			request.start = 0;
		}
		// At this point we should have an unbounded range, but it may
		// be clamped to the resource length below.
		OP_ASSERT(!request.IsFinite());
	}
	else
	{
		// When not streaming (using multiple range disk cache), both
		// pending and preload requests are taken into account.
		//
		// Example 1: Everything should be preloaded, but since there is a
		// pending read, start buffering from that offset first. Also,
		// don't refetch the end of the resource.
		//
		// resource: <---------------------->
		// buffered: <-->               <--->
		// pending:           <---->
		// preload:  <---------------------->
		// request:           <-------->
		//
		// Example 2: The requested preload is already buffered, so the
		// request is the empty range.
		//
		// resource: <---------------------->
		// buffered: <-------->
		// pending:  empty range
		// preload:  <----->
		// request:  empty range

		MediaByteRange pending, preload;
		ReduceRanges(m_clients, pending, preload);
		CombineRanges(pending, preload, request);
		IntersectWithUnavailable(request, m_use_url);
	}

	if (!request.IsEmpty())
	{
		// Extra restrictions if resource length is known (this won't
		// be needed after CORE-30311 is fixed).
		OpFileLength resource_length = GetTotalBytes();
		if (resource_length > 0)
		{
			OP_ASSERT(request.start <= resource_length);

			MediaByteRange resource(0, resource_length - 1);

			// Clamp request to resource.
			request.IntersectWith(resource);

			// Increase size if it is unreasonably small at the end...
			if (!request.IsEmpty() &&
				request.Length() < MEDIA_SOURCE_MIN_SIZE &&
				resource.Length() >= MEDIA_SOURCE_MIN_SIZE &&
				request.end == resource.end)
			{
				// ... but only if nothing in that range is available.
				MediaByteRange cand_request(resource_length - MEDIA_SOURCE_MIN_SIZE, resource_length - 1);
				OP_ASSERT(cand_request.Length() == MEDIA_SOURCE_MIN_SIZE);
				IntersectWithUnavailable(cand_request, m_use_url);
				if (cand_request.Length() == MEDIA_SOURCE_MIN_SIZE)
					request = cand_request;
			}
		}
	}

	OP_NEW_DBG("CalcRequest", "MediaSource");
	OP_DBG(("request: ") << request);
}