gecko-dev/dom/media/DOMMediaStream.cpp
Gabriele Svelto ace6d1063f Bug 1600545 - Remove useless inclusions of header files generated from IDL files in dom/ r=Ehsan
The inclusions were removed with the following very crude script and the
resulting breakage was fixed up by hand. The manual fixups did either
revert the changes done by the script, replace a generic header with a more
specific one or replace a header with a forward declaration.

find . -name "*.idl" | grep -v web-platform | grep -v third_party | while read path; do
    interfaces=$(grep "^\(class\|interface\).*:.*" "$path" | cut -d' ' -f2)
    if [ -n "$interfaces" ]; then
        if [[ "$interfaces" == *$'\n'* ]]; then
          regexp="\("
          for i in $interfaces; do regexp="$regexp$i\|"; done
          regexp="${regexp%%\\\|}\)"
        else
          regexp="$interfaces"
        fi
        interface=$(basename "$path")
        rg -l "#include.*${interface%%.idl}.h" . | while read path2; do
            hits=$(grep -v "#include.*${interface%%.idl}.h" "$path2" | grep -c "$regexp" )
            if [ $hits -eq 0 ]; then
                echo "Removing ${interface} from ${path2}"
                grep -v "#include.*${interface%%.idl}.h" "$path2" > "$path2".tmp
                mv -f "$path2".tmp "$path2"
            fi
        done
    fi
done

Differential Revision: https://phabricator.services.mozilla.com/D55442

--HG--
extra : moz-landing-system : lando
2019-12-06 09:24:56 +00:00

