--- a/dom/media/MediaStreamTrack.h
+++ b/dom/media/MediaStreamTrack.h
@@ -25,16 +25,17 @@ class MediaStreamGraph;
class MediaStreamGraphImpl;
class MediaStreamTrackListener;
class MediaStreamTrackDirectListener;
class PeerConnectionImpl;
class PeerConnectionMedia;
class PeerIdentity;
class ProcessedMediaStream;
class RemoteSourceStreamInfo;
+class SourceStreamInfo;
namespace dom {
class AudioStreamTrack;
class VideoStreamTrack;
/**
* Common interface through which a MediaStreamTrack can communicate with its
@@ -223,16 +224,17 @@ class MediaStreamTrack : public DOMEvent
{
// 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::SourceStreamInfo;
friend class mozilla::RemoteSourceStreamInfo;
class PrincipalHandleListener;
public:
/**
* aTrackID is the MediaStreamGraph track ID for the track in the
* MediaStream owned by aStream.
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
@@ -53,18 +53,21 @@
#include "webrtc/common_types.h"
#include "webrtc/common_video/interface/native_handle.h"
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#include "webrtc/video_engine/include/vie_errors.h"
#include "logging.h"
-// Should come from MediaEngineWebRTC.h, but that's a pain to include here
-#define DEFAULT_SAMPLE_RATE 32000
+// Max size given stereo is 480*2*2 = 1920 (48KHz)
+#define AUDIO_SAMPLE_BUFFER_MAX 480*2*2
+static_assert((WEBRTC_DEFAULT_SAMPLE_RATE/100)*sizeof(uint16_t) * 2
+ <= AUDIO_SAMPLE_BUFFER_MAX,
+ "AUDIO_SAMPLE_BUFFER_MAX is not large enough");
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::gfx;
using namespace mozilla::layers;
// Logging context
MOZ_MTLOG_MODULE("mediapipeline")
@@ -1708,19 +1711,16 @@ void MediaPipelineTransmit::PipelineList
packetizer_->Input(samples, chunk.mDuration);
while (packetizer_->PacketsAvailable()) {
uint32_t samplesPerPacket = packetizer_->PacketSize() *
packetizer_->Channels();
// We know that webrtc.org's code going to copy the samples down the line,
// so we can just use a stack buffer here instead of malloc-ing.
- // Max size given stereo is 480*2*2 = 1920 (10ms of 16-bits stereo audio at
- // 48KHz)
- const size_t AUDIO_SAMPLE_BUFFER_MAX = 1920;
int16_t packet[AUDIO_SAMPLE_BUFFER_MAX];
packetizer_->Output(packet);
conduit->SendAudioFrame(packet,
samplesPerPacket,
rate, 0);
}
}
@@ -1744,127 +1744,54 @@ class GenericReceiveCallback : public Tr
: listener_(listener) {}
void TrackAdded(TrackTicks time);
private:
RefPtr<GenericReceiveListener> listener_;
};
-// Add a track and listener on the MSG thread using the MSG command queue
-static void AddTrackAndListener(MediaStream* source,
- TrackID track_id, TrackRate track_rate,
- MediaStreamListener* listener, MediaSegment* segment,
- const RefPtr<TrackAddedCallback>& completed,
- bool queue_track) {
- // This both adds the listener and the track
+// Add a listener on the MSG thread using the MSG command queue
+static void AddListener(MediaStream* source, MediaStreamListener* listener) {
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
class Message : public ControlMessage {
public:
- Message(MediaStream* stream, TrackID track, TrackRate rate,
- MediaSegment* segment, MediaStreamListener* listener,
- const RefPtr<TrackAddedCallback>& completed)
+ Message(MediaStream* stream, MediaStreamListener* listener)
: ControlMessage(stream),
- track_id_(track),
- track_rate_(rate),
- segment_(segment),
- listener_(listener),
- completed_(completed) {}
+ listener_(listener) {}
virtual void Run() override {
- StreamTime current_end = mStream->GetTracksEnd();
- TrackTicks current_ticks =
- mStream->TimeToTicksRoundUp(track_rate_, current_end);
-
mStream->AddListenerImpl(listener_.forget());
-
- // Add a track 'now' to avoid possible underrun, especially if we add
- // a track "later".
-
- if (current_end != 0L) {
- MOZ_MTLOG(ML_DEBUG, "added track @ " << current_end <<
- " -> " << mStream->StreamTimeToSeconds(current_end));
- }
-
- // To avoid assertions, we need to insert a dummy segment that covers up
- // to the "start" time for the track
- segment_->AppendNullData(current_ticks);
- if (segment_->GetType() == MediaSegment::AUDIO) {
- mStream->AsSourceStream()->AddAudioTrack(track_id_, track_rate_, 0,
- static_cast<AudioSegment*>(segment_.forget()));
- } else {
- NS_ASSERTION(mStream->GraphRate() == track_rate_, "Rate mismatch");
- mStream->AsSourceStream()->AddTrack(track_id_, 0, segment_.forget());
- }
-
- // We need to know how much has been "inserted" because we're given absolute
- // times in NotifyPull.
- completed_->TrackAdded(current_ticks);
}
private:
- TrackID track_id_;
- TrackRate track_rate_;
- nsAutoPtr<MediaSegment> segment_;
RefPtr<MediaStreamListener> listener_;
- const RefPtr<TrackAddedCallback> completed_;
};
MOZ_ASSERT(listener);
- if (!queue_track) {
- // We're only queueing the initial set of tracks since they are added
- // atomically and have start time 0. When not queueing we have to add
- // the track on the MediaStreamGraph thread so it can be added with the
- // appropriate start time.
- source->GraphImpl()->AppendMessage(MakeUnique<Message>(source, track_id, track_rate, segment, listener, completed));
- MOZ_MTLOG(ML_INFO, "Dispatched track-add for track id " << track_id <<
- " on stream " << source);
- return;
- }
+ source->GraphImpl()->AppendMessage(MakeUnique<Message>(source, listener));
+#else
+ source->AddListener(listener);
#endif
- source->AddListener(listener);
- if (segment->GetType() == MediaSegment::AUDIO) {
- source->AsSourceStream()->AddAudioTrack(track_id, track_rate, 0,
- static_cast<AudioSegment*>(segment),
- SourceMediaStream::ADDTRACK_QUEUED);
- } else {
- source->AsSourceStream()->AddTrack(track_id, 0, segment,
- SourceMediaStream::ADDTRACK_QUEUED);
- }
- MOZ_MTLOG(ML_INFO, "Queued track-add for track id " << track_id <<
- " on MediaStream " << source);
}
class GenericReceiveListener : public MediaStreamListener
{
public:
- GenericReceiveListener(SourceMediaStream *source, TrackID track_id,
- TrackRate track_rate, bool queue_track)
+ GenericReceiveListener(SourceMediaStream *source, TrackID track_id)
: source_(source),
track_id_(track_id),
- track_rate_(track_rate),
played_ticks_(0),
- queue_track_(queue_track),
principal_handle_(PRINCIPAL_HANDLE_NONE) {}
virtual ~GenericReceiveListener() {}
- void AddSelf(MediaSegment* segment)
+ void AddSelf()
{
- RefPtr<TrackAddedCallback> callback = new GenericReceiveCallback(this);
- AddTrackAndListener(source_, track_id_, track_rate_, this, segment, callback,
- queue_track_);
- }
-
- void SetPlayedTicks(TrackTicks time) {
- played_ticks_ = time;
- }
-
- void EndTrack() {
- source_->EndTrack(track_id_);
+ AddListener(source_, this);
}
#ifndef USE_FAKE_MEDIA_STREAMS
// Must be called on the main thread
void SetPrincipalHandle_m(const PrincipalHandle& principal_handle)
{
class Message : public ControlMessage
{
@@ -1893,27 +1820,20 @@ class GenericReceiveListener : public Me
{
principal_handle_ = principal_handle;
}
#endif // USE_FAKE_MEDIA_STREAMS
protected:
SourceMediaStream *source_;
TrackID track_id_;
- TrackRate track_rate_;
TrackTicks played_ticks_;
- bool queue_track_;
PrincipalHandle principal_handle_;
};
-void GenericReceiveCallback::TrackAdded(TrackTicks time)
-{
- listener_->SetPlayedTicks(time);
-}
-
MediaPipelineReceive::MediaPipelineReceive(
const std::string& pc,
nsCOMPtr<nsIEventTarget> main_thread,
nsCOMPtr<nsIEventTarget> sts_thread,
SourceMediaStream *stream,
const std::string& track_id,
int level,
RefPtr<MediaSessionConduit> conduit,
@@ -1934,22 +1854,20 @@ MediaPipelineReceive::~MediaPipelineRece
MOZ_ASSERT(!stream_); // Check that we have shut down already.
}
class MediaPipelineReceiveAudio::PipelineListener
: public GenericReceiveListener
{
public:
PipelineListener(SourceMediaStream * source, TrackID track_id,
- const RefPtr<MediaSessionConduit>& conduit,
- bool queue_track)
- : GenericReceiveListener(source, track_id, DEFAULT_SAMPLE_RATE, queue_track), // XXX rate assumption
+ const RefPtr<MediaSessionConduit>& conduit)
+ : GenericReceiveListener(source, track_id),
conduit_(conduit)
{
- MOZ_ASSERT(track_rate_%100 == 0);
}
~PipelineListener()
{
if (!NS_IsMainThread()) {
// release conduit on mainthread. Must use forget()!
nsresult rv = NS_DispatchToMainThread(new
ConduitDeleteEvent(conduit_.forget()));
@@ -1967,56 +1885,53 @@ public:
{
MOZ_ASSERT(source_);
if (!source_) {
MOZ_MTLOG(ML_ERROR, "NotifyPull() called from a non-SourceMediaStream");
return;
}
// This comparison is done in total time to avoid accumulated roundoff errors.
- while (source_->TicksToTimeRoundDown(track_rate_, played_ticks_) <
- desired_time) {
- // Max size given stereo is 480*2*2 = 1920 (48KHz)
- const size_t AUDIO_SAMPLE_BUFFER_MAX = 1920;
- MOZ_ASSERT((track_rate_/100)*sizeof(uint16_t) * 2 <= AUDIO_SAMPLE_BUFFER_MAX);
-
+ while (source_->TicksToTimeRoundDown(WEBRTC_DEFAULT_SAMPLE_RATE,
+ played_ticks_) < desired_time) {
int16_t scratch_buffer[AUDIO_SAMPLE_BUFFER_MAX];
int samples_length;
// This fetches 10ms of data, either mono or stereo
MediaConduitErrorCode err =
static_cast<AudioSessionConduit*>(conduit_.get())->GetAudioFrame(
scratch_buffer,
- track_rate_,
+ WEBRTC_DEFAULT_SAMPLE_RATE,
0, // TODO(ekr@rtfm.com): better estimate of "capture" (really playout) delay
samples_length);
if (err != kMediaConduitNoError) {
// Insert silence on conduit/GIPS failure (extremely unlikely)
MOZ_MTLOG(ML_ERROR, "Audio conduit failed (" << err
<< ") to return data @ " << played_ticks_
<< " (desired " << desired_time << " -> "
<< source_->StreamTimeToSeconds(desired_time) << ")");
- samples_length = track_rate_/100; // if this is not enough we'll loop and provide more
+ // if this is not enough we'll loop and provide more
+ samples_length = WEBRTC_DEFAULT_SAMPLE_RATE/100;
PodArrayZero(scratch_buffer);
}
MOZ_ASSERT(samples_length * sizeof(uint16_t) < AUDIO_SAMPLE_BUFFER_MAX);
MOZ_MTLOG(ML_DEBUG, "Audio conduit returned buffer of length "
<< samples_length);
RefPtr<SharedBuffer> samples = SharedBuffer::Create(samples_length * sizeof(uint16_t));
int16_t *samples_data = static_cast<int16_t *>(samples->Data());
AudioSegment segment;
// We derive the number of channels of the stream from the number of samples
// the AudioConduit gives us, considering it gives us packets of 10ms and we
// know the rate.
- uint32_t channelCount = samples_length / (track_rate_ / 100);
+ uint32_t channelCount = samples_length / (WEBRTC_DEFAULT_SAMPLE_RATE / 100);
AutoTArray<int16_t*,2> channels;
AutoTArray<const int16_t*,2> outputChannels;
size_t frames = samples_length / channelCount;
channels.SetLength(channelCount);
size_t offset = 0;
for (size_t i = 0; i < channelCount; i++) {
@@ -2056,62 +1971,58 @@ MediaPipelineReceiveAudio::MediaPipeline
nsCOMPtr<nsIEventTarget> sts_thread,
SourceMediaStream* stream,
const std::string& media_stream_track_id,
TrackID numeric_track_id,
int level,
RefPtr<AudioSessionConduit> conduit,
RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> rtcp_transport,
- nsAutoPtr<MediaPipelineFilter> filter,
- bool queue_track) :
+ nsAutoPtr<MediaPipelineFilter> filter) :
MediaPipelineReceive(pc, main_thread, sts_thread,
stream, media_stream_track_id, level, conduit,
rtp_transport, rtcp_transport, filter),
- listener_(new PipelineListener(stream, numeric_track_id, conduit,
- queue_track))
+ listener_(new PipelineListener(stream, numeric_track_id, conduit))
{}
void MediaPipelineReceiveAudio::DetachMedia()
{
ASSERT_ON_THREAD(main_thread_);
- listener_->EndTrack();
if (stream_) {
stream_->RemoveListener(listener_);
stream_ = nullptr;
}
}
nsresult MediaPipelineReceiveAudio::Init() {
ASSERT_ON_THREAD(main_thread_);
MOZ_MTLOG(ML_DEBUG, __FUNCTION__);
description_ = pc_ + "| Receive audio[";
description_ += track_id_;
description_ += "]";
- listener_->AddSelf(new AudioSegment());
+ listener_->AddSelf();
return MediaPipelineReceive::Init();
}
#ifndef USE_FAKE_MEDIA_STREAMS
void MediaPipelineReceiveAudio::SetPrincipalHandle_m(const PrincipalHandle& principal_handle)
{
listener_->SetPrincipalHandle_m(principal_handle);
}
#endif // USE_FAKE_MEDIA_STREAMS
class MediaPipelineReceiveVideo::PipelineListener
: public GenericReceiveListener {
public:
- PipelineListener(SourceMediaStream * source, TrackID track_id,
- bool queue_track)
- : GenericReceiveListener(source, track_id, source->GraphRate(), queue_track),
+ PipelineListener(SourceMediaStream * source, TrackID track_id)
+ : GenericReceiveListener(source, track_id),
width_(0),
height_(0),
#if defined(MOZILLA_INTERNAL_API)
image_container_(),
image_(),
#endif
monitor_("Video PipelineListener")
{
@@ -2119,25 +2030,20 @@ public:
image_container_ =
LayerManager::CreateImageContainer(ImageContainer::ASYNCHRONOUS);
#endif
}
// Implement MediaStreamListener
void NotifyPull(MediaStreamGraph* graph, StreamTime desired_time) override
{
+ #if defined(MOZILLA_INTERNAL_API)
ReentrantMonitorAutoEnter enter(monitor_);
- #if defined(MOZILLA_INTERNAL_API)
RefPtr<Image> image = image_;
- // our constructor sets track_rate_ to the graph rate
- MOZ_ASSERT(track_rate_ == source_->GraphRate());
- #endif
-
- #if defined(MOZILLA_INTERNAL_API)
StreamTime delta = desired_time - played_ticks_;
// Don't append if we've already provided a frame that supposedly
// goes past the current aDesiredTime Doing so means a negative
// delta and thus messes up handling of the graph
if (delta > 0) {
VideoSegment segment;
segment.AppendFrame(image.forget(), delta, IntSize(width_, height_),
@@ -2290,30 +2196,28 @@ MediaPipelineReceiveVideo::MediaPipeline
nsCOMPtr<nsIEventTarget> sts_thread,
SourceMediaStream *stream,
const std::string& media_stream_track_id,
TrackID numeric_track_id,
int level,
RefPtr<VideoSessionConduit> conduit,
RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> rtcp_transport,
- nsAutoPtr<MediaPipelineFilter> filter,
- bool queue_track) :
+ nsAutoPtr<MediaPipelineFilter> filter) :
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, numeric_track_id, queue_track))
+ listener_(new PipelineListener(stream, numeric_track_id))
{}
void MediaPipelineReceiveVideo::DetachMedia()
{
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();
if (stream_) {
stream_->RemoveListener(listener_);
stream_ = nullptr;
@@ -2324,17 +2228,17 @@ nsresult MediaPipelineReceiveVideo::Init
ASSERT_ON_THREAD(main_thread_);
MOZ_MTLOG(ML_DEBUG, __FUNCTION__);
description_ = pc_ + "| Receive video[";
description_ += track_id_;
description_ += "]";
#if defined(MOZILLA_INTERNAL_API)
- listener_->AddSelf(new VideoSegment());
+ listener_->AddSelf();
#endif
// Always happens before we can DetachMedia()
static_cast<VideoSessionConduit *>(conduit_.get())->
AttachRenderer(renderer_);
return MediaPipelineReceive::Init();
}
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
@@ -20,16 +20,20 @@
#include "databuffer.h"
#include "runnable_utils.h"
#include "transportflow.h"
#include "AudioPacketizer.h"
#include "StreamTracks.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
+// Should come from MediaEngine.h, but that's a pain to include here
+// because of the MOZILLA_EXTERNAL_LINKAGE stuff.
+#define WEBRTC_DEFAULT_SAMPLE_RATE 32000
+
class nsIPrincipal;
namespace mozilla {
class MediaPipelineFilter;
class PeerIdentity;
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
class VideoFrameConverter;
#endif
@@ -399,18 +403,17 @@ class MediaPipelineReceiveAudio : public
// 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);
+ nsAutoPtr<MediaPipelineFilter> filter);
void DetachMedia() override;
nsresult Init() override;
bool IsVideo() const override { return false; }
#ifndef USE_FAKE_MEDIA_STREAMS
void SetPrincipalHandle_m(const PrincipalHandle& principal_handle) override;
@@ -438,18 +441,17 @@ class MediaPipelineReceiveVideo : public
// 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<VideoSessionConduit> conduit,
RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> rtcp_transport,
- nsAutoPtr<MediaPipelineFilter> filter,
- bool queue_track);
+ nsAutoPtr<MediaPipelineFilter> filter);
// Called on the main thread.
void DetachMedia() override;
nsresult Init() override;
bool IsVideo() const override { return true; }
#ifndef USE_FAKE_MEDIA_STREAMS
--- a/media/webrtc/signaling/src/peerconnection/MediaPipelineFactory.cpp
+++ b/media/webrtc/signaling/src/peerconnection/MediaPipelineFactory.cpp
@@ -530,49 +530,45 @@ MediaPipelineFactory::CreateMediaPipelin
RefPtr<RemoteSourceStreamInfo> stream =
mPCMedia->GetRemoteStreamById(aTrack.GetStreamId());
RefPtr<MediaPipelineReceive> pipeline;
TrackID numericTrackId = stream->GetNumericTrackId(aTrack.GetTrackId());
MOZ_ASSERT(IsTrackIDExplicit(numericTrackId));
- bool queue_track = stream->ShouldQueueTracks();
-
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()->AsSourceStream(),
aTrack.GetTrackId(),
numericTrackId,
aLevel,
static_cast<AudioSessionConduit*>(aConduit.get()), // Ugly downcast.
aRtpFlow,
aRtcpFlow,
- aFilter,
- queue_track);
+ aFilter);
} else if (aTrack.GetMediaType() == SdpMediaSection::kVideo) {
pipeline = new MediaPipelineReceiveVideo(
mPC->GetHandle(),
mPC->GetMainThread().get(),
mPC->GetSTSThread(),
stream->GetMediaStream()->GetInputStream()->AsSourceStream(),
aTrack.GetTrackId(),
numericTrackId,
aLevel,
static_cast<VideoSessionConduit*>(aConduit.get()), // Ugly downcast.
aRtpFlow,
aRtcpFlow,
- aFilter,
- queue_track);
+ aFilter);
} else {
MOZ_ASSERT(false);
MOZ_MTLOG(ML_ERROR, "Invalid media type in CreateMediaPipelineReceiving");
return NS_ERROR_FAILURE;
}
nsresult rv = pipeline->Init();
if (NS_FAILED(rv)) {
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -92,16 +92,20 @@
#include "rlogringbuffer.h"
#include "WebrtcGlobalInformation.h"
#include "mozilla/dom/Event.h"
#include "nsIDOMCustomEvent.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/net/DataChannelProtocol.h"
#endif
+#ifndef USE_FAKE_MEDIA_STREAMS
+#include "MediaStreamGraphImpl.h"
+#endif
+
#ifdef XP_WIN
// We need to undef the MS macro again in case the windows include file
// got imported after we included nsIDocument.h
#ifdef CreateEvent
#undef CreateEvent
#endif
#endif // XP_WIN
@@ -1738,16 +1742,71 @@ static void DeferredSetRemote(const std:
if (!PeerConnectionCtx::GetInstance()->isReady()) {
MOZ_CRASH("Why is DeferredSetRemote being executed when the "
"PeerConnectionCtx isn't ready?");
}
wrapper.impl()->SetRemoteDescription(aAction, aSdp.c_str());
}
}
+static void StartTrack(MediaStream* aSource,
+ TrackID aTrackId,
+ nsAutoPtr<MediaSegment>&& aSegment) {
+#if !defined(MOZILLA_EXTERNAL_LINKAGE)
+ class Message : public ControlMessage {
+ public:
+ Message(MediaStream* aStream,
+ TrackID aTrack,
+ nsAutoPtr<MediaSegment>&& aSegment)
+ : ControlMessage(aStream),
+ track_id_(aTrack),
+ segment_(aSegment) {}
+
+ virtual void Run() override {
+ TrackRate track_rate = segment_->GetType() == MediaSegment::AUDIO ?
+ WEBRTC_DEFAULT_SAMPLE_RATE : mStream->GraphRate();
+ StreamTime current_end = mStream->GetTracksEnd();
+ TrackTicks current_ticks =
+ mStream->TimeToTicksRoundUp(track_rate, current_end);
+
+ // Add a track 'now' to avoid possible underrun, especially if we add
+ // a track "later".
+
+ if (current_end != 0L) {
+ CSFLogDebug(logTag, "added track @ %u -> %f",
+ static_cast<unsigned>(current_end),
+ mStream->StreamTimeToSeconds(current_end));
+ }
+
+ // To avoid assertions, we need to insert a dummy segment that covers up
+ // to the "start" time for the track
+ segment_->AppendNullData(current_ticks);
+ if (segment_->GetType() == MediaSegment::AUDIO) {
+ mStream->AsSourceStream()->AddAudioTrack(
+ track_id_,
+ WEBRTC_DEFAULT_SAMPLE_RATE,
+ 0,
+ static_cast<AudioSegment*>(segment_.forget()));
+ } else {
+ mStream->AsSourceStream()->AddTrack(track_id_, 0, segment_.forget());
+ }
+ }
+ private:
+ TrackID track_id_;
+ nsAutoPtr<MediaSegment> segment_;
+ };
+
+ aSource->GraphImpl()->AppendMessage(
+ MakeUnique<Message>(aSource, aTrackId, Move(aSegment)));
+ CSFLogInfo(logTag, "Dispatched track-add for track id %u on stream %p",
+ aTrackId, aSource);
+#endif
+}
+
+
nsresult
PeerConnectionImpl::CreateNewRemoteTracks(RefPtr<PeerConnectionObserver>& aPco)
{
JSErrorResult jrv;
std::vector<RefPtr<JsepTrack>> newTracks =
mJsepSession->GetRemoteTracksAdded();
@@ -1821,39 +1880,56 @@ PeerConnectionImpl::CreateNewRemoteTrack
principal = doc->NodePrincipal();
} else {
// we're either certain that we need isolation for the streams, OR
// we're not sure and we can fix the stream in SetDtlsConnected
principal = nsNullPrincipal::CreateWithInheritedAttributes(doc->NodePrincipal());
}
#endif
+ // We need to select unique ids, just use max + 1
+ TrackID maxTrackId = 0;
+ {
+ nsTArray<RefPtr<dom::MediaStreamTrack>> domTracks;
+ info->GetMediaStream()->GetTracks(domTracks);
+ for (auto& track : domTracks) {
+ maxTrackId = std::max(maxTrackId, track->mTrackID);
+ }
+ }
+
for (RefPtr<JsepTrack>& track : tracks) {
std::string webrtcTrackId(track->GetTrackId());
if (!info->HasTrack(webrtcTrackId)) {
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
RefPtr<RemoteTrackSource> source =
new RemoteTrackSource(principal, nsString());
#else
RefPtr<MediaStreamTrackSource> source = new MediaStreamTrackSource();
#endif
- TrackID trackID = info->GetNextAvailableNumericTrackId();
+ TrackID trackID = ++maxTrackId;
RefPtr<MediaStreamTrack> domTrack;
+ nsAutoPtr<MediaSegment> segment;
if (track->GetMediaType() == SdpMediaSection::kAudio) {
domTrack =
info->GetMediaStream()->CreateDOMTrack(trackID,
MediaSegment::AUDIO,
source);
+ segment = new AudioSegment;
} else {
domTrack =
info->GetMediaStream()->CreateDOMTrack(trackID,
MediaSegment::VIDEO,
source);
+#if !defined(MOZILLA_EXTERNAL_LINKAGE)
+ segment = new VideoSegment;
+#endif
}
+ StartTrack(info->GetMediaStream()->GetInputStream()->AsSourceStream(),
+ trackID, Move(segment));
info->AddTrack(webrtcTrackId, domTrack);
CSFLogDebug(logTag, "Added remote track %s/%s",
info->GetId().c_str(), webrtcTrackId.c_str());
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
domTrack->AssignId(NS_ConvertUTF8toUTF16(webrtcTrackId.c_str()));
aPco->OnAddTrack(*domTrack, streams, jrv);
if (jrv.Failed()) {
@@ -2204,30 +2280,16 @@ PeerConnectionImpl::PrincipalChanged(Med
if (doc) {
mMedia->UpdateSinkIdentity_m(aTrack, doc->NodePrincipal(), mPeerIdentity);
} else {
CSFLogInfo(logTag, "Can't update sink principal; document gone");
}
}
#endif
-#if !defined(MOZILLA_EXTERNAL_LINKAGE)
-nsresult
-PeerConnectionImpl::GetRemoteTrackId(const std::string streamId,
- const MediaStreamTrack& aTrack,
- std::string* trackId) const
-{
- if (IsClosed()) {
- return NS_ERROR_UNEXPECTED;
- }
-
- return mMedia->GetRemoteTrackId(streamId, aTrack, trackId);
-}
-#endif
-
std::string
PeerConnectionImpl::GetTrackId(const MediaStreamTrack& aTrack)
{
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
nsString wideTrackId;
aTrack.GetId(wideTrackId);
return NS_ConvertUTF16toUTF8(wideTrackId).get();
#else
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -643,19 +643,16 @@ public:
RTCStatsQuery *query);
static nsresult ExecuteStatsQuery_s(RTCStatsQuery *query);
// for monitoring changes in track ownership
// PeerConnectionMedia can't do it because it doesn't know about principals
virtual void PrincipalChanged(dom::MediaStreamTrack* aTrack) override;
- nsresult GetRemoteTrackId(const std::string streamId,
- const dom::MediaStreamTrack& track,
- std::string* trackId) const;
#endif
static std::string GetStreamId(const DOMMediaStream& aStream);
static std::string GetTrackId(const dom::MediaStreamTrack& track);
void OnMediaError(const std::string& aError);
private:
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -28,16 +28,20 @@
#include "FakeMediaStreams.h"
#else
#include "MediaSegment.h"
#ifdef MOZILLA_INTERNAL_API
#include "MediaStreamGraph.h"
#endif
#endif
+#ifndef USE_FAKE_MEDIA_STREAMS
+#include "MediaStreamGraphImpl.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"
@@ -106,19 +110,47 @@ PipelineDetachTransport_s(RefPtr<MediaPi
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
+SourceStreamInfo::EndTrack(MediaStream* stream, dom::MediaStreamTrack* track)
+{
+ if (!stream || !stream->AsSourceStream()) {
+ return;
+ }
+
+#if !defined(MOZILLA_EXTERNAL_LINKAGE)
+ class Message : public ControlMessage {
+ public:
+ Message(MediaStream* stream, TrackID track)
+ : ControlMessage(stream),
+ track_id_(track) {}
+
+ virtual void Run() override {
+ mStream->AsSourceStream()->EndTrack(track_id_);
+ }
+ private:
+ TrackID track_id_;
+ };
+
+ stream->GraphImpl()->AppendMessage(
+ MakeUnique<Message>(stream, track->mTrackID));
+#endif
+
+}
+
+void
SourceStreamInfo::RemoveTrack(const std::string& trackId)
{
mTracks.erase(trackId);
+
RefPtr<MediaPipeline> pipeline = GetPipelineByTrackId_m(trackId);
if (pipeline) {
mPipelines.erase(trackId);
pipeline->ShutdownMedia_m();
mParent->GetSTSThread()->Dispatch(
WrapRunnableNM(PipelineDetachTransport_s,
pipeline.forget(),
mParent->GetMainThread()),
@@ -940,33 +972,16 @@ PeerConnectionMedia::RemoveRemoteTrack(c
remoteSourceStream->RemoveTrack(trackId);
if (!remoteSourceStream->GetTrackCount()) {
mRemoteSourceStreams.RemoveElement(remoteSourceStream);
}
return NS_OK;
}
-nsresult
-PeerConnectionMedia::GetRemoteTrackId(const std::string streamId,
- const MediaStreamTrack& track,
- std::string* trackId) const
-{
- auto* ncThis = const_cast<PeerConnectionMedia*>(this);
- const RemoteSourceStreamInfo* info =
- ncThis->GetRemoteStreamById(streamId);
-
- if (!info) {
- CSFLogError(logTag, "%s: Could not find stream info", __FUNCTION__);
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return info->GetTrackId(track, trackId);
-}
-
void
PeerConnectionMedia::SelfDestruct()
{
ASSERT_ON_THREAD(mMainThread);
CSFLogDebug(logTag, "%s: ", __FUNCTION__);
// Shut down the media
@@ -1508,16 +1523,36 @@ SourceStreamInfo::StorePipeline(
return NS_ERROR_FAILURE;
}
mPipelines[trackId] = aPipeline;
return NS_OK;
}
void
+RemoteSourceStreamInfo::DetachMedia_m()
+{
+ for (auto& webrtcIdAndTrack : mTracks) {
+ EndTrack(mMediaStream->GetInputStream(), webrtcIdAndTrack.second);
+ }
+ SourceStreamInfo::DetachMedia_m();
+}
+
+void
+RemoteSourceStreamInfo::RemoveTrack(const std::string& trackId)
+{
+ auto it = mTracks.find(trackId);
+ if (it != mTracks.end()) {
+ EndTrack(mMediaStream->GetInputStream(), it->second);
+ }
+
+ SourceStreamInfo::RemoveTrack(trackId);
+}
+
+void
RemoteSourceStreamInfo::SyncPipeline(
RefPtr<MediaPipelineReceive> aPipeline)
{
// See if we have both audio and video here, and if so cross the streams and
// sync them
// TODO: Do we need to prevent multiple syncs if there is more than one audio
// or video track in a single media stream? What are we supposed to do in this
// case?
@@ -1545,17 +1580,16 @@ RemoteSourceStreamInfo::StartReceiving()
{
if (mReceiving || mPipelines.empty()) {
return;
}
mReceiving = true;
SourceMediaStream* source = GetMediaStream()->GetInputStream()->AsSourceStream();
- source->FinishAddTracks();
source->SetPullEnabled(true);
// AdvanceKnownTracksTicksTime(HEAT_DEATH_OF_UNIVERSE) means that in
// theory per the API, we can't add more tracks before that
// time. However, the impl actually allows it, and it avoids a whole
// bunch of locking that would be required (and potential blocking)
// if we used smaller values and updated them on each NotifyPull.
source->AdvanceKnownTracksTime(STREAM_TIME_MAX);
CSFLogDebug(logTag, "Finished adding tracks to MediaStream %p", source);
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
@@ -80,47 +80,48 @@ public:
nsresult StorePipeline(const std::string& trackId,
const RefPtr<MediaPipeline>& aPipeline);
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);
+ virtual 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);
// This is needed so PeerConnectionImpl can unregister itself as
// PrincipalChangeObserver from each track.
const std::map<std::string, RefPtr<dom::MediaStreamTrack>>&
GetMediaStreamTracks() const { return mTracks; }
- dom::MediaStreamTrack* GetTrackById(const std::string& trackId)
+ dom::MediaStreamTrack* GetTrackById(const std::string& trackId) const
{
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();
+ virtual void DetachMedia_m();
bool AnyCodecHasPluginID(uint64_t aPluginID);
protected:
+ void EndTrack(MediaStream* stream, dom::MediaStreamTrack* track);
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::map<std::string, RefPtr<dom::MediaStreamTrack>> mTracks;
std::map<std::string, RefPtr<MediaPipeline>> mPipelines;
};
@@ -195,81 +196,44 @@ class RemoteSourceStreamInfo : public So
RemoteSourceStreamInfo(already_AddRefed<DOMMediaStream> aMediaStream,
PeerConnectionMedia *aParent,
const std::string& aId)
: SourceStreamInfo(aMediaStream, aParent, aId),
mReceiving(false)
{
}
+ void DetachMedia_m() override;
+ void RemoveTrack(const std::string& trackId) override;
void SyncPipeline(RefPtr<MediaPipelineReceive> aPipeline);
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
void UpdatePrincipal_m(nsIPrincipal* aPrincipal);
#endif
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RemoteSourceStreamInfo)
void AddTrack(const std::string& trackId,
const RefPtr<dom::MediaStreamTrack>& aTrack) override
{
- 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);
- }
+ dom::MediaStreamTrack* track = GetTrackById(trackId);
+ if (!track) {
+ return TRACK_INVALID;
}
- return TRACK_INVALID;
- }
-
- nsresult GetTrackId(const dom::MediaStreamTrack& track, std::string* trackId) const
- {
- TrackID numericTrackId = track.mTrackID;
-
- if (numericTrackId <= 0 ||
- static_cast<size_t>(numericTrackId) > mTrackIdMap.size()) {
- return NS_ERROR_INVALID_ARG;;
- }
-
- *trackId = mTrackIdMap[numericTrackId - 1];
- return NS_OK;
+ return track->mTrackID;
}
void StartReceiving();
- /**
- * Returns true if a |MediaPipeline| should be queueing its track instead of
- * adding it to the |SourceMediaStream| directly.
- */
- bool ShouldQueueTracks() const
- {
- return !mReceiving;
- }
-
private:
- // For remote streams, the MediaStreamGraph API forces us to select a
- // numeric track id before creation of the MediaStreamTrack, and does not
- // allow us to specify a string-based id until later. We cannot simply use
- // something based on mline index, since renegotiation can move tracks
- // around. Hopefully someday we'll be able to specify the string id up-front,
- // and have the numeric track id selected for us, in which case this variable
- // and its dependencies can go away.
- std::vector<std::string> mTrackIdMap;
-
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
// MediaStreamTrackSources associated with this remote stream.
// We use them for updating their principal if that's needed.
std::vector<RefPtr<RemoteTrackSource>> mTrackSources;
#endif
// True iff SetPullEnabled(true) has been called on the DOMMediaStream. This
// happens when offer/answer concludes.
@@ -344,20 +308,16 @@ class PeerConnectionMedia : public sigsl
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,
- const dom::MediaStreamTrack& track,
- std::string* trackId) const;
-
// Get a specific local stream
uint32_t LocalStreamsLength()
{
return mLocalSourceStreams.Length();
}
LocalSourceStreamInfo* GetLocalStreamByIndex(int index);
LocalSourceStreamInfo* GetLocalStreamById(const std::string& id);
LocalSourceStreamInfo* GetLocalStreamByTrackId(const std::string& id);
--- a/media/webrtc/signaling/test/mediapipeline_unittest.cpp
+++ b/media/webrtc/signaling/test/mediapipeline_unittest.cpp
@@ -329,18 +329,17 @@ class TestAgentReceive : public TestAgen
audio_pipeline_ = new mozilla::MediaPipelineReceiveAudio(
test_pc,
nullptr,
test_utils->sts_target(),
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);
+ bundle_filter_);
audio_pipeline_->Init();
}
void SetBundleFilter(nsAutoPtr<MediaPipelineFilter> filter) {
bundle_filter_ = filter;
}