зеркало из https://github.com/mozilla/gecko-dev.git
337 строки
8.6 KiB
C++
337 строки
8.6 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* 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 "DOMMediaStream.h"
|
|
#include "mozilla/dom/Promise.h"
|
|
#include "mozilla/dom/TVCurrentSourceChangedEvent.h"
|
|
#include "mozilla/dom/TVServiceCallbacks.h"
|
|
#include "mozilla/dom/TVServiceFactory.h"
|
|
#include "mozilla/dom/TVSource.h"
|
|
#include "mozilla/dom/TVUtils.h"
|
|
#include "nsISupportsPrimitives.h"
|
|
#include "nsITVService.h"
|
|
#include "nsITVSimulatorService.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
#include "TVTuner.h"
|
|
#include "mozilla/dom/HTMLVideoElement.h"
|
|
|
|
namespace mozilla {
|
|
namespace dom {
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_INHERITED(TVTuner, DOMEventTargetHelper,
|
|
mTVService, mStream, mCurrentSource, mSources)
|
|
|
|
NS_IMPL_ADDREF_INHERITED(TVTuner, DOMEventTargetHelper)
|
|
NS_IMPL_RELEASE_INHERITED(TVTuner, DOMEventTargetHelper)
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TVTuner)
|
|
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
|
|
|
TVTuner::TVTuner(nsPIDOMWindow* aWindow)
|
|
: DOMEventTargetHelper(aWindow)
|
|
{
|
|
}
|
|
|
|
TVTuner::~TVTuner()
|
|
{
|
|
}
|
|
|
|
/* static */ already_AddRefed<TVTuner>
|
|
TVTuner::Create(nsPIDOMWindow* aWindow,
|
|
nsITVTunerData* aData)
|
|
{
|
|
RefPtr<TVTuner> tuner = new TVTuner(aWindow);
|
|
return (tuner->Init(aData)) ? tuner.forget() : nullptr;
|
|
}
|
|
|
|
bool
|
|
TVTuner::Init(nsITVTunerData* aData)
|
|
{
|
|
NS_ENSURE_TRUE(aData, false);
|
|
|
|
nsresult rv = aData->GetId(mId);
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
if (NS_WARN_IF(mId.IsEmpty())) {
|
|
return false;
|
|
}
|
|
|
|
uint32_t count;
|
|
char** supportedSourceTypes;
|
|
rv = aData->GetSupportedSourceTypes(&count, &supportedSourceTypes);
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
for (uint32_t i = 0; i < count; i++) {
|
|
TVSourceType sourceType = ToTVSourceType(supportedSourceTypes[i]);
|
|
if (NS_WARN_IF(sourceType == TVSourceType::EndGuard_)) {
|
|
continue;
|
|
}
|
|
|
|
// Generate the source instance based on the supported source type.
|
|
RefPtr<TVSource> source = TVSource::Create(GetOwner(), sourceType, this);
|
|
if (NS_WARN_IF(!source)) {
|
|
continue;
|
|
}
|
|
|
|
mSupportedSourceTypes.AppendElement(sourceType);
|
|
mSources.AppendElement(source);
|
|
}
|
|
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, supportedSourceTypes);
|
|
|
|
mTVService = TVServiceFactory::AutoCreateTVService();
|
|
NS_ENSURE_TRUE(mTVService, false);
|
|
|
|
rv = aData->GetStreamType(&mStreamType);
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
return true;
|
|
}
|
|
|
|
/* virtual */ JSObject*
|
|
TVTuner::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|
{
|
|
return TVTunerBinding::Wrap(aCx, this, aGivenProto);
|
|
}
|
|
|
|
nsresult
|
|
TVTuner::SetCurrentSource(TVSourceType aSourceType)
|
|
{
|
|
ErrorResult error;
|
|
if (mCurrentSource) {
|
|
if (aSourceType == mCurrentSource->Type()) {
|
|
// No actual change.
|
|
return NS_OK;
|
|
}
|
|
|
|
// No need to stay tuned for non-current sources.
|
|
nsresult rv = mCurrentSource->UnsetCurrentChannel();
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
for (uint32_t i = 0; i < mSources.Length(); i++) {
|
|
if (aSourceType == mSources[i]->Type()) {
|
|
mCurrentSource = mSources[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
nsresult rv = InitMediaStream();
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
return DispatchCurrentSourceChangedEvent(mCurrentSource);
|
|
}
|
|
|
|
nsresult
|
|
TVTuner::DispatchTVEvent(nsIDOMEvent* aEvent)
|
|
{
|
|
return DispatchTrustedEvent(aEvent);
|
|
}
|
|
|
|
void
|
|
TVTuner::GetSupportedSourceTypes(nsTArray<TVSourceType>& aSourceTypes,
|
|
ErrorResult& aRv) const
|
|
{
|
|
aSourceTypes = mSupportedSourceTypes;
|
|
}
|
|
|
|
already_AddRefed<Promise>
|
|
TVTuner::GetSources(ErrorResult& aRv)
|
|
{
|
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
|
|
MOZ_ASSERT(global);
|
|
|
|
RefPtr<Promise> promise = Promise::Create(global, aRv);
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
return nullptr;
|
|
}
|
|
|
|
promise->MaybeResolve(mSources);
|
|
|
|
return promise.forget();
|
|
}
|
|
|
|
already_AddRefed<Promise>
|
|
TVTuner::SetCurrentSource(const TVSourceType aSourceType, ErrorResult& aRv)
|
|
{
|
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
|
|
MOZ_ASSERT(global);
|
|
|
|
RefPtr<Promise> promise = Promise::Create(global, aRv);
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
return nullptr;
|
|
}
|
|
|
|
// |SetCurrentSource(const TVSourceType)| will be called once |notifySuccess|
|
|
// of the callback is invoked.
|
|
nsCOMPtr<nsITVServiceCallback> callback =
|
|
new TVServiceSourceSetterCallback(this, promise, aSourceType);
|
|
nsresult rv = mTVService->SetSource(mId, ToTVSourceTypeStr(aSourceType), callback);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
|
|
}
|
|
|
|
return promise.forget();
|
|
}
|
|
|
|
void
|
|
TVTuner::GetId(nsAString& aId) const
|
|
{
|
|
aId = mId;
|
|
}
|
|
|
|
already_AddRefed<TVSource>
|
|
TVTuner::GetCurrentSource() const
|
|
{
|
|
RefPtr<TVSource> currentSource = mCurrentSource;
|
|
return currentSource.forget();
|
|
}
|
|
|
|
already_AddRefed<DOMMediaStream>
|
|
TVTuner::GetStream() const
|
|
{
|
|
RefPtr<DOMMediaStream> stream = mStream;
|
|
return stream.forget();
|
|
}
|
|
|
|
nsresult
|
|
TVTuner::ReloadMediaStream()
|
|
{
|
|
return InitMediaStream();
|
|
}
|
|
|
|
nsresult
|
|
TVTuner::InitMediaStream()
|
|
{
|
|
nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(GetOwner());
|
|
RefPtr<DOMMediaStream> stream = nullptr;
|
|
if (mStreamType == nsITVTunerData::TV_STREAM_TYPE_HW) {
|
|
stream = DOMHwMediaStream::CreateHwStream(window);
|
|
} else if (mStreamType == nsITVTunerData::TV_STREAM_TYPE_SIMULATOR) {
|
|
stream = CreateSimulatedMediaStream();
|
|
}
|
|
|
|
mStream = stream.forget();
|
|
return NS_OK;
|
|
}
|
|
|
|
already_AddRefed<DOMMediaStream>
|
|
TVTuner::CreateSimulatedMediaStream()
|
|
{
|
|
ErrorResult error;
|
|
|
|
nsIDocument* doc = GetOwner()->GetExtantDoc();
|
|
if (NS_WARN_IF(!doc)) {
|
|
return nullptr;
|
|
}
|
|
RefPtr<Element> element = doc->CreateElement(VIDEO_TAG, error);
|
|
if (NS_WARN_IF(error.Failed())) {
|
|
return nullptr;
|
|
}
|
|
|
|
nsCOMPtr<nsIContent> content(do_QueryInterface(element));
|
|
if (NS_WARN_IF(!content)) {
|
|
return nullptr;
|
|
}
|
|
|
|
HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(content.get());
|
|
if (NS_WARN_IF(!mediaElement)) {
|
|
return nullptr;
|
|
}
|
|
|
|
mediaElement->SetAutoplay(true, error);
|
|
if (NS_WARN_IF(error.Failed())) {
|
|
return nullptr;
|
|
}
|
|
|
|
mediaElement->SetLoop(true, error);
|
|
if (NS_WARN_IF(error.Failed())) {
|
|
return nullptr;
|
|
}
|
|
|
|
nsCOMPtr<nsIDOMWindow> domWin(do_QueryInterface(GetOwner()));
|
|
if (NS_WARN_IF(!domWin)) {
|
|
return nullptr;
|
|
}
|
|
|
|
nsCOMPtr<nsITVSimulatorService> simService(do_QueryInterface(mTVService));
|
|
if (NS_WARN_IF(!simService)) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (NS_WARN_IF(!mCurrentSource)) {
|
|
return nullptr;
|
|
}
|
|
|
|
RefPtr<TVChannel> currentChannel = mCurrentSource->GetCurrentChannel();
|
|
if (NS_WARN_IF(!currentChannel)) {
|
|
return nullptr;
|
|
}
|
|
|
|
nsString currentChannelNumber;
|
|
currentChannel->GetNumber(currentChannelNumber);
|
|
if (currentChannelNumber.IsEmpty()) {
|
|
return nullptr;
|
|
}
|
|
|
|
nsString currentVideoBlobUrl;
|
|
nsresult rv = simService->GetSimulatorVideoBlobURL(mId,
|
|
ToTVSourceTypeStr(mCurrentSource->Type()),
|
|
currentChannelNumber,
|
|
domWin,
|
|
currentVideoBlobUrl);
|
|
if (NS_WARN_IF(NS_FAILED(rv) || currentVideoBlobUrl.IsEmpty())) {
|
|
return nullptr;
|
|
}
|
|
|
|
mediaElement->SetSrc(currentVideoBlobUrl, error);
|
|
if (NS_WARN_IF(error.Failed())) {
|
|
return nullptr;
|
|
}
|
|
|
|
// See Media Capture from DOM Elements spec.
|
|
// http://www.w3.org/TR/mediacapture-fromelement/
|
|
RefPtr<DOMMediaStream> stream = mediaElement->MozCaptureStream(error);
|
|
if (NS_WARN_IF(error.Failed())) {
|
|
return nullptr;
|
|
}
|
|
|
|
return stream.forget();
|
|
}
|
|
|
|
nsresult
|
|
TVTuner::DispatchCurrentSourceChangedEvent(TVSource* aSource)
|
|
{
|
|
TVCurrentSourceChangedEventInit init;
|
|
init.mSource = aSource;
|
|
nsCOMPtr<nsIDOMEvent> event =
|
|
TVCurrentSourceChangedEvent::Constructor(this,
|
|
NS_LITERAL_STRING("currentsourcechanged"),
|
|
init);
|
|
nsCOMPtr<nsIRunnable> runnable =
|
|
NS_NewRunnableMethodWithArg<nsCOMPtr<nsIDOMEvent>>(this,
|
|
&TVTuner::DispatchTVEvent,
|
|
event);
|
|
return NS_DispatchToCurrentThread(runnable);
|
|
}
|
|
|
|
nsresult
|
|
TVTuner::NotifyImageSizeChanged(uint32_t aWidth, uint32_t aHeight)
|
|
{
|
|
DOMHwMediaStream* hwMediaStream = mStream->AsDOMHwMediaStream();
|
|
|
|
if (hwMediaStream) {
|
|
hwMediaStream->SetImageSize(aWidth, aHeight);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
} // namespace dom
|
|
} // namespace mozilla
|