michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=8 sts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "SourceBufferResource.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "nsISeekableStream.h" michael@0: #include "nsISupportsImpl.h" michael@0: #include "prenv.h" michael@0: #include "prlog.h" michael@0: michael@0: #ifdef PR_LOGGING michael@0: extern PRLogModuleInfo* gMediaSourceLog; michael@0: #define MSE_DEBUG(...) PR_LOG(gMediaSourceLog, PR_LOG_DEBUG, (__VA_ARGS__)) michael@0: #else michael@0: #define MSE_DEBUG(...) michael@0: #endif michael@0: michael@0: namespace mozilla { michael@0: michael@0: namespace dom { michael@0: michael@0: class SourceBuffer; michael@0: michael@0: } // namespace dom michael@0: michael@0: nsresult michael@0: SourceBufferResource::Close() michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mMonitor); michael@0: MSE_DEBUG("%p SBR::Close", this); michael@0: //MOZ_ASSERT(!mClosed); michael@0: mClosed = true; michael@0: mon.NotifyAll(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: SourceBufferResource::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes) michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mMonitor); michael@0: bool blockingRead = !!aBytes; michael@0: michael@0: while (blockingRead && michael@0: !mEnded && michael@0: mOffset + aCount > static_cast(GetLength())) { michael@0: MSE_DEBUG("%p SBR::Read waiting for data", this); michael@0: mon.Wait(); michael@0: } michael@0: michael@0: uint32_t available = GetLength() - mOffset; michael@0: uint32_t count = std::min(aCount, available); michael@0: if (!PR_GetEnv("MOZ_QUIET")) { michael@0: MSE_DEBUG("%p SBR::Read aCount=%u length=%u offset=%u " michael@0: "available=%u count=%u, blocking=%d bufComplete=%d", michael@0: this, aCount, GetLength(), mOffset, available, count, michael@0: blockingRead, mEnded); michael@0: } michael@0: if (available == 0) { michael@0: MSE_DEBUG("%p SBR::Read EOF", this); michael@0: *aBytes = 0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: mInputBuffer.CopyData(mOffset, count, aBuffer); michael@0: *aBytes = count; michael@0: mOffset += count; michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: SourceBufferResource::ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount, uint32_t* aBytes) michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mMonitor); michael@0: nsresult rv = Seek(nsISeekableStream::NS_SEEK_SET, aOffset); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: return Read(aBuffer, aCount, aBytes); michael@0: } michael@0: michael@0: nsresult michael@0: SourceBufferResource::Seek(int32_t aWhence, int64_t aOffset) michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mMonitor); michael@0: if (mClosed) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: int64_t newOffset = mOffset; michael@0: switch (aWhence) { michael@0: case nsISeekableStream::NS_SEEK_END: michael@0: newOffset = GetLength() - aOffset; michael@0: break; michael@0: case nsISeekableStream::NS_SEEK_CUR: michael@0: newOffset += aOffset; michael@0: break; michael@0: case nsISeekableStream::NS_SEEK_SET: michael@0: newOffset = aOffset; michael@0: break; michael@0: } michael@0: michael@0: if (newOffset < 0 || uint64_t(newOffset) < mInputBuffer.GetOffset() || newOffset > GetLength()) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: mOffset = newOffset; michael@0: mon.NotifyAll(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: SourceBufferResource::ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount) michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mMonitor); michael@0: nsresult rv = Seek(nsISeekableStream::NS_SEEK_SET, aOffset); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: return Read(aBuffer, aCount, nullptr); michael@0: } michael@0: michael@0: bool michael@0: SourceBufferResource::EvictData(uint32_t aThreshold) michael@0: { michael@0: return mInputBuffer.Evict(mOffset, aThreshold); michael@0: } michael@0: michael@0: void michael@0: SourceBufferResource::EvictBefore(uint64_t aOffset) michael@0: { michael@0: // If aOffset is past the current playback offset we don't evict. michael@0: if (aOffset < mOffset) { michael@0: mInputBuffer.Evict(aOffset, 0); michael@0: } michael@0: } michael@0: michael@0: void michael@0: SourceBufferResource::AppendData(const uint8_t* aData, uint32_t aLength) michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mMonitor); michael@0: mInputBuffer.PushBack(new ResourceItem(aData, aLength)); michael@0: mon.NotifyAll(); michael@0: } michael@0: michael@0: void michael@0: SourceBufferResource::Ended() michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mMonitor); michael@0: mEnded = true; michael@0: mon.NotifyAll(); michael@0: } michael@0: michael@0: SourceBufferResource::~SourceBufferResource() michael@0: { michael@0: MOZ_COUNT_DTOR(SourceBufferResource); michael@0: MSE_DEBUG("%p SBR::~SBR", this); michael@0: } michael@0: michael@0: SourceBufferResource::SourceBufferResource(nsIPrincipal* aPrincipal, michael@0: const nsACString& aType) michael@0: : mPrincipal(aPrincipal) michael@0: , mType(aType) michael@0: , mMonitor("mozilla::SourceBufferResource::mMonitor") michael@0: , mOffset(0) michael@0: , mClosed(false) michael@0: , mEnded(false) michael@0: { michael@0: MOZ_COUNT_CTOR(SourceBufferResource); michael@0: MSE_DEBUG("%p SBR::SBR()", this); michael@0: } michael@0: michael@0: } // namespace mozilla