541 lines
16 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* 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 "AudioCaptureTrack.h"
#include "AudioChannelAgent.h"
#include "AudioStreamTrack.h"
#include "Layers.h"
#include "MediaTrackGraph.h"
#include "MediaTrackGraphImpl.h"
#include "MediaTrackListener.h"
#include "VideoStreamTrack.h"
#include "mozilla/dom/AudioTrack.h"
#include "mozilla/dom/AudioTrackList.h"
#include "mozilla/dom/DocGroup.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "mozilla/dom/MediaStreamBinding.h"
#include "mozilla/dom/MediaStreamTrackEvent.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/VideoTrack.h"
#include "mozilla/dom/VideoTrackList.h"
#include "mozilla/media/MediaUtils.h"
#include "nsContentUtils.h"
#include "nsGlobalWindowInner.h"
#include "nsIUUIDGenerator.h"
#include "nsPIDOMWindow.h"
#include "nsProxyRelease.h"
#include "nsRFPService.h"
#include "nsServiceManagerUtils.h"
#ifdef LOG
# undef LOG
#endif
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::layers;
using namespace mozilla::media;
static LazyLogModule gMediaStreamLog("MediaStream");
#define LOG(type, msg) MOZ_LOG(gMediaStreamLog, type, msg)
static bool ContainsLiveTracks(
const nsTArray<RefPtr<MediaStreamTrack>>& aTracks) {
for (const auto& track : aTracks) {
if (track->ReadyState() == MediaStreamTrackState::Live) {
return true;
}
}
return false;
}
static bool ContainsLiveAudioTracks(
const nsTArray<RefPtr<MediaStreamTrack>>& aTracks) {
for (const auto& track : aTracks) {
if (track->AsAudioStreamTrack() &&
track->ReadyState() == MediaStreamTrackState::Live) {
return true;
}
}
return false;
}
class DOMMediaStream::PlaybackTrackListener : public MediaStreamTrackConsumer {
public:
explicit PlaybackTrackListener(DOMMediaStream* aStream) : mStream(aStream) {}
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PlaybackTrackListener)
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(PlaybackTrackListener)
void NotifyEnded(MediaStreamTrack* aTrack) override {
if (!mStream) {
MOZ_ASSERT(false);
return;
}
if (!aTrack) {
MOZ_ASSERT(false);
return;
}
MOZ_ASSERT(mStream->HasTrack(*aTrack));
mStream->NotifyTrackRemoved(aTrack);
}
protected:
virtual ~PlaybackTrackListener() {}
RefPtr<DOMMediaStream> mStream;
};
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMMediaStream::PlaybackTrackListener,
AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMMediaStream::PlaybackTrackListener,
Release)
NS_IMPL_CYCLE_COLLECTION(DOMMediaStream::PlaybackTrackListener, mStream)
NS_IMPL_CYCLE_COLLECTION_CLASS(DOMMediaStream)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DOMMediaStream,
DOMEventTargetHelper)
tmp->Destroy();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTracks)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsumersToKeepAlive)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPlaybackTrackListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DOMMediaStream,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTracks)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsumersToKeepAlive)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlaybackTrackListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_ADDREF_INHERITED(DOMMediaStream, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(DOMMediaStream, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMMediaStream)
NS_INTERFACE_MAP_ENTRY(DOMMediaStream)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
DOMMediaStream::DOMMediaStream(nsPIDOMWindowInner* aWindow)
: mWindow(aWindow),
mPlaybackTrackListener(MakeAndAddRef<PlaybackTrackListener>(this)) {
nsresult rv;
nsCOMPtr<nsIUUIDGenerator> uuidgen =
do_GetService("@mozilla.org/uuid-generator;1", &rv);
if (NS_SUCCEEDED(rv) && uuidgen) {
nsID uuid;
memset(&uuid, 0, sizeof(uuid));
rv = uuidgen->GenerateUUIDInPlace(&uuid);
if (NS_SUCCEEDED(rv)) {
char buffer[NSID_LENGTH];
uuid.ToProvidedString(buffer);
mID = NS_ConvertASCIItoUTF16(buffer);
}
}
}
DOMMediaStream::~DOMMediaStream() { Destroy(); }
void DOMMediaStream::Destroy() {
LOG(LogLevel::Debug, ("DOMMediaStream %p Being destroyed.", this));
for (const auto& track : mTracks) {
// We must remove ourselves from each track's principal change observer list
// before we die.
if (!track->Ended()) {
track->RemoveConsumer(mPlaybackTrackListener);
}
}
mTrackListeners.Clear();
}
JSObject* DOMMediaStream::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
return dom::MediaStream_Binding::Wrap(aCx, this, aGivenProto);
}
/* static */
already_AddRefed<DOMMediaStream> DOMMediaStream::Constructor(
const GlobalObject& aGlobal, ErrorResult& aRv) {
Sequence<OwningNonNull<MediaStreamTrack>> emptyTrackSeq;
return Constructor(aGlobal, emptyTrackSeq, aRv);
}
/* static */
already_AddRefed<DOMMediaStream> DOMMediaStream::Constructor(
const GlobalObject& aGlobal, const DOMMediaStream& aStream,
ErrorResult& aRv) {
nsTArray<RefPtr<MediaStreamTrack>> tracks;
aStream.GetTracks(tracks);
Sequence<OwningNonNull<MediaStreamTrack>> nonNullTrackSeq;
if (!nonNullTrackSeq.SetLength(tracks.Length(), fallible)) {
MOZ_ASSERT(false);
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}
for (size_t i = 0; i < tracks.Length(); ++i) {
nonNullTrackSeq[i] = tracks[i];
}
return Constructor(aGlobal, nonNullTrackSeq, aRv);
}
/* static */
already_AddRefed<DOMMediaStream> DOMMediaStream::Constructor(
const GlobalObject& aGlobal,
const Sequence<OwningNonNull<MediaStreamTrack>>& aTracks,
ErrorResult& aRv) {
nsCOMPtr<nsPIDOMWindowInner> ownerWindow =
do_QueryInterface(aGlobal.GetAsSupports());
if (!ownerWindow) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
auto newStream = MakeRefPtr<DOMMediaStream>(ownerWindow);
for (MediaStreamTrack& track : aTracks) {
newStream->AddTrack(track);
}
return newStream.forget();
}
already_AddRefed<Promise> DOMMediaStream::CountUnderlyingStreams(
const GlobalObject& aGlobal, ErrorResult& aRv) {
nsCOMPtr<nsPIDOMWindowInner> window =
do_QueryInterface(aGlobal.GetAsSupports());
if (!window) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(aGlobal.GetAsSupports());
if (!go) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
RefPtr<Promise> p = Promise::Create(go, aRv);
if (aRv.Failed()) {
return nullptr;
}
MediaTrackGraph* graph = MediaTrackGraph::GetInstanceIfExists(
window, MediaTrackGraph::REQUEST_DEFAULT_SAMPLE_RATE);
if (!graph) {
p->MaybeResolve(0);
return p.forget();
}
auto* graphImpl = static_cast<MediaTrackGraphImpl*>(graph);
class Counter : public ControlMessage {
public:
Counter(MediaTrackGraphImpl* aGraph, const RefPtr<Promise>& aPromise)
: ControlMessage(nullptr), mGraph(aGraph), mPromise(aPromise) {
MOZ_ASSERT(NS_IsMainThread());
}
void Run() override {
uint32_t streams =
mGraph->mTracks.Length() + mGraph->mSuspendedTracks.Length();
mGraph->DispatchToMainThreadStableState(NS_NewRunnableFunction(
"DOMMediaStream::CountUnderlyingStreams (stable state)",
[promise = std::move(mPromise), streams]() mutable {
NS_DispatchToMainThread(NS_NewRunnableFunction(
"DOMMediaStream::CountUnderlyingStreams",
[promise = std::move(promise), streams]() {
promise->MaybeResolve(streams);
}));
}));
}
// mPromise can only be AddRefed/Released on main thread.
// In case of shutdown, Run() does not run, so we dispatch mPromise to be
// released on main thread here.
void RunDuringShutdown() override {
NS_ReleaseOnMainThreadSystemGroup(
"DOMMediaStream::CountUnderlyingStreams::Counter::RunDuringShutdown",
mPromise.forget());
}
private:
// mGraph owns this Counter instance and decides its lifetime.
MediaTrackGraphImpl* mGraph;
RefPtr<Promise> mPromise;
};
graphImpl->AppendMessage(MakeUnique<Counter>(graphImpl, p));
return p.forget();
}
void DOMMediaStream::GetId(nsAString& aID) const { aID = mID; }
void DOMMediaStream::GetAudioTracks(
nsTArray<RefPtr<AudioStreamTrack>>& aTracks) const {
for (const auto& track : mTracks) {
if (AudioStreamTrack* t = track->AsAudioStreamTrack()) {
aTracks.AppendElement(t);
}
}
}
void DOMMediaStream::GetAudioTracks(
nsTArray<RefPtr<MediaStreamTrack>>& aTracks) const {
for (const auto& track : mTracks) {
if (track->AsAudioStreamTrack()) {
aTracks.AppendElement(track);
}
}
}
void DOMMediaStream::GetVideoTracks(
nsTArray<RefPtr<VideoStreamTrack>>& aTracks) const {
for (const auto& track : mTracks) {
if (VideoStreamTrack* t = track->AsVideoStreamTrack()) {
aTracks.AppendElement(t);
}
}
}
void DOMMediaStream::GetVideoTracks(
nsTArray<RefPtr<MediaStreamTrack>>& aTracks) const {
for (const auto& track : mTracks) {
if (track->AsVideoStreamTrack()) {
aTracks.AppendElement(track);
}
}
}
void DOMMediaStream::GetTracks(
nsTArray<RefPtr<MediaStreamTrack>>& aTracks) const {
for (const auto& track : mTracks) {
aTracks.AppendElement(track);
}
}
void DOMMediaStream::AddTrack(MediaStreamTrack& aTrack) {
LOG(LogLevel::Info, ("DOMMediaStream %p Adding track %p (from track %p)",
this, &aTrack, aTrack.GetTrack()));
if (HasTrack(aTrack)) {
LOG(LogLevel::Debug,
("DOMMediaStream %p already contains track %p", this, &aTrack));
return;
}
mTracks.AppendElement(&aTrack);
NotifyTrackAdded(&aTrack);
}
void DOMMediaStream::RemoveTrack(MediaStreamTrack& aTrack) {
LOG(LogLevel::Info, ("DOMMediaStream %p Removing track %p (from track %p)",
this, &aTrack, aTrack.GetTrack()));
if (!mTracks.RemoveElement(&aTrack)) {
LOG(LogLevel::Debug,
("DOMMediaStream %p does not contain track %p", this, &aTrack));
return;
}
if (!aTrack.Ended()) {
NotifyTrackRemoved(&aTrack);
}
}
already_AddRefed<DOMMediaStream> DOMMediaStream::Clone() {
auto newStream = MakeRefPtr<DOMMediaStream>(GetParentObject());
LOG(LogLevel::Info,
("DOMMediaStream %p created clone %p", this, newStream.get()));
for (const auto& track : mTracks) {
LOG(LogLevel::Debug,
("DOMMediaStream %p forwarding external track %p to clone %p", this,
track.get(), newStream.get()));
RefPtr<MediaStreamTrack> clone = track->Clone();
newStream->AddTrack(*clone);
}
return newStream.forget();
}
bool DOMMediaStream::Active() const { return mActive; }
bool DOMMediaStream::Audible() const { return mAudible; }
MediaStreamTrack* DOMMediaStream::GetTrackById(const nsAString& aId) const {
for (const auto& track : mTracks) {
nsString id;
track->GetId(id);
if (id == aId) {
return track;
}
}
return nullptr;
}
bool DOMMediaStream::HasTrack(const MediaStreamTrack& aTrack) const {
return mTracks.Contains(&aTrack);
}
void DOMMediaStream::AddTrackInternal(MediaStreamTrack* aTrack) {
LOG(LogLevel::Debug,
("DOMMediaStream %p Adding owned track %p", this, aTrack));
AddTrack(*aTrack);
DispatchTrackEvent(NS_LITERAL_STRING("addtrack"), aTrack);
}
void DOMMediaStream::RemoveTrackInternal(MediaStreamTrack* aTrack) {
LOG(LogLevel::Debug,
("DOMMediaStream %p Removing owned track %p", this, aTrack));
if (!HasTrack(*aTrack)) {
return;
}
RemoveTrack(*aTrack);
DispatchTrackEvent(NS_LITERAL_STRING("removetrack"), aTrack);
}
already_AddRefed<nsIPrincipal> DOMMediaStream::GetPrincipal() {
nsCOMPtr<nsIPrincipal> principal =
nsGlobalWindowInner::Cast(mWindow)->GetPrincipal();
for (const auto& t : mTracks) {
if (t->Ended()) {
continue;
}
nsContentUtils::CombineResourcePrincipals(&principal, t->GetPrincipal());
}
return principal.forget();
}
void DOMMediaStream::NotifyActive() {
LOG(LogLevel::Info, ("DOMMediaStream %p NotifyActive(). ", this));
MOZ_ASSERT(mActive);
for (int32_t i = mTrackListeners.Length() - 1; i >= 0; --i) {
mTrackListeners[i]->NotifyActive();
}
}
void DOMMediaStream::NotifyInactive() {
LOG(LogLevel::Info, ("DOMMediaStream %p NotifyInactive(). ", this));
MOZ_ASSERT(!mActive);
for (int32_t i = mTrackListeners.Length() - 1; i >= 0; --i) {
mTrackListeners[i]->NotifyInactive();
}
}
void DOMMediaStream::NotifyAudible() {
LOG(LogLevel::Info, ("DOMMediaStream %p NotifyAudible(). ", this));
MOZ_ASSERT(mAudible);
for (int32_t i = mTrackListeners.Length() - 1; i >= 0; --i) {
mTrackListeners[i]->NotifyAudible();
}
}
void DOMMediaStream::NotifyInaudible() {
LOG(LogLevel::Info, ("DOMMediaStream %p NotifyInaudible(). ", this));
MOZ_ASSERT(!mAudible);
for (int32_t i = mTrackListeners.Length() - 1; i >= 0; --i) {
mTrackListeners[i]->NotifyInaudible();
}
}
void DOMMediaStream::RegisterTrackListener(TrackListener* aListener) {
MOZ_ASSERT(NS_IsMainThread());
mTrackListeners.AppendElement(aListener);
}
void DOMMediaStream::UnregisterTrackListener(TrackListener* aListener) {
MOZ_ASSERT(NS_IsMainThread());
mTrackListeners.RemoveElement(aListener);
}
void DOMMediaStream::NotifyTrackAdded(const RefPtr<MediaStreamTrack>& aTrack) {
MOZ_ASSERT(NS_IsMainThread());
aTrack->AddConsumer(mPlaybackTrackListener);
for (int32_t i = mTrackListeners.Length() - 1; i >= 0; --i) {
mTrackListeners[i]->NotifyTrackAdded(aTrack);
}
if (!mActive) {
// Check if we became active.
if (ContainsLiveTracks(mTracks)) {
mActive = true;
NotifyActive();
}
}
if (!mAudible) {
// Check if we became audible.
if (ContainsLiveAudioTracks(mTracks)) {
mAudible = true;
NotifyAudible();
}
}
}
void DOMMediaStream::NotifyTrackRemoved(
const RefPtr<MediaStreamTrack>& aTrack) {
MOZ_ASSERT(NS_IsMainThread());
if (aTrack) {
// aTrack may be null to allow HTMLMediaElement::MozCaptureStream streams
// to be played until the source media element has ended. The source media
// element will then call NotifyTrackRemoved(nullptr) to signal that we can
// go inactive, regardless of the timing of the last track ending.
aTrack->RemoveConsumer(mPlaybackTrackListener);
for (int32_t i = mTrackListeners.Length() - 1; i >= 0; --i) {
mTrackListeners[i]->NotifyTrackRemoved(aTrack);
}
if (!mActive) {
NS_ASSERTION(false, "Shouldn't remove a live track if already inactive");
return;
}
}
if (mAudible) {
// Check if we became inaudible.
if (!ContainsLiveAudioTracks(mTracks)) {
mAudible = false;
NotifyInaudible();
}
}
// Check if we became inactive.
if (!ContainsLiveTracks(mTracks)) {
mActive = false;
NotifyInactive();
}
}
nsresult DOMMediaStream::DispatchTrackEvent(
const nsAString& aName, const RefPtr<MediaStreamTrack>& aTrack) {
MediaStreamTrackEventInit init;
init.mTrack = aTrack;
RefPtr<MediaStreamTrackEvent> event =
MediaStreamTrackEvent::Constructor(this, aName, init);
return DispatchTrustedEvent(event);
}