Bug 1208371 - Let PeerConnection consume principals from tracks instead of streams. r?mt
MozReview-Commit-ID: 4kp8wTFohxZ
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
@@ -673,20 +673,29 @@ void MediaPipelineTransmit::AttachToTrac
#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,
+void MediaPipelineTransmit::UpdateSinkIdentity_m(MediaStreamTrack* track,
+ nsIPrincipal* principal,
const PeerIdentity* sinkIdentity) {
ASSERT_ON_THREAD(main_thread_);
+ if (track != nullptr && track != domtrack_) {
+ // If a track is specified, then it might not be for this pipeline,
+ // since we receive notifications for all tracks on the PC.
+ // nullptr means that the PeerIdentity has changed and shall be applied
+ // to all tracks of the PC.
+ return;
+ }
+
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 = domtrack_->GetPeerIdentity();
if (sinkIdentity && trackIdentity) {
enableTrack = (*sinkIdentity == *trackIdentity);
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
@@ -396,19 +396,21 @@ public:
virtual nsresult Init() override;
virtual void AttachToTrack(const std::string& track_id);
// written and used from MainThread
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,
+ // When the principal of the domtrack changes, it calls through to here
+ // so that we can determine whether to enable track transmission.
+ // `track` has to be null or equal `domtrack_` for us to apply the update.
+ virtual void UpdateSinkIdentity_m(dom::MediaStreamTrack* track,
+ nsIPrincipal* principal,
const PeerIdentity* sinkIdentity);
#endif
// Called on the main thread.
virtual void DetachMedia() override {
ASSERT_ON_THREAD(main_thread_);
if (domtrack_) {
domtrack_->RemoveDirectListener(listener_);
--- a/media/webrtc/signaling/src/peerconnection/MediaPipelineFactory.cpp
+++ b/media/webrtc/signaling/src/peerconnection/MediaPipelineFactory.cpp
@@ -586,17 +586,18 @@ MediaPipelineFactory::CreateMediaPipelin
aRtpFlow,
aRtcpFlow,
aFilter);
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
// implement checking for peerIdentity (where failure == black/silence)
nsIDocument* doc = mPC->GetWindow()->GetExtantDoc();
if (doc) {
- pipeline->UpdateSinkIdentity_m(doc->NodePrincipal(),
+ pipeline->UpdateSinkIdentity_m(track,
+ doc->NodePrincipal(),
mPC->GetPeerIdentity());
} else {
MOZ_MTLOG(ML_ERROR, "Cannot initialize pipeline without attached doc");
return NS_ERROR_FAILURE; // Don't remove this till we know it's safe.
}
#endif
rv = pipeline->Init();
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -2135,17 +2135,18 @@ PeerConnectionImpl::SetPeerIdentity(cons
}
} else {
mPeerIdentity = new PeerIdentity(aPeerIdentity);
nsIDocument* doc = GetWindow()->GetExtantDoc();
if (!doc) {
CSFLogInfo(logTag, "Can't update principal on streams; document gone");
return NS_ERROR_FAILURE;
}
- mMedia->UpdateSinkIdentity_m(doc->NodePrincipal(), mPeerIdentity);
+ MediaStreamTrack* allTracks = nullptr;
+ mMedia->UpdateSinkIdentity_m(allTracks, doc->NodePrincipal(), mPeerIdentity);
}
return NS_OK;
}
#endif
nsresult
PeerConnectionImpl::SetDtlsConnected(bool aPrivacyRequested)
{
@@ -2168,20 +2169,20 @@ PeerConnectionImpl::SetDtlsConnected(boo
#endif
mDtlsConnected = true;
mPrivacyRequested = mPrivacyRequested || aPrivacyRequested;
return NS_OK;
}
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
void
-PeerConnectionImpl::PrincipalChanged(DOMMediaStream* aMediaStream) {
+PeerConnectionImpl::PrincipalChanged(MediaStreamTrack* aTrack) {
nsIDocument* doc = GetWindow()->GetExtantDoc();
if (doc) {
- mMedia->UpdateSinkIdentity_m(doc->NodePrincipal(), mPeerIdentity);
+ mMedia->UpdateSinkIdentity_m(aTrack, doc->NodePrincipal(), mPeerIdentity);
} else {
CSFLogInfo(logTag, "Can't update sink principal; document gone");
}
}
#endif
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
nsresult
@@ -2245,31 +2246,28 @@ PeerConnectionImpl::AddTrack(MediaStream
nsresult
PeerConnectionImpl::AddTrack(MediaStreamTrack& aTrack,
DOMMediaStream& aMediaStream)
{
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, 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()) {
- aMediaStream.AddPrincipalChangeObserver(this);
- }
+ aTrack.AddPrincipalChangeObserver(this);
if (aTrack.AsAudioStreamTrack()) {
res = AddTrackToJsepSession(SdpMediaSection::kAudio, streamId, trackId);
if (NS_FAILED(res)) {
return res;
}
mNumAudioStreams++;
}
@@ -2331,16 +2329,18 @@ PeerConnectionImpl::RemoveTrack(MediaStr
__FUNCTION__,
info->GetId().c_str(),
trackId.c_str());
return rv;
}
media()->RemoveLocalTrack(info->GetId(), trackId);
+ aTrack.RemovePrincipalChangeObserver(this);
+
OnNegotiationNeeded();
return NS_OK;
}
NS_IMETHODIMP
PeerConnectionImpl::ReplaceTrack(MediaStreamTrack& aThisTrack,
MediaStreamTrack& aWithTrack) {
@@ -2420,16 +2420,18 @@ PeerConnectionImpl::ReplaceTrack(MediaSt
ObString("Failed to replace track"),
jrv);
if (jrv.Failed()) {
CSFLogError(logTag, "Error firing replaceTrack error callback");
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
+ aThisTrack.RemovePrincipalChangeObserver(this);
+ aWithTrack.AddPrincipalChangeObserver(this);
pco->OnReplaceTrackSuccess(jrv);
if (jrv.Failed()) {
CSFLogError(logTag, "Error firing replaceTrack success callback");
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
@@ -2783,20 +2785,22 @@ void
PeerConnectionImpl::ShutdownMedia()
{
PC_AUTO_ENTER_API_CALL_NO_CHECK();
if (!mMedia)
return;
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
- // before we destroy references to local streams, detach from them
+ // before we destroy references to local tracks, detach from them
for(uint32_t i = 0; i < media()->LocalStreamsLength(); ++i) {
LocalSourceStreamInfo *info = media()->GetLocalStreamByIndex(i);
- info->GetMediaStream()->RemovePrincipalChangeObserver(this);
+ for (const auto& pair : info->GetMediaStreamTracks()) {
+ pair.second->RemovePrincipalChangeObserver(this);
+ }
}
// End of call to be recorded in Telemetry
if (!mStartTime.IsNull()){
TimeDuration timeDelta = TimeStamp::Now() - mStartTime;
Telemetry::Accumulate(mIsLoop ? Telemetry::LOOP_CALL_DURATION :
Telemetry::WEBRTC_CALL_DURATION,
timeDelta.ToSeconds());
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -26,29 +26,27 @@
#include "nsIThread.h"
#include "signaling/src/jsep/JsepSession.h"
#include "signaling/src/jsep/JsepSessionImpl.h"
#include "signaling/src/sdp/SdpMediaSection.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/PeerConnectionImplEnumsBinding.h"
+#include "PrincipalChangeObserver.h"
#include "StreamBuffer.h"
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
#include "mozilla/TimeStamp.h"
#include "mozilla/net/DataChannel.h"
#include "VideoUtils.h"
#include "VideoSegment.h"
#include "mozilla/dom/RTCStatsReportBinding.h"
#include "nsIPrincipal.h"
#include "mozilla/PeerIdentity.h"
-#ifndef USE_FAKE_MEDIA_STREAMS
-#include "DOMMediaStream.h"
-#endif
#endif
namespace test {
#ifdef USE_FAKE_PCOBSERVER
class AFakePCObserver;
#endif
}
@@ -243,17 +241,17 @@ class RTCStatsQuery {
nsresult res = CheckApiState(assert_ice_ready); \
if (NS_FAILED(res)) return; \
} while(0)
#define PC_AUTO_ENTER_API_CALL_NO_CHECK() CheckThread()
class PeerConnectionImpl final : public nsISupports,
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
public mozilla::DataChannelConnection::DataConnectionListener,
- public dom::PrincipalChangeObserver<DOMMediaStream>,
+ public dom::PrincipalChangeObserver<dom::MediaStreamTrack>,
#endif
public sigslot::has_slots<>
{
struct Internal; // Avoid exposing c includes to bindings
public:
explicit PeerConnectionImpl(const mozilla::dom::GlobalObject* aGlobal = nullptr);
@@ -643,19 +641,19 @@ public:
void startCallTelem();
nsresult BuildStatsQuery_m(
mozilla::dom::MediaStreamTrack *aSelector,
RTCStatsQuery *query);
static nsresult ExecuteStatsQuery_s(RTCStatsQuery *query);
- // for monitoring changes in stream ownership
+ // for monitoring changes in track ownership
// PeerConnectionMedia can't do it because it doesn't know about principals
- virtual void PrincipalChanged(DOMMediaStream* aMediaStream) override;
+ 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);
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -1227,34 +1227,37 @@ PeerConnectionMedia::UpdateRemoteStreamP
ASSERT_ON_THREAD(mMainThread);
for (uint32_t u = 0; u < mRemoteSourceStreams.Length(); u++) {
mRemoteSourceStreams[u]->UpdatePrincipal_m(aPrincipal);
}
}
void
-PeerConnectionMedia::UpdateSinkIdentity_m(nsIPrincipal* aPrincipal,
+PeerConnectionMedia::UpdateSinkIdentity_m(MediaStreamTrack* aTrack,
+ nsIPrincipal* aPrincipal,
const PeerIdentity* aSinkIdentity)
{
ASSERT_ON_THREAD(mMainThread);
for (uint32_t u = 0; u < mLocalSourceStreams.Length(); u++) {
- mLocalSourceStreams[u]->UpdateSinkIdentity_m(aPrincipal, aSinkIdentity);
+ mLocalSourceStreams[u]->UpdateSinkIdentity_m(aTrack, aPrincipal,
+ aSinkIdentity);
}
}
void
-LocalSourceStreamInfo::UpdateSinkIdentity_m(nsIPrincipal* aPrincipal,
+LocalSourceStreamInfo::UpdateSinkIdentity_m(MediaStreamTrack* aTrack,
+ nsIPrincipal* aPrincipal,
const PeerIdentity* aSinkIdentity)
{
for (auto it = mPipelines.begin(); it != mPipelines.end(); ++it) {
MediaPipelineTransmit* pipeline =
static_cast<MediaPipelineTransmit*>((*it).second.get());
- pipeline->UpdateSinkIdentity_m(aPrincipal, aSinkIdentity);
+ pipeline->UpdateSinkIdentity_m(aTrack, aPrincipal, aSinkIdentity);
}
}
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.
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
@@ -92,16 +92,20 @@ public:
}
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)
{
auto it = mTracks.find(trackId);
if (it == mTracks.end()) {
return nullptr;
}
return it->second;
@@ -137,17 +141,18 @@ public:
: 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,
+ void UpdateSinkIdentity_m(dom::MediaStreamTrack* aTrack,
+ nsIPrincipal* aPrincipal,
const PeerIdentity* aSinkIdentity);
#endif
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LocalSourceStreamInfo)
private:
already_AddRefed<MediaPipeline> ForgetPipelineByTrackId_m(
const std::string& trackId);
@@ -359,17 +364,19 @@ class PeerConnectionMedia : public sigsl
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,
+ // aTrack will be set if this update came from a principal change on aTrack.
+ void UpdateSinkIdentity_m(dom::MediaStreamTrack* aTrack,
+ nsIPrincipal* aPrincipal,
const PeerIdentity* aSinkIdentity);
// this determines if any stream is peerIdentity constrained
bool AnyLocalStreamHasPeerIdentity() const;
// When we finally learn who is on the other end, we need to change the ownership
// on streams
void UpdateRemoteStreamPrincipals_m(nsIPrincipal* aPrincipal);
#endif
--- a/media/webrtc/signaling/test/FakeMediaStreams.h
+++ b/media/webrtc/signaling/test/FakeMediaStreams.h
@@ -400,16 +400,25 @@ public:
AddListener(aListener);
aListener->NotifyDirectListenerInstalled(
Fake_MediaStreamTrackDirectListener::InstallationResult::STREAM_NOT_SUPPORTED);
}
void RemoveDirectListener(Fake_MediaStreamTrackDirectListener *aListener)
{
RemoveListener(aListener);
}
+
+ class PrincipalChangeObserver
+ {
+ public:
+ virtual void PrincipalChanged(Fake_MediaStreamTrack* aMediaStreamTrack) = 0;
+ };
+ void AddPrincipalChangeObserver(void* ignoredObserver) {}
+ void RemovePrincipalChangeObserver(void* ignoredObserver) {}
+
private:
~Fake_MediaStreamTrack() {}
const bool mIsVideo;
Fake_DOMMediaStream* mOwningStream;
mozilla::TrackID mTrackID;
std::string mID;
};
@@ -532,24 +541,16 @@ public:
return mVideoTrack;
}
default: {
MOZ_CRASH("Unkown media type");
}
}
}
- class PrincipalChangeObserver
- {
- public:
- virtual void PrincipalChanged(Fake_DOMMediaStream* aMediaStream) = 0;
- };
- void AddPrincipalChangeObserver(void* ignoredObserver) {}
- void RemovePrincipalChangeObserver(void* ignoredObserver) {}
-
private:
RefPtr<Fake_MediaStream> mMediaStream;
// tells the SDP generator about whether this
// MediaStream probably has audio and/or video
uint32_t mHintContents;
RefPtr<Fake_MediaStreamTrack> mVideoTrack;
RefPtr<Fake_MediaStreamTrack> mAudioTrack;