Fix for bug 711628 (Implement PeerConnection.localStreams/remoteStreams). r=bz.
authorPeter Van der Beken <peterv@propagandism.org>
Thu, 13 Sep 2012 18:04:31 +0200
changeset 110213 f7019f73a5f04902790c166d545dc946994bc207
parent 110212 a484a3a904da362b29305774990b4d8bad81b2d8
child 110214 2dbcd6d16b43f7aa2b7ba48e04cd3f8f303c04e5
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersbz
bugs711628
milestone19.0a1
Fix for bug 711628 (Implement PeerConnection.localStreams/remoteStreams). r=bz.
dom/bindings/Bindings.conf
dom/bindings/Makefile.in
dom/media/PeerConnection.js
dom/media/bridge/IPeerConnection.idl
dom/webidl/MediaStreamList.webidl
dom/webidl/WebIDL.mk
media/webrtc/signaling/signaling.gyp
media/webrtc/signaling/src/peerconnection/MediaStreamList.cpp
media/webrtc/signaling/src/peerconnection/MediaStreamList.h
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -242,16 +242,24 @@ DOMInterfaces = {
 {
     'nativeType': 'nsIInputStream',
     'notflattened': True
 },
 {
     'workers': True,
 }],
 
+'MediaStreamList': {
+    'headerFile': 'MediaStreamList.h',
+    'wrapperCache': False,
+    'nativeOwnership': 'owned',
+    'resultNotAddRefed': [ '__indexedGetter' ],
+    'binaryNames': { '__indexedGetter': 'IndexedGetter' }
+},
+
 'MozChannel': [
 {
     'nativeType': 'nsIChannel',
     'notflattened': True
 },
 {
     'workers': True,
 }],
@@ -603,16 +611,17 @@ addExternalIface('CSSRule')
 addExternalIface('CSSValue')
 addExternalIface('DOMStringList', nativeType='nsDOMStringList',
                  headerFile='nsDOMLists.h')
 addExternalIface('Element', nativeType='nsGenericElement')
 addExternalIface('File')
 addExternalIface('HitRegionOptions', nativeType='nsISupports')
 addExternalIface('HTMLElement')
 addExternalIface('ImageData', nativeType='mozilla::dom::ImageData')
+addExternalIface('MediaStream')
 addExternalIface('Node', nativeType='nsINode')
 addExternalIface('PaintRequest')
 addExternalIface('SVGLength')
 addExternalIface('SVGMatrix')
 addExternalIface('SVGNumber')
 addExternalIface('SVGPathSeg')
 addExternalIface('SVGPoint')
 addExternalIface('SVGTransform')
--- a/dom/bindings/Makefile.in
+++ b/dom/bindings/Makefile.in
@@ -67,17 +67,18 @@ EXPORTS_$(binding_include_path) = \
   UnionConversions.h \
   UnionTypes.h \
   $(exported_binding_headers) \
   $(NULL)
 
 LOCAL_INCLUDES += -I$(topsrcdir)/js/xpconnect/src \
   -I$(topsrcdir)/js/xpconnect/wrappers \
   -I$(topsrcdir)/content/canvas/src \
-  -I$(topsrcdir)/content/html/content/src
+  -I$(topsrcdir)/content/html/content/src \
+  -I$(topsrcdir)/media/webrtc/signaling/src/peerconnection
 
 include $(topsrcdir)/config/rules.mk
 
 # If you change bindinggen_dependencies here, change it in
 # dom/bindings/test/Makefile.in too.
 bindinggen_dependencies := \
   BindingGen.py \
   Bindings.conf \
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -399,16 +399,23 @@ PeerConnection.prototype = {
   close: function() {
     this._queueOrRun({
       func: this._pc.close,
       args: [],
       wait: false
     });
   },
 
+  get localStreams() {
+    return this._pc.localStreams;
+  },
+  get remoteStreams() {
+    return this._pc.remoteStreams;
+  },
+
   createDataChannel: function(label, dict) {
     if (dict &&
         dict.maxRetransmitTime != undefined &&
         dict.maxRetransmitNum != undefined) {
       throw new Error("Both maxRetransmitTime and maxRetransmitNum cannot be provided");
     }
 
     // Must determine the type where we still know if entries are undefined.
--- a/dom/media/bridge/IPeerConnection.idl
+++ b/dom/media/bridge/IPeerConnection.idl
@@ -78,16 +78,19 @@ interface IPeerConnection : nsISupports
   void setLocalDescription(in long action, in string sdp);
   void setRemoteDescription(in long action, in string sdp);
 
   /* Adds the stream created by GetUserMedia */
   void addStream(in nsIDOMMediaStream stream);
   void removeStream(in nsIDOMMediaStream stream);
   void closeStreams();
 
+  [implicit_jscontext] readonly attribute jsval localStreams; // MediaStream[]
+  [implicit_jscontext] readonly attribute jsval remoteStreams; // MediaStream[]
+
   /* As the ICE candidates roll in this one should be called each time
    * in order to keep the candidate list up-to-date for the next SDP-related
    * call PeerConnectionImpl does not parse ICE candidates, just sticks them
    * into the SDP.
    */
   void addIceCandidate(in string candidate, in string mid, in unsigned short level);
 
   /* Puts the SIPCC engine back to 'kIdle', shuts down threads, deletes state */
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MediaStreamList.webidl
@@ -0,0 +1,13 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+interface MediaStream;
+
+[NoInterfaceObject]
+interface MediaStreamList {
+  getter MediaStream? (unsigned long index);
+  readonly attribute unsigned long length;
+};
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -25,16 +25,17 @@ webidl_files = \
   EventHandler.webidl \
   EventListener.webidl \
   EventTarget.webidl \
   FileList.webidl \
   FileReaderSync.webidl \
   HTMLCollection.webidl \
   HTMLOptionsCollection.webidl \
   HTMLPropertiesCollection.webidl \
+  MediaStreamList.webidl \
   NodeList.webidl \
   PaintRequestList.webidl \
   Performance.webidl \
   PerformanceNavigation.webidl \
   PerformanceTiming.webidl \
   SVGLengthList.webidl \
   SVGNumberList.webidl \
   SVGPathSegList.webidl \
--- a/media/webrtc/signaling/signaling.gyp
+++ b/media/webrtc/signaling/signaling.gyp
@@ -123,16 +123,18 @@
         './src/softphonewrapper/CC_SIPCCCallServerInfo.h',
         './src/softphonewrapper/CC_SIPCCDevice.h',
         './src/softphonewrapper/CC_SIPCCDeviceInfo.h',
         './src/softphonewrapper/CC_SIPCCFeatureInfo.h',
         './src/softphonewrapper/CC_SIPCCLine.h',
         './src/softphonewrapper/CC_SIPCCLineInfo.h',
         './src/softphonewrapper/CC_SIPCCService.h',
         # PeerConnection
+        './src/peerconnection/MediaStreamList.cpp',
+        './src/peerconnection/MediaStreamList.h',
         './src/peerconnection/PeerConnectionCtx.cpp',
         './src/peerconnection/PeerConnectionCtx.h',
         './src/peerconnection/PeerConnectionImpl.cpp',
         './src/peerconnection/PeerConnectionImpl.h',
         # Media pipeline
         './src/mediapipeline/MediaPipeline.h',
         './src/mediapipeline/MediaPipeline.cpp',
         './src/mediapipeline/SrtpFlow.h',
new file mode 100644
--- /dev/null
+++ b/media/webrtc/signaling/src/peerconnection/MediaStreamList.cpp
@@ -0,0 +1,83 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "base/basictypes.h"
+#include "MediaStreamList.h"
+#ifdef MOZILLA_INTERNAL_API
+#include "mozilla/dom/MediaStreamListBinding.h"
+#endif
+#include "nsIScriptGlobalObject.h"
+#include "PeerConnectionImpl.h"
+
+namespace mozilla {
+namespace dom {
+
+MediaStreamList::MediaStreamList(sipcc::PeerConnectionImpl* peerConnection,
+                                 StreamType type)
+  : mPeerConnection(peerConnection),
+    mType(type)
+{
+  MOZ_COUNT_CTOR(mozilla::dom::MediaStreamList);
+}
+
+MediaStreamList::~MediaStreamList()
+{
+  MOZ_COUNT_DTOR(mozilla::dom::MediaStreamList);
+}
+
+JSObject*
+MediaStreamList::WrapObject(JSContext* cx, ErrorResult& error)
+{
+#ifdef MOZILLA_INTERNAL_API
+  nsCOMPtr<nsIScriptGlobalObject> global =
+    do_QueryInterface(mPeerConnection->GetWindow());
+  JSObject* scope = global->GetGlobalJSObject();
+  if (!scope) {
+    error.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  JSAutoCompartment ac(cx, scope);
+  JSObject* obj = MediaStreamListBinding::Wrap(cx, scope, this);
+  if (!obj) {
+    error.Throw(NS_ERROR_FAILURE);
+  }
+  return obj;
+#else
+  return nullptr;
+#endif
+}
+
+template<class T>
+static nsIDOMMediaStream*
+GetStreamFromInfo(T* info, bool& found)
+{
+  if (!info) {
+    found = false;
+    return nullptr;
+  }
+
+  found = true;
+  return info->GetMediaStream();
+}
+
+nsIDOMMediaStream*
+MediaStreamList::IndexedGetter(uint32_t index, bool& found)
+{
+  if (mType == Local) {
+    return GetStreamFromInfo(mPeerConnection->GetLocalStream(index), found);
+  }
+
+  return GetStreamFromInfo(mPeerConnection->GetRemoteStream(index), found);
+}
+
+uint32_t
+MediaStreamList::Length()
+{
+  return mType == Local ? mPeerConnection->LocalStreamsLength() :
+                          mPeerConnection->RemoteStreamsLength();
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/media/webrtc/signaling/src/peerconnection/MediaStreamList.h
@@ -0,0 +1,46 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MediaStreamList_h__
+#define MediaStreamList_h__
+
+#include "mozilla/ErrorResult.h"
+#include "nsISupportsImpl.h"
+#include "nsAutoPtr.h"
+#include "jspubtd.h"
+#include "mozilla/dom/NonRefcountedDOMObject.h"
+
+class nsIDOMMediaStream;
+namespace sipcc {
+class PeerConnectionImpl;
+} // namespace sipcc
+
+namespace mozilla {
+namespace dom {
+
+class MediaStreamList : public NonRefcountedDOMObject
+{
+public:
+  enum StreamType {
+    Local,
+    Remote
+  };
+
+  MediaStreamList(sipcc::PeerConnectionImpl* peerConnection, StreamType type);
+  ~MediaStreamList();
+
+  JSObject* WrapObject(JSContext* cx, ErrorResult& error);
+
+  nsIDOMMediaStream* IndexedGetter(uint32_t index, bool& found);
+  uint32_t Length();
+
+private:
+  nsRefPtr<sipcc::PeerConnectionImpl> mPeerConnection;
+  StreamType mType;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // MediaStreamList_h__
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -26,16 +26,21 @@
 #include "nsProxyRelease.h"
 
 #include "runnable_utils.h"
 #include "PeerConnectionCtx.h"
 #include "PeerConnectionImpl.h"
 
 #include "nsPIDOMWindow.h"
 #include "nsDOMDataChannel.h"
+#ifdef MOZILLA_INTERNAL_API
+#include "MediaStreamList.h"
+#include "nsIScriptGlobalObject.h"
+#include "jsapi.h"
+#endif
 
 #ifndef USE_FAKE_MEDIA_STREAMS
 #include "MediaSegment.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -1125,28 +1130,28 @@ PeerConnectionImpl::IceCompleted(NrIceCt
 void
 PeerConnectionImpl::IceStreamReady(NrIceMediaStream *aStream)
 {
   MOZ_ASSERT(aStream);
 
   CSFLogDebugS(logTag, __FUNCTION__ << ": "  << aStream->name().c_str());
 }
 
-nsRefPtr<LocalSourceStreamInfo>
+LocalSourceStreamInfo*
 PeerConnectionImpl::GetLocalStream(int aIndex)
 {
   if(aIndex < 0 || aIndex >= (int) mLocalSourceStreams.Length()) {
     return NULL;
   }
 
   MOZ_ASSERT(mLocalSourceStreams[aIndex]);
   return mLocalSourceStreams[aIndex];
 }
 
-nsRefPtr<RemoteSourceStreamInfo>
+RemoteSourceStreamInfo*
 PeerConnectionImpl::GetRemoteStream(int aIndex)
 {
   if(aIndex < 0 || aIndex >= (int) mRemoteSourceStreams.Length()) {
     return NULL;
   }
 
   MOZ_ASSERT(mRemoteSourceStreams[aIndex]);
   return mRemoteSourceStreams[aIndex];
@@ -1160,16 +1165,57 @@ PeerConnectionImpl::AddRemoteStream(nsRe
 
   *aIndex = mRemoteSourceStreams.Length();
 
   mRemoteSourceStreams.AppendElement(aInfo);
 
   return NS_OK;
 }
 
+#ifdef MOZILLA_INTERNAL_API
+static nsresult
+GetStreams(JSContext* cx, PeerConnectionImpl* peerConnection,
+           MediaStreamList::StreamType type, JS::Value* streams)
+{
+  nsAutoPtr<MediaStreamList> list(new MediaStreamList(peerConnection, type));
+
+  ErrorResult rv;
+  JSObject* obj = list->WrapObject(cx, rv);
+  if (rv.Failed()) {
+    streams->setNull();
+    return rv.ErrorCode();
+  }
+
+  // Transfer ownership to the binding.
+  streams->setObject(*obj);
+  list.forget();
+  return NS_OK;
+}
+#endif
+
+NS_IMETHODIMP
+PeerConnectionImpl::GetLocalStreams(JSContext* cx, JS::Value* streams)
+{
+#ifdef MOZILLA_INTERNAL_API
+  return GetStreams(cx, this, MediaStreamList::Local, streams);
+#else
+  return NS_ERROR_FAILURE;
+#endif
+}
+
+NS_IMETHODIMP
+PeerConnectionImpl::GetRemoteStreams(JSContext* cx, JS::Value* streams)
+{
+#ifdef MOZILLA_INTERNAL_API
+  return GetStreams(cx, this, MediaStreamList::Remote, streams);
+#else
+  return NS_ERROR_FAILURE;
+#endif
+}
+
 void
 LocalSourceStreamInfo::StorePipeline(int aTrack,
   mozilla::RefPtr<mozilla::MediaPipeline> aPipeline)
 {
   MOZ_ASSERT(mPipelines.find(aTrack) == mPipelines.end());
   if (mPipelines.find(aTrack) != mPipelines.end()) {
     CSFLogErrorS(logTag, __FUNCTION__ << ": Storing duplicate track");
     return;
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -324,20 +324,28 @@ public:
     // make one.
     if (i >= mIceStreams.size()) {
       return NULL;
     }
     return mIceStreams[i];
   }
 
   // Get a specific local stream
-  nsRefPtr<LocalSourceStreamInfo> GetLocalStream(int aIndex);
+  uint32_t LocalStreamsLength()
+  {
+    return mLocalSourceStreams.Length();
+  }
+  LocalSourceStreamInfo* GetLocalStream(int index);
 
   // Get a specific remote stream
-  nsRefPtr<RemoteSourceStreamInfo> GetRemoteStream(int aIndex);
+  uint32_t RemoteStreamsLength()
+  {
+    return mRemoteSourceStreams.Length();
+  }
+  RemoteSourceStreamInfo* GetRemoteStream(int index);
 
   // Add a remote stream. Returns the index in index
   nsresult AddRemoteStream(nsRefPtr<RemoteSourceStreamInfo> aInfo, int *aIndex);
 
   // Get a transport flow either RTP/RTCP for a particular stream
   // A stream can be of audio/video/datachannel/budled(?) types
   mozilla::RefPtr<TransportFlow> GetTransportFlow(int aStreamIndex, bool aIsRtcp) {
     int index_inner = aStreamIndex * 2 + (aIsRtcp ? 1 : 0);
@@ -365,16 +373,18 @@ public:
   nsCOMPtr<nsIEventTarget> GetSTSThread() { return mSTSThread; }
 
   // Get the DTLS identity
   mozilla::RefPtr<DtlsIdentity> const GetIdentity() { return mIdentity; }
 
   // Create a fake media stream
   nsresult CreateFakeMediaStream(uint32_t hint, nsIDOMMediaStream** retval);
 
+  nsPIDOMWindow* GetWindow() const { return mWindow; }
+
 private:
   PeerConnectionImpl(const PeerConnectionImpl&rhs);
   PeerConnectionImpl& operator=(PeerConnectionImpl);
 
   void ChangeReadyState(ReadyState aReadyState);
   void CheckIceState() {
     PR_ASSERT(mIceState != kIceGathering);
   }