--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -21,27 +21,29 @@ const PC_OBS_CONTRACT = "@mozilla.org/do
const PC_ICE_CONTRACT = "@mozilla.org/dom/rtcicecandidate;1";
const PC_SESSION_CONTRACT = "@mozilla.org/dom/rtcsessiondescription;1";
const PC_MANAGER_CONTRACT = "@mozilla.org/dom/peerconnectionmanager;1";
const PC_STATS_CONTRACT = "@mozilla.org/dom/rtcstatsreport;1";
const PC_STATIC_CONTRACT = "@mozilla.org/dom/peerconnectionstatic;1";
const PC_SENDER_CONTRACT = "@mozilla.org/dom/rtpsender;1";
const PC_RECEIVER_CONTRACT = "@mozilla.org/dom/rtpreceiver;1";
const PC_COREQUEST_CONTRACT = "@mozilla.org/dom/createofferrequest;1";
+const PC_DTMF_SENDER_CONTRACT = "@mozilla.org/dom/rtcdtmfsender;1";
const PC_CID = Components.ID("{bdc2e533-b308-4708-ac8e-a8bfade6d851}");
const PC_OBS_CID = Components.ID("{d1748d4c-7f6a-4dc5-add6-d55b7678537e}");
const PC_ICE_CID = Components.ID("{02b9970c-433d-4cc2-923d-f7028ac66073}");
const PC_SESSION_CID = Components.ID("{1775081b-b62d-4954-8ffe-a067bbf508a7}");
const PC_MANAGER_CID = Components.ID("{7293e901-2be3-4c02-b4bd-cbef6fc24f78}");
const PC_STATS_CID = Components.ID("{7fe6e18b-0da3-4056-bf3b-440ef3809e06}");
const PC_STATIC_CID = Components.ID("{0fb47c47-a205-4583-a9fc-cbadf8c95880}");
const PC_SENDER_CID = Components.ID("{4fff5d46-d827-4cd4-a970-8fd53977440e}");
const PC_RECEIVER_CID = Components.ID("{d974b814-8fde-411c-8c45-b86791b81030}");
const PC_COREQUEST_CID = Components.ID("{74b2122d-65a8-4824-aa9e-3d664cb75dc2}");
+const PC_DTMF_SENDER_CID = Components.ID("{3610C242-654E-11E6-8EC0-6D1BE389A607}");
// Global list of PeerConnection objects, so they can be cleaned up when
// a page is torn down. (Maps inner window ID to an array of PC objects).
function GlobalPCList() {
this._list = {};
this._networkdown = false; // XXX Need to query current state somehow
this._lifecycleobservers = {};
this._nextId = 1;
@@ -1061,16 +1063,24 @@ RTCPeerConnection.prototype = {
this._checkClosed();
var i = this._senders.indexOf(sender);
if (i >= 0) {
this._senders.splice(i, 1);
this._impl.removeTrack(sender.track); // fires negotiation needed
}
},
+ _insertDTMF: function(sender, tones, duration, interToneGap) {
+ return this._impl.insertDTMF(sender.__DOM_IMPL__, tones, duration, interToneGap);
+ },
+
+ _getDTMFToneBuffer: function(sender) {
+ return this._impl.getDTMFToneBuffer(sender.__DOM_IMPL__);
+ },
+
_replaceTrack: function(sender, withTrack) {
// TODO: Do a (sender._stream.getTracks().indexOf(track) < 0) 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.
@@ -1555,17 +1565,21 @@ PeerConnectionObserver.prototype = {
{ candidate: cand } ));
},
notifyDataChannel: function(channel) {
this.dispatchEvent(new this._dompc._win.RTCDataChannelEvent("datachannel",
{ channel: channel }));
},
- onDTMFToneChangeEvent: function(trackId, tone) {
+ onDTMFToneChange: function(trackId, tone) {
+ var pc = this._dompc;
+ var sender = pc._senders.find(sender => sender.track.id == trackId)
+ sender.dtmf.dispatchEvent(new pc._win.RTCDTMFToneChangeEvent("tonechange",
+ { tone: tone }));
}
};
function RTCPeerConnectionStatic() {
}
RTCPeerConnectionStatic.prototype = {
classDescription: "RTCPeerConnectionStatic",
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
@@ -1579,20 +1593,68 @@ RTCPeerConnectionStatic.prototype = {
.getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
},
registerPeerConnectionLifecycleCallback: function(cb) {
_globalPCList._registerPeerConnectionLifecycleCallback(this._winID, cb);
},
};
+function RTCDTMFSender(sender) {
+ this._sender = sender;
+ this.duration = 100;
+ this.interToneGap = 70;
+}
+RTCDTMFSender.prototype = {
+ classDescription: "RTCDTMFSender",
+ classID: PC_DTMF_SENDER_CID,
+ contractID: PC_DTMF_SENDER_CONTRACT,
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
+
+ get toneBuffer() {
+ return this._sender._pc._getDTMFToneBuffer(this._sender);
+ },
+
+ get ontonechange() {
+ return this.__DOM_IMPL__.getEventHandler("ontonechange");
+ },
+
+ set ontonechange(handler) {
+ this.__DOM_IMPL__.setEventHandler("ontonechange", handler);
+ },
+
+ insertDTMF: function(tones, duration, interToneGap) {
+ this._sender._pc._checkClosed();
+
+ if (this._sender._pc._senders.indexOf(this._sender.__DOM_IMPL__) == -1) {
+ throw new this._sender._pc._win.DOMException("RTCRtpSender is stopped",
+ "InvalidStateError");
+ }
+
+ this.duration = Math.max(40, Math.min(duration, 6000));
+
+ if (interToneGap < 30) interToneGap = 30;
+ this.interToneGap = interToneGap;
+
+ tones = tones.toUpperCase();
+
+ if (tones.match(/[^0-9A-D#*,]/)) {
+ throw new this._sender._pc._win.DOMException("Invalid DTMF characters",
+ "InvalidCharacterError");
+ }
+
+ this._sender._pc._insertDTMF(this._sender, tones, duration, interToneGap);
+ },
+};
+
function RTCRtpSender(pc, track, stream) {
this._pc = pc;
this.track = track;
this._stream = stream;
+ this.dtmf = pc._win.RTCDTMFSender._create(pc._win, new RTCDTMFSender(this));
}
RTCRtpSender.prototype = {
classDescription: "RTCRtpSender",
classID: PC_SENDER_CID,
contractID: PC_SENDER_CONTRACT,
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
replaceTrack: function(withTrack) {
@@ -1630,16 +1692,17 @@ CreateOfferRequest.prototype = {
classDescription: "CreateOfferRequest",
classID: PC_COREQUEST_CID,
contractID: PC_COREQUEST_CONTRACT,
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(
[GlobalPCList,
+ RTCDTMFSender,
RTCIceCandidate,
RTCSessionDescription,
RTCPeerConnection,
RTCPeerConnectionStatic,
RTCRtpReceiver,
RTCRtpSender,
RTCStatsReport,
PeerConnectionObserver,