dom/media/MediaStreamTrack.cpp
author Andreas Pehrson <pehrsons@gmail.com>
Tue, 05 Jan 2016 10:16:30 +0800
changeset 342153 2b8ce704b0745150f21ae464f517a72c4678795b
parent 342151 2734e42f96a537cc91e4b9b531f3c6bf329dbd09
child 327702 f3a0fe0c3cad03b935c0d5e1642402486d491389
child 342172 146465c1d9a3fd779fe144b8ba2c487f75dee0e5
permissions -rw-r--r--
Bug 1208371 - Switch MediaStreamTrack to enable/disable tracks on owned stream. r?jesup MozReview-Commit-ID: DY7Du6vRBqT

/* -*- 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 "MediaStreamTrack.h"

#include "DOMMediaStream.h"
#include "MediaStreamGraph.h"
#include "nsIUUIDGenerator.h"
#include "nsServiceManagerUtils.h"

#ifdef LOG
#undef LOG
#endif

static PRLogModuleInfo* gMediaStreamTrackLog;
#define LOG(type, msg) MOZ_LOG(gMediaStreamTrackLog, type, msg)

namespace mozilla {
namespace dom {

NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaStreamTrackSource)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaStreamTrackSource)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaStreamTrackSource)
  NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION(MediaStreamTrackSource, mPrincipal)

already_AddRefed<Promise>
MediaStreamTrackSource::ApplyConstraints(nsPIDOMWindowInner* aWindow,
                                         const dom::MediaTrackConstraints& aConstraints,
                                         ErrorResult &aRv)
{
  nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(aWindow);
  RefPtr<Promise> promise = Promise::Create(go, aRv);
  MOZ_RELEASE_ASSERT(!aRv.Failed());

  promise->MaybeReject(new MediaStreamError(
    aWindow,
    NS_LITERAL_STRING("OverconstrainedError"),
    NS_LITERAL_STRING(""),
    NS_LITERAL_STRING("")));
  return promise.forget();
}

MediaStreamTrack::MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID,
                                   TrackID aInputTrackID, const nsString& aLabel,
                                   MediaStreamTrackSource* aSource)
  : mOwningStream(aStream), mTrackID(aTrackID),
    mInputTrackID(aInputTrackID), mSource(aSource), mLabel(aLabel),
    mEnded(false), mEnabled(true), mRemote(aSource->IsRemote()), mStopped(false)
{

  if (!gMediaStreamTrackLog) {
    gMediaStreamTrackLog = PR_NewLogModule("MediaStreamTrack");
  }

  GetSource().RegisterSink(this);

  nsresult rv;
  nsCOMPtr<nsIUUIDGenerator> uuidgen =
    do_GetService("@mozilla.org/uuid-generator;1", &rv);

  nsID uuid;
  memset(&uuid, 0, sizeof(uuid));
  if (uuidgen) {
    uuidgen->GenerateUUIDInPlace(&uuid);
  }

  char chars[NSID_LENGTH];
  uuid.ToProvidedString(chars);
  mID = NS_ConvertASCIItoUTF16(chars);
}

MediaStreamTrack::~MediaStreamTrack()
{
}

NS_IMPL_CYCLE_COLLECTION_CLASS(MediaStreamTrack)

NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MediaStreamTrack,
                                                DOMEventTargetHelper)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwningStream)
  if (tmp->mSource) {
    tmp->mSource->UnregisterSink(tmp);
  }
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSource)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOriginalTrack)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END

NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MediaStreamTrack,
                                                  DOMEventTargetHelper)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwningStream)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSource)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginalTrack)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

NS_IMPL_ADDREF_INHERITED(MediaStreamTrack, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(MediaStreamTrack, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaStreamTrack)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)

nsPIDOMWindowInner*
MediaStreamTrack::GetParentObject() const
{
  MOZ_RELEASE_ASSERT(mOwningStream);
  return mOwningStream->GetParentObject();
}

void
MediaStreamTrack::GetId(nsAString& aID) const
{
  aID = mID;
}

void
MediaStreamTrack::SetEnabled(bool aEnabled)
{
  LOG(LogLevel::Info, ("MediaStreamTrack %p %s",
                       this, aEnabled ? "Enabled" : "Disabled"));

  mEnabled = aEnabled;
  GetOwnedStream()->SetTrackEnabled(mTrackID, aEnabled);
}

void
MediaStreamTrack::Stop()
{
  LOG(LogLevel::Info, ("MediaStreamTrack %p Stop()", this));

  if (mStopped) {
    LOG(LogLevel::Warning, ("MediaStreamTrack %p Already stopped", this));
    return;
  }

  if (mRemote) {
    LOG(LogLevel::Warning, ("MediaStreamTrack %p is remote. Can't be stopped.", this));
    return;
  }

  if (!mSource) {
    MOZ_ASSERT(false);
    return;
  }

  mSource->UnregisterSink(this);
  mStopped = true;
}

already_AddRefed<Promise>
MediaStreamTrack::ApplyConstraints(const MediaTrackConstraints& aConstraints,
                                   ErrorResult &aRv)
{
  if (MOZ_LOG_TEST(gMediaStreamTrackLog, LogLevel::Info)) {
    nsString str;
    aConstraints.ToJSON(str);

    LOG(LogLevel::Info, ("MediaStreamTrack %p ApplyConstraints() with "
                         "constraints %s", this, NS_ConvertUTF16toUTF8(str).get()));
  }

  nsPIDOMWindowInner* window = mOwningStream->GetParentObject();
  return GetSource().ApplyConstraints(window, aConstraints, aRv);
}

MediaStreamGraph*
MediaStreamTrack::Graph()
{
  return GetOwnedStream()->Graph();
}

MediaStreamGraphImpl*
MediaStreamTrack::GraphImpl()
{
  return GetOwnedStream()->GraphImpl();
}

void
MediaStreamTrack::PrincipalChanged()
{
  LOG(LogLevel::Info, ("MediaStreamTrack %p Principal changed. Now: "
                       "null=%d, codebase=%d, expanded=%d, system=%d", this,
                       GetPrincipal()->GetIsNullPrincipal(),
                       GetPrincipal()->GetIsCodebasePrincipal(),
                       GetPrincipal()->GetIsExpandedPrincipal(),
                       GetPrincipal()->GetIsSystemPrincipal()));
  for (PrincipalChangeObserver<MediaStreamTrack>* observer
      : mPrincipalChangeObservers) {
    observer->PrincipalChanged(this);
  }
}

bool
MediaStreamTrack::AddPrincipalChangeObserver(
  PrincipalChangeObserver<MediaStreamTrack>* aObserver)
{
  return mPrincipalChangeObservers.AppendElement(aObserver) != nullptr;
}

bool
MediaStreamTrack::RemovePrincipalChangeObserver(
  PrincipalChangeObserver<MediaStreamTrack>* aObserver)
{
  return mPrincipalChangeObservers.RemoveElement(aObserver);
}

already_AddRefed<MediaStreamTrack>
MediaStreamTrack::Clone()
{
  // MediaStreamTracks are currently governed by streams, so we need a dummy
  // DOMMediaStream to own our track clone. The dummy will never see any
  // dynamically created tracks (no input stream) so no need for a SourceGetter.
  RefPtr<DOMMediaStream> newStream =
    new DOMMediaStream(mOwningStream->GetParentObject(), nullptr);

  MediaStreamGraph* graph = Graph();
  newStream->InitOwnedStreamCommon(graph);
  newStream->InitPlaybackStreamCommon(graph);

  return newStream->CloneDOMTrack(*this, mTrackID);
}

DOMMediaStream*
MediaStreamTrack::GetInputDOMStream()
{
  MediaStreamTrack* originalTrack =
    mOriginalTrack ? mOriginalTrack.get() : this;
  MOZ_RELEASE_ASSERT(originalTrack->mOwningStream);
  return originalTrack->mOwningStream;
}

MediaStream*
MediaStreamTrack::GetInputStream()
{
  DOMMediaStream* inputDOMStream = GetInputDOMStream();
  MOZ_RELEASE_ASSERT(inputDOMStream->GetInputStream());
  return inputDOMStream->GetInputStream();
}

ProcessedMediaStream*
MediaStreamTrack::GetOwnedStream()
{
  return mOwningStream->GetOwnedStream();
}

void
MediaStreamTrack::AddListener(MediaStreamTrackListener* aListener)
{
  LOG(LogLevel::Debug, ("MediaStreamTrack %p adding listener %p",
                        this, aListener));

  GetOwnedStream()->AddTrackListener(aListener, mTrackID);
}

void
MediaStreamTrack::RemoveListener(MediaStreamTrackListener* aListener)
{
  LOG(LogLevel::Debug, ("MediaStreamTrack %p removing listener %p",
                        this, aListener));

  GetOwnedStream()->RemoveTrackListener(aListener, mTrackID);
}

void
MediaStreamTrack::AddDirectListener(MediaStreamTrackDirectListener *aListener)
{
  LOG(LogLevel::Debug, ("MediaStreamTrack %p (%s) adding direct listener %p to "
                        "stream %p, track %d",
                        this, AsAudioStreamTrack() ? "audio" : "video",
                        aListener, GetOwnedStream(), mTrackID));

  GetOwnedStream()->AddDirectTrackListener(aListener, mTrackID);
}

void
MediaStreamTrack::RemoveDirectListener(MediaStreamTrackDirectListener *aListener)
{
  LOG(LogLevel::Debug, ("MediaStreamTrack %p removing direct listener %p from stream %p",
                        this, aListener, GetOwnedStream()));

  GetOwnedStream()->RemoveDirectTrackListener(aListener, mTrackID);
}

already_AddRefed<MediaInputPort>
MediaStreamTrack::ForwardTrackContentsTo(ProcessedMediaStream* aStream)
{
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_RELEASE_ASSERT(aStream);
  RefPtr<MediaInputPort> port =
    aStream->AllocateInputPort(GetOwnedStream(), mTrackID);
  return port.forget();
}

bool
MediaStreamTrack::IsForwardedThrough(MediaInputPort* aPort)
{
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(aPort);
  if (!aPort) {
    return false;
  }
  return aPort->GetSource() == GetOwnedStream() &&
         aPort->PassTrackThrough(mTrackID);
}

} // namespace dom
} // namespace mozilla