gecko-dev/dom/media/CloneableWithRangeMediaReso...

232 строки
5.4 KiB
C++

/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CloneableWithRangeMediaResource.h"
#include "mozilla/AbstractThread.h"
#include "mozilla/Monitor.h"
#include "nsContentUtils.h"
#include "nsIAsyncInputStream.h"
#include "nsNetCID.h"
namespace mozilla {
namespace {
class InputStreamReader final : public nsIInputStreamCallback
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
static already_AddRefed<InputStreamReader>
Create(nsICloneableInputStreamWithRange* aStream, int64_t aStart,
uint32_t aLength)
{
MOZ_ASSERT(aStream);
nsCOMPtr<nsIInputStream> stream;
nsresult rv = aStream->CloneWithRange(aStart, aLength,
getter_AddRefs(stream));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
RefPtr<InputStreamReader> reader = new InputStreamReader(stream);
return reader.forget();
}
nsresult
Read(char* aBuffer, uint32_t aSize, uint32_t* aRead)
{
uint32_t done = 0;
do {
uint32_t read;
nsresult rv = SyncRead(aBuffer + done, aSize - done, &read);
if (NS_SUCCEEDED(rv) && read == 0) {
break;
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
done += read;
} while(done != aSize);
*aRead = done;
return NS_OK;
}
NS_IMETHOD
OnInputStreamReady(nsIAsyncInputStream* aStream) override
{
// Let's continue with SyncRead().
MonitorAutoLock lock(mMonitor);
return lock.Notify();
}
private:
explicit InputStreamReader(nsIInputStream* aStream)
: mStream(aStream)
, mMonitor("InputStreamReader::mMonitor")
{
MOZ_ASSERT(aStream);
}
~InputStreamReader() = default;
nsresult
SyncRead(char* aBuffer, uint32_t aSize, uint32_t* aRead)
{
while (1) {
nsresult rv = mStream->Read(aBuffer, aSize, aRead);
// All good.
if (rv == NS_BASE_STREAM_CLOSED || NS_SUCCEEDED(rv)) {
return NS_OK;
}
// An error.
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
return rv;
}
// We need to proceed async.
if (!mAsyncStream) {
mAsyncStream = do_QueryInterface(mStream);
}
if (!mAsyncStream) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIEventTarget> target =
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
MOZ_ASSERT(target);
{
// We wait for ::OnInputStreamReady() to be called.
MonitorAutoLock lock(mMonitor);
rv = mAsyncStream->AsyncWait(this, 0, aSize, target);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
lock.Wait();
}
}
}
nsCOMPtr<nsIInputStream> mStream;
nsCOMPtr<nsIAsyncInputStream> mAsyncStream;
Monitor mMonitor;
};
NS_IMPL_ADDREF(InputStreamReader);
NS_IMPL_RELEASE(InputStreamReader);
NS_INTERFACE_MAP_BEGIN(InputStreamReader)
NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStreamCallback)
NS_INTERFACE_MAP_END
} // anonymous
void
CloneableWithRangeMediaResource::MaybeInitialize()
{
if (!mInitialized) {
mInitialized = true;
mCallback->AbstractMainThread()->Dispatch(
NewRunnableMethod<nsresult>("MediaResourceCallback::NotifyDataEnded",
mCallback.get(),
&MediaResourceCallback::NotifyDataEnded,
NS_OK));
}
}
nsresult
CloneableWithRangeMediaResource::GetCachedRanges(MediaByteRangeSet& aRanges)
{
MaybeInitialize();
aRanges += MediaByteRange(0, (int64_t)mSize);
return NS_OK;
}
nsresult
CloneableWithRangeMediaResource::Open(nsIStreamListener** aStreamListener)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aStreamListener);
*aStreamListener = nullptr;
return NS_OK;
}
nsresult
CloneableWithRangeMediaResource::Close()
{
return NS_OK;
}
already_AddRefed<nsIPrincipal>
CloneableWithRangeMediaResource::GetCurrentPrincipal()
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIPrincipal> principal;
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
if (!secMan || !mChannel) {
return nullptr;
}
secMan->GetChannelResultPrincipal(mChannel, getter_AddRefs(principal));
return principal.forget();
}
nsresult
CloneableWithRangeMediaResource::ReadFromCache(char* aBuffer, int64_t aOffset,
uint32_t aCount)
{
MaybeInitialize();
if (!aCount) {
return NS_OK;
}
RefPtr<InputStreamReader> reader =
InputStreamReader::Create(mStream, aOffset, aCount);
if (!reader) {
return NS_ERROR_FAILURE;
}
uint32_t bytes = 0;
nsresult rv = reader->Read(aBuffer, aCount, &bytes);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return bytes == aCount ? NS_OK : NS_ERROR_FAILURE;
}
nsresult
CloneableWithRangeMediaResource::ReadAt(int64_t aOffset, char* aBuffer,
uint32_t aCount, uint32_t* aBytes)
{
MOZ_ASSERT(!NS_IsMainThread());
RefPtr<InputStreamReader> reader =
InputStreamReader::Create(mStream, aOffset, aCount);
if (!reader) {
return NS_ERROR_FAILURE;
}
nsresult rv = reader->Read(aBuffer, aCount, aBytes);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
} // mozilla namespace