--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -2624,17 +2624,17 @@ SourceMediaStream::NotifyDirectConsumers
}
for (const TrackBound<MediaStreamTrackDirectListener>& source
: mDirectTrackListeners) {
if (aTrack->mID != source.mTrackID) {
continue;
}
StreamTime offset = 0; // FIX! need a separate StreamTime.... or the end of the internal buffer
- source.mListener->NotifyRealtimeTrackData(Graph(), offset, *aSegment);
+ source.mListener->NotifyRealtimeTrackDataAndApplyTrackDisabling(Graph(), offset, *aSegment);
}
}
// These handle notifying all the listeners of an event
void
SourceMediaStream::NotifyListenersEventImpl(MediaStreamListener::MediaStreamGraphEvent aEvent)
{
for (uint32_t j = 0; j < mListeners.Length(); ++j) {
@@ -2790,16 +2790,39 @@ SourceMediaStream::FinishWithLockHeld()
mMutex.AssertCurrentThreadOwns();
mUpdateFinished = true;
if (auto graph = GraphImpl()) {
graph->EnsureNextIteration();
}
}
void
+SourceMediaStream::SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled)
+{
+ MutexAutoLock lock(mMutex);
+ for (TrackBound<MediaStreamTrackDirectListener>& l: mDirectTrackListeners) {
+ if (l.mTrackID == aTrackID) {
+ bool oldEnabled = !mDisabledTrackIDs.Contains(aTrackID);
+ if (!oldEnabled && aEnabled) {
+ STREAM_LOG(LogLevel::Debug, ("SourceMediaStream %p track %d setting "
+ "direct listener enabled",
+ this, aTrackID));
+ l.mListener->DecreaseDisabled();
+ } else if (oldEnabled && !aEnabled) {
+ STREAM_LOG(LogLevel::Debug, ("SourceMediaStream %p track %d setting "
+ "direct listener disabled",
+ this, aTrackID));
+ l.mListener->IncreaseDisabled();
+ }
+ }
+ }
+ MediaStream::SetTrackEnabledImpl(aTrackID, aEnabled);
+}
+
+void
SourceMediaStream::EndAllTrackAndFinish()
{
MutexAutoLock lock(mMutex);
for (uint32_t i = 0; i < mUpdateTracks.Length(); ++i) {
SourceMediaStream::TrackData* data = &mUpdateTracks[i];
data->mCommands |= TRACK_END;
}
mPendingTracks.Clear();
--- a/dom/media/MediaStreamGraph.h
+++ b/dom/media/MediaStreamGraph.h
@@ -287,22 +287,29 @@ public:
* Other types of streams will fail installation since they are not supported.
*
* Note that this listener and others for the same track will still get
* NotifyQueuedChanges() callbacks from the MSG tread, so you must be careful
* to ignore them if this listener was successfully installed.
*/
class MediaStreamTrackDirectListener : public MediaStreamTrackListener
{
+ friend class SourceMediaStream;
+ friend class TrackUnionStream;
+
public:
/*
* This will be called on any MediaStreamTrackDirectListener added to a
* SourceMediaStream when AppendToTrack() is called for the listener's bound
* track. The MediaSegment will be the RawSegment (unresampled) if available
- * in AppendToTrack(). Note that NotifyQueuedTrackChanges() calls will also
+ * in AppendToTrack().
+ * If the track is enabled at the source but has been disabled in one of the
+ * streams in between the source and where it was originally added, aMedia
+ * will be a disabled version of the one passed to AppendToTrack() as well.
+ * Note that NotifyQueuedTrackChanges() calls will also
* still occur.
*/
virtual void NotifyRealtimeTrackData(MediaStreamGraph* aGraph,
StreamTime aTrackOffset,
const MediaSegment& aMedia) {}
/**
* When a direct listener is processed for installation by the
@@ -327,16 +334,60 @@ public:
STREAM_NOT_SUPPORTED,
SUCCESS
};
virtual void NotifyDirectListenerInstalled(InstallationResult aResult) {}
virtual void NotifyDirectListenerUninstalled() {}
protected:
virtual ~MediaStreamTrackDirectListener() {}
+
+ void MirrorAndDisableSegment(AudioSegment& aFrom, AudioSegment& aTo)
+ {
+ aTo.Clear();
+ aTo.AppendNullData(aFrom.GetDuration());
+ }
+
+ void NotifyRealtimeTrackDataAndApplyTrackDisabling(MediaStreamGraph* aGraph,
+ StreamTime aTrackOffset,
+ MediaSegment& aMedia)
+ {
+ if (mDisabledCount == 0) {
+ NotifyRealtimeTrackData(aGraph, aTrackOffset, aMedia);
+ return;
+ }
+
+ if (!mMedia) {
+ mMedia = aMedia.CreateEmptyClone();
+ }
+ if (aMedia.GetType() == MediaSegment::AUDIO) {
+ MirrorAndDisableSegment(static_cast<AudioSegment&>(aMedia),
+ static_cast<AudioSegment&>(*mMedia));
+ } else {
+ MOZ_CRASH("Unsupported media type");
+ }
+ NotifyRealtimeTrackData(aGraph, aTrackOffset, *mMedia);
+ }
+
+ void IncreaseDisabled()
+ {
+ ++mDisabledCount;
+ }
+ void DecreaseDisabled()
+ {
+ --mDisabledCount;
+ MOZ_ASSERT(mDisabledCount >= 0, "Double decrease");
+ }
+
+ // Matches the number of disabled streams to which this listener is attached.
+ // The number of streams are those between the stream the listener was added
+ // and the SourceMediaStream that is the input of the data.
+ Atomic<int32_t> mDisabledCount;
+
+ nsAutoPtr<MediaSegment> mMedia;
};
/**
* This is a base class for main-thread listener callbacks.
* This callback is invoked on the main thread when the main-thread-visible
* state of a stream has changed.
*
* These methods are called with the media graph monitor held, so
@@ -987,21 +1038,17 @@ public:
void FinishWithLockHeld();
void Finish()
{
MutexAutoLock lock(mMutex);
FinishWithLockHeld();
}
// Overriding allows us to hold the mMutex lock while changing the track enable status
- void
- SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled) override {
- MutexAutoLock lock(mMutex);
- MediaStream::SetTrackEnabledImpl(aTrackID, aEnabled);
- }
+ void SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled) override;
// Overriding allows us to ensure mMutex is locked while changing the track enable status
void
ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment,
MediaSegment* aRawSegment = nullptr) override {
mMutex.AssertCurrentThreadOwns();
MediaStream::ApplyTrackDisabling(aTrackID, aSegment, aRawSegment);
}
--- a/dom/media/MediaStreamTrack.cpp
+++ b/dom/media/MediaStreamTrack.cpp
@@ -166,16 +166,22 @@ MediaStreamTrack::ApplyConstraints(const
}
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(),
--- a/dom/media/MediaStreamTrack.h
+++ b/dom/media/MediaStreamTrack.h
@@ -16,19 +16,21 @@
namespace mozilla {
class DOMMediaStream;
class MediaEnginePhotoCallback;
class MediaInputPort;
class MediaStream;
class MediaStreamGraph;
+class MediaStreamGraphImpl;
class MediaStreamTrackListener;
class MediaStreamTrackDirectListener;
class PeerConnectionImpl;
+class PeerConnectionMedia;
class PeerIdentity;
class ProcessedMediaStream;
class RemoteSourceStreamInfo;
namespace dom {
class AudioStreamTrack;
class VideoStreamTrack;
@@ -199,16 +201,17 @@ class MediaStreamTrack : public DOMEvent
public MediaStreamTrackSource::Sink
{
// DOMMediaStream owns MediaStreamTrack instances, and requires access to
// some internal state, e.g., GetInputStream(), GetOwnedStream().
friend class mozilla::DOMMediaStream;
// PeerConnection and friends need to know our owning DOMStream and track id.
friend class mozilla::PeerConnectionImpl;
+ friend class mozilla::PeerConnectionMedia;
friend class mozilla::RemoteSourceStreamInfo;
public:
/**
* aTrackID is the MediaStreamGraph track ID for the track in the
* MediaStream owned by aStream.
*/
MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID,
@@ -254,16 +257,17 @@ public:
CORSMode GetCORSMode() const { return GetSource().GetCORSMode(); }
/**
* Get this track's PeerIdentity.
*/
const PeerIdentity* GetPeerIdentity() const { return GetSource().GetPeerIdentity(); }
MediaStreamGraph* Graph();
+ MediaStreamGraphImpl* GraphImpl();
MediaStreamTrackSource& GetSource() const
{
MOZ_RELEASE_ASSERT(mSource, "The track source is only removed on destruction");
return *mSource;
}
// Webrtc allows the remote side to name tracks whatever it wants, and we
--- a/dom/media/TrackUnionStream.cpp
+++ b/dom/media/TrackUnionStream.cpp
@@ -222,16 +222,20 @@ TrackUnionStream::TrackUnionStream(DOMMe
for (int32_t i = mPendingDirectTrackListeners.Length() - 1; i >= 0; --i) {
TrackBound<MediaStreamTrackDirectListener>& bound =
mPendingDirectTrackListeners[i];
if (bound.mTrackID != map->mOutputTrackID) {
continue;
}
MediaStream* source = map->mInputPort->GetSource();
+ map->mOwnedDirectListeners.AppendElement(bound.mListener);
+ if (mDisabledTrackIDs.Contains(bound.mTrackID)) {
+ bound.mListener->IncreaseDisabled();
+ }
STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p adding direct listener "
"%p for track %d. Forwarding to input "
"stream %p track %d.",
this, bound.mListener.get(), bound.mTrackID,
source, map->mInputTrackID));
source->AddDirectTrackListenerImpl(bound.mListener.forget(),
map->mInputTrackID);
mPendingDirectTrackListeners.RemoveElementAt(i);
@@ -331,29 +335,58 @@ TrackUnionStream::TrackUnionStream(DOMMe
}
b.mListener->NotifyQueuedChanges(Graph(), outputStart, *segment);
}
outputTrack->GetSegment()->AppendFrom(segment);
}
}
void
+TrackUnionStream::SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled) {
+ for (TrackMapEntry& entry : mTrackMap) {
+ if (entry.mOutputTrackID == aTrackID) {
+ STREAM_LOG(LogLevel::Info, ("TrackUnionStream %p track %d was explicitly %s",
+ this, aTrackID, aEnabled ? "enabled" : "disabled"));
+ for (MediaStreamTrackDirectListener* listener : entry.mOwnedDirectListeners) {
+ bool oldEnabled = !mDisabledTrackIDs.Contains(aTrackID);
+ if (!oldEnabled && aEnabled) {
+ STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p track %d setting "
+ "direct listener enabled",
+ this, aTrackID));
+ listener->DecreaseDisabled();
+ } else if (oldEnabled && !aEnabled) {
+ STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p track %d setting "
+ "direct listener disabled",
+ this, aTrackID));
+ listener->IncreaseDisabled();
+ }
+ }
+ }
+ }
+ MediaStream::SetTrackEnabledImpl(aTrackID, aEnabled);
+}
+
+void
TrackUnionStream::AddDirectTrackListenerImpl(already_AddRefed<MediaStreamTrackDirectListener> aListener,
TrackID aTrackID)
{
RefPtr<MediaStreamTrackDirectListener> listener = aListener;
for (TrackMapEntry& entry : mTrackMap) {
if (entry.mOutputTrackID == aTrackID) {
MediaStream* source = entry.mInputPort->GetSource();
STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p adding direct listener "
"%p for track %d. Forwarding to input "
"stream %p track %d.",
this, listener.get(), aTrackID, source,
entry.mInputTrackID));
+ entry.mOwnedDirectListeners.AppendElement(listener);
+ if (mDisabledTrackIDs.Contains(aTrackID)) {
+ listener->IncreaseDisabled();
+ }
source->AddDirectTrackListenerImpl(listener.forget(),
entry.mInputTrackID);
return;
}
}
TrackBound<MediaStreamTrackDirectListener>* bound =
mPendingDirectTrackListeners.AppendElement();
@@ -365,16 +398,32 @@ void
TrackUnionStream::RemoveDirectTrackListenerImpl(MediaStreamTrackDirectListener* aListener,
TrackID aTrackID)
{
for (TrackMapEntry& entry : mTrackMap) {
// OutputTrackID is unique to this stream so we only need to do this once.
if (entry.mOutputTrackID != aTrackID) {
continue;
}
+ for (size_t i = 0; i < entry.mOwnedDirectListeners.Length(); ++i) {
+ if (entry.mOwnedDirectListeners[i] == aListener) {
+ STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p removing direct "
+ "listener %p for track %d, forwarding "
+ "to input stream %p track %d",
+ this, aListener, aTrackID,
+ entry.mInputPort->GetSource(),
+ entry.mInputTrackID));
+ if (mDisabledTrackIDs.Contains(aTrackID)) {
+ // Reset the listener's state.
+ aListener->DecreaseDisabled();
+ }
+ entry.mOwnedDirectListeners.RemoveElementAt(i);
+ break;
+ }
+ }
// Forward to the input
MediaStream* source = entry.mInputPort->GetSource();
source->RemoveDirectTrackListenerImpl(aListener, entry.mInputTrackID);
return;
}
for (size_t i = 0; i < mPendingDirectTrackListeners.Length(); ++i) {
TrackBound<MediaStreamTrackDirectListener>& bound =
--- a/dom/media/TrackUnionStream.h
+++ b/dom/media/TrackUnionStream.h
@@ -16,16 +16,18 @@ namespace mozilla {
*/
class TrackUnionStream : public ProcessedMediaStream {
public:
explicit TrackUnionStream(DOMMediaStream* aWrapper);
void RemoveInput(MediaInputPort* aPort) override;
void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) override;
+ void SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled) override;
+
protected:
// Only non-ended tracks are allowed to persist in this map.
struct TrackMapEntry {
// mEndOfConsumedInputTicks is the end of the input ticks that we've consumed.
// 0 if we haven't consumed any yet.
StreamTime mEndOfConsumedInputTicks;
// mEndOfLastInputIntervalInInputStream is the timestamp for the end of the
// previous interval which was unblocked for both the input and output
@@ -39,16 +41,20 @@ protected:
// We keep track IDs instead of track pointers because
// tracks can be removed without us being notified (e.g.
// when a finished track is forgotten.) When we need a Track*,
// we call StreamBuffer::FindTrack, which will return null if
// the track has been deleted.
TrackID mInputTrackID;
TrackID mOutputTrackID;
nsAutoPtr<MediaSegment> mSegment;
+ // These are direct track listeners that have been added to this
+ // TrackUnionStream-track and forwarded to the input track. We will update
+ // these when this track's disabled status changes.
+ nsTArray<RefPtr<MediaStreamTrackDirectListener>> mOwnedDirectListeners;
};
// Add the track to this stream, retaining its TrackID if it has never
// been previously used in this stream, allocating a new TrackID otherwise.
uint32_t AddTrack(MediaInputPort* aPort, StreamBuffer::Track* aTrack,
GraphTime aFrom);
void EndTrack(uint32_t aIndex);
void CopyTrackData(StreamBuffer::Track* aInputTrack,
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
@@ -67,17 +67,16 @@ using namespace mozilla::layers;
MOZ_MTLOG_MODULE("mediapipeline")
namespace mozilla {
static char kDTLSExporterLabel[] = "EXTRACTOR-dtls_srtp";
MediaPipeline::~MediaPipeline() {
ASSERT_ON_THREAD(main_thread_);
- MOZ_ASSERT(!stream_); // Check that we have shut down already.
MOZ_MTLOG(ML_INFO, "Destroying MediaPipeline: " << description_);
}
nsresult MediaPipeline::Init() {
ASSERT_ON_THREAD(main_thread_);
if (direction_ == RECEIVE) {
conduit_->SetReceiverTransport(transport_);
@@ -99,23 +98,16 @@ nsresult MediaPipeline::Init_s() {
return AttachTransport_s();
}
// Disconnect us from the transport so that we can cleanly destruct the
// pipeline on the main thread. ShutdownMedia_m() must have already been
// called
-void MediaPipeline::ShutdownTransport_s() {
- ASSERT_ON_THREAD(sts_thread_);
- MOZ_ASSERT(!stream_); // verifies that ShutdownMedia_m() has run
-
- DetachTransport_s();
-}
-
void
MediaPipeline::DetachTransport_s()
{
ASSERT_ON_THREAD(sts_thread_);
disconnect_all();
transport_->Detach();
rtp_.Detach();
@@ -663,48 +655,44 @@ void MediaPipelineTransmit::AttachToTrac
description_ = pc_ + "| ";
description_ += conduit_->type() == MediaSessionConduit::AUDIO ?
"Transmit audio[" : "Transmit video[";
description_ += track_id;
description_ += "]";
// TODO(ekr@rtfm.com): Check for errors
- MOZ_MTLOG(ML_DEBUG, "Attaching pipeline to stream "
- << static_cast<void *>(stream_) << " conduit type=" <<
+ MOZ_MTLOG(ML_DEBUG, "Attaching pipeline to track "
+ << static_cast<void *>(domtrack_) << " conduit type=" <<
(conduit_->type() == MediaSessionConduit::AUDIO ?"audio":"video"));
- stream_->AddListener(listener_);
-
- // Is this a gUM mediastream? If so, also register the Listener directly with
- // the SourceMediaStream that's attached to the TrackUnion so we can get direct
- // unqueued (and not resampled) data
- listener_->direct_connect_ = domstream_->AddDirectListener(listener_);
+ // Register the Listener directly with the source if we can.
+ // We also register it as a non-direct listener so we fall back to that
+ // if installing the direct listener fails. As a direct listener we get access
+ // to direct unqueued (and not resampled) data.
+ domtrack_->AddDirectListener(listener_);
+ domtrack_->AddListener(listener_);
#ifndef MOZILLA_INTERNAL_API
// this enables the unit tests that can't fiddle with principals and the like
listener_->SetEnabled(true);
#endif
}
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
void MediaPipelineTransmit::UpdateSinkIdentity_m(nsIPrincipal* principal,
const PeerIdentity* sinkIdentity) {
ASSERT_ON_THREAD(main_thread_);
- MediaStreamTrack* track =
- domstream_->GetOwnedTrackById(NS_ConvertUTF8toUTF16(trackid().c_str()));
- MOZ_RELEASE_ASSERT(track);
-
- bool enableTrack = principal->Subsumes(track->GetPrincipal());
+ bool enableTrack = principal->Subsumes(domtrack_->GetPrincipal());
if (!enableTrack) {
// first try didn't work, but there's a chance that this is still available
// if our track is bound to a peerIdentity, and the peer connection (our
// sink) is bound to the same identity, then we can enable the track.
- const PeerIdentity* trackIdentity = track->GetPeerIdentity();
+ const PeerIdentity* trackIdentity = domtrack_->GetPeerIdentity();
if (sinkIdentity && trackIdentity) {
enableTrack = (*sinkIdentity == *trackIdentity);
}
}
listener_->SetEnabled(enableTrack);
}
#endif
@@ -717,31 +705,34 @@ nsresult MediaPipelineTransmit::Transpor
// Should not be set for a transmitter
if (&info == &rtp_) {
listener_->SetActive(true);
}
return NS_OK;
}
-nsresult MediaPipelineTransmit::ReplaceTrack(DOMMediaStream *domstream,
- const std::string& track_id) {
+nsresult MediaPipelineTransmit::ReplaceTrack(MediaStreamTrack& domtrack) {
// MainThread, checked in calls we make
- MOZ_MTLOG(ML_DEBUG, "Reattaching pipeline " << description_ << " to stream "
- << static_cast<void *>(domstream->GetOwnedStream())
+#if !defined(MOZILLA_EXTERNAL_LINKAGE)
+ nsString nsTrackId;
+ domtrack.GetId(nsTrackId);
+ std::string track_id(NS_ConvertUTF16toUTF8(nsTrackId).get());
+#else
+ std::string track_id = domtrack.GetId();
+#endif
+ MOZ_MTLOG(ML_DEBUG, "Reattaching pipeline " << description_ << " to track "
+ << static_cast<void *>(&domtrack)
<< " track " << track_id << " conduit type=" <<
(conduit_->type() == MediaSessionConduit::AUDIO ?"audio":"video"));
- if (domstream_) { // may be excessive paranoia
- DetachMediaStream();
- }
- domstream_ = domstream; // Detach clears it
- stream_ = domstream->GetOwnedStream();
+ DetachMedia();
+ domtrack_ = &domtrack; // Detach clears it
// Unsets the track id after RemoveListener() takes effect.
- listener_->UnsetTrackId(stream_->GraphImpl());
+ listener_->UnsetTrackId(domtrack_->GraphImpl());
track_id_ = track_id;
AttachToTrack(track_id);
return NS_OK;
}
void MediaPipeline::DisconnectTransport_s(TransportInfo &info) {
MOZ_ASSERT(info.transport_);
ASSERT_ON_THREAD(sts_thread_);
@@ -893,71 +884,72 @@ UnsetTrackId(MediaStreamGraphImpl* graph
};
graph->AppendMessage(MakeUnique<Message>(this));
#else
UnsetTrackIdImpl();
#endif
}
// Called if we're attached with AddDirectListener()
void MediaPipelineTransmit::PipelineListener::
-NotifyRealtimeData(MediaStreamGraph* graph, TrackID tid,
- StreamTime offset,
- uint32_t events,
- const MediaSegment& media) {
- MOZ_MTLOG(ML_DEBUG, "MediaPipeline::NotifyRealtimeData()");
+NotifyRealtimeTrackData(MediaStreamGraph* graph,
+ StreamTime offset,
+ const MediaSegment& media) {
+ MOZ_MTLOG(ML_DEBUG, "MediaPipeline::NotifyRealtimeTrackData() listener=" <<
+ this << ", offset=" << offset <<
+ ", duration=" << media.GetDuration());
- NewData(graph, tid, offset, events, media);
+ NewData(graph, offset, media);
}
void MediaPipelineTransmit::PipelineListener::
-NotifyQueuedTrackChanges(MediaStreamGraph* graph, TrackID tid,
- StreamTime offset,
- uint32_t events,
- const MediaSegment& queued_media,
- MediaStream* aInputStream,
- TrackID aInputTrackID) {
- MOZ_MTLOG(ML_DEBUG, "MediaPipeline::NotifyQueuedTrackChanges()");
+NotifyQueuedChanges(MediaStreamGraph* graph,
+ StreamTime offset,
+ const MediaSegment& queued_media) {
+ MOZ_MTLOG(ML_DEBUG, "MediaPipeline::NotifyQueuedChanges()");
// ignore non-direct data if we're also getting direct data
if (!direct_connect_) {
- NewData(graph, tid, offset, events, queued_media);
+ NewData(graph, offset, queued_media);
}
}
+void MediaPipelineTransmit::PipelineListener::
+NotifyDirectListenerInstalled(InstallationResult aResult) {
+ MOZ_MTLOG(ML_INFO, "MediaPipeline::NotifyDirectListenerInstalled() listener= " <<
+ this << ", result=" << static_cast<int32_t>(aResult));
+
+ direct_connect_ = InstallationResult::SUCCESS == aResult;
+}
+
+void MediaPipelineTransmit::PipelineListener::
+NotifyDirectListenerUninstalled() {
+ MOZ_MTLOG(ML_INFO, "MediaPipeline::NotifyDirectListenerUninstalled() listener=" << this);
+
+ direct_connect_ = false;
+}
+
// I420 buffer size macros
#define YSIZE(x,y) ((x)*(y))
#define CRSIZE(x,y) ((((x)+1) >> 1) * (((y)+1) >> 1))
#define I420SIZE(x,y) (YSIZE((x),(y)) + 2 * CRSIZE((x),(y)))
-// XXX NOTE: this code will have to change when we get support for multiple tracks of type
-// in a MediaStream and especially in a PeerConnection stream. bug 1056650
-// It should be matching on the "correct" track for the pipeline, not just "any video track".
-
void MediaPipelineTransmit::PipelineListener::
-NewData(MediaStreamGraph* graph, TrackID tid,
+NewData(MediaStreamGraph* graph,
StreamTime offset,
- uint32_t events,
const MediaSegment& media) {
if (!active_) {
MOZ_MTLOG(ML_DEBUG, "Discarding packets because transport not ready");
return;
}
if (conduit_->type() !=
(media.GetType() == MediaSegment::AUDIO ? MediaSessionConduit::AUDIO :
MediaSessionConduit::VIDEO)) {
- // Ignore data of wrong kind in case we have a muxed stream
- return;
- }
-
- if (track_id_ == TRACK_INVALID) {
- // Don't lock during normal media flow except on first sample
- MutexAutoLock lock(mMutex);
- track_id_ = track_id_external_ = tid;
- } else if (tid != track_id_) {
+ MOZ_ASSERT(false, "The media type should always be correct since the "
+ "listener is locked to a specific track");
return;
}
// TODO(ekr@rtfm.com): For now assume that we have only one
// track type and it's destined for us
// See bug 784517
if (media.GetType() == MediaSegment::AUDIO) {
AudioSegment* audio = const_cast<AudioSegment *>(
@@ -1502,17 +1494,17 @@ nsresult MediaPipelineReceiveVideo::Init
description_ = pc_ + "| Receive video[";
description_ += track_id_;
description_ += "]";
#if defined(MOZILLA_INTERNAL_API)
listener_->AddSelf(new VideoSegment());
#endif
- // Always happens before we can DetachMediaStream()
+ // Always happens before we can DetachMedia()
static_cast<VideoSessionConduit *>(conduit_.get())->
AttachRenderer(renderer_);
return MediaPipelineReceive::Init();
}
MediaPipelineReceiveVideo::PipelineListener::PipelineListener(
SourceMediaStream* source, TrackID track_id, bool queue_track)
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
@@ -9,16 +9,17 @@
#define mediapipeline_h__
#include "sigslot.h"
#ifdef USE_FAKE_MEDIA_STREAMS
#include "FakeMediaStreams.h"
#else
#include "DOMMediaStream.h"
+#include "MediaStreamTrack.h"
#include "MediaStreamGraph.h"
#include "VideoUtils.h"
#endif
#include "MediaConduitInterface.h"
#include "MediaPipelineFilter.h"
#include "AudioSegment.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/Atomics.h"
@@ -72,25 +73,23 @@ class PeerIdentity;
class MediaPipeline : public sigslot::has_slots<> {
public:
enum Direction { TRANSMIT, RECEIVE };
enum State { MP_CONNECTING, MP_OPEN, MP_CLOSED };
MediaPipeline(const std::string& pc,
Direction direction,
nsCOMPtr<nsIEventTarget> main_thread,
nsCOMPtr<nsIEventTarget> sts_thread,
- MediaStream *stream,
const std::string& track_id,
int level,
RefPtr<MediaSessionConduit> conduit,
RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> rtcp_transport,
nsAutoPtr<MediaPipelineFilter> filter)
: direction_(direction),
- stream_(stream),
track_id_(track_id),
level_(level),
conduit_(conduit),
rtp_(rtp_transport, rtcp_transport ? RTP : MUX),
rtcp_(rtcp_transport ? rtcp_transport : rtp_transport,
rtcp_transport ? RTCP : MUX),
main_thread_(main_thread),
sts_thread_(sts_thread),
@@ -109,31 +108,29 @@ class MediaPipeline : public sigslot::ha
// both rtp and rtcp.
MOZ_ASSERT(rtp_transport != rtcp_transport);
// PipelineTransport() will access this->sts_thread_; moved here for safety
transport_ = new PipelineTransport(this);
}
// Must be called on the STS thread. Must be called after ShutdownMedia_m().
- void ShutdownTransport_s();
+ void DetachTransport_s();
// Must be called on the main thread.
- void ShutdownMedia_m() {
+ void ShutdownMedia_m()
+ {
ASSERT_ON_THREAD(main_thread_);
if (direction_ == RECEIVE) {
conduit_->StopReceiving();
} else {
conduit_->StopTransmitting();
}
-
- if (stream_) {
- DetachMediaStream();
- }
+ DetachMedia();
}
virtual nsresult Init();
void UpdateTransport_m(int level,
RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> rtcp_transport,
nsAutoPtr<MediaPipelineFilter> filter);
@@ -173,19 +170,18 @@ class MediaPipeline : public sigslot::ha
RTP,
RTCP,
MUX,
MAX_RTP_TYPE
} RtpType;
protected:
virtual ~MediaPipeline();
- virtual void DetachMediaStream() {}
+ virtual void DetachMedia() {}
nsresult AttachTransport_s();
- void DetachTransport_s();
// Separate class to allow ref counting
class PipelineTransport : public TransportInterface {
public:
// Implement the TransportInterface functions
explicit PipelineTransport(MediaPipeline *pipeline)
: pipeline_(pipeline),
sts_thread_(pipeline->sts_thread_) {}
@@ -252,22 +248,19 @@ class MediaPipeline : public sigslot::ha
void RtpPacketReceived(TransportLayer *layer, const unsigned char *data,
size_t len);
void RtcpPacketReceived(TransportLayer *layer, const unsigned char *data,
size_t len);
void PacketReceived(TransportLayer *layer, const unsigned char *data,
size_t len);
Direction direction_;
- RefPtr<MediaStream> stream_; // A pointer to the stream we are servicing.
+ std::string track_id_; // The track on the stream.
// Written on the main thread.
// Used on STS and MediaStreamGraph threads.
- // May be changed by rtpSender.replaceTrack()
- std::string track_id_; // The track on the stream.
- // Written and used as with the stream_;
// Not used outside initialization in MediaPipelineTransmit
// The m-line index (starting at 0, to match convention) Atomic because
// this value is updated from STS, but read on main, and we don't want to
// bother with dispatches just to get an int occasionally.
Atomic<int> level_;
RefPtr<MediaSessionConduit> conduit_; // Our conduit. Written on the main
// thread. Read on STS thread.
@@ -381,74 +374,67 @@ private:
// A specialization of pipeline for reading from an input device
// and transmitting to the network.
class MediaPipelineTransmit : public MediaPipeline {
public:
// Set rtcp_transport to nullptr to use rtcp-mux
MediaPipelineTransmit(const std::string& pc,
nsCOMPtr<nsIEventTarget> main_thread,
nsCOMPtr<nsIEventTarget> sts_thread,
- DOMMediaStream *domstream,
+ dom::MediaStreamTrack* domtrack,
const std::string& track_id,
int level,
- bool is_video,
RefPtr<MediaSessionConduit> conduit,
RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> rtcp_transport,
nsAutoPtr<MediaPipelineFilter> filter) :
- MediaPipeline(pc, TRANSMIT, main_thread, sts_thread,
- domstream->GetOwnedStream(), track_id, level,
+ MediaPipeline(pc, TRANSMIT, main_thread, sts_thread, track_id, level,
conduit, rtp_transport, rtcp_transport, filter),
listener_(new PipelineListener(conduit)),
- domstream_(domstream),
- is_video_(is_video)
+ domtrack_(domtrack)
{}
// Initialize (stuff here may fail)
virtual nsresult Init() override;
virtual void AttachToTrack(const std::string& track_id);
- // Index used to refer to this before we know the TrackID
- // Note: unlike MediaPipeline::trackid(), this is threadsafe
- // Not set until first media is received
- virtual TrackID trackid_locked() const { return listener_->trackid(); }
// written and used from MainThread
- virtual bool IsVideo() const override { return is_video_; }
+ virtual bool IsVideo() const override { return !!domtrack_->AsVideoStreamTrack(); }
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
// when the principal of the PeerConnection changes, it calls through to here
// so that we can determine whether to enable stream transmission
virtual void UpdateSinkIdentity_m(nsIPrincipal* principal,
const PeerIdentity* sinkIdentity);
#endif
// Called on the main thread.
- virtual void DetachMediaStream() override {
+ virtual void DetachMedia() override {
ASSERT_ON_THREAD(main_thread_);
- domstream_->RemoveDirectListener(listener_);
- domstream_ = nullptr;
- stream_->RemoveListener(listener_);
+ if (domtrack_) {
+ domtrack_->RemoveDirectListener(listener_);
+ domtrack_->RemoveListener(listener_);
+ domtrack_ = nullptr;
+ }
// Let the listener be destroyed with the pipeline (or later).
- stream_ = nullptr;
}
// Override MediaPipeline::TransportReady.
virtual nsresult TransportReady_s(TransportInfo &info) override;
// Replace a track with a different one
// In non-compliance with the likely final spec, allow the new
// track to be part of a different stream (since we don't support
// multiple tracks of a type in a stream yet). bug 1056650
- virtual nsresult ReplaceTrack(DOMMediaStream *domstream,
- const std::string& track_id);
+ virtual nsresult ReplaceTrack(dom::MediaStreamTrack& domtrack);
// Separate class to allow ref counting
- class PipelineListener : public MediaStreamDirectListener {
+ class PipelineListener : public MediaStreamTrackDirectListener {
friend class MediaPipelineTransmit;
public:
explicit PipelineListener(const RefPtr<MediaSessionConduit>& conduit)
: conduit_(conduit),
track_id_(TRACK_INVALID),
mMutex("MediaPipelineTransmit::PipelineListener"),
track_id_external_(TRACK_INVALID),
active_(false),
@@ -475,45 +461,37 @@ public:
// Dispatches setting the internal TrackID to TRACK_INVALID to the media
// graph thread to keep it in sync with other MediaStreamGraph operations
// like RemoveListener() and AddListener(). The TrackID will be updated on
// the next NewData() callback.
void UnsetTrackId(MediaStreamGraphImpl* graph);
void SetActive(bool active) { active_ = active; }
void SetEnabled(bool enabled) { enabled_ = enabled; }
- TrackID trackid() {
- MutexAutoLock lock(mMutex);
- return track_id_external_;
- }
+
+ // Implement MediaStreamTrackListener
+ void NotifyQueuedChanges(MediaStreamGraph* aGraph,
+ StreamTime aTrackOffset,
+ const MediaSegment& aQueuedMedia) override;
- // Implement MediaStreamListener
- virtual void NotifyQueuedTrackChanges(MediaStreamGraph* graph, TrackID tid,
- StreamTime offset,
- uint32_t events,
- const MediaSegment& queued_media,
- MediaStream* input_stream,
- TrackID input_tid) override;
- virtual void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime) override {}
-
- // Implement MediaStreamDirectListener
- virtual void NotifyRealtimeData(MediaStreamGraph* graph, TrackID tid,
- StreamTime offset,
- uint32_t events,
- const MediaSegment& media) override;
+ // Implement MediaStreamTrackDirectListener
+ void NotifyRealtimeTrackData(MediaStreamGraph* aGraph,
+ StreamTime aTrackOffset,
+ const MediaSegment& aMedia) override;
+ void NotifyDirectListenerInstalled(InstallationResult aResult) override;
+ void NotifyDirectListenerUninstalled() override;
private:
void UnsetTrackIdImpl() {
MutexAutoLock lock(mMutex);
track_id_ = track_id_external_ = TRACK_INVALID;
}
- void NewData(MediaStreamGraph* graph, TrackID tid,
+ void NewData(MediaStreamGraph* graph,
StreamTime offset,
- uint32_t events,
const MediaSegment& media);
virtual void ProcessAudioChunk(AudioSessionConduit *conduit,
TrackRate rate, AudioChunk& chunk);
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
virtual void ProcessVideoChunk(VideoSessionConduit *conduit,
VideoChunk& chunk);
#endif
@@ -527,94 +505,102 @@ public:
TrackID track_id_external_; // this is queried from other threads
// active is true if there is a transport to send on
mozilla::Atomic<bool> active_;
// enabled is true if the media access control permits sending
// actual content; when false you get black/silence
mozilla::Atomic<bool> enabled_;
+ // Written and read on the MediaStreamGraph thread
bool direct_connect_;
nsAutoPtr<AudioPacketizer<int16_t, int16_t>> packetizer_;
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
int32_t last_img_; // serial number of last Image
#endif // MOZILLA_INTERNAL_API
};
private:
RefPtr<PipelineListener> listener_;
- DOMMediaStream *domstream_;
- bool is_video_;
+ dom::MediaStreamTrack* domtrack_;
};
// A specialization of pipeline for reading from the network and
// rendering video.
class MediaPipelineReceive : public MediaPipeline {
public:
// Set rtcp_transport to nullptr to use rtcp-mux
MediaPipelineReceive(const std::string& pc,
nsCOMPtr<nsIEventTarget> main_thread,
nsCOMPtr<nsIEventTarget> sts_thread,
- MediaStream *stream,
+ SourceMediaStream *stream,
const std::string& track_id,
int level,
RefPtr<MediaSessionConduit> conduit,
RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> rtcp_transport,
nsAutoPtr<MediaPipelineFilter> filter) :
MediaPipeline(pc, RECEIVE, main_thread, sts_thread,
- stream, track_id, level, conduit, rtp_transport,
+ track_id, level, conduit, rtp_transport,
rtcp_transport, filter),
+ stream_(stream),
segments_added_(0) {
+ MOZ_ASSERT(stream_);
}
int segments_added() const { return segments_added_; }
protected:
+ ~MediaPipelineReceive() {
+ MOZ_ASSERT(!stream_); // Check that we have shut down already.
+ }
+
+ RefPtr<SourceMediaStream> stream_;
int segments_added_;
private:
};
// A specialization of pipeline for reading from the network and
// rendering audio.
class MediaPipelineReceiveAudio : public MediaPipelineReceive {
public:
MediaPipelineReceiveAudio(const std::string& pc,
nsCOMPtr<nsIEventTarget> main_thread,
nsCOMPtr<nsIEventTarget> sts_thread,
- MediaStream *stream,
+ SourceMediaStream* stream,
// This comes from an msid attribute. Everywhere
// but MediaStreamGraph uses this.
const std::string& media_stream_track_id,
// This is an integer identifier that is only
// unique within a single DOMMediaStream, which is
// used by MediaStreamGraph
TrackID numeric_track_id,
int level,
RefPtr<AudioSessionConduit> conduit,
RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> rtcp_transport,
nsAutoPtr<MediaPipelineFilter> filter,
bool queue_track) :
MediaPipelineReceive(pc, main_thread, sts_thread,
stream, media_stream_track_id, level, conduit,
rtp_transport, rtcp_transport, filter),
- listener_(new PipelineListener(stream->AsSourceStream(),
- numeric_track_id, conduit, queue_track)) {
+ listener_(new PipelineListener(stream, numeric_track_id, conduit,
+ queue_track)) {
}
- virtual void DetachMediaStream() override {
+ virtual void DetachMedia() override {
ASSERT_ON_THREAD(main_thread_);
- listener_->EndTrack();
- stream_->RemoveListener(listener_);
- stream_ = nullptr;
+ if (stream_) {
+ stream_->RemoveListener(listener_);
+ stream_ = nullptr;
+ }
}
virtual nsresult Init() override;
virtual bool IsVideo() const override { return false; }
private:
// Separate class to allow ref counting
class PipelineListener : public GenericReceiveListener {
@@ -653,17 +639,17 @@ class MediaPipelineReceiveAudio : public
// A specialization of pipeline for reading from the network and
// rendering video.
class MediaPipelineReceiveVideo : public MediaPipelineReceive {
public:
MediaPipelineReceiveVideo(const std::string& pc,
nsCOMPtr<nsIEventTarget> main_thread,
nsCOMPtr<nsIEventTarget> sts_thread,
- MediaStream *stream,
+ SourceMediaStream *stream,
// This comes from an msid attribute. Everywhere
// but MediaStreamGraph uses this.
const std::string& media_stream_track_id,
// This is an integer identifier that is only
// unique within a single DOMMediaStream, which is
// used by MediaStreamGraph
TrackID numeric_track_id,
int level,
@@ -671,32 +657,33 @@ class MediaPipelineReceiveVideo : public
RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> rtcp_transport,
nsAutoPtr<MediaPipelineFilter> filter,
bool queue_track) :
MediaPipelineReceive(pc, main_thread, sts_thread,
stream, media_stream_track_id, level, conduit,
rtp_transport, rtcp_transport, filter),
renderer_(new PipelineRenderer(this)),
- listener_(new PipelineListener(stream->AsSourceStream(),
- numeric_track_id, queue_track)) {
+ listener_(new PipelineListener(stream, numeric_track_id, queue_track)) {
}
// Called on the main thread.
- virtual void DetachMediaStream() override {
+ virtual void DetachMedia() override {
ASSERT_ON_THREAD(main_thread_);
listener_->EndTrack();
// stop generating video and thus stop invoking the PipelineRenderer
// and PipelineListener - the renderer has a raw ptr to the Pipeline to
// avoid cycles, and the render callbacks are invoked from a different
// thread so simple null-checks would cause TSAN bugs without locks.
static_cast<VideoSessionConduit*>(conduit_.get())->DetachRenderer();
- stream_->RemoveListener(listener_);
- stream_ = nullptr;
+ if (stream_) {
+ stream_->RemoveListener(listener_);
+ stream_ = nullptr;
+ }
}
virtual nsresult Init() override;
virtual bool IsVideo() const override { return true; }
private:
class PipelineRenderer : public VideoRenderer {
public:
--- a/media/webrtc/signaling/src/peerconnection/MediaPipelineFactory.cpp
+++ b/media/webrtc/signaling/src/peerconnection/MediaPipelineFactory.cpp
@@ -433,21 +433,25 @@ MediaPipelineFactory::CreateOrUpdateMedi
RefPtr<MediaPipeline> pipeline =
stream->GetPipelineByTrackId_m(aTrack.GetTrackId());
if (pipeline && pipeline->level() != static_cast<int>(level)) {
MOZ_MTLOG(ML_WARNING, "Track " << aTrack.GetTrackId() <<
" has moved from level " << pipeline->level() <<
" to level " << level <<
". This requires re-creating the MediaPipeline.");
+ RefPtr<dom::MediaStreamTrack> domTrack =
+ stream->GetTrackById(aTrack.GetTrackId());
+ MOZ_ASSERT(domTrack, "MediaPipeline existed for a track, but no MediaStreamTrack");
+
// Since we do not support changing the conduit on a pre-existing
// MediaPipeline
pipeline = nullptr;
stream->RemoveTrack(aTrack.GetTrackId());
- stream->AddTrack(aTrack.GetTrackId());
+ stream->AddTrack(aTrack.GetTrackId(), domTrack);
}
if (pipeline) {
pipeline->UpdateTransport_m(level, rtpFlow, rtcpFlow, filter);
return NS_OK;
}
MOZ_MTLOG(ML_DEBUG,
@@ -497,31 +501,31 @@ MediaPipelineFactory::CreateMediaPipelin
MOZ_MTLOG(ML_DEBUG, __FUNCTION__ << ": Creating pipeline for "
<< numericTrackId << " -> " << aTrack.GetTrackId());
if (aTrack.GetMediaType() == SdpMediaSection::kAudio) {
pipeline = new MediaPipelineReceiveAudio(
mPC->GetHandle(),
mPC->GetMainThread().get(),
mPC->GetSTSThread(),
- stream->GetMediaStream()->GetInputStream(),
+ stream->GetMediaStream()->GetInputStream()->AsSourceStream(),
aTrack.GetTrackId(),
numericTrackId,
aLevel,
static_cast<AudioSessionConduit*>(aConduit.get()), // Ugly downcast.
aRtpFlow,
aRtcpFlow,
aFilter,
queue_track);
} else if (aTrack.GetMediaType() == SdpMediaSection::kVideo) {
pipeline = new MediaPipelineReceiveVideo(
mPC->GetHandle(),
mPC->GetMainThread().get(),
mPC->GetSTSThread(),
- stream->GetMediaStream()->GetInputStream(),
+ stream->GetMediaStream()->GetInputStream()->AsSourceStream(),
aTrack.GetTrackId(),
numericTrackId,
aLevel,
static_cast<VideoSessionConduit*>(aConduit.get()), // Ugly downcast.
aRtpFlow,
aRtcpFlow,
aFilter,
queue_track);
@@ -561,25 +565,28 @@ MediaPipelineFactory::CreateMediaPipelin
const RefPtr<MediaSessionConduit>& aConduit)
{
nsresult rv;
// This is checked earlier
RefPtr<LocalSourceStreamInfo> stream =
mPCMedia->GetLocalStreamById(aTrack.GetStreamId());
+ dom::MediaStreamTrack* track =
+ stream->GetTrackById(aTrack.GetTrackId());
+ MOZ_ASSERT(track);
+
// Now we have all the pieces, create the pipeline
RefPtr<MediaPipelineTransmit> pipeline = new MediaPipelineTransmit(
mPC->GetHandle(),
mPC->GetMainThread().get(),
mPC->GetSTSThread(),
- stream->GetMediaStream(),
+ track,
aTrack.GetTrackId(),
aLevel,
- aTrack.GetMediaType() == SdpMediaSection::kVideo,
aConduit,
aRtpFlow,
aRtcpFlow,
aFilter);
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
// implement checking for peerIdentity (where failure == black/silence)
nsIDocument* doc = mPC->GetWindow()->GetExtantDoc();
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -1801,36 +1801,37 @@ PeerConnectionImpl::CreateNewRemoteTrack
if (track->GetMediaType() == SdpMediaSection::kAudio) {
++numNewAudioTracks;
} else if (track->GetMediaType() == SdpMediaSection::kVideo) {
++numNewVideoTracks;
} else {
MOZ_ASSERT(false);
continue;
}
- info->AddTrack(track->GetTrackId());
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
RefPtr<RemoteTrackSource> source = new RemoteTrackSource(principal);
- DebugOnly<bool> sourceSet =
- info->SetTrackSource(track->GetTrackId(), source);
- NS_ASSERTION(sourceSet, "TrackSource was added in the wrong order. "
- "Did someone add a track from elsewhere?");
- TrackID trackID = info->GetNumericTrackId(track->GetTrackId());
+#else
+ RefPtr<MediaStreamTrackSource> source = new MediaStreamTrackSource();
+#endif
+ TrackID trackID = info->GetNextAvailableNumericTrackId();
+ RefPtr<MediaStreamTrack> domTrack;
if (track->GetMediaType() == SdpMediaSection::kAudio) {
- info->GetMediaStream()->CreateDOMTrack(trackID,
- MediaSegment::AUDIO,
- nsString(),
- source);
+ domTrack =
+ info->GetMediaStream()->CreateDOMTrack(trackID,
+ MediaSegment::AUDIO,
+ nsString(),
+ source);
} else {
- info->GetMediaStream()->CreateDOMTrack(trackID,
- MediaSegment::VIDEO,
- nsString(),
- source);
+ domTrack =
+ info->GetMediaStream()->CreateDOMTrack(trackID,
+ MediaSegment::VIDEO,
+ nsString(),
+ source);
}
-#endif
+ info->AddTrack(track->GetTrackId(), domTrack);
CSFLogDebug(logTag, "Added remote track %s/%s",
info->GetId().c_str(), track->GetTrackId().c_str());
} else {
++numPreexistingTrackIds;
}
}
// Now that the streams are all set up, notify about track availability.
@@ -2248,17 +2249,17 @@ PeerConnectionImpl::AddTrack(MediaStream
if (!aMediaStream.HasTrack(aTrack)) {
CSFLogError(logTag, "%s: Track is not in stream", __FUNCTION__);
return NS_ERROR_FAILURE;
}
uint32_t num = mMedia->LocalStreamsLength();
std::string streamId = PeerConnectionImpl::GetStreamId(aMediaStream);
std::string trackId = PeerConnectionImpl::GetTrackId(aTrack);
- nsresult res = mMedia->AddTrack(&aMediaStream, streamId, trackId);
+ nsresult res = mMedia->AddTrack(aMediaStream, streamId, aTrack, trackId);
if (NS_FAILED(res)) {
return res;
}
CSFLogDebug(logTag, "Added track (%s) to stream %s",
trackId.c_str(), streamId.c_str());
if (num != mMedia->LocalStreamsLength()) {
@@ -2403,17 +2404,17 @@ PeerConnectionImpl::ReplaceTrack(MediaSt
CSFLogError(logTag, "Error firing replaceTrack error callback");
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
rv = media()->ReplaceTrack(origStreamId,
origTrackId,
- aWithTrack.mOwningStream,
+ aWithTrack,
newStreamId,
newTrackId);
if (NS_FAILED(rv)) {
CSFLogError(logTag, "Unexpected error in ReplaceTrack: %d",
static_cast<int>(rv));
pco->OnReplaceTrackError(kInvalidMediastreamTrack,
ObString("Failed to replace track"),
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -18,16 +18,23 @@
#include "AudioConduit.h"
#include "VideoConduit.h"
#include "runnable_utils.h"
#include "transportlayerice.h"
#include "transportlayerdtls.h"
#include "signaling/src/jsep/JsepSession.h"
#include "signaling/src/jsep/JsepTransport.h"
+#ifdef USE_FAKE_STREAMS
+#include "DOMMediaStream.h"
+#include "FakeMediaStreams.h"
+#else
+#include "MediaSegment.h"
+#endif
+
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsIURI.h"
#include "nsIScriptSecurityManager.h"
#include "nsICancelable.h"
#include "nsIDocument.h"
#include "nsILoadInfo.h"
#include "nsIContentPolicy.h"
@@ -50,53 +57,54 @@
namespace mozilla {
using namespace dom;
static const char* logTag = "PeerConnectionMedia";
nsresult
PeerConnectionMedia::ReplaceTrack(const std::string& aOldStreamId,
const std::string& aOldTrackId,
- DOMMediaStream* aNewStream,
+ MediaStreamTrack& aNewTrack,
const std::string& aNewStreamId,
const std::string& aNewTrackId)
{
RefPtr<LocalSourceStreamInfo> oldInfo(GetLocalStreamById(aOldStreamId));
if (!oldInfo) {
CSFLogError(logTag, "Failed to find stream id %s", aOldStreamId.c_str());
return NS_ERROR_NOT_AVAILABLE;
}
- nsresult rv = AddTrack(aNewStream, aNewStreamId, aNewTrackId);
+ nsresult rv = AddTrack(*aNewTrack.mOwningStream, aNewStreamId,
+ aNewTrack, aNewTrackId);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<LocalSourceStreamInfo> newInfo(GetLocalStreamById(aNewStreamId));
if (!newInfo) {
CSFLogError(logTag, "Failed to add track id %s", aNewTrackId.c_str());
MOZ_ASSERT(false);
return NS_ERROR_FAILURE;
}
- rv = newInfo->TakePipelineFrom(oldInfo, aOldTrackId, aNewTrackId);
+ rv = newInfo->TakePipelineFrom(oldInfo, aOldTrackId, aNewTrack, aNewTrackId);
NS_ENSURE_SUCCESS(rv, rv);
return RemoveLocalTrack(aOldStreamId, aOldTrackId);
}
static void
PipelineReleaseRef_m(RefPtr<MediaPipeline> pipeline)
{}
static void
PipelineDetachTransport_s(RefPtr<MediaPipeline> pipeline,
nsCOMPtr<nsIThread> mainThread)
{
- pipeline->ShutdownTransport_s();
+ pipeline->DetachTransport_s();
mainThread->Dispatch(
// Make sure we let go of our reference before dispatching
// If the dispatch fails, well, we're hosed anyway.
WrapRunnableNM(PipelineReleaseRef_m, pipeline.forget()),
NS_DISPATCH_NORMAL);
}
void
@@ -116,17 +124,17 @@ SourceStreamInfo::RemoveTrack(const std:
}
void SourceStreamInfo::DetachTransport_s()
{
ASSERT_ON_THREAD(mParent->GetSTSThread());
// walk through all the MediaPipelines and call the shutdown
// transport functions. Must be on the STS thread.
for (auto it = mPipelines.begin(); it != mPipelines.end(); ++it) {
- it->second->ShutdownTransport_s();
+ it->second->DetachTransport_s();
}
}
void SourceStreamInfo::DetachMedia_m()
{
ASSERT_ON_THREAD(mParent->GetMainThread());
// walk through all the MediaPipelines and call the shutdown
@@ -673,38 +681,34 @@ PeerConnectionMedia::EnsureIceGathering_
// If there are no streams, we're probably in a situation where we've rolled
// back while still waiting for our proxy configuration to come back. Make
// sure content knows that the rollback has stuck wrt gathering.
IceGatheringStateChange_s(mIceCtx.get(), NrIceCtx::ICE_CTX_GATHER_COMPLETE);
}
nsresult
-PeerConnectionMedia::AddTrack(DOMMediaStream* aMediaStream,
+PeerConnectionMedia::AddTrack(DOMMediaStream& aMediaStream,
const std::string& streamId,
+ MediaStreamTrack& aTrack,
const std::string& trackId)
{
ASSERT_ON_THREAD(mMainThread);
- if (!aMediaStream) {
- CSFLogError(logTag, "%s - aMediaStream is NULL", __FUNCTION__);
- return NS_ERROR_FAILURE;
- }
-
- CSFLogDebug(logTag, "%s: MediaStream: %p", __FUNCTION__, aMediaStream);
+ CSFLogDebug(logTag, "%s: MediaStream: %p", __FUNCTION__, &aMediaStream);
RefPtr<LocalSourceStreamInfo> localSourceStream =
GetLocalStreamById(streamId);
if (!localSourceStream) {
- localSourceStream = new LocalSourceStreamInfo(aMediaStream, this, streamId);
+ localSourceStream = new LocalSourceStreamInfo(&aMediaStream, this, streamId);
mLocalSourceStreams.AppendElement(localSourceStream);
}
- localSourceStream->AddTrack(trackId);
+ localSourceStream->AddTrack(trackId, &aTrack);
return NS_OK;
}
nsresult
PeerConnectionMedia::RemoveLocalTrack(const std::string& streamId,
const std::string& trackId)
{
ASSERT_ON_THREAD(mMainThread);
@@ -1156,16 +1160,17 @@ PeerConnectionMedia::ConnectDtlsListener
if (dtls) {
dtls->SignalStateChange.connect(this, &PeerConnectionMedia::DtlsConnected_s);
}
}
nsresult
LocalSourceStreamInfo::TakePipelineFrom(RefPtr<LocalSourceStreamInfo>& info,
const std::string& oldTrackId,
+ MediaStreamTrack& aNewTrack,
const std::string& newTrackId)
{
if (mPipelines.count(newTrackId)) {
CSFLogError(logTag, "%s: Pipeline already exists for %s/%s",
__FUNCTION__, mId.c_str(), newTrackId.c_str());
return NS_ERROR_INVALID_ARG;
}
@@ -1175,18 +1180,17 @@ LocalSourceStreamInfo::TakePipelineFrom(
// Replacetrack can potentially happen in the middle of offer/answer, before
// the pipeline has been created.
CSFLogInfo(logTag, "%s: Replacing track before the pipeline has been "
"created, nothing to do.", __FUNCTION__);
return NS_OK;
}
nsresult rv =
- static_cast<MediaPipelineTransmit*>(pipeline.get())->ReplaceTrack(
- mMediaStream, newTrackId);
+ static_cast<MediaPipelineTransmit*>(pipeline.get())->ReplaceTrack(aNewTrack);
NS_ENSURE_SUCCESS(rv, rv);
mPipelines[newTrackId] = pipeline;
return NS_OK;
}
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
@@ -1249,19 +1253,21 @@ LocalSourceStreamInfo::UpdateSinkIdentit
}
}
void RemoteSourceStreamInfo::UpdatePrincipal_m(nsIPrincipal* aPrincipal)
{
// This blasts away the existing principal.
// We only do this when we become certain that the all tracks are safe to make
// accessible to the script principal.
- for (RefPtr<RemoteTrackSource>& source : mTrackSources) {
- MOZ_RELEASE_ASSERT(source);
- source->SetPrincipal(aPrincipal);
+ for (auto& trackPair : mTracks) {
+ MOZ_RELEASE_ASSERT(trackPair.second);
+ RemoteTrackSource& source =
+ static_cast<RemoteTrackSource&>(trackPair.second->GetSource());
+ source.SetPrincipal(aPrincipal);
}
}
#endif // MOZILLA_INTERNAL_API
bool
PeerConnectionMedia::AnyCodecHasPluginID(uint64_t aPluginID)
{
for (uint32_t i=0; i < mLocalSourceStreams.Length(); ++i) {
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
@@ -12,23 +12,16 @@
#include "nspr.h"
#include "prlock.h"
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
#include "nsComponentManagerUtils.h"
#include "nsIProtocolProxyCallback.h"
-#ifdef USE_FAKE_MEDIA_STREAMS
-#include "FakeMediaStreams.h"
-#else
-#include "DOMMediaStream.h"
-#include "MediaSegment.h"
-#endif
-
#include "signaling/src/jsep/JsepSession.h"
#include "AudioSegment.h"
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
#include "Layers.h"
#include "VideoUtils.h"
#include "ImageLayers.h"
#include "VideoSegment.h"
@@ -82,44 +75,57 @@ public:
DOMMediaStream* GetMediaStream() const {
return mMediaStream;
}
nsresult StorePipeline(const std::string& trackId,
const RefPtr<MediaPipeline>& aPipeline);
- virtual void AddTrack(const std::string& trackId) { mTracks.insert(trackId); }
+ virtual void AddTrack(const std::string& trackId,
+ const RefPtr<dom::MediaStreamTrack>& aTrack)
+ {
+ mTracks.insert(std::make_pair(trackId, aTrack));
+ }
void RemoveTrack(const std::string& trackId);
bool HasTrack(const std::string& trackId) const
{
return !!mTracks.count(trackId);
}
size_t GetTrackCount() const { return mTracks.size(); }
// This method exists for stats and the unittests.
// It allows visibility into the pipelines and flows.
const std::map<std::string, RefPtr<MediaPipeline>>&
GetPipelines() const { return mPipelines; }
RefPtr<MediaPipeline> GetPipelineByTrackId_m(const std::string& trackId);
+ dom::MediaStreamTrack* GetTrackById(const std::string& trackId)
+ {
+ auto it = mTracks.find(trackId);
+ if (it == mTracks.end()) {
+ return nullptr;
+ }
+
+ return it->second;
+ }
const std::string& GetId() const { return mId; }
void DetachTransport_s();
void DetachMedia_m();
bool AnyCodecHasPluginID(uint64_t aPluginID);
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
RefPtr<mozilla::dom::VideoStreamTrack> GetVideoTrackByTrackId(const std::string& trackId);
#endif
protected:
RefPtr<DOMMediaStream> mMediaStream;
PeerConnectionMedia *mParent;
const std::string mId;
// These get set up before we generate our local description, the pipelines
// and conduits are set up once offer/answer completes.
- std::set<std::string> mTracks;
+ std::map<std::string, RefPtr<dom::MediaStreamTrack>> mTracks;
std::map<std::string, RefPtr<MediaPipeline>> mPipelines;
};
// TODO(ekr@rtfm.com): Refactor {Local,Remote}SourceStreamInfo
// bug 837539.
class LocalSourceStreamInfo : public SourceStreamInfo {
~LocalSourceStreamInfo() {
mMediaStream = nullptr;
@@ -127,16 +133,17 @@ class LocalSourceStreamInfo : public Sou
public:
LocalSourceStreamInfo(DOMMediaStream *aMediaStream,
PeerConnectionMedia *aParent,
const std::string& aId)
: SourceStreamInfo(aMediaStream, aParent, aId) {}
nsresult TakePipelineFrom(RefPtr<LocalSourceStreamInfo>& info,
const std::string& oldTrackId,
+ dom::MediaStreamTrack& aNewTrack,
const std::string& newTrackId);
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
void UpdateSinkIdentity_m(nsIPrincipal* aPrincipal,
const PeerIdentity* aSinkIdentity);
#endif
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LocalSourceStreamInfo)
@@ -190,36 +197,31 @@ class RemoteSourceStreamInfo : public So
mReceiving(false)
{
}
void SyncPipeline(RefPtr<MediaPipelineReceive> aPipeline);
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
void UpdatePrincipal_m(nsIPrincipal* aPrincipal);
-
- // Track sources may only be set in the same order as tracks were added.
- // Returns true if the source was added, false otherwise.
- bool SetTrackSource(const std::string& track, RemoteTrackSource* source)
- {
- size_t nextIndex = mTrackSources.size();
- if (mTrackIdMap.size() < nextIndex || mTrackIdMap[nextIndex] != track) {
- return false;
- }
- mTrackSources.push_back(source);
- return true;
- }
#endif
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RemoteSourceStreamInfo)
- virtual void AddTrack(const std::string& track) override
+ void AddTrack(const std::string& trackId,
+ const RefPtr<dom::MediaStreamTrack>& aTrack) override
{
- mTrackIdMap.push_back(track);
- SourceStreamInfo::AddTrack(track);
+ mTrackIdMap.push_back(trackId);
+ MOZ_RELEASE_ASSERT(GetNumericTrackId(trackId) == aTrack->mTrackID);
+ SourceStreamInfo::AddTrack(trackId, aTrack);
+ }
+
+ TrackID GetNextAvailableNumericTrackId() const
+ {
+ return mTrackIdMap.size() + 1;
}
TrackID GetNumericTrackId(const std::string& trackId) const
{
for (size_t i = 0; i < mTrackIdMap.size(); ++i) {
if (mTrackIdMap[i] == trackId) {
return static_cast<TrackID>(i + 1);
}
@@ -311,18 +313,19 @@ class PeerConnectionMedia : public sigsl
// Process a trickle ICE candidate.
void AddIceCandidate(const std::string& candidate, const std::string& mid,
uint32_t aMLine);
// Handle complete media pipelines.
nsresult UpdateMediaPipelines(const JsepSession& session);
// Add a track (main thread only)
- nsresult AddTrack(DOMMediaStream* aMediaStream,
+ nsresult AddTrack(DOMMediaStream& aMediaStream,
const std::string& streamId,
+ dom::MediaStreamTrack& aTrack,
const std::string& trackId);
nsresult RemoveLocalTrack(const std::string& streamId,
const std::string& trackId);
nsresult RemoveRemoteTrack(const std::string& streamId,
const std::string& trackId);
nsresult GetRemoteTrackId(const std::string streamId,
@@ -346,21 +349,21 @@ class PeerConnectionMedia : public sigsl
RemoteSourceStreamInfo* GetRemoteStreamByIndex(size_t index);
RemoteSourceStreamInfo* GetRemoteStreamById(const std::string& id);
RemoteSourceStreamInfo* GetRemoteStreamByTrackId(const std::string& id);
// Add a remote stream.
nsresult AddRemoteStream(RefPtr<RemoteSourceStreamInfo> aInfo);
- nsresult ReplaceTrack(const std::string& oldStreamId,
- const std::string& oldTrackId,
- DOMMediaStream* aNewStream,
- const std::string& newStreamId,
- const std::string& aNewTrack);
+ nsresult ReplaceTrack(const std::string& aOldStreamId,
+ const std::string& aOldTrackId,
+ dom::MediaStreamTrack& aNewTrack,
+ const std::string& aNewStreamId,
+ const std::string& aNewTrackId);
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
// In cases where the peer isn't yet identified, we disable the pipeline (not
// the stream, that would potentially affect others), so that it sends
// black/silence. Once the peer is identified, re-enable those streams.
void UpdateSinkIdentity_m(nsIPrincipal* aPrincipal,
const PeerIdentity* aSinkIdentity);
// this determines if any stream is peerIdentity constrained
--- a/media/webrtc/signaling/test/FakeMediaStreams.h
+++ b/media/webrtc/signaling/test/FakeMediaStreams.h
@@ -3,16 +3,17 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef FAKE_MEDIA_STREAM_H_
#define FAKE_MEDIA_STREAM_H_
#include <set>
#include <string>
#include <sstream>
+#include <vector>
#include "nsNetCID.h"
#include "nsITimer.h"
#include "nsComponentManagerUtils.h"
#include "nsIComponentManager.h"
#include "nsIComponentRegistrar.h"
#include "nsISupportsImpl.h"
#include "nsServiceManagerUtils.h"
@@ -27,16 +28,17 @@
#include "nsISupportsImpl.h"
class nsPIDOMWindowInner;
namespace mozilla {
class MediaStreamGraphImpl;
class MediaSegment;
class PeerConnectionImpl;
+ class PeerConnectionMedia;
class RemoteSourceStreamInfo;
};
namespace mozilla {
class MediaStreamGraph;
@@ -99,45 +101,101 @@ public:
class Fake_MediaStreamDirectListener : public Fake_MediaStreamListener
{
protected:
virtual ~Fake_MediaStreamDirectListener() {}
public:
virtual void NotifyRealtimeData(mozilla::MediaStreamGraph* graph, mozilla::TrackID tid,
mozilla::StreamTime offset,
- uint32_t events,
const mozilla::MediaSegment& media) = 0;
};
+class Fake_MediaStreamTrackListener
+{
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Fake_MediaStreamTrackListener)
+
+protected:
+ virtual ~Fake_MediaStreamTrackListener() {}
+
+public:
+ virtual void NotifyQueuedChanges(mozilla::MediaStreamGraph* aGraph,
+ mozilla::StreamTime aTrackOffset,
+ const mozilla::MediaSegment& aQueuedMedia) = 0;
+};
+
+class Fake_MediaStreamTrackDirectListener : public Fake_MediaStreamTrackListener
+{
+protected:
+ virtual ~Fake_MediaStreamTrackDirectListener() {}
+
+public:
+ virtual void NotifyRealtimeTrackData(mozilla::MediaStreamGraph* aGraph,
+ mozilla::StreamTime aTrackOffset,
+ const mozilla::MediaSegment& aMedia) = 0;
+ enum class InstallationResult {
+ STREAM_NOT_SUPPORTED,
+ SUCCESS
+ };
+ virtual void NotifyDirectListenerInstalled(InstallationResult aResult) = 0;
+ virtual void NotifyDirectListenerUninstalled() = 0;
+};
+
// Note: only one listener supported
class Fake_MediaStream {
protected:
virtual ~Fake_MediaStream() { Stop(); }
+ struct BoundTrackListener
+ {
+ BoundTrackListener(Fake_MediaStreamTrackListener* aListener,
+ mozilla::TrackID aTrackID)
+ : mListener(aListener), mTrackID(aTrackID) {}
+ RefPtr<Fake_MediaStreamTrackListener> mListener;
+ mozilla::TrackID mTrackID;
+ };
+
public:
- Fake_MediaStream () : mListeners(), mMutex("Fake MediaStream") {}
+ Fake_MediaStream () : mListeners(), mTrackListeners(), mMutex("Fake MediaStream") {}
static uint32_t GraphRate() { return 16000; }
void AddListener(Fake_MediaStreamListener *aListener) {
mozilla::MutexAutoLock lock(mMutex);
mListeners.insert(aListener);
}
void RemoveListener(Fake_MediaStreamListener *aListener) {
mozilla::MutexAutoLock lock(mMutex);
mListeners.erase(aListener);
}
+ void AddTrackListener(Fake_MediaStreamTrackListener *aListener,
+ mozilla::TrackID aTrackID) {
+ mozilla::MutexAutoLock lock(mMutex);
+ mTrackListeners.push_back(BoundTrackListener(aListener, aTrackID));
+ }
+
+ void RemoveTrackListener(Fake_MediaStreamTrackListener *aListener,
+ mozilla::TrackID aTrackID) {
+ mozilla::MutexAutoLock lock(mMutex);
+ for (std::vector<BoundTrackListener>::iterator it = mTrackListeners.begin();
+ it != mTrackListeners.end(); ++it) {
+ if (it->mListener == aListener && it->mTrackID == aTrackID) {
+ mTrackListeners.erase(it);
+ return;
+ }
+ }
+ }
+
void NotifyPull(mozilla::MediaStreamGraph* graph,
mozilla::StreamTime aDesiredTime) {
mozilla::MutexAutoLock lock(mMutex);
- std::set<Fake_MediaStreamListener *>::iterator it;
+ std::set<RefPtr<Fake_MediaStreamListener>>::iterator it;
for (it = mListeners.begin(); it != mListeners.end(); ++it) {
(*it)->NotifyPull(graph, aDesiredTime);
}
}
virtual Fake_SourceMediaStream *AsSourceStream() { return nullptr; }
virtual mozilla::MediaStreamGraphImpl *GraphImpl() { return nullptr; }
@@ -149,17 +207,18 @@ class Fake_MediaStream {
double StreamTimeToSeconds(mozilla::StreamTime aTime);
mozilla::StreamTime
TicksToTimeRoundDown(mozilla::TrackRate aRate, mozilla::TrackTicks aTicks);
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Fake_MediaStream);
protected:
- std::set<Fake_MediaStreamListener *> mListeners;
+ std::set<RefPtr<Fake_MediaStreamListener>> mListeners;
+ std::vector<BoundTrackListener> mTrackListeners;
mozilla::Mutex mMutex; // Lock to prevent the listener list from being modified while
// executing Periodic().
};
class Fake_MediaPeriodic : public nsITimerCallback {
public:
explicit Fake_MediaPeriodic(Fake_MediaStream *aStream) : mStream(aStream),
mCount(0) {}
@@ -294,16 +353,17 @@ class Fake_MediaStreamTrackSource
protected:
virtual ~Fake_MediaStreamTrackSource() {}
};
class Fake_MediaStreamTrack
{
friend class mozilla::PeerConnectionImpl;
+ friend class mozilla::PeerConnectionMedia;
friend class mozilla::RemoteSourceStreamInfo;
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Fake_MediaStreamTrack)
Fake_MediaStreamTrack(bool aIsVideo, Fake_DOMMediaStream* aOwningStream) :
mIsVideo (aIsVideo),
mOwningStream (aOwningStream),
mTrackID(mIsVideo ? 1 : 0)
@@ -311,43 +371,57 @@ public:
static size_t counter = 0;
std::ostringstream os;
os << counter++;
mID = os.str();
}
std::string GetId() const { return mID; }
void AssignId(const std::string& id) { mID = id; }
+ mozilla::MediaStreamGraphImpl* GraphImpl() { return nullptr; }
const Fake_MediaStreamTrack* AsVideoStreamTrack() const
{
return mIsVideo? this : nullptr;
}
const Fake_MediaStreamTrack* AsAudioStreamTrack() const
{
return mIsVideo? nullptr : this;
}
uint32_t typeSize () const
{
return sizeof(Fake_MediaStreamTrack);
}
const char* typeName () const
{
return "Fake_MediaStreamTrack";
}
+ void AddListener(Fake_MediaStreamTrackListener *aListener);
+ void RemoveListener(Fake_MediaStreamTrackListener *aListener);
+ void AddDirectListener(Fake_MediaStreamTrackDirectListener *aListener)
+ {
+ AddListener(aListener);
+ aListener->NotifyDirectListenerInstalled(
+ Fake_MediaStreamTrackDirectListener::InstallationResult::STREAM_NOT_SUPPORTED);
+ }
+ void RemoveDirectListener(Fake_MediaStreamTrackDirectListener *aListener)
+ {
+ RemoveListener(aListener);
+ }
private:
~Fake_MediaStreamTrack() {}
const bool mIsVideo;
Fake_DOMMediaStream* mOwningStream;
mozilla::TrackID mTrackID;
std::string mID;
};
class Fake_DOMMediaStream : public nsISupports
{
+ friend class mozilla::PeerConnectionMedia;
protected:
virtual ~Fake_DOMMediaStream() {
// Note: memory leak
mMediaStream->Stop();
}
public:
explicit Fake_DOMMediaStream(Fake_MediaStream *stream = nullptr)
@@ -381,16 +455,34 @@ public:
virtual void RemoveDirectListener(Fake_MediaStreamListener *aListener) {}
Fake_MediaStream *GetInputStream() { return mMediaStream; }
Fake_MediaStream *GetOwnedStream() { return mMediaStream; }
Fake_MediaStream *GetPlaybackStream() { return mMediaStream; }
Fake_MediaStream *GetStream() { return mMediaStream; }
std::string GetId() const { return mID; }
void AssignId(const std::string& id) { mID = id; }
+ Fake_MediaStreamTrack* GetTrackById(const std::string& aId)
+ {
+ if (mHintContents & HINT_CONTENTS_AUDIO) {
+ if (mAudioTrack && mAudioTrack->GetId() == aId) {
+ return mAudioTrack;
+ }
+ }
+ if (mHintContents & HINT_CONTENTS_VIDEO) {
+ if (mVideoTrack && mVideoTrack->GetId() == aId) {
+ return mVideoTrack;
+ }
+ }
+ return nullptr;
+ }
+ Fake_MediaStreamTrack* GetOwnedTrackById(const std::string& aId)
+ {
+ return GetTrackById(aId);
+ }
// Hints to tell the SDP generator about whether this
// MediaStream probably has audio and/or video
typedef uint8_t TrackTypeHints;
enum {
HINT_CONTENTS_AUDIO = 0x01,
HINT_CONTENTS_VIDEO = 0x02
};
@@ -503,16 +595,18 @@ class Fake_VideoStreamSource : public Fa
};
namespace mozilla {
typedef Fake_MediaStream MediaStream;
typedef Fake_SourceMediaStream SourceMediaStream;
typedef Fake_MediaStreamListener MediaStreamListener;
typedef Fake_MediaStreamDirectListener MediaStreamDirectListener;
+typedef Fake_MediaStreamTrackListener MediaStreamTrackListener;
+typedef Fake_MediaStreamTrackDirectListener MediaStreamTrackDirectListener;
typedef Fake_DOMMediaStream DOMMediaStream;
typedef Fake_DOMMediaStream DOMLocalMediaStream;
namespace dom {
typedef Fake_MediaStreamTrack MediaStreamTrack;
typedef Fake_MediaStreamTrackSource MediaStreamTrackSource;
}
}
--- a/media/webrtc/signaling/test/FakeMediaStreamsImpl.h
+++ b/media/webrtc/signaling/test/FakeMediaStreamsImpl.h
@@ -53,24 +53,34 @@ nsresult Fake_SourceMediaStream::Stop()
void Fake_SourceMediaStream::Periodic() {
mozilla::MutexAutoLock lock(mMutex);
// Pull more audio-samples iff pulling is enabled
// and we are not asked by the signaling agent to stop
//pulling data.
if (mPullEnabled && !mStop) {
// 100 ms matches timer interval and AUDIO_BUFFER_SIZE @ 16000 Hz
mDesiredTime += 100;
- for (std::set<Fake_MediaStreamListener *>::iterator it =
+ for (std::set<RefPtr<Fake_MediaStreamListener>>::iterator it =
mListeners.begin(); it != mListeners.end(); ++it) {
(*it)->NotifyPull(nullptr, TicksToTimeRoundDown(1000 /* ms per s */,
mDesiredTime));
}
}
}
+// Fake_MediaStreamTrack
+void Fake_MediaStreamTrack::AddListener(Fake_MediaStreamTrackListener *aListener)
+{
+ mOwningStream->GetInputStream()->AddTrackListener(aListener, mTrackID);
+}
+void Fake_MediaStreamTrack::RemoveListener(Fake_MediaStreamTrackListener *aListener)
+{
+ mOwningStream->GetInputStream()->RemoveTrackListener(aListener, mTrackID);
+}
+
// Fake_MediaStreamBase
nsresult Fake_MediaStreamBase::Start() {
mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
if (!mTimer) {
return NS_ERROR_FAILURE;
}
mTimer->InitWithCallback(mPeriodic, 100, nsITimer::TYPE_REPEATING_SLACK);
@@ -105,26 +115,32 @@ void Fake_AudioStreamSource::Periodic()
mCount++;
}
mozilla::AudioSegment segment;
AutoTArray<const int16_t *,1> channels;
channels.AppendElement(data);
segment.AppendFrames(samples.forget(), channels, AUDIO_BUFFER_SIZE);
- for(std::set<Fake_MediaStreamListener *>::iterator it = mListeners.begin();
+ for(std::set<RefPtr<Fake_MediaStreamListener>>::iterator it = mListeners.begin();
it != mListeners.end(); ++it) {
(*it)->NotifyQueuedTrackChanges(nullptr, // Graph
0, // TrackID
0, // Offset TODO(ekr@rtfm.com) fix
0, // ???
segment,
nullptr, // Input stream
-1); // Input track id
}
+ for(std::vector<BoundTrackListener>::iterator it = mTrackListeners.begin();
+ it != mTrackListeners.end(); ++it) {
+ it->mListener->NotifyQueuedChanges(nullptr, // Graph
+ 0, // Offset TODO(ekr@rtfm.com) fix
+ segment);
+ }
}
// Fake_MediaPeriodic
NS_IMPL_ISUPPORTS(Fake_MediaPeriodic, nsITimerCallback)
NS_IMETHODIMP
Fake_MediaPeriodic::Notify(nsITimer *timer) {
--- a/media/webrtc/signaling/test/mediapipeline_unittest.cpp
+++ b/media/webrtc/signaling/test/mediapipeline_unittest.cpp
@@ -187,17 +187,17 @@ class TestAgent {
WrapRunnable(this, &TestAgent::StopInt));
}
void Shutdown_s() {
audio_rtp_transport_.Shutdown();
audio_rtcp_transport_.Shutdown();
bundle_transport_.Shutdown();
if (audio_pipeline_)
- audio_pipeline_->ShutdownTransport_s();
+ audio_pipeline_->DetachTransport_s();
}
void Shutdown() {
if (audio_pipeline_)
audio_pipeline_->ShutdownMedia_m();
mozilla::SyncRunnable::DispatchToThread(
test_utils->sts_target(),
@@ -246,16 +246,21 @@ class TestAgent {
};
class TestAgentSend : public TestAgent {
public:
TestAgentSend() : use_bundle_(false) {}
virtual void CreatePipelines_s(bool aIsRtcpMux) {
audio_ = new Fake_DOMMediaStream(new Fake_AudioStreamSource());
+ audio_->SetHintContents(Fake_DOMMediaStream::HINT_CONTENTS_AUDIO);
+
+ nsTArray<RefPtr<Fake_MediaStreamTrack>> tracks;
+ audio_->GetAudioTracks(tracks);
+ ASSERT_EQ(1U, tracks.Length());
mozilla::MediaConduitErrorCode err =
static_cast<mozilla::AudioSessionConduit *>(audio_conduit_.get())->
ConfigureSendMediaCodec(&audio_config_);
EXPECT_EQ(mozilla::kMediaConduitNoError, err);
std::string test_pc("PC");
@@ -270,20 +275,19 @@ class TestAgentSend : public TestAgent {
rtp = bundle_transport_.flow_;
rtcp = nullptr;
}
audio_pipeline_ = new mozilla::MediaPipelineTransmit(
test_pc,
nullptr,
test_utils->sts_target(),
- audio_,
+ tracks[0],
"audio_track_fake_uuid",
1,
- false,
audio_conduit_,
rtp,
rtcp,
nsAutoPtr<MediaPipelineFilter>());
audio_pipeline_->Init();
}
@@ -321,17 +325,17 @@ class TestAgentReceive : public TestAgen
if (aIsRtcpMux) {
ASSERT_FALSE(audio_rtcp_transport_.flow_);
}
audio_pipeline_ = new mozilla::MediaPipelineReceiveAudio(
test_pc,
nullptr,
test_utils->sts_target(),
- audio_->GetStream(), "audio_track_fake_uuid", 1, 1,
+ audio_->GetStream()->AsSourceStream(), "audio_track_fake_uuid", 1, 1,
static_cast<mozilla::AudioSessionConduit *>(audio_conduit_.get()),
audio_rtp_transport_.flow_,
audio_rtcp_transport_.flow_,
bundle_filter_,
false);
audio_pipeline_->Init();
}