mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1095218 - Part 2: Multistream support. r=mt
--HG-- extra : rebase_source : d699a4408c351014e30be3b3dfe148bda14c643f
This commit is contained in:
parent
cc7a4509dc
commit
24ec1efc5e
@ -15,14 +15,20 @@ namespace dom {
|
||||
MediaStreamTrack::MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID)
|
||||
: mStream(aStream), mTrackID(aTrackID), mEnded(false), mEnabled(true)
|
||||
{
|
||||
memset(&mID, 0, sizeof(mID));
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIUUIDGenerator> uuidgen =
|
||||
do_GetService("@mozilla.org/uuid-generator;1", &rv);
|
||||
|
||||
nsID uuid;
|
||||
memset(&uuid, 0, sizeof(uuid));
|
||||
if (uuidgen) {
|
||||
uuidgen->GenerateUUIDInPlace(&mID);
|
||||
uuidgen->GenerateUUIDInPlace(&uuid);
|
||||
}
|
||||
|
||||
char chars[NSID_LENGTH];
|
||||
uuid.ToProvidedString(chars);
|
||||
mID = NS_ConvertASCIItoUTF16(chars);
|
||||
}
|
||||
|
||||
MediaStreamTrack::~MediaStreamTrack()
|
||||
@ -38,11 +44,9 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaStreamTrack)
|
||||
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
||||
|
||||
void
|
||||
MediaStreamTrack::GetId(nsAString& aID)
|
||||
MediaStreamTrack::GetId(nsAString& aID) const
|
||||
{
|
||||
char chars[NSID_LENGTH];
|
||||
mID.ToProvidedString(chars);
|
||||
aID = NS_ConvertASCIItoUTF16(chars);
|
||||
aID = mID;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -44,7 +44,7 @@ public:
|
||||
|
||||
// WebIDL
|
||||
virtual void GetKind(nsAString& aKind) = 0;
|
||||
void GetId(nsAString& aID);
|
||||
void GetId(nsAString& aID) const;
|
||||
void GetLabel(nsAString& aLabel) { aLabel.Truncate(); }
|
||||
bool Enabled() { return mEnabled; }
|
||||
void SetEnabled(bool aEnabled);
|
||||
@ -53,12 +53,16 @@ public:
|
||||
// Notifications from the MediaStreamGraph
|
||||
void NotifyEnded() { mEnded = true; }
|
||||
|
||||
// Webrtc allows the remote side to name tracks whatever it wants, and we
|
||||
// need to surface this to content.
|
||||
void AssignId(const nsAString& aID) { mID = aID; }
|
||||
|
||||
protected:
|
||||
virtual ~MediaStreamTrack();
|
||||
|
||||
nsRefPtr<DOMMediaStream> mStream;
|
||||
TrackID mTrackID;
|
||||
nsID mID;
|
||||
nsString mID;
|
||||
bool mEnded;
|
||||
bool mEnabled;
|
||||
};
|
||||
|
@ -132,12 +132,16 @@ skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabl
|
||||
[test_peerConnection_toJSON.html]
|
||||
skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
|
||||
|
||||
# multistream is not ready quite yet (bug 1056650)
|
||||
# [test_peerConnection_twoAudioStreams.html]
|
||||
# [test_peerConnection_twoAudioVideoStreams.html]
|
||||
# [test_peerConnection_twoAudioVideoStreamsCombined.html]
|
||||
# [test_peerConnection_twoVideoStreams.html]
|
||||
# [test_peerConnection_addSecondAudioStream.html]
|
||||
[test_peerConnection_twoAudioStreams.html]
|
||||
skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
|
||||
[test_peerConnection_twoAudioVideoStreams.html]
|
||||
skip-if = (toolkit == 'gonk' || (e10s && debug)) # b2g (Bug 1059867) or fd exhaustion on e10s debug intermittent (Bug 1126078)
|
||||
[test_peerConnection_twoAudioVideoStreamsCombined.html]
|
||||
skip-if = (toolkit == 'gonk' || (e10s && debug)) # b2g (Bug 1059867) or fd exhaustion on e10s debug intermittent (Bug 1126078)
|
||||
[test_peerConnection_twoVideoStreams.html]
|
||||
skip-if = (toolkit == 'gonk' || (e10s && debug)) # b2g (Bug 1059867) or fd exhaustion on e10s debug intermittent (Bug 1126078)
|
||||
# Renegotiation is not yet supported (bug 1017888)
|
||||
#[test_peerConnection_addSecondAudioStream.html]
|
||||
|
||||
# Bug 950317: Hack for making a cleanup hook after finishing all WebRTC cases
|
||||
[test_zmedia_cleanup.html]
|
||||
|
@ -1689,7 +1689,7 @@ PeerConnectionWrapper.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
var element = createMediaElement(type, this.label + '_' + side);
|
||||
var element = createMediaElement(type, this.label + '_' + side + this.streams.length);
|
||||
this.mediaCheckers.push(new MediaElementChecker(element));
|
||||
element.mozSrcObject = stream;
|
||||
element.play();
|
||||
@ -2321,6 +2321,27 @@ PeerConnectionWrapper.prototype = {
|
||||
|
||||
},
|
||||
|
||||
checkMsids : function PCW_checkMsids() {
|
||||
function _checkMsids(desc, streams, sdpLabel) {
|
||||
streams.forEach(function(stream) {
|
||||
stream.getTracks().forEach(function(track) {
|
||||
// TODO(bug 1089798): Once DOMMediaStream has an id field, we
|
||||
// should be verifying that the SDP contains
|
||||
// a=msid:<stream-id> <track-id>
|
||||
ok(desc.sdp.match(new RegExp("a=msid:[^ ]+ " + track.id)),
|
||||
sdpLabel + " SDP contains track id " + track.id );
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_checkMsids(this.localDescription,
|
||||
this._pc.getLocalStreams(),
|
||||
"local");
|
||||
_checkMsids(this.remoteDescription,
|
||||
this._pc.getRemoteStreams(),
|
||||
"remote");
|
||||
},
|
||||
|
||||
verifySdp : function PCW_verifySdp(desc, expectedType, offerConstraintsList,
|
||||
offerOptions, trickleIceCallback) {
|
||||
info("Examining this SessionDescription: " + JSON.stringify(desc));
|
||||
|
@ -492,6 +492,20 @@ var commandsPeerConnection = [
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_CHECK_MSID',
|
||||
function (test) {
|
||||
test.pcLocal.checkMsids();
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_CHECK_MSID',
|
||||
function (test) {
|
||||
test.pcRemote.checkMsids();
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_CHECK_STATS',
|
||||
function (test) {
|
||||
|
@ -1513,6 +1513,8 @@ JsepSessionImpl::ParseSdp(const std::string& sdp, UniquePtr<Sdp>* parsedp)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
std::set<std::string> trackIds;
|
||||
|
||||
for (size_t i = 0; i < parsed->GetMediaSectionCount(); ++i) {
|
||||
if (parsed->GetMediaSection(i).GetPort() == 0) {
|
||||
// Disabled, let this stuff slide.
|
||||
@ -1554,6 +1556,26 @@ JsepSessionImpl::ParseSdp(const std::string& sdp, UniquePtr<Sdp>* parsedp)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
std::string streamId;
|
||||
std::string trackId;
|
||||
nsresult rv = GetIdsFromMsid(*parsed,
|
||||
parsed->GetMediaSection(i),
|
||||
&streamId,
|
||||
&trackId);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (trackIds.count(trackId)) {
|
||||
JSEP_SET_ERROR("track id:" << trackId
|
||||
<< " appears in more than one m-section at level " << i);
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
trackIds.insert(trackId);
|
||||
} else if (rv != NS_ERROR_NOT_AVAILABLE) {
|
||||
// Error has already been set
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
*parsedp = Move(parsed);
|
||||
|
@ -547,17 +547,13 @@ nsresult MediaPipelineTransmit::Init() {
|
||||
return MediaPipeline::Init();
|
||||
}
|
||||
|
||||
void MediaPipelineTransmit::AttachToTrack(TrackID track_id) {
|
||||
char track_id_string[11];
|
||||
void MediaPipelineTransmit::AttachToTrack(const std::string& track_id) {
|
||||
ASSERT_ON_THREAD(main_thread_);
|
||||
|
||||
// We can replace this when we are allowed to do streams or std::to_string
|
||||
PR_snprintf(track_id_string, sizeof(track_id_string), "%d", track_id);
|
||||
|
||||
description_ = pc_ + "| ";
|
||||
description_ += conduit_->type() == MediaSessionConduit::AUDIO ?
|
||||
"Transmit audio[" : "Transmit video[";
|
||||
description_ += track_id_string;
|
||||
description_ += track_id;
|
||||
description_ += "]";
|
||||
|
||||
// TODO(ekr@rtfm.com): Check for errors
|
||||
@ -613,10 +609,11 @@ nsresult MediaPipelineTransmit::TransportReady_s(TransportInfo &info) {
|
||||
}
|
||||
|
||||
nsresult MediaPipelineTransmit::ReplaceTrack(DOMMediaStream *domstream,
|
||||
TrackID track_id) {
|
||||
const std::string& track_id) {
|
||||
// MainThread, checked in calls we make
|
||||
MOZ_MTLOG(ML_DEBUG, "Reattaching pipeline to stream "
|
||||
<< static_cast<void *>(domstream->GetStream()) << " conduit type=" <<
|
||||
MOZ_MTLOG(ML_DEBUG, "Reattaching pipeline " << description_ << " to stream "
|
||||
<< static_cast<void *>(domstream->GetStream())
|
||||
<< " track " << track_id << " conduit type=" <<
|
||||
(conduit_->type() == MediaSessionConduit::AUDIO ?"audio":"video"));
|
||||
|
||||
if (domstream_) { // may be excessive paranoia
|
||||
@ -624,7 +621,7 @@ nsresult MediaPipelineTransmit::ReplaceTrack(DOMMediaStream *domstream,
|
||||
}
|
||||
domstream_ = domstream; // Detach clears it
|
||||
stream_ = domstream->GetStream();
|
||||
//track_id_ = track_id; not threadsafe to change this; and we don't need to
|
||||
track_id_ = track_id;
|
||||
AttachToTrack(track_id);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1165,15 +1162,11 @@ void MediaPipelineTransmit::PipelineListener::ProcessVideoChunk(
|
||||
#endif
|
||||
|
||||
nsresult MediaPipelineReceiveAudio::Init() {
|
||||
char track_id_string[11];
|
||||
ASSERT_ON_THREAD(main_thread_);
|
||||
MOZ_MTLOG(ML_DEBUG, __FUNCTION__);
|
||||
|
||||
// We can replace this when we are allowed to do streams or std::to_string
|
||||
PR_snprintf(track_id_string, sizeof(track_id_string), "%d", track_id_);
|
||||
|
||||
description_ = pc_ + "| Receive audio[";
|
||||
description_ += track_id_string;
|
||||
description_ += track_id_;
|
||||
description_ += "]";
|
||||
|
||||
listener_->AddSelf(new AudioSegment());
|
||||
@ -1336,15 +1329,11 @@ NotifyPull(MediaStreamGraph* graph, StreamTime desired_time) {
|
||||
}
|
||||
|
||||
nsresult MediaPipelineReceiveVideo::Init() {
|
||||
char track_id_string[11];
|
||||
ASSERT_ON_THREAD(main_thread_);
|
||||
MOZ_MTLOG(ML_DEBUG, __FUNCTION__);
|
||||
|
||||
// We can replace this when we are allowed to do streams or std::to_string
|
||||
PR_snprintf(track_id_string, sizeof(track_id_string), "%d", track_id_);
|
||||
|
||||
description_ = pc_ + "| Receive video[";
|
||||
description_ += track_id_string;
|
||||
description_ += track_id_;
|
||||
description_ += "]";
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
|
@ -77,7 +77,7 @@ class MediaPipeline : public sigslot::has_slots<> {
|
||||
nsCOMPtr<nsIEventTarget> main_thread,
|
||||
nsCOMPtr<nsIEventTarget> sts_thread,
|
||||
MediaStream *stream,
|
||||
TrackID track_id,
|
||||
const std::string& track_id,
|
||||
int level,
|
||||
RefPtr<MediaSessionConduit> conduit,
|
||||
RefPtr<TransportFlow> rtp_transport,
|
||||
@ -130,9 +130,9 @@ class MediaPipeline : public sigslot::has_slots<> {
|
||||
nsAutoPtr<MediaPipelineFilter> filter);
|
||||
|
||||
virtual Direction direction() const { return direction_; }
|
||||
virtual TrackID trackid() const { return track_id_; }
|
||||
virtual const std::string& trackid() const { return track_id_; }
|
||||
virtual int level() const { return level_; }
|
||||
virtual bool IsVideo() const { return false; }
|
||||
virtual bool IsVideo() const = 0;
|
||||
|
||||
bool IsDoingRtcpMux() const {
|
||||
return (rtp_.type_ == MUX);
|
||||
@ -233,10 +233,10 @@ class MediaPipeline : public sigslot::has_slots<> {
|
||||
// Written on the main thread.
|
||||
// Used on STS and MediaStreamGraph threads.
|
||||
// May be changed by rtpSender.replaceTrack()
|
||||
TrackID track_id_; // The track on the stream.
|
||||
std::string track_id_; // The track on the stream.
|
||||
// Written and used as with the stream_;
|
||||
// Not used outside initialization in MediaPipelineTransmit
|
||||
int level_; // The m-line index (starting at 1, to match convention)
|
||||
int level_; // The m-line index (starting at 0, to match convention)
|
||||
RefPtr<MediaSessionConduit> conduit_; // Our conduit. Written on the main
|
||||
// thread. Read on STS thread.
|
||||
|
||||
@ -352,6 +352,7 @@ public:
|
||||
nsCOMPtr<nsIEventTarget> main_thread,
|
||||
nsCOMPtr<nsIEventTarget> sts_thread,
|
||||
DOMMediaStream *domstream,
|
||||
const std::string& track_id,
|
||||
int level,
|
||||
bool is_video,
|
||||
RefPtr<MediaSessionConduit> conduit,
|
||||
@ -359,7 +360,7 @@ public:
|
||||
RefPtr<TransportFlow> rtcp_transport,
|
||||
nsAutoPtr<MediaPipelineFilter> filter) :
|
||||
MediaPipeline(pc, TRANSMIT, main_thread, sts_thread,
|
||||
domstream->GetStream(), TRACK_INVALID, level,
|
||||
domstream->GetStream(), track_id, level,
|
||||
conduit, rtp_transport, rtcp_transport, filter),
|
||||
listener_(new PipelineListener(conduit)),
|
||||
domstream_(domstream),
|
||||
@ -369,7 +370,7 @@ public:
|
||||
// Initialize (stuff here may fail)
|
||||
virtual nsresult Init() MOZ_OVERRIDE;
|
||||
|
||||
virtual void AttachToTrack(TrackID track_id);
|
||||
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
|
||||
@ -403,7 +404,7 @@ public:
|
||||
// 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,
|
||||
TrackID track_id);
|
||||
const std::string& track_id);
|
||||
|
||||
|
||||
// Separate class to allow ref counting
|
||||
@ -518,7 +519,7 @@ class MediaPipelineReceive : public MediaPipeline {
|
||||
nsCOMPtr<nsIEventTarget> main_thread,
|
||||
nsCOMPtr<nsIEventTarget> sts_thread,
|
||||
MediaStream *stream,
|
||||
TrackID track_id,
|
||||
const std::string& track_id,
|
||||
int level,
|
||||
RefPtr<MediaSessionConduit> conduit,
|
||||
RefPtr<TransportFlow> rtp_transport,
|
||||
@ -547,17 +548,23 @@ class MediaPipelineReceiveAudio : public MediaPipelineReceive {
|
||||
nsCOMPtr<nsIEventTarget> main_thread,
|
||||
nsCOMPtr<nsIEventTarget> sts_thread,
|
||||
MediaStream *stream,
|
||||
TrackID track_id,
|
||||
// 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) :
|
||||
MediaPipelineReceive(pc, main_thread, sts_thread,
|
||||
stream, track_id, level, conduit, rtp_transport,
|
||||
rtcp_transport, filter),
|
||||
stream, media_stream_track_id, level, conduit,
|
||||
rtp_transport, rtcp_transport, filter),
|
||||
listener_(new PipelineListener(stream->AsSourceStream(),
|
||||
track_id, conduit)) {
|
||||
numeric_track_id, conduit)) {
|
||||
}
|
||||
|
||||
virtual void DetachMediaStream() MOZ_OVERRIDE {
|
||||
@ -568,6 +575,7 @@ class MediaPipelineReceiveAudio : public MediaPipelineReceive {
|
||||
}
|
||||
|
||||
virtual nsresult Init() MOZ_OVERRIDE;
|
||||
virtual bool IsVideo() const MOZ_OVERRIDE { return false; }
|
||||
|
||||
private:
|
||||
// Separate class to allow ref counting
|
||||
@ -610,17 +618,24 @@ class MediaPipelineReceiveVideo : public MediaPipelineReceive {
|
||||
nsCOMPtr<nsIEventTarget> main_thread,
|
||||
nsCOMPtr<nsIEventTarget> sts_thread,
|
||||
MediaStream *stream,
|
||||
TrackID track_id,
|
||||
// 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<VideoSessionConduit> conduit,
|
||||
RefPtr<TransportFlow> rtp_transport,
|
||||
RefPtr<TransportFlow> rtcp_transport,
|
||||
nsAutoPtr<MediaPipelineFilter> filter) :
|
||||
MediaPipelineReceive(pc, main_thread, sts_thread,
|
||||
stream, track_id, level, conduit, rtp_transport,
|
||||
rtcp_transport, filter),
|
||||
stream, media_stream_track_id, level, conduit,
|
||||
rtp_transport, rtcp_transport, filter),
|
||||
renderer_(new PipelineRenderer(this)),
|
||||
listener_(new PipelineListener(stream->AsSourceStream(), track_id)) {
|
||||
listener_(new PipelineListener(stream->AsSourceStream(),
|
||||
numeric_track_id)) {
|
||||
}
|
||||
|
||||
// Called on the main thread.
|
||||
@ -638,6 +653,7 @@ class MediaPipelineReceiveVideo : public MediaPipelineReceive {
|
||||
}
|
||||
|
||||
virtual nsresult Init() MOZ_OVERRIDE;
|
||||
virtual bool IsVideo() const MOZ_OVERRIDE { return true; }
|
||||
|
||||
private:
|
||||
class PipelineRenderer : public VideoRenderer {
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "signaling/src/jsep/JsepTransport.h"
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
#include "MediaStreamTrack.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@ -338,14 +339,18 @@ MediaPipelineFactory::CreateMediaPipelineReceiving(
|
||||
}
|
||||
}
|
||||
|
||||
// We need to choose a numeric track id for MediaStreamGraph to use. Must be
|
||||
// unique within the MediaStream, so level + 1 should be fine (cannot use 0).
|
||||
TrackID numericTrackId = aTrackPair.mLevel + 1;
|
||||
|
||||
if (aTrack.GetMediaType() == SdpMediaSection::kAudio) {
|
||||
pipeline = new MediaPipelineReceiveAudio(
|
||||
mPC->GetHandle(),
|
||||
mPC->GetMainThread().get(),
|
||||
mPC->GetSTSThread(),
|
||||
stream->GetMediaStream()->GetStream(),
|
||||
// Use the level + 1 as the track id. 0 is forbidden
|
||||
aTrackPair.mLevel + 1,
|
||||
aTrack.GetTrackId(),
|
||||
numericTrackId,
|
||||
aTrackPair.mLevel,
|
||||
static_cast<AudioSessionConduit*>(aConduit.get()), // Ugly downcast.
|
||||
aRtpFlow,
|
||||
@ -358,8 +363,8 @@ MediaPipelineFactory::CreateMediaPipelineReceiving(
|
||||
mPC->GetMainThread().get(),
|
||||
mPC->GetSTSThread(),
|
||||
stream->GetMediaStream()->GetStream(),
|
||||
// Use the level + 1 as the track id. 0 is forbidden
|
||||
aTrackPair.mLevel + 1,
|
||||
aTrack.GetTrackId(),
|
||||
numericTrackId,
|
||||
aTrackPair.mLevel,
|
||||
static_cast<VideoSessionConduit*>(aConduit.get()), // Ugly downcast.
|
||||
aRtpFlow,
|
||||
@ -377,7 +382,15 @@ MediaPipelineFactory::CreateMediaPipelineReceiving(
|
||||
return rv;
|
||||
}
|
||||
|
||||
stream->StorePipeline(aTrackPair.mLevel, SdpMediaSection::kVideo, pipeline);
|
||||
rv = stream->StorePipeline(aTrack.GetTrackId(),
|
||||
RefPtr<MediaPipeline>(pipeline));
|
||||
if (NS_FAILED(rv)) {
|
||||
MOZ_MTLOG(ML_ERROR, "Couldn't store receiving pipeline " <<
|
||||
static_cast<unsigned>(rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
stream->SyncPipeline(pipeline);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -415,10 +428,17 @@ MediaPipelineFactory::CreateMediaPipelineSending(
|
||||
|
||||
// Now we have all the pieces, create the pipeline
|
||||
RefPtr<MediaPipelineTransmit> pipeline = new MediaPipelineTransmit(
|
||||
mPC->GetHandle(), mPC->GetMainThread().get(), mPC->GetSTSThread(),
|
||||
stream->GetMediaStream(), aTrackPair.mLevel,
|
||||
aTrack.GetMediaType() == SdpMediaSection::kVideo, aConduit, aRtpFlow,
|
||||
aRtcpFlow, filter);
|
||||
mPC->GetHandle(),
|
||||
mPC->GetMainThread().get(),
|
||||
mPC->GetSTSThread(),
|
||||
stream->GetMediaStream(),
|
||||
aTrack.GetTrackId(),
|
||||
aTrackPair.mLevel,
|
||||
aTrack.GetMediaType() == SdpMediaSection::kVideo,
|
||||
aConduit,
|
||||
aRtpFlow,
|
||||
aRtcpFlow,
|
||||
filter);
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
// implement checking for peerIdentity (where failure == black/silence)
|
||||
@ -438,7 +458,13 @@ MediaPipelineFactory::CreateMediaPipelineSending(
|
||||
return rv;
|
||||
}
|
||||
|
||||
stream->StorePipeline(aTrackPair.mLevel, pipeline);
|
||||
rv = stream->StorePipeline(aTrack.GetTrackId(),
|
||||
RefPtr<MediaPipeline>(pipeline));
|
||||
if (NS_FAILED(rv)) {
|
||||
MOZ_MTLOG(ML_ERROR, "Couldn't store receiving pipeline " <<
|
||||
static_cast<unsigned>(rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -178,10 +178,18 @@ private:
|
||||
class TracksAvailableCallback : public DOMMediaStream::OnTracksAvailableCallback
|
||||
{
|
||||
public:
|
||||
TracksAvailableCallback(DOMMediaStream::TrackTypeHints aTrackTypeHints,
|
||||
TracksAvailableCallback(const std::list<std::string>& audioTrackIds,
|
||||
const std::list<std::string>& videoTrackIds,
|
||||
const std::set<std::string>& preexistingTrackIds,
|
||||
nsRefPtr<PeerConnectionObserver> aObserver)
|
||||
: DOMMediaStream::OnTracksAvailableCallback(aTrackTypeHints)
|
||||
, mObserver(aObserver) {}
|
||||
: DOMMediaStream::OnTracksAvailableCallback(
|
||||
// Once DOMMediaStream can handle more than one of each, this will change.
|
||||
(audioTrackIds.empty() ? 0 : DOMMediaStream::HINT_CONTENTS_AUDIO) |
|
||||
(videoTrackIds.empty() ? 0 : DOMMediaStream::HINT_CONTENTS_VIDEO))
|
||||
, mObserver(aObserver)
|
||||
, mAudioTrackIds(audioTrackIds)
|
||||
, mVideoTrackIds(videoTrackIds)
|
||||
, mPreexistingTrackIds(preexistingTrackIds) {}
|
||||
|
||||
virtual void NotifyTracksAvailable(DOMMediaStream* aStream) MOZ_OVERRIDE
|
||||
{
|
||||
@ -197,24 +205,68 @@ public:
|
||||
|
||||
nsTArray<nsRefPtr<MediaStreamTrack>> tracks;
|
||||
aStream->GetTracks(tracks);
|
||||
for (uint32_t i = 0; i < tracks.Length(); i++) {
|
||||
|
||||
for (size_t i = 0; i < tracks.Length(); i++) {
|
||||
if (mPreexistingTrackIds.count(
|
||||
PeerConnectionImpl::GetTrackId(*tracks[i]))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AssignNextIdToTrack(tracks[i]);
|
||||
JSErrorResult rv;
|
||||
mObserver->OnAddTrack(*tracks[i], rv);
|
||||
CSFLogInfo(logTag, "Calling OnAddTrack");
|
||||
CSFLogInfo(logTag, "Calling OnAddTrack(%s)",
|
||||
PeerConnectionImpl::GetTrackId(*tracks[i]).c_str());
|
||||
if (rv.Failed()) {
|
||||
CSFLogError(logTag, ": OnAddTrack(%d) failed! Error: %u", i,
|
||||
static_cast<uint32_t>(rv.ErrorCode()));
|
||||
CSFLogError(logTag, ": OnAddTrack(%u) failed! Error: %u",
|
||||
static_cast<unsigned>(i),
|
||||
static_cast<unsigned>(rv.ErrorCode()));
|
||||
}
|
||||
}
|
||||
|
||||
JSErrorResult rv;
|
||||
CSFLogInfo(logTag, "Calling OnAddStream");
|
||||
mObserver->OnAddStream(*aStream, rv);
|
||||
if (rv.Failed()) {
|
||||
CSFLogError(logTag, ": OnAddStream() failed! Error: %u", static_cast<uint32_t>(rv.ErrorCode()));
|
||||
CSFLogError(logTag, ": OnAddStream() failed! Error: %u",
|
||||
static_cast<unsigned>(rv.ErrorCode()));
|
||||
}
|
||||
|
||||
if (!mAudioTrackIds.empty() || !mVideoTrackIds.empty()) {
|
||||
CSFLogError(logTag, "Failed to assign %u audio and %u video tracks!",
|
||||
static_cast<unsigned>(mAudioTrackIds.size()),
|
||||
static_cast<unsigned>(mVideoTrackIds.size()));
|
||||
}
|
||||
}
|
||||
|
||||
void AssignNextIdToTrack(MediaStreamTrack* track)
|
||||
{
|
||||
std::list<std::string>* trackIds;
|
||||
|
||||
if (track->AsAudioStreamTrack()) {
|
||||
trackIds = &mAudioTrackIds;
|
||||
} else if (track->AsVideoStreamTrack()) {
|
||||
trackIds = &mVideoTrackIds;
|
||||
} else {
|
||||
MOZ_ASSERT(false, "Track is neither an AudioStreamTrack nor "
|
||||
"VideoStreamTrack");
|
||||
return;
|
||||
}
|
||||
|
||||
if (trackIds->empty()) {
|
||||
MOZ_ASSERT(false, "Too many new MediaStreamTracks were created");
|
||||
return;
|
||||
}
|
||||
|
||||
track->AssignId(NS_ConvertUTF8toUTF16(trackIds->front().c_str()));
|
||||
trackIds->pop_front();
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<PeerConnectionObserver> mObserver;
|
||||
std::list<std::string> mAudioTrackIds;
|
||||
std::list<std::string> mVideoTrackIds;
|
||||
const std::set<std::string> mPreexistingTrackIds;
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -1594,15 +1646,11 @@ PeerConnectionImpl::SetRemoteDescription(int32_t action, const char* aSDP)
|
||||
} else {
|
||||
// Add the tracks. This code is pretty complicated because the tracks
|
||||
// come in arbitrary orders and we want to group them by streamId.
|
||||
// We go through all the tracks and then for each track that represents
|
||||
// a new stream id, go through the rest of the tracks and deal with
|
||||
// them at once.
|
||||
size_t numTracks = mJsepSession->GetRemoteTrackCount();
|
||||
MOZ_ASSERT(numTracks <= 3);
|
||||
bool hasAudio = false;
|
||||
bool hasVideo = false;
|
||||
|
||||
std::set<std::string> streamsToNotify;
|
||||
// Group tracks by stream id
|
||||
std::map<std::string, std::vector<RefPtr<JsepTrack>>> tracksByStreamId;
|
||||
|
||||
for (size_t i = 0; i < numTracks; ++i) {
|
||||
RefPtr<JsepTrack> track;
|
||||
nrv = mJsepSession->GetRemoteTrack(i, &track);
|
||||
@ -1618,10 +1666,17 @@ PeerConnectionImpl::SetRemoteDescription(int32_t action, const char* aSDP)
|
||||
continue;
|
||||
}
|
||||
|
||||
tracksByStreamId[track->GetStreamId()].push_back(track);
|
||||
}
|
||||
|
||||
for (auto i = tracksByStreamId.begin(); i != tracksByStreamId.end(); ++i) {
|
||||
std::string streamId = i->first;
|
||||
std::vector<RefPtr<JsepTrack>>& tracks = i->second;
|
||||
|
||||
nsRefPtr<RemoteSourceStreamInfo> info =
|
||||
mMedia->GetRemoteStreamById(track->GetStreamId());
|
||||
mMedia->GetRemoteStreamById(streamId);
|
||||
if (!info) {
|
||||
nsresult nrv = CreateRemoteSourceStreamInfo(&info, track->GetStreamId());
|
||||
nsresult nrv = CreateRemoteSourceStreamInfo(&info, streamId);
|
||||
if (NS_FAILED(nrv)) {
|
||||
pco->OnSetRemoteDescriptionError(
|
||||
kInternalError,
|
||||
@ -1640,31 +1695,35 @@ PeerConnectionImpl::SetRemoteDescription(int32_t action, const char* aSDP)
|
||||
}
|
||||
}
|
||||
|
||||
streamsToNotify.insert(track->GetStreamId());
|
||||
// TODO(bug 1017888): Only get new tracks for renegotiation
|
||||
std::list<std::string> newAudioTrackIds;
|
||||
std::list<std::string> newVideoTrackIds;
|
||||
// TODO(bug 1017888): Fill in for renegotiation
|
||||
std::set<std::string> preexistingTrackIds;
|
||||
|
||||
for (auto j = tracks.begin(); j != tracks.end(); ++j) {
|
||||
RefPtr<JsepTrack> track = *j;
|
||||
if (track->GetMediaType() == SdpMediaSection::kAudio) {
|
||||
info->AddTrack(track->GetTrackId());
|
||||
newAudioTrackIds.push_back(track->GetTrackId());
|
||||
} else if (track->GetMediaType() == SdpMediaSection::kVideo) {
|
||||
info->AddTrack(track->GetTrackId());
|
||||
newVideoTrackIds.push_back(track->GetTrackId());
|
||||
} else {
|
||||
MOZ_ASSERT(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (track->GetMediaType() == mozilla::SdpMediaSection::kAudio) {
|
||||
MOZ_ASSERT(!hasAudio);
|
||||
(void)hasAudio;
|
||||
hasAudio = true;
|
||||
info->mTrackTypeHints |= DOMMediaStream::HINT_CONTENTS_AUDIO;
|
||||
} else if (track->GetMediaType() == mozilla::SdpMediaSection::kVideo) {
|
||||
MOZ_ASSERT(!hasVideo);
|
||||
(void)hasVideo;
|
||||
hasVideo = true;
|
||||
info->mTrackTypeHints |= DOMMediaStream::HINT_CONTENTS_VIDEO;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i = streamsToNotify.begin(); i != streamsToNotify.end(); ++i) {
|
||||
// Now that the streams are all set up, notify about track availability.
|
||||
// TODO(bug 1017888): Suppress on renegotiation when no change.
|
||||
nsRefPtr<RemoteSourceStreamInfo> info =
|
||||
mMedia->GetRemoteStreamById(*i);
|
||||
MOZ_ASSERT(info);
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
TracksAvailableCallback* tracksAvailableCallback =
|
||||
new TracksAvailableCallback(info->mTrackTypeHints, pco);
|
||||
new TracksAvailableCallback(newAudioTrackIds,
|
||||
newVideoTrackIds,
|
||||
preexistingTrackIds,
|
||||
pco);
|
||||
info->GetMediaStream()->OnTracksAvailable(tracksAvailableCallback);
|
||||
#else
|
||||
pco->OnAddStream(info->GetMediaStream(), jrv);
|
||||
@ -1875,6 +1934,18 @@ PeerConnectionImpl::PrincipalChanged(DOMMediaStream* aMediaStream) {
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string
|
||||
PeerConnectionImpl::GetTrackId(const MediaStreamTrack& aTrack)
|
||||
{
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
nsString wideTrackId;
|
||||
aTrack.GetId(wideTrackId);
|
||||
return NS_ConvertUTF16toUTF8(wideTrackId).get();
|
||||
#else
|
||||
return aTrack.GetId();
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult
|
||||
PeerConnectionImpl::AddTrack(MediaStreamTrack& aTrack,
|
||||
const Sequence<OwningNonNull<DOMMediaStream>>& aStreams)
|
||||
@ -1896,48 +1967,28 @@ PeerConnectionImpl::AddTrack(MediaStreamTrack& aTrack,
|
||||
CSFLogError(logTag, "%s: Track is not in stream", __FUNCTION__);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
uint32_t hints = aMediaStream.GetHintContents() &
|
||||
((aTrack.AsAudioStreamTrack()? DOMMediaStream::HINT_CONTENTS_AUDIO : 0) |
|
||||
(aTrack.AsVideoStreamTrack()? DOMMediaStream::HINT_CONTENTS_VIDEO : 0));
|
||||
|
||||
// XXX Remove this check once addStream has an error callback
|
||||
// available and/or we have plumbing to handle multiple
|
||||
// local audio streams. bug 1056650
|
||||
if ((hints & DOMMediaStream::HINT_CONTENTS_AUDIO) &&
|
||||
mNumAudioStreams > 0) {
|
||||
CSFLogError(logTag, "%s: Only one local audio stream is supported for now",
|
||||
__FUNCTION__);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// XXX Remove this check once addStream has an error callback
|
||||
// available and/or we have plumbing to handle multiple
|
||||
// local video streams. bug 1056650
|
||||
if ((hints & DOMMediaStream::HINT_CONTENTS_VIDEO) &&
|
||||
mNumVideoStreams > 0) {
|
||||
CSFLogError(logTag, "%s: Only one local video stream is supported for now",
|
||||
__FUNCTION__);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
uint32_t num = mMedia->LocalStreamsLength();
|
||||
|
||||
std::string streamId;
|
||||
// TODO(bug 1089798): These ids should really come from the MS.
|
||||
nsresult res = mMedia->AddStream(&aMediaStream, hints, &streamId);
|
||||
std::string trackId = PeerConnectionImpl::GetTrackId(aTrack);
|
||||
// TODO(bug 1089798): streamId should really come from the MS.
|
||||
nsresult res = mMedia->AddTrack(&aMediaStream, &streamId, trackId);
|
||||
if (NS_FAILED(res)) {
|
||||
return res;
|
||||
}
|
||||
|
||||
CSFLogDebug(logTag, "Added track (%s) to stream %p",
|
||||
trackId.c_str(), &aMediaStream);
|
||||
|
||||
if (num != mMedia->LocalStreamsLength()) {
|
||||
aMediaStream.AddPrincipalChangeObserver(this);
|
||||
}
|
||||
|
||||
if (hints & DOMMediaStream::HINT_CONTENTS_AUDIO) {
|
||||
if (aTrack.AsAudioStreamTrack()) {
|
||||
res = mJsepSession->AddTrack(new JsepTrack(
|
||||
mozilla::SdpMediaSection::kAudio,
|
||||
streamId,
|
||||
"audio_track_id",
|
||||
trackId,
|
||||
JsepTrack::kJsepTrackSending));
|
||||
if (NS_FAILED(res)) {
|
||||
std::string errorString = mJsepSession->GetLastError();
|
||||
@ -1948,11 +1999,19 @@ PeerConnectionImpl::AddTrack(MediaStreamTrack& aTrack,
|
||||
mNumAudioStreams++;
|
||||
}
|
||||
|
||||
if (hints & DOMMediaStream::HINT_CONTENTS_VIDEO) {
|
||||
if (aTrack.AsVideoStreamTrack()) {
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
if (!Preferences::GetBool("media.peerconnection.video.enabled", true)) {
|
||||
// Before this code was moved, this would silently ignore just like it
|
||||
// does now. Is this actually what we want to do?
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
res = mJsepSession->AddTrack(new JsepTrack(
|
||||
mozilla::SdpMediaSection::kVideo,
|
||||
streamId,
|
||||
"video_track_id",
|
||||
trackId,
|
||||
JsepTrack::kJsepTrackSending));
|
||||
if (NS_FAILED(res)) {
|
||||
std::string errorString = mJsepSession->GetLastError();
|
||||
@ -1977,6 +2036,15 @@ PeerConnectionImpl::ReplaceTrack(MediaStreamTrack& aThisTrack,
|
||||
DOMMediaStream& aStream) {
|
||||
PC_AUTO_ENTER_API_CALL(true);
|
||||
|
||||
JSErrorResult jrv;
|
||||
nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
|
||||
if (!pco) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
std::string origTrackId = PeerConnectionImpl::GetTrackId(aThisTrack);
|
||||
std::string newTrackId = PeerConnectionImpl::GetTrackId(aWithTrack);
|
||||
|
||||
// TODO: Do an aStream.HasTrack() check on both track args someday.
|
||||
//
|
||||
// The proposed API will be that both tracks must already be in the same
|
||||
@ -1984,9 +2052,15 @@ PeerConnectionImpl::ReplaceTrack(MediaStreamTrack& aThisTrack,
|
||||
// track per type, we allow replacement with an outside track not already
|
||||
// in the same stream. This works because sync happens receiver-side and
|
||||
// timestamps are tied to capture.
|
||||
//
|
||||
// Since a track may be replaced more than once, the track being replaced
|
||||
// may not be in the stream either, so we check neither arg right now.
|
||||
|
||||
if (!aStream.HasTrack(aThisTrack)) {
|
||||
CSFLogError(logTag, "Track to replace (%s) is not in stream",
|
||||
origTrackId.c_str());
|
||||
pco->OnReplaceTrackError(kInvalidMediastreamTrack,
|
||||
ObString("Track to replace is not in stream"),
|
||||
jrv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// XXX This MUST be addressed when we add multiple tracks of a type!!
|
||||
// This is needed because the track IDs used by MSG are from TrackUnion
|
||||
@ -1997,41 +2071,38 @@ PeerConnectionImpl::ReplaceTrack(MediaStreamTrack& aThisTrack,
|
||||
// TrackUnionStream's TrackID's, this value won't currently match what is used in
|
||||
// MediaPipelineTransmit. Bug 1056652
|
||||
// TrackID thisID = aThisTrack.GetTrackID();
|
||||
TrackID withID = aWithTrack.GetTrackID();
|
||||
//
|
||||
|
||||
bool success = false;
|
||||
for(uint32_t i = 0; i < media()->LocalStreamsLength(); ++i) {
|
||||
LocalSourceStreamInfo *info = media()->GetLocalStreamByIndex(i);
|
||||
// XXX use type instead of TrackID - bug 1056650
|
||||
int pipeline = info->HasTrackType(&aStream, !!(aThisTrack.AsVideoStreamTrack()));
|
||||
if (pipeline >= 0) {
|
||||
// XXX GetStream() will likely be invalid once a track can be in more than one
|
||||
info->ReplaceTrack(pipeline, aWithTrack.GetStream(), withID);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!success) {
|
||||
return NS_ERROR_FAILURE;
|
||||
nsRefPtr<LocalSourceStreamInfo> info =
|
||||
media()->GetLocalStreamByDomStream(aStream);
|
||||
|
||||
if (!info || !info->HasTrack(origTrackId)) {
|
||||
CSFLogError(logTag, "Track to replace (%s) was never added",
|
||||
origTrackId.c_str());
|
||||
pco->OnReplaceTrackError(kInvalidMediastreamTrack,
|
||||
ObString("Track to replace was never added"),
|
||||
jrv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
|
||||
if (!pco) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
JSErrorResult rv;
|
||||
|
||||
if (success) {
|
||||
pco->OnReplaceTrackSuccess(rv);
|
||||
} else {
|
||||
nsresult rv =
|
||||
info->ReplaceTrack(origTrackId, aWithTrack.GetStream(), newTrackId);
|
||||
if (NS_FAILED(rv)) {
|
||||
CSFLogError(logTag, "Failed to replace track (%s)",
|
||||
origTrackId.c_str());
|
||||
pco->OnReplaceTrackError(kInternalError,
|
||||
ObString("Failed to replace track"),
|
||||
rv);
|
||||
jrv);
|
||||
return NS_OK;
|
||||
}
|
||||
if (rv.Failed()) {
|
||||
|
||||
pco->OnReplaceTrackSuccess(jrv);
|
||||
|
||||
if (jrv.Failed()) {
|
||||
CSFLogError(logTag, "Error firing replaceTrack callback");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2676,16 +2747,19 @@ PeerConnectionImpl::BuildStatsQuery_m(
|
||||
|
||||
// Gather up pipelines from mMedia so they may be inspected on STS
|
||||
|
||||
std::string trackId;
|
||||
if (aSelector) {
|
||||
trackId = PeerConnectionImpl::GetTrackId(*aSelector);
|
||||
}
|
||||
|
||||
for (int i = 0, len = mMedia->LocalStreamsLength(); i < len; i++) {
|
||||
auto& pipelines = mMedia->GetLocalStreamByIndex(i)->GetPipelines();
|
||||
if (aSelector) {
|
||||
if (mMedia->GetLocalStreamByIndex(i)->GetMediaStream()->
|
||||
HasTrack(*aSelector)) {
|
||||
// XXX use type instead of TrackID - bug 1056650
|
||||
for (auto it = pipelines.begin(); it != pipelines.end(); ++it) {
|
||||
if (it->second->IsVideo() == !!aSelector->AsVideoStreamTrack()) {
|
||||
query->pipelines.AppendElement(it->second);
|
||||
}
|
||||
auto it = pipelines.find(trackId);
|
||||
if (it != pipelines.end()) {
|
||||
query->pipelines.AppendElement(it->second);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -2700,10 +2774,9 @@ PeerConnectionImpl::BuildStatsQuery_m(
|
||||
if (aSelector) {
|
||||
if (mMedia->GetRemoteStreamByIndex(i)->
|
||||
GetMediaStream()->HasTrack(*aSelector)) {
|
||||
for (auto it = pipelines.begin(); it != pipelines.end(); ++it) {
|
||||
if (it->second->trackid() == aSelector->GetTrackID()) {
|
||||
query->pipelines.AppendElement(it->second);
|
||||
}
|
||||
auto it = pipelines.find(trackId);
|
||||
if (it != pipelines.end()) {
|
||||
query->pipelines.AppendElement(it->second);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -2844,7 +2917,7 @@ PeerConnectionImpl::ExecuteStatsQuery_s(RTCStatsQuery *query) {
|
||||
NS_LITERAL_STRING("audio") : NS_LITERAL_STRING("video");
|
||||
nsString idstr = mediaType;
|
||||
idstr.AppendLiteral("_");
|
||||
idstr.AppendInt(mp.trackid());
|
||||
idstr.AppendInt(mp.level());
|
||||
|
||||
// Gather pipeline stats.
|
||||
switch (mp.direction()) {
|
||||
|
@ -601,6 +601,8 @@ public:
|
||||
virtual void PrincipalChanged(DOMMediaStream* aMediaStream) MOZ_OVERRIDE;
|
||||
#endif
|
||||
|
||||
static std::string GetTrackId(const dom::MediaStreamTrack& track);
|
||||
|
||||
private:
|
||||
virtual ~PeerConnectionImpl();
|
||||
PeerConnectionImpl(const PeerConnectionImpl&rhs);
|
||||
|
@ -43,144 +43,46 @@ using namespace mozilla::dom;
|
||||
namespace mozilla {
|
||||
|
||||
static const char* logTag = "PeerConnectionMedia";
|
||||
static const mozilla::TrackID TRACK_AUDIO = 0;
|
||||
static const mozilla::TrackID TRACK_VIDEO = 1;
|
||||
|
||||
/* If the ExpectAudio hint is on we will add a track at the default first
|
||||
* audio track ID (0)
|
||||
* FIX - Do we need to iterate over the tracks instead of taking these hints?
|
||||
*/
|
||||
void
|
||||
LocalSourceStreamInfo::ExpectAudio(const mozilla::TrackID aID)
|
||||
{
|
||||
mAudioTracks.AppendElement(aID);
|
||||
}
|
||||
|
||||
void
|
||||
LocalSourceStreamInfo::RemoveAudio(const mozilla::TrackID aID)
|
||||
{
|
||||
mAudioTracks.RemoveElement(aID);
|
||||
}
|
||||
|
||||
// If the ExpectVideo hint is on we will add a track at the default first
|
||||
// video track ID (1).
|
||||
void
|
||||
LocalSourceStreamInfo::ExpectVideo(const mozilla::TrackID aID)
|
||||
{
|
||||
mVideoTracks.AppendElement(aID);
|
||||
}
|
||||
|
||||
void
|
||||
LocalSourceStreamInfo::RemoveVideo(const mozilla::TrackID aID)
|
||||
{
|
||||
mVideoTracks.RemoveElement(aID);
|
||||
}
|
||||
|
||||
unsigned
|
||||
LocalSourceStreamInfo::AudioTrackCount()
|
||||
{
|
||||
return mAudioTracks.Length();
|
||||
}
|
||||
|
||||
unsigned
|
||||
LocalSourceStreamInfo::VideoTrackCount()
|
||||
{
|
||||
return mVideoTracks.Length();
|
||||
}
|
||||
|
||||
void LocalSourceStreamInfo::DetachTransport_s()
|
||||
{
|
||||
ASSERT_ON_THREAD(mParent->GetSTSThread());
|
||||
// walk through all the MediaPipelines and call the shutdown
|
||||
// functions for transport. Must be on the STS thread.
|
||||
for (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it =
|
||||
mPipelines.begin(); it != mPipelines.end();
|
||||
++it) {
|
||||
it->second->ShutdownTransport_s();
|
||||
}
|
||||
}
|
||||
|
||||
void LocalSourceStreamInfo::DetachMedia_m()
|
||||
{
|
||||
ASSERT_ON_THREAD(mParent->GetMainThread());
|
||||
// walk through all the MediaPipelines and call the shutdown
|
||||
// functions. Must be on the main thread.
|
||||
for (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it =
|
||||
mPipelines.begin(); it != mPipelines.end();
|
||||
++it) {
|
||||
it->second->ShutdownMedia_m();
|
||||
}
|
||||
mAudioTracks.Clear();
|
||||
mVideoTracks.Clear();
|
||||
mMediaStream = nullptr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// XXX bug 1056652 makes this not very useful for transmit streams
|
||||
// NOTE: index is != the trackid in the MediaStream
|
||||
int LocalSourceStreamInfo::HasTrack(DOMMediaStream* aStream, TrackID aTrack)
|
||||
{
|
||||
if (aStream != mMediaStream) {
|
||||
return -1;
|
||||
}
|
||||
for (auto it = mPipelines.begin(); it != mPipelines.end(); ++it) {
|
||||
if (it->second->trackid_locked() == aTrack) {
|
||||
return it->first;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// NOTE: index is != the trackid in the MediaStream
|
||||
int LocalSourceStreamInfo::HasTrackType(DOMMediaStream* aStream, bool aIsVideo)
|
||||
{
|
||||
if (aStream != mMediaStream) {
|
||||
return -1;
|
||||
}
|
||||
for (auto it = mPipelines.begin(); it != mPipelines.end(); ++it) {
|
||||
if (it->second->IsVideo() == aIsVideo) {
|
||||
return it->first;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// XXX revisit once we support multiple tracks of a type - bug 1056650
|
||||
nsresult LocalSourceStreamInfo::ReplaceTrack(int aMLine,
|
||||
nsresult LocalSourceStreamInfo::ReplaceTrack(const std::string& oldTrackId,
|
||||
DOMMediaStream* aNewStream,
|
||||
TrackID aNewTrack)
|
||||
const std::string& newTrackId)
|
||||
{
|
||||
// Note aMLine != aOldTrack!
|
||||
mozilla::RefPtr<mozilla::MediaPipeline> pipeline = mPipelines[aMLine];
|
||||
MOZ_ASSERT(pipeline);
|
||||
if (NS_SUCCEEDED(static_cast<mozilla::MediaPipelineTransmit*>(pipeline.get())->ReplaceTrack(aNewStream, aNewTrack))) {
|
||||
return NS_OK;
|
||||
mozilla::RefPtr<mozilla::MediaPipeline> pipeline = mPipelines[oldTrackId];
|
||||
|
||||
if (!pipeline || !mTracks.count(oldTrackId)) {
|
||||
CSFLogError(logTag, "Failed to find track id %s", oldTrackId.c_str());
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsresult rv =
|
||||
static_cast<mozilla::MediaPipelineTransmit*>(pipeline.get())->ReplaceTrack(
|
||||
aNewStream, newTrackId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mTracks.erase(oldTrackId);
|
||||
mTracks.insert(newTrackId);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void RemoteSourceStreamInfo::DetachTransport_s()
|
||||
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 (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it =
|
||||
mPipelines.begin(); it != mPipelines.end();
|
||||
++it) {
|
||||
for (auto it = mPipelines.begin(); it != mPipelines.end(); ++it) {
|
||||
it->second->ShutdownTransport_s();
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteSourceStreamInfo::DetachMedia_m()
|
||||
void SourceStreamInfo::DetachMedia_m()
|
||||
{
|
||||
ASSERT_ON_THREAD(mParent->GetMainThread());
|
||||
|
||||
// walk through all the MediaPipelines and call the shutdown
|
||||
// media functions. Must be on the main thread.
|
||||
for (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it =
|
||||
mPipelines.begin(); it != mPipelines.end();
|
||||
++it) {
|
||||
for (auto it = mPipelines.begin(); it != mPipelines.end(); ++it) {
|
||||
it->second->ShutdownMedia_m();
|
||||
}
|
||||
mMediaStream = nullptr;
|
||||
@ -663,9 +565,9 @@ PeerConnectionMedia::UpdateIceMediaStream_s(size_t aMLine,
|
||||
}
|
||||
|
||||
nsresult
|
||||
PeerConnectionMedia::AddStream(DOMMediaStream* aMediaStream,
|
||||
uint32_t hints,
|
||||
std::string *stream_id)
|
||||
PeerConnectionMedia::AddTrack(DOMMediaStream* aMediaStream,
|
||||
std::string* streamId,
|
||||
const std::string& trackId)
|
||||
{
|
||||
ASSERT_ON_THREAD(mMainThread);
|
||||
|
||||
@ -676,38 +578,9 @@ PeerConnectionMedia::AddStream(DOMMediaStream* aMediaStream,
|
||||
|
||||
CSFLogDebug(logTag, "%s: MediaStream: %p", __FUNCTION__, aMediaStream);
|
||||
|
||||
// Adding tracks here based on nsDOMMediaStream expectation settings
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
if (!Preferences::GetBool("media.peerconnection.video.enabled", true)) {
|
||||
hints &= ~(DOMMediaStream::HINT_CONTENTS_VIDEO);
|
||||
}
|
||||
#endif
|
||||
nsRefPtr<LocalSourceStreamInfo> localSourceStream =
|
||||
GetLocalStreamByDomStream(*aMediaStream);
|
||||
|
||||
if (!(hints & (DOMMediaStream::HINT_CONTENTS_AUDIO |
|
||||
DOMMediaStream::HINT_CONTENTS_VIDEO))) {
|
||||
CSFLogDebug(logTag, "Empty Stream !!");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Now see if we already have this stream or another stream with
|
||||
// tracks of the same type, since we only allow one track of each type.
|
||||
// TODO(ekr@rtfm.com): remove this when multiple of each stream
|
||||
// is allowed bug 1056650
|
||||
nsRefPtr<LocalSourceStreamInfo> localSourceStream = nullptr;
|
||||
|
||||
for (uint32_t u = 0; u < mLocalSourceStreams.Length(); u++) {
|
||||
auto& lss = mLocalSourceStreams[u];
|
||||
if (((hints & DOMMediaStream::HINT_CONTENTS_AUDIO) && lss->AudioTrackCount()) ||
|
||||
((hints & DOMMediaStream::HINT_CONTENTS_VIDEO) && lss->VideoTrackCount())) {
|
||||
CSFLogError(logTag, "Only one stream of any given type allowed");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (aMediaStream == lss->GetMediaStream()) {
|
||||
localSourceStream = lss;
|
||||
*stream_id = lss->GetId();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!localSourceStream) {
|
||||
std::string id;
|
||||
if (!mUuidGen->Generate(&id)) {
|
||||
@ -717,50 +590,38 @@ PeerConnectionMedia::AddStream(DOMMediaStream* aMediaStream,
|
||||
|
||||
localSourceStream = new LocalSourceStreamInfo(aMediaStream, this, id);
|
||||
mLocalSourceStreams.AppendElement(localSourceStream);
|
||||
*stream_id = id;
|
||||
}
|
||||
|
||||
if (hints & DOMMediaStream::HINT_CONTENTS_AUDIO) {
|
||||
localSourceStream->ExpectAudio(TRACK_AUDIO);
|
||||
}
|
||||
|
||||
if (hints & DOMMediaStream::HINT_CONTENTS_VIDEO) {
|
||||
localSourceStream->ExpectVideo(TRACK_VIDEO);
|
||||
}
|
||||
localSourceStream->AddTrack(trackId);
|
||||
*streamId = localSourceStream->GetId();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PeerConnectionMedia::RemoveStream(DOMMediaStream* aMediaStream,
|
||||
uint32_t hints,
|
||||
uint32_t *stream_id)
|
||||
PeerConnectionMedia::RemoveTrack(DOMMediaStream* aMediaStream,
|
||||
const std::string& trackId)
|
||||
{
|
||||
MOZ_ASSERT(aMediaStream);
|
||||
ASSERT_ON_THREAD(mMainThread);
|
||||
|
||||
CSFLogDebug(logTag, "%s: MediaStream: %p",
|
||||
__FUNCTION__, aMediaStream);
|
||||
CSFLogDebug(logTag, "%s: MediaStream: %p", __FUNCTION__, aMediaStream);
|
||||
|
||||
for (uint32_t u = 0; u < mLocalSourceStreams.Length(); u++) {
|
||||
nsRefPtr<LocalSourceStreamInfo> localSourceStream = mLocalSourceStreams[u];
|
||||
if (localSourceStream->GetMediaStream() == aMediaStream) {
|
||||
*stream_id = u;
|
||||
|
||||
if (hints & DOMMediaStream::HINT_CONTENTS_AUDIO) {
|
||||
localSourceStream->RemoveAudio(TRACK_AUDIO);
|
||||
}
|
||||
if (hints & DOMMediaStream::HINT_CONTENTS_VIDEO) {
|
||||
localSourceStream->RemoveAudio(TRACK_VIDEO);
|
||||
}
|
||||
if (!(localSourceStream->AudioTrackCount() +
|
||||
localSourceStream->VideoTrackCount())) {
|
||||
mLocalSourceStreams.RemoveElementAt(u);
|
||||
}
|
||||
return NS_OK;
|
||||
size_t i;
|
||||
for (i = 0; i < mLocalSourceStreams.Length(); ++i) {
|
||||
if (mLocalSourceStreams[i]->GetMediaStream() == aMediaStream) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
if (i == mLocalSourceStreams.Length()) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
mLocalSourceStreams[i]->RemoveTrack(trackId);
|
||||
if (!(mLocalSourceStreams[i]->GetTrackCount())) {
|
||||
mLocalSourceStreams.RemoveElementAt(i);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
@ -860,6 +721,33 @@ PeerConnectionMedia::GetLocalStreamById(const std::string& id)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LocalSourceStreamInfo*
|
||||
PeerConnectionMedia::GetLocalStreamByDomStream(const DOMMediaStream& stream)
|
||||
{
|
||||
ASSERT_ON_THREAD(mMainThread);
|
||||
for (size_t i = 0; i < mLocalSourceStreams.Length(); ++i) {
|
||||
if (&stream == mLocalSourceStreams[i]->GetMediaStream()) {
|
||||
return mLocalSourceStreams[i];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RemoteSourceStreamInfo*
|
||||
PeerConnectionMedia::GetRemoteStreamByDomStream(const DOMMediaStream& stream)
|
||||
{
|
||||
ASSERT_ON_THREAD(mMainThread);
|
||||
for (size_t i = 0; i < mRemoteSourceStreams.Length(); ++i) {
|
||||
if (&stream == mRemoteSourceStreams[i]->GetMediaStream()) {
|
||||
return mRemoteSourceStreams[i];
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RemoteSourceStreamInfo*
|
||||
PeerConnectionMedia::GetRemoteStreamByIndex(size_t aIndex)
|
||||
{
|
||||
@ -905,19 +793,19 @@ UpdateFilterFromRemoteDescription_s(
|
||||
|
||||
bool
|
||||
PeerConnectionMedia::UpdateFilterFromRemoteDescription_m(
|
||||
int aMLine,
|
||||
const std::string& trackId,
|
||||
nsAutoPtr<mozilla::MediaPipelineFilter> filter)
|
||||
{
|
||||
ASSERT_ON_THREAD(mMainThread);
|
||||
|
||||
RefPtr<mozilla::MediaPipeline> receive;
|
||||
for (size_t i = 0; !receive && i < mRemoteSourceStreams.Length(); ++i) {
|
||||
receive = mRemoteSourceStreams[i]->GetPipelineByLevel_m(aMLine);
|
||||
receive = mRemoteSourceStreams[i]->GetPipelineByTrackId_m(trackId);
|
||||
}
|
||||
|
||||
RefPtr<mozilla::MediaPipeline> transmit;
|
||||
for (size_t i = 0; !transmit && i < mLocalSourceStreams.Length(); ++i) {
|
||||
transmit = mLocalSourceStreams[i]->GetPipelineByLevel_m(aMLine);
|
||||
transmit = mLocalSourceStreams[i]->GetPipelineByTrackId_m(trackId);
|
||||
}
|
||||
|
||||
if (receive && transmit) {
|
||||
@ -935,8 +823,8 @@ PeerConnectionMedia::UpdateFilterFromRemoteDescription_m(
|
||||
NS_DISPATCH_NORMAL);
|
||||
return true;
|
||||
} else {
|
||||
CSFLogWarn(logTag, "Could not locate level %d to update filter",
|
||||
static_cast<int>(aMLine));
|
||||
CSFLogWarn(logTag, "Could not locate track %s to update filter",
|
||||
trackId.c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -951,27 +839,6 @@ PeerConnectionMedia::AddRemoteStream(nsRefPtr<RemoteSourceStreamInfo> aInfo)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PeerConnectionMedia::AddRemoteStreamHint(int aIndex, bool aIsVideo)
|
||||
{
|
||||
if (aIndex < 0 ||
|
||||
static_cast<unsigned int>(aIndex) >= mRemoteSourceStreams.Length()) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
RemoteSourceStreamInfo *pInfo = mRemoteSourceStreams.ElementAt(aIndex);
|
||||
MOZ_ASSERT(pInfo);
|
||||
|
||||
if (aIsVideo) {
|
||||
pInfo->mTrackTypeHints |= DOMMediaStream::HINT_CONTENTS_VIDEO;
|
||||
} else {
|
||||
pInfo->mTrackTypeHints |= DOMMediaStream::HINT_CONTENTS_AUDIO;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PeerConnectionMedia::IceGatheringStateChange_s(NrIceCtx* ctx,
|
||||
NrIceCtx::GatheringState state)
|
||||
@ -1235,7 +1102,7 @@ PeerConnectionMedia::AnyCodecHasPluginID(uint64_t aPluginID)
|
||||
}
|
||||
|
||||
bool
|
||||
LocalSourceStreamInfo::AnyCodecHasPluginID(uint64_t aPluginID)
|
||||
SourceStreamInfo::AnyCodecHasPluginID(uint64_t aPluginID)
|
||||
{
|
||||
// Scan the videoConduits for this plugin ID
|
||||
for (auto it = mPipelines.begin(); it != mPipelines.end(); ++it) {
|
||||
@ -1246,70 +1113,50 @@ LocalSourceStreamInfo::AnyCodecHasPluginID(uint64_t aPluginID)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RemoteSourceStreamInfo::AnyCodecHasPluginID(uint64_t aPluginID)
|
||||
nsresult
|
||||
SourceStreamInfo::StorePipeline(
|
||||
const std::string& trackId,
|
||||
const mozilla::RefPtr<mozilla::MediaPipeline>& aPipeline)
|
||||
{
|
||||
// Scan the videoConduits for this plugin ID
|
||||
for (auto it = mPipelines.begin(); it != mPipelines.end(); ++it) {
|
||||
if (it->second->Conduit()->CodecPluginID() == aPluginID) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
LocalSourceStreamInfo::StorePipeline(
|
||||
int aMLine, mozilla::RefPtr<mozilla::MediaPipelineTransmit> aPipeline)
|
||||
{
|
||||
MOZ_ASSERT(mPipelines.find(aMLine) == mPipelines.end());
|
||||
if (mPipelines.find(aMLine) != mPipelines.end()) {
|
||||
MOZ_ASSERT(mPipelines.find(trackId) == mPipelines.end());
|
||||
if (mPipelines.find(trackId) != mPipelines.end()) {
|
||||
CSFLogError(logTag, "%s: Storing duplicate track", __FUNCTION__);
|
||||
return;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
//TODO: Revisit once we start supporting multiple streams or multiple tracks
|
||||
// of same type bug 1056650
|
||||
mPipelines[aMLine] = aPipeline;
|
||||
mPipelines[trackId] = aPipeline;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
RemoteSourceStreamInfo::StorePipeline(
|
||||
int aMLine, bool aIsVideo,
|
||||
RemoteSourceStreamInfo::SyncPipeline(
|
||||
mozilla::RefPtr<mozilla::MediaPipelineReceive> aPipeline)
|
||||
{
|
||||
MOZ_ASSERT(mPipelines.find(aMLine) == mPipelines.end());
|
||||
if (mPipelines.find(aMLine) != mPipelines.end()) {
|
||||
CSFLogError(logTag, "%s: Request to store duplicate track %d", __FUNCTION__, aMLine);
|
||||
return;
|
||||
}
|
||||
CSFLogDebug(logTag, "%s track %d %s = %p", __FUNCTION__, aMLine, aIsVideo ? "video" : "audio",
|
||||
aPipeline.get());
|
||||
// See if we have both audio and video here, and if so cross the streams and sync them
|
||||
// XXX Needs to be adjusted when we support multiple streams of the same type bug 1056650
|
||||
for (std::map<int, bool>::iterator it = mTypes.begin(); it != mTypes.end(); ++it) {
|
||||
if (it->second != aIsVideo) {
|
||||
// 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?
|
||||
for (auto i = mPipelines.begin(); i != mPipelines.end(); ++i) {
|
||||
if (i->second->IsVideo() != aPipeline->IsVideo()) {
|
||||
// Ok, we have one video, one non-video - cross the streams!
|
||||
mozilla::WebrtcAudioConduit *audio_conduit = static_cast<mozilla::WebrtcAudioConduit*>
|
||||
(aIsVideo ?
|
||||
mPipelines[it->first]->Conduit() :
|
||||
aPipeline->Conduit());
|
||||
mozilla::WebrtcVideoConduit *video_conduit = static_cast<mozilla::WebrtcVideoConduit*>
|
||||
(aIsVideo ?
|
||||
aPipeline->Conduit() :
|
||||
mPipelines[it->first]->Conduit());
|
||||
mozilla::WebrtcAudioConduit *audio_conduit =
|
||||
static_cast<mozilla::WebrtcAudioConduit*>(aPipeline->IsVideo() ?
|
||||
i->second->Conduit() :
|
||||
aPipeline->Conduit());
|
||||
mozilla::WebrtcVideoConduit *video_conduit =
|
||||
static_cast<mozilla::WebrtcVideoConduit*>(aPipeline->IsVideo() ?
|
||||
aPipeline->Conduit() :
|
||||
i->second->Conduit());
|
||||
video_conduit->SyncTo(audio_conduit);
|
||||
CSFLogDebug(logTag, "Syncing %p to %p, %d to %d", video_conduit, audio_conduit,
|
||||
aMLine, it->first);
|
||||
CSFLogDebug(logTag, "Syncing %p to %p, %s to %s",
|
||||
video_conduit, audio_conduit,
|
||||
i->first.c_str(), aPipeline->trackid().c_str());
|
||||
}
|
||||
}
|
||||
//TODO: Revisit once we start supporting multiple streams or multiple tracks
|
||||
// of same type bug 1056650
|
||||
mPipelines[aMLine] = aPipeline;
|
||||
//TODO: move to attribute on Pipeline
|
||||
mTypes[aMLine] = aIsVideo;
|
||||
}
|
||||
|
||||
RefPtr<MediaPipeline> SourceStreamInfo::GetPipelineByLevel_m(int aMLine) {
|
||||
RefPtr<MediaPipeline> SourceStreamInfo::GetPipelineByTrackId_m(
|
||||
const std::string& trackId) {
|
||||
ASSERT_ON_THREAD(mParent->GetMainThread());
|
||||
|
||||
// Refuse to hand out references if we're tearing down.
|
||||
@ -1318,10 +1165,8 @@ RefPtr<MediaPipeline> SourceStreamInfo::GetPipelineByLevel_m(int aMLine) {
|
||||
// RefPtr<MediaPipeline>, since that reference won't be the last one
|
||||
// standing)
|
||||
if (mMediaStream) {
|
||||
for (auto p = mPipelines.begin(); p != mPipelines.end(); ++p) {
|
||||
if (p->second->level() == aMLine) {
|
||||
return p->second;
|
||||
}
|
||||
if (mPipelines.count(trackId)) {
|
||||
return mPipelines[trackId];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,18 +198,38 @@ public:
|
||||
return mMediaStream;
|
||||
}
|
||||
|
||||
nsresult StorePipeline(
|
||||
const std::string& trackId,
|
||||
const mozilla::RefPtr<mozilla::MediaPipeline>& aPipeline);
|
||||
|
||||
void AddTrack(const std::string& trackId) { mTracks.insert(trackId); }
|
||||
void RemoveTrack(const std::string& trackId) { mTracks.erase(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<mozilla::TrackID, mozilla::RefPtr<mozilla::MediaPipeline>>&
|
||||
const std::map<std::string, mozilla::RefPtr<mozilla::MediaPipeline>>&
|
||||
GetPipelines() const { return mPipelines; }
|
||||
mozilla::RefPtr<mozilla::MediaPipeline> GetPipelineByLevel_m(int aMLine);
|
||||
mozilla::RefPtr<mozilla::MediaPipeline> GetPipelineByTrackId_m(
|
||||
const std::string& trackId);
|
||||
const std::string& GetId() const { return mId; }
|
||||
|
||||
void DetachTransport_s();
|
||||
void DetachMedia_m();
|
||||
bool AnyCodecHasPluginID(uint64_t aPluginID);
|
||||
protected:
|
||||
std::map<mozilla::TrackID, mozilla::RefPtr<mozilla::MediaPipeline>> mPipelines;
|
||||
nsRefPtr<DOMMediaStream> mMediaStream;
|
||||
PeerConnectionMedia *mParent;
|
||||
const std::string mId;
|
||||
// These get set up before we generate our local description, the pipelines
|
||||
// are set up once offer/answer completes.
|
||||
std::set<std::string> mTracks;
|
||||
// Indexed by track id, might contain pipelines for removed tracks
|
||||
std::map<std::string, mozilla::RefPtr<mozilla::MediaPipeline>> mPipelines;
|
||||
};
|
||||
|
||||
// TODO(ekr@rtfm.com): Refactor {Local,Remote}SourceStreamInfo
|
||||
@ -224,40 +244,19 @@ public:
|
||||
const std::string& aId)
|
||||
: SourceStreamInfo(aMediaStream, aParent, aId) {}
|
||||
|
||||
// Returns the mPipelines index for the track or -1.
|
||||
#if 0
|
||||
int HasTrack(DOMMediaStream* aStream, mozilla::TrackID aMLine);
|
||||
#endif
|
||||
int HasTrackType(DOMMediaStream* aStream, bool aIsVideo);
|
||||
// XXX NOTE: does not change mMediaStream, even if it replaces the last track
|
||||
// in a LocalSourceStreamInfo. Revise when we have support for multiple tracks
|
||||
// of a type.
|
||||
// Note aMLine != aOldTrack! It's the result of HasTrackType()
|
||||
nsresult ReplaceTrack(int aMLine, DOMMediaStream* aNewStream, mozilla::TrackID aNewTrack);
|
||||
|
||||
void StorePipeline(int aMLine,
|
||||
mozilla::RefPtr<mozilla::MediaPipelineTransmit> aPipeline);
|
||||
nsresult ReplaceTrack(const std::string& oldTrackId,
|
||||
DOMMediaStream* aNewStream,
|
||||
const std::string& aNewTrack);
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
void UpdateSinkIdentity_m(nsIPrincipal* aPrincipal,
|
||||
const mozilla::PeerIdentity* aSinkIdentity);
|
||||
#endif
|
||||
|
||||
void ExpectAudio(const mozilla::TrackID);
|
||||
void ExpectVideo(const mozilla::TrackID);
|
||||
void RemoveAudio(const mozilla::TrackID);
|
||||
void RemoveVideo(const mozilla::TrackID);
|
||||
unsigned AudioTrackCount();
|
||||
unsigned VideoTrackCount();
|
||||
void DetachTransport_s();
|
||||
void DetachMedia_m();
|
||||
|
||||
bool AnyCodecHasPluginID(uint64_t aPluginID);
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LocalSourceStreamInfo)
|
||||
private:
|
||||
nsTArray<mozilla::TrackID> mAudioTracks;
|
||||
nsTArray<mozilla::TrackID> mVideoTracks;
|
||||
};
|
||||
|
||||
class RemoteSourceStreamInfo : public SourceStreamInfo {
|
||||
@ -266,28 +265,17 @@ class RemoteSourceStreamInfo : public SourceStreamInfo {
|
||||
RemoteSourceStreamInfo(already_AddRefed<DOMMediaStream> aMediaStream,
|
||||
PeerConnectionMedia *aParent,
|
||||
const std::string& aId)
|
||||
: SourceStreamInfo(aMediaStream, aParent, aId),
|
||||
mTrackTypeHints(0) {
|
||||
: SourceStreamInfo(aMediaStream, aParent, aId)
|
||||
{
|
||||
}
|
||||
|
||||
void StorePipeline(int aMLine, bool aIsVideo,
|
||||
mozilla::RefPtr<mozilla::MediaPipelineReceive> aPipeline);
|
||||
|
||||
void DetachTransport_s();
|
||||
void DetachMedia_m();
|
||||
void SyncPipeline(RefPtr<MediaPipelineReceive> aPipeline);
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
void UpdatePrincipal_m(nsIPrincipal* aPrincipal);
|
||||
#endif
|
||||
|
||||
bool AnyCodecHasPluginID(uint64_t aPluginID);
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RemoteSourceStreamInfo)
|
||||
|
||||
public:
|
||||
DOMMediaStream::TrackTypeHints mTrackTypeHints;
|
||||
private:
|
||||
std::map<int, bool> mTypes;
|
||||
};
|
||||
|
||||
class PeerConnectionMedia : public sigslot::has_slots<> {
|
||||
@ -333,14 +321,18 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
|
||||
// Handle complete media pipelines.
|
||||
nsresult UpdateMediaPipelines(const mozilla::JsepSession& session);
|
||||
|
||||
// Add a stream (main thread only)
|
||||
nsresult AddStream(DOMMediaStream* aMediaStream, uint32_t hints,
|
||||
std::string* stream_id);
|
||||
// Add a track (main thread only)
|
||||
// TODO(bug 1089798): Once DOMMediaStream has an id field, use it instead of
|
||||
// letting PCMedia choose a streamId
|
||||
nsresult AddTrack(DOMMediaStream* aMediaStream,
|
||||
std::string* streamId,
|
||||
const std::string& trackId);
|
||||
|
||||
// Remove a stream (main thread only)
|
||||
nsresult RemoveStream(DOMMediaStream* aMediaStream,
|
||||
uint32_t hints,
|
||||
uint32_t *stream_id);
|
||||
// Remove a track (main thread only)
|
||||
// TODO(bug 1089798): Once DOMMediaStream has an id field, use it instead of
|
||||
// passing |aMediaStream|
|
||||
nsresult RemoveTrack(DOMMediaStream* aMediaStream,
|
||||
const std::string& trackId);
|
||||
|
||||
// Get a specific local stream
|
||||
uint32_t LocalStreamsLength()
|
||||
@ -349,6 +341,8 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
|
||||
}
|
||||
LocalSourceStreamInfo* GetLocalStreamByIndex(int index);
|
||||
LocalSourceStreamInfo* GetLocalStreamById(const std::string& id);
|
||||
LocalSourceStreamInfo* GetLocalStreamByDomStream(
|
||||
const DOMMediaStream& stream);
|
||||
|
||||
// Get a specific remote stream
|
||||
uint32_t RemoteStreamsLength()
|
||||
@ -358,14 +352,16 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
|
||||
|
||||
RemoteSourceStreamInfo* GetRemoteStreamByIndex(size_t index);
|
||||
RemoteSourceStreamInfo* GetRemoteStreamById(const std::string& id);
|
||||
RemoteSourceStreamInfo* GetRemoteStreamByDomStream(
|
||||
const DOMMediaStream& stream);
|
||||
|
||||
|
||||
bool UpdateFilterFromRemoteDescription_m(
|
||||
int aMLine,
|
||||
const std::string& trackId,
|
||||
nsAutoPtr<mozilla::MediaPipelineFilter> filter);
|
||||
|
||||
// Add a remote stream.
|
||||
nsresult AddRemoteStream(nsRefPtr<RemoteSourceStreamInfo> aInfo);
|
||||
nsresult AddRemoteStreamHint(int aIndex, bool aIsVideo);
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
// In cases where the peer isn't yet identified, we disable the pipeline (not
|
||||
|
@ -556,7 +556,7 @@ typedef enum sdp_srtp_crypto_suite_t_ {
|
||||
|
||||
|
||||
/* Max number of stream ids that can be grouped together */
|
||||
#define SDP_MAX_MEDIA_STREAMS 10
|
||||
#define SDP_MAX_MEDIA_STREAMS 32
|
||||
|
||||
|
||||
#define SDP_MAGIC_NUM 0xabcdabcd
|
||||
|
@ -6,6 +6,8 @@
|
||||
#define FAKE_MEDIA_STREAM_H_
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "nsNetCID.h"
|
||||
#include "nsITimer.h"
|
||||
@ -13,6 +15,7 @@
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIComponentRegistrar.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
// #includes from MediaStream.h
|
||||
#include "mozilla/Mutex.h"
|
||||
@ -220,8 +223,16 @@ class Fake_MediaStreamTrack
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Fake_MediaStreamTrack)
|
||||
|
||||
explicit Fake_MediaStreamTrack(bool aIsVideo) : mIsVideo (aIsVideo) {}
|
||||
explicit Fake_MediaStreamTrack(bool aIsVideo) : mIsVideo (aIsVideo)
|
||||
{
|
||||
static size_t counter = 0;
|
||||
std::ostringstream os;
|
||||
os << counter++;
|
||||
mID = os.str();
|
||||
}
|
||||
mozilla::TrackID GetTrackID() { return mIsVideo ? 1 : 0; }
|
||||
std::string GetId() const { return mID; }
|
||||
void AssignId(const std::string& id) { mID = id; }
|
||||
Fake_DOMMediaStream *GetStream() { return nullptr; }
|
||||
const Fake_MediaStreamTrack* AsVideoStreamTrack() const
|
||||
{
|
||||
@ -235,6 +246,7 @@ private:
|
||||
~Fake_MediaStreamTrack() {}
|
||||
|
||||
const bool mIsVideo;
|
||||
std::string mID;
|
||||
};
|
||||
|
||||
class Fake_DOMMediaStream : public nsISupports
|
||||
|
@ -270,6 +270,7 @@ class TestAgentSend : public TestAgent {
|
||||
nullptr,
|
||||
test_utils->sts_target(),
|
||||
audio_,
|
||||
"audio_track_fake_uuid",
|
||||
1,
|
||||
false,
|
||||
audio_conduit_,
|
||||
@ -319,7 +320,7 @@ class TestAgentReceive : public TestAgent {
|
||||
test_pc,
|
||||
nullptr,
|
||||
test_utils->sts_target(),
|
||||
audio_->GetStream(), 1, 1,
|
||||
audio_->GetStream(), "audio_track_fake_uuid", 1, 1,
|
||||
static_cast<mozilla::AudioSessionConduit *>(audio_conduit_.get()),
|
||||
audio_rtp_transport_.flow_,
|
||||
audio_rtcp_transport_.flow_,
|
||||
|
@ -1327,8 +1327,14 @@ class SignalingAgent {
|
||||
}
|
||||
}
|
||||
|
||||
// Right now we have no convenient way for this unit-test to learn the track
|
||||
// ids of the tracks, so they can be queried later. We could either expose
|
||||
// the JsepSessionImpl in some way, or we could parse the identifiers out of
|
||||
// the SDP. For now, we just specify audio/video, since a given DOMMediaStream
|
||||
// can have only one of each anyway. Once this is fixed, we will need to
|
||||
// pass a real track id if we want to test that case.
|
||||
mozilla::RefPtr<mozilla::MediaPipeline> GetMediaPipeline(
|
||||
bool local, size_t stream, int track) {
|
||||
bool local, size_t stream, bool video) {
|
||||
SourceStreamInfo* streamInfo;
|
||||
if (local) {
|
||||
mozilla::SyncRunnable::DispatchToThread(
|
||||
@ -1348,11 +1354,16 @@ class SignalingAgent {
|
||||
|
||||
const auto &pipelines = streamInfo->GetPipelines();
|
||||
|
||||
auto it = pipelines.find(track);
|
||||
return (it == pipelines.end())? nullptr : it->second;
|
||||
for (auto i = pipelines.begin(); i != pipelines.end(); ++i) {
|
||||
if (i->second->IsVideo() == video) {
|
||||
std::cout << "Got MediaPipeline " << i->second->trackid();
|
||||
return i->second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CheckMediaPipeline(int stream, int track, uint32_t flags,
|
||||
void CheckMediaPipeline(int stream, bool video, uint32_t flags,
|
||||
VideoSessionConduit::FrameRequestType frameRequestMethod =
|
||||
VideoSessionConduit::FrameRequestNone) {
|
||||
|
||||
@ -1361,13 +1372,13 @@ class SignalingAgent {
|
||||
<< ((flags & PIPELINE_SEND) ? "sending " : "receiving ")
|
||||
<< ((flags & PIPELINE_VIDEO) ? "video" : "audio")
|
||||
<< " pipeline (stream " << stream
|
||||
<< ", track " << track << "); expect "
|
||||
<< ", track " << video << "); expect "
|
||||
<< ((flags & PIPELINE_RTCP_MUX) ? "MUX, " : "no MUX, ")
|
||||
<< ((flags & PIPELINE_RTCP_NACK) ? "NACK." : "no NACK.")
|
||||
<< std::endl;
|
||||
|
||||
mozilla::RefPtr<mozilla::MediaPipeline> pipeline =
|
||||
GetMediaPipeline((flags & PIPELINE_LOCAL), stream, track);
|
||||
GetMediaPipeline((flags & PIPELINE_LOCAL), stream, video);
|
||||
ASSERT_TRUE(pipeline);
|
||||
ASSERT_EQ(pipeline->IsDoingRtcpMux(), !!(flags & PIPELINE_RTCP_MUX));
|
||||
// We cannot yet test send/recv with video.
|
||||
@ -1938,12 +1949,12 @@ public:
|
||||
a2_->CloseReceiveStreams();
|
||||
|
||||
// Check caller video settings for remote pipeline
|
||||
a1_->CheckMediaPipeline(0, 1, (fRtcpMux ? PIPELINE_RTCP_MUX : 0) |
|
||||
a1_->CheckMediaPipeline(0, true, (fRtcpMux ? PIPELINE_RTCP_MUX : 0) |
|
||||
PIPELINE_VIDEO | rtcpFbFlags, frameRequestMethod);
|
||||
|
||||
// Check caller video settings for remote pipeline
|
||||
// (Should use pli and nack, regardless of what was in the offer)
|
||||
a2_->CheckMediaPipeline(0, 1,
|
||||
a2_->CheckMediaPipeline(0, true,
|
||||
(fRtcpMux ? PIPELINE_RTCP_MUX : 0) |
|
||||
PIPELINE_VIDEO |
|
||||
PIPELINE_SEND |
|
||||
@ -1978,12 +1989,12 @@ public:
|
||||
a2_->CloseReceiveStreams();
|
||||
|
||||
// Check callee video settings for remote pipeline
|
||||
a2_->CheckMediaPipeline(0, 1, (fRtcpMux ? PIPELINE_RTCP_MUX : 0) |
|
||||
a2_->CheckMediaPipeline(0, true, (fRtcpMux ? PIPELINE_RTCP_MUX : 0) |
|
||||
PIPELINE_VIDEO | rtcpFbFlags, frameRequestMethod);
|
||||
|
||||
// Check caller video settings for remote pipeline
|
||||
// (Should use pli and nack, regardless of what was in the offer)
|
||||
a1_->CheckMediaPipeline(0, 1,
|
||||
a1_->CheckMediaPipeline(0, true,
|
||||
(fRtcpMux ? PIPELINE_RTCP_MUX : 0) |
|
||||
PIPELINE_VIDEO |
|
||||
PIPELINE_SEND |
|
||||
@ -2559,12 +2570,12 @@ TEST_P(SignalingTest, FullCall)
|
||||
// Check the low-level media pipeline
|
||||
// for RTP and RTCP flows
|
||||
// The first Local pipeline gets stored at 0
|
||||
a1_->CheckMediaPipeline(0, 0, fRtcpMux ?
|
||||
a1_->CheckMediaPipeline(0, false, fRtcpMux ?
|
||||
PIPELINE_LOCAL | PIPELINE_RTCP_MUX | PIPELINE_SEND :
|
||||
PIPELINE_LOCAL | PIPELINE_SEND);
|
||||
|
||||
// The first Remote pipeline gets stored at 0
|
||||
a2_->CheckMediaPipeline(0, 0, (fRtcpMux ? PIPELINE_RTCP_MUX : 0));
|
||||
a2_->CheckMediaPipeline(0, false, (fRtcpMux ? PIPELINE_RTCP_MUX : 0));
|
||||
}
|
||||
|
||||
TEST_P(SignalingTest, FullCallAudioOnly)
|
||||
@ -3397,10 +3408,8 @@ TEST_P(SignalingTest, AudioOnlyCalleeNoRtcpMux)
|
||||
// Check the low-level media pipeline
|
||||
// for RTP and RTCP flows
|
||||
// The first Local pipeline gets stored at 0
|
||||
a1_->CheckMediaPipeline(0, 0, PIPELINE_LOCAL | PIPELINE_SEND);
|
||||
|
||||
// The first Remote pipeline gets stored at 1
|
||||
a2_->CheckMediaPipeline(0, 0, 0);
|
||||
a1_->CheckMediaPipeline(0, false, PIPELINE_LOCAL | PIPELINE_SEND);
|
||||
a2_->CheckMediaPipeline(0, false, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -3537,18 +3546,18 @@ TEST_P(SignalingTest, FullCallAudioNoMuxVideoMux)
|
||||
// Check the low-level media pipeline
|
||||
// for RTP and RTCP flows
|
||||
// The first Local pipeline gets stored at 0
|
||||
a1_->CheckMediaPipeline(0, 0, PIPELINE_LOCAL | PIPELINE_SEND);
|
||||
a1_->CheckMediaPipeline(0, false, PIPELINE_LOCAL | PIPELINE_SEND);
|
||||
|
||||
// Now check video mux.
|
||||
a1_->CheckMediaPipeline(0, 1,
|
||||
a1_->CheckMediaPipeline(0, true,
|
||||
PIPELINE_LOCAL | (fRtcpMux ? PIPELINE_RTCP_MUX : 0) | PIPELINE_SEND |
|
||||
PIPELINE_VIDEO);
|
||||
|
||||
// The first Remote pipeline gets stored at 0
|
||||
a2_->CheckMediaPipeline(0, 0, 0);
|
||||
a2_->CheckMediaPipeline(0, false, 0);
|
||||
|
||||
// Now check video mux.
|
||||
a2_->CheckMediaPipeline(0, 1, (fRtcpMux ? PIPELINE_RTCP_MUX : 0) |
|
||||
a2_->CheckMediaPipeline(0, true, (fRtcpMux ? PIPELINE_RTCP_MUX : 0) |
|
||||
PIPELINE_VIDEO | PIPELINE_RTCP_NACK, VideoSessionConduit::FrameRequestPli);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user