2012-05-11 10:35:36 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
2012-04-29 20:11:34 -07:00
|
|
|
/* 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/. */
|
|
|
|
|
2013-02-15 00:01:58 -08:00
|
|
|
#include "DOMMediaStream.h"
|
2012-04-29 20:11:34 -07:00
|
|
|
#include "nsDOMClassInfoID.h"
|
|
|
|
#include "nsContentUtils.h"
|
2013-02-15 00:04:11 -08:00
|
|
|
#include "mozilla/dom/MediaStreamBinding.h"
|
|
|
|
#include "mozilla/dom/LocalMediaStreamBinding.h"
|
|
|
|
#include "MediaStreamGraph.h"
|
2013-04-16 22:18:24 -07:00
|
|
|
#include "AudioStreamTrack.h"
|
|
|
|
#include "VideoStreamTrack.h"
|
2012-04-29 20:11:34 -07:00
|
|
|
|
|
|
|
using namespace mozilla;
|
2013-04-16 22:18:24 -07:00
|
|
|
using namespace mozilla::dom;
|
2012-04-29 20:11:34 -07:00
|
|
|
|
2013-02-15 00:01:58 -08:00
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMMediaStream)
|
2013-02-15 00:04:11 -08:00
|
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
2012-04-29 20:11:34 -07:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMMediaStream)
|
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
2013-02-15 00:01:58 -08:00
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMMediaStream)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMMediaStream)
|
2013-04-16 22:18:24 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(DOMMediaStream, mWindow, mTracks)
|
2012-10-24 16:21:32 -07:00
|
|
|
|
2013-02-07 02:19:08 -08:00
|
|
|
NS_IMPL_ISUPPORTS_INHERITED1(DOMLocalMediaStream, DOMMediaStream,
|
|
|
|
nsIDOMLocalMediaStream)
|
2012-10-24 16:21:32 -07:00
|
|
|
|
2013-04-16 22:18:24 -07:00
|
|
|
class DOMMediaStream::StreamListener : public MediaStreamListener {
|
|
|
|
public:
|
|
|
|
StreamListener(DOMMediaStream* aStream)
|
|
|
|
: mStream(aStream)
|
|
|
|
{}
|
|
|
|
|
|
|
|
// Main thread only
|
|
|
|
void Forget() { mStream = nullptr; }
|
|
|
|
DOMMediaStream* GetStream() { return mStream; }
|
|
|
|
|
|
|
|
class TrackChange : public nsRunnable {
|
|
|
|
public:
|
|
|
|
TrackChange(StreamListener* aListener,
|
|
|
|
TrackID aID, TrackTicks aTrackOffset,
|
|
|
|
uint32_t aEvents, MediaSegment::Type aType)
|
|
|
|
: mListener(aListener), mID(aID), mEvents(aEvents), mType(aType)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD Run()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(NS_IsMainThread(), "main thread only");
|
|
|
|
|
|
|
|
DOMMediaStream* stream = mListener->GetStream();
|
|
|
|
if (!stream) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRefPtr<MediaStreamTrack> track;
|
|
|
|
if (mEvents & MediaStreamListener::TRACK_EVENT_CREATED) {
|
|
|
|
track = stream->CreateDOMTrack(mID, mType);
|
|
|
|
} else {
|
|
|
|
track = stream->GetDOMTrackFor(mID);
|
|
|
|
}
|
|
|
|
if (mEvents & MediaStreamListener::TRACK_EVENT_ENDED) {
|
|
|
|
track->NotifyEnded();
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
StreamTime mEndTime;
|
|
|
|
nsRefPtr<StreamListener> mListener;
|
|
|
|
TrackID mID;
|
|
|
|
uint32_t mEvents;
|
|
|
|
MediaSegment::Type mType;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Notify that changes to one of the stream tracks have been queued.
|
|
|
|
* aTrackEvents can be any combination of TRACK_EVENT_CREATED and
|
|
|
|
* TRACK_EVENT_ENDED. aQueuedMedia is the data being added to the track
|
|
|
|
* at aTrackOffset (relative to the start of the stream).
|
|
|
|
* aQueuedMedia can be null if there is no output.
|
|
|
|
*/
|
|
|
|
virtual void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
|
|
|
|
TrackRate aTrackRate,
|
|
|
|
TrackTicks aTrackOffset,
|
|
|
|
uint32_t aTrackEvents,
|
|
|
|
const MediaSegment& aQueuedMedia)
|
|
|
|
{
|
|
|
|
if (aTrackEvents & (TRACK_EVENT_CREATED | TRACK_EVENT_ENDED)) {
|
|
|
|
nsRefPtr<TrackChange> runnable =
|
|
|
|
new TrackChange(this, aID, aTrackOffset, aTrackEvents,
|
|
|
|
aQueuedMedia.GetType());
|
|
|
|
NS_DispatchToMainThread(runnable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
// These fields may only be accessed on the main thread
|
|
|
|
DOMMediaStream* mStream;
|
|
|
|
};
|
|
|
|
|
|
|
|
DOMMediaStream::DOMMediaStream()
|
|
|
|
: mStream(nullptr), mHintContents(0)
|
|
|
|
{
|
|
|
|
SetIsDOMBinding();
|
|
|
|
}
|
|
|
|
|
2013-02-15 00:01:58 -08:00
|
|
|
DOMMediaStream::~DOMMediaStream()
|
2012-04-29 20:11:34 -07:00
|
|
|
{
|
2013-04-16 22:18:24 -07:00
|
|
|
if (mListener) {
|
|
|
|
mListener->Forget();
|
|
|
|
}
|
2012-04-29 20:11:34 -07:00
|
|
|
if (mStream) {
|
|
|
|
mStream->Destroy();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-15 00:04:11 -08:00
|
|
|
JSObject*
|
2013-03-11 16:03:47 -07:00
|
|
|
DOMMediaStream::WrapObject(JSContext* aCx, JSObject* aScope)
|
2012-04-29 20:11:34 -07:00
|
|
|
{
|
2013-03-11 16:03:47 -07:00
|
|
|
return dom::MediaStreamBinding::Wrap(aCx, aScope, this);
|
2012-04-29 20:11:34 -07:00
|
|
|
}
|
|
|
|
|
2013-02-15 00:04:11 -08:00
|
|
|
double
|
|
|
|
DOMMediaStream::CurrentTime()
|
2013-01-06 18:31:34 -08:00
|
|
|
{
|
2013-02-15 00:04:11 -08:00
|
|
|
return mStream ? MediaTimeToSeconds(mStream->GetCurrentTime()) : 0.0;
|
2013-01-06 18:31:34 -08:00
|
|
|
}
|
|
|
|
|
2013-02-15 00:04:11 -08:00
|
|
|
bool
|
|
|
|
DOMMediaStream::IsFinished()
|
2012-10-24 16:21:32 -07:00
|
|
|
{
|
2013-02-15 00:04:11 -08:00
|
|
|
return !mStream || mStream->IsFinished();
|
2012-10-24 16:21:32 -07:00
|
|
|
}
|
|
|
|
|
2013-02-15 00:04:11 -08:00
|
|
|
void
|
|
|
|
DOMMediaStream::InitSourceStream(nsIDOMWindow* aWindow, uint32_t aHintContents)
|
2012-04-29 20:11:40 -07:00
|
|
|
{
|
2013-02-15 00:04:11 -08:00
|
|
|
mWindow = aWindow;
|
|
|
|
SetHintContents(aHintContents);
|
|
|
|
MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
|
2013-04-16 22:18:24 -07:00
|
|
|
InitStreamCommon(gm->CreateSourceStream(this));
|
2012-04-29 20:11:40 -07:00
|
|
|
}
|
|
|
|
|
2013-02-15 00:04:11 -08:00
|
|
|
void
|
|
|
|
DOMMediaStream::InitTrackUnionStream(nsIDOMWindow* aWindow, uint32_t aHintContents)
|
2012-10-24 16:21:32 -07:00
|
|
|
{
|
2013-02-15 00:04:11 -08:00
|
|
|
mWindow = aWindow;
|
|
|
|
SetHintContents(aHintContents);
|
|
|
|
MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
|
2013-04-16 22:18:24 -07:00
|
|
|
InitStreamCommon(gm->CreateTrackUnionStream(this));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DOMMediaStream::InitStreamCommon(MediaStream* aStream)
|
|
|
|
{
|
|
|
|
mStream = aStream;
|
|
|
|
|
|
|
|
// Setup track listener
|
|
|
|
mListener = new StreamListener(this);
|
|
|
|
aStream->AddListener(mListener);
|
2012-10-24 16:21:32 -07:00
|
|
|
}
|
|
|
|
|
2013-02-15 00:01:58 -08:00
|
|
|
already_AddRefed<DOMMediaStream>
|
2013-02-15 00:04:11 -08:00
|
|
|
DOMMediaStream::CreateSourceStream(nsIDOMWindow* aWindow, uint32_t aHintContents)
|
2012-07-31 05:17:22 -07:00
|
|
|
{
|
2013-02-15 00:01:58 -08:00
|
|
|
nsRefPtr<DOMMediaStream> stream = new DOMMediaStream();
|
2013-02-15 00:04:11 -08:00
|
|
|
stream->InitSourceStream(aWindow, aHintContents);
|
2012-07-31 05:17:22 -07:00
|
|
|
return stream.forget();
|
|
|
|
}
|
|
|
|
|
2013-02-15 00:04:11 -08:00
|
|
|
already_AddRefed<DOMMediaStream>
|
|
|
|
DOMMediaStream::CreateTrackUnionStream(nsIDOMWindow* aWindow, uint32_t aHintContents)
|
2012-10-24 16:21:32 -07:00
|
|
|
{
|
2013-02-15 00:04:11 -08:00
|
|
|
nsRefPtr<DOMMediaStream> stream = new DOMMediaStream();
|
|
|
|
stream->InitTrackUnionStream(aWindow, aHintContents);
|
2012-10-24 16:21:32 -07:00
|
|
|
return stream.forget();
|
|
|
|
}
|
|
|
|
|
2012-04-29 20:11:34 -07:00
|
|
|
bool
|
2013-02-15 00:01:58 -08:00
|
|
|
DOMMediaStream::CombineWithPrincipal(nsIPrincipal* aPrincipal)
|
2012-04-29 20:11:34 -07:00
|
|
|
{
|
|
|
|
return nsContentUtils::CombineResourcePrincipals(&mPrincipal, aPrincipal);
|
|
|
|
}
|
2013-02-15 00:04:11 -08:00
|
|
|
|
2013-04-16 22:18:24 -07:00
|
|
|
MediaStreamTrack*
|
|
|
|
DOMMediaStream::CreateDOMTrack(TrackID aTrackID, MediaSegment::Type aType)
|
|
|
|
{
|
|
|
|
MediaStreamTrack* track;
|
|
|
|
switch (aType) {
|
|
|
|
case MediaSegment::AUDIO:
|
|
|
|
track = new AudioStreamTrack(this, aTrackID);
|
|
|
|
break;
|
|
|
|
case MediaSegment::VIDEO:
|
|
|
|
track = new VideoStreamTrack(this, aTrackID);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
MOZ_NOT_REACHED("Unhandled track type");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
mTracks.AppendElement(track);
|
|
|
|
return track;
|
|
|
|
}
|
|
|
|
|
|
|
|
MediaStreamTrack*
|
|
|
|
DOMMediaStream::GetDOMTrackFor(TrackID aTrackID)
|
|
|
|
{
|
|
|
|
for (uint32_t i = 0; i < mTracks.Length(); ++i) {
|
|
|
|
MediaStreamTrack* t = mTracks[i];
|
|
|
|
// We may add streams to our track list that are actually owned by
|
|
|
|
// a different DOMMediaStream. Ignore those.
|
|
|
|
if (t->GetTrackID() == aTrackID && t->GetStream() == this) {
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2013-02-15 00:04:11 -08:00
|
|
|
DOMLocalMediaStream::~DOMLocalMediaStream()
|
|
|
|
{
|
|
|
|
if (mStream) {
|
|
|
|
// Make sure Listeners of this stream know it's going away
|
|
|
|
Stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JSObject*
|
2013-03-11 16:03:47 -07:00
|
|
|
DOMLocalMediaStream::WrapObject(JSContext* aCx, JSObject* aScope)
|
2013-02-15 00:04:11 -08:00
|
|
|
{
|
2013-03-11 16:03:47 -07:00
|
|
|
return dom::LocalMediaStreamBinding::Wrap(aCx, aScope, this);
|
2013-02-15 00:04:11 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DOMLocalMediaStream::Stop()
|
|
|
|
{
|
|
|
|
if (mStream && mStream->AsSourceStream()) {
|
|
|
|
mStream->AsSourceStream()->EndAllTrackAndFinish();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<DOMLocalMediaStream>
|
|
|
|
DOMLocalMediaStream::CreateSourceStream(nsIDOMWindow* aWindow, uint32_t aHintContents)
|
|
|
|
{
|
|
|
|
nsRefPtr<DOMLocalMediaStream> stream = new DOMLocalMediaStream();
|
|
|
|
stream->InitSourceStream(aWindow, aHintContents);
|
|
|
|
return stream.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<DOMLocalMediaStream>
|
|
|
|
DOMLocalMediaStream::CreateTrackUnionStream(nsIDOMWindow* aWindow, uint32_t aHintContents)
|
|
|
|
{
|
|
|
|
nsRefPtr<DOMLocalMediaStream> stream = new DOMLocalMediaStream();
|
|
|
|
stream->InitTrackUnionStream(aWindow, aHintContents);
|
|
|
|
return stream.forget();
|
|
|
|
}
|