mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 01:48:05 +00:00
Bug 1032839 - replaceTrack API. r=smaug, r=jesup
This commit is contained in:
parent
7b12f55430
commit
838b08d7a0
@ -303,6 +303,9 @@ function RTCPeerConnection() {
|
||||
this._onCreateAnswerFailure = null;
|
||||
this._onGetStatsSuccess = null;
|
||||
this._onGetStatsFailure = null;
|
||||
this._onReplaceTrackSender = null;
|
||||
this._onReplaceTrackSuccess = null;
|
||||
this._onReplaceTrackFailure = null;
|
||||
|
||||
this._pendingType = null;
|
||||
this._localType = null;
|
||||
@ -812,7 +815,8 @@ RTCPeerConnection.prototype = {
|
||||
this._checkClosed();
|
||||
this._impl.addTrack(track, stream);
|
||||
let sender = this._win.RTCRtpSender._create(this._win,
|
||||
new RTCRtpSender(this, track));
|
||||
new RTCRtpSender(this, track,
|
||||
stream));
|
||||
this._senders.push({ sender: sender, stream: stream });
|
||||
return sender;
|
||||
},
|
||||
@ -822,6 +826,24 @@ RTCPeerConnection.prototype = {
|
||||
throw new this._win.DOMError("", "removeTrack not yet implemented");
|
||||
},
|
||||
|
||||
_replaceTrack: function(sender, withTrack, onSuccess, onError) {
|
||||
// TODO: Do a (sender._stream.getTracks().indexOf(track) == -1) check
|
||||
// on both track args someday.
|
||||
//
|
||||
// The proposed API will be that both tracks must already be in the same
|
||||
// stream. However, since our MediaStreams currently are limited to one
|
||||
// track per type, we allow replacement with an outside track not already
|
||||
// in the same stream.
|
||||
//
|
||||
// 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.
|
||||
|
||||
this._onReplaceTrackSender = sender;
|
||||
this._onReplaceTrackSuccess = onSuccess;
|
||||
this._onReplaceTrackFailure = onError;
|
||||
this._impl.replaceTrack(sender.track, withTrack, sender._stream);
|
||||
},
|
||||
|
||||
close: function() {
|
||||
if (this._closed) {
|
||||
return;
|
||||
@ -1306,6 +1328,15 @@ PeerConnectionObserver.prototype = {
|
||||
{ track: track }));
|
||||
},
|
||||
|
||||
onReplaceTrackSuccess: function() {
|
||||
this._dompc.callCB(this._dompc._onReplaceTrackSuccess);
|
||||
},
|
||||
|
||||
onReplaceTrackError: function(code, message) {
|
||||
this._dompc.callCB(this._dompc._onReplaceTrackError,
|
||||
new RTCError(code, message));
|
||||
},
|
||||
|
||||
foundIceCandidate: function(cand) {
|
||||
this.dispatchEvent(new this._dompc._win.RTCPeerConnectionIceEvent("icecandidate",
|
||||
{ candidate: cand } ));
|
||||
@ -1337,15 +1368,25 @@ RTCPeerConnectionStatic.prototype = {
|
||||
},
|
||||
};
|
||||
|
||||
function RTCRtpSender(pc, track) {
|
||||
this.pc = pc;
|
||||
function RTCRtpSender(pc, track, stream) {
|
||||
this._pc = pc;
|
||||
this.track = track;
|
||||
this._stream = stream;
|
||||
}
|
||||
RTCRtpSender.prototype = {
|
||||
classDescription: "RTCRtpSender",
|
||||
classID: PC_SENDER_CID,
|
||||
contractID: PC_SENDER_CONTRACT,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
|
||||
|
||||
replaceTrack: function(withTrack, onSuccess, onError) {
|
||||
this._pc._checkClosed();
|
||||
this._pc._queueOrRun({
|
||||
func: this._pc._replaceTrack,
|
||||
args: [this, withTrack, onSuccess, onError],
|
||||
wait: false
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function RTCRtpReceiver(pc, track) {
|
||||
|
@ -87,6 +87,8 @@ skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabl
|
||||
skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_offerRequiresReceiveVideoAudio.html]
|
||||
skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_replaceTrack.html]
|
||||
skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_setLocalAnswerInHaveLocalOffer.html]
|
||||
[test_peerConnection_setLocalAnswerInStable.html]
|
||||
[test_peerConnection_setLocalOfferInHaveRemoteOffer.html]
|
||||
|
@ -0,0 +1,61 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="templates.js"></script>
|
||||
<script type="application/javascript" src="turnConfig.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.8">
|
||||
createHTML({
|
||||
bug: "1032839",
|
||||
title: "Replace video track"
|
||||
});
|
||||
|
||||
function isSenderOfTrack(sender) {
|
||||
return sender.track == this;
|
||||
}
|
||||
|
||||
// Test basically just verifies that success callback is called at this point
|
||||
|
||||
var test;
|
||||
runNetworkTest(function () {
|
||||
test = new PeerConnectionTest();
|
||||
test.setMediaConstraints([{video: true}], [{video: true}]);
|
||||
test.chain.removeAfter("PC_REMOTE_CHECK_MEDIA_FLOW_PRESENT");
|
||||
test.chain.insertBefore("PC_LOCAL_CHECK_MEDIA_FLOW_PRESENT", [[
|
||||
"PC_LOCAL_REPLACE_VIDEOTRACK",
|
||||
function (test) {
|
||||
var stream = test.pcLocal._pc.getLocalStreams()[0];
|
||||
var track = stream.getVideoTracks()[0];
|
||||
var sender = test.pcLocal._pc.getSenders().find(isSenderOfTrack, track);
|
||||
ok(sender, "track has a sender");
|
||||
navigator.mozGetUserMedia({video:true, fake: true}, function(newStream) {
|
||||
sender.replaceTrack(newStream.getVideoTracks()[0],
|
||||
function() {
|
||||
ok(true, "replaceTrack success callback is called");
|
||||
test.next();
|
||||
},
|
||||
function(err) {
|
||||
ok(false, "replaceTrack failed with error = " + err);
|
||||
test.next();
|
||||
});
|
||||
},
|
||||
function(err) {
|
||||
ok(false, "mozGetUserMedia failed. error = " + err);
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
]]);
|
||||
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -44,6 +44,9 @@ interface PeerConnectionImpl {
|
||||
[Throws]
|
||||
void removeTrack(MediaStreamTrack track);
|
||||
[Throws]
|
||||
void replaceTrack(MediaStreamTrack thisTrack, MediaStreamTrack withTrack,
|
||||
MediaStream stream);
|
||||
[Throws]
|
||||
void closeStreams();
|
||||
|
||||
sequence<MediaStream> getLocalStreams();
|
||||
|
@ -28,6 +28,10 @@ interface PeerConnectionObserver
|
||||
void onGetStatsSuccess(optional RTCStatsReportInternal report);
|
||||
void onGetStatsError(unsigned long name, DOMString message);
|
||||
|
||||
/* replaceTrack callbacks */
|
||||
void onReplaceTrackSuccess();
|
||||
void onReplaceTrackError(unsigned long name, DOMString message);
|
||||
|
||||
/* Data channel callbacks */
|
||||
void notifyDataChannel(DataChannel channel);
|
||||
|
||||
|
@ -11,4 +11,8 @@
|
||||
JSImplementation="@mozilla.org/dom/rtpsender;1"]
|
||||
interface RTCRtpSender {
|
||||
readonly attribute MediaStreamTrack track;
|
||||
|
||||
void replaceTrack(MediaStreamTrack track,
|
||||
VoidFunction successCallback,
|
||||
RTCPeerConnectionErrorCallback failureCallback);
|
||||
};
|
||||
|
@ -1568,6 +1568,46 @@ PeerConnectionImpl::RemoveTrack(MediaStreamTrack& aTrack) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PeerConnectionImpl::ReplaceTrack(MediaStreamTrack& aThisTrack,
|
||||
MediaStreamTrack& aWithTrack,
|
||||
DOMMediaStream& aStream) {
|
||||
PC_AUTO_ENTER_API_CALL(true);
|
||||
|
||||
// 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
|
||||
// stream. However, since our MediaStreams currently are limited to one
|
||||
// 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.
|
||||
|
||||
// Insert magic here.
|
||||
bool success = true;
|
||||
|
||||
nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
|
||||
if (!pco) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
JSErrorResult rv;
|
||||
|
||||
if (success) {
|
||||
pco->OnReplaceTrackSuccess(rv);
|
||||
} else {
|
||||
pco->OnReplaceTrackError(kInternalError,
|
||||
ObString("Failed to replace track"),
|
||||
rv);
|
||||
}
|
||||
if (rv.Failed()) {
|
||||
CSFLogError(logTag, "Error firing replaceTrack callback");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
NS_IMETHODIMP
|
||||
PeerConnectionImpl::SetRemoteFingerprint(const char* hash, const char* fingerprint)
|
||||
|
@ -384,6 +384,14 @@ public:
|
||||
nsresult
|
||||
AddTrack(mozilla::dom::MediaStreamTrack& aTrack, DOMMediaStream& aStream);
|
||||
|
||||
NS_IMETHODIMP_TO_ERRORRESULT(ReplaceTrack, ErrorResult &rv,
|
||||
mozilla::dom::MediaStreamTrack& aThisTrack,
|
||||
mozilla::dom::MediaStreamTrack& aWithTrack,
|
||||
DOMMediaStream& aStream)
|
||||
{
|
||||
rv = ReplaceTrack(aThisTrack, aWithTrack, aStream);
|
||||
}
|
||||
|
||||
nsresult GetPeerIdentity(nsAString& peerIdentity)
|
||||
{
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
|
@ -84,6 +84,8 @@ public:
|
||||
virtual NS_IMETHODIMP OnRemoveStream(ER&) = 0;
|
||||
virtual NS_IMETHODIMP OnAddTrack(ER&) = 0;
|
||||
virtual NS_IMETHODIMP OnRemoveTrack(ER&) = 0;
|
||||
virtual NS_IMETHODIMP OnReplaceTrackSuccess(ER&) = 0;
|
||||
virtual NS_IMETHODIMP OnReplaceTrackError(uint32_t code, const char *msg, ER&) = 0;
|
||||
virtual NS_IMETHODIMP OnAddIceCandidateSuccess(ER&) = 0;
|
||||
virtual NS_IMETHODIMP OnAddIceCandidateError(uint32_t code, const char *msg, ER&) = 0;
|
||||
virtual NS_IMETHODIMP OnIceCandidate(uint16_t level, const char *mid,
|
||||
|
@ -273,6 +273,8 @@ public:
|
||||
NS_IMETHODIMP OnRemoveStream(ER&);
|
||||
NS_IMETHODIMP OnAddTrack(ER&);
|
||||
NS_IMETHODIMP OnRemoveTrack(ER&);
|
||||
NS_IMETHODIMP OnReplaceTrackSuccess(ER&);
|
||||
NS_IMETHODIMP OnReplaceTrackError(uint32_t code, const char *msg, ER&);
|
||||
NS_IMETHODIMP OnAddIceCandidateSuccess(ER&);
|
||||
NS_IMETHODIMP OnAddIceCandidateError(uint32_t code, const char *msg, ER&);
|
||||
NS_IMETHODIMP OnIceCandidate(uint16_t level, const char *mid, const char *cand, ER&);
|
||||
@ -472,6 +474,18 @@ TestObserver::OnRemoveTrack(ER&)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TestObserver::OnReplaceTrackSuccess(ER&)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TestObserver::OnReplaceTrackError(uint32_t code, const char *message, ER&)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TestObserver::OnIceCandidate(uint16_t level,
|
||||
const char * mid,
|
||||
|
Loading…
Reference in New Issue
Block a user