Bug 992568 - Part 2: Refactor RtspChannel to support redirection. r=sworkman
authorEthan Tseng <ettseng@mozilla.com>
Thu, 03 Apr 2014 19:08:34 +0800
changeset 198071 93cc1760dbbb17537ca5b46fba7a016a6198426a
parent 198070 fa91f01d12363cd91b706118c0923e246a594b40
child 198072 37a543d6ae3764a1ba4d69ee65f5b6b08f26bbf6
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssworkman
bugs992568
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 992568 - Part 2: Refactor RtspChannel to support redirection. r=sworkman
content/media/RtspMediaResource.cpp
content/media/moz.build
netwerk/ipc/NeckoChannelParams.ipdlh
netwerk/ipc/NeckoChild.cpp
netwerk/ipc/NeckoChild.h
netwerk/ipc/NeckoParent.cpp
netwerk/ipc/NeckoParent.h
netwerk/ipc/PNecko.ipdl
netwerk/ipc/PRtspChannel.ipdl
netwerk/ipc/moz.build
netwerk/protocol/rtsp/RtspChannelChild.cpp
netwerk/protocol/rtsp/RtspChannelChild.h
netwerk/protocol/rtsp/RtspChannelParent.cpp
netwerk/protocol/rtsp/RtspChannelParent.h
netwerk/protocol/rtsp/RtspHandler.cpp
netwerk/protocol/rtsp/controller/RtspControllerChild.cpp
netwerk/protocol/rtsp/controller/RtspControllerChild.h
netwerk/protocol/rtsp/moz.build
--- a/content/media/RtspMediaResource.cpp
+++ b/content/media/RtspMediaResource.cpp
@@ -10,16 +10,20 @@
 
 #include "MediaDecoder.h"
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/Preferences.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIStreamingProtocolService.h"
 #include "nsServiceManagerUtils.h"
+#ifdef NECKO_PROTOCOL_rtsp
+#include "mozilla/net/RtspChannelChild.h"
+#endif
+using namespace mozilla::net;
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* gRtspMediaResourceLog;
 #define RTSP_LOG(msg, ...) PR_LOG(gRtspMediaResourceLog, PR_LOG_DEBUG, \
                                   (msg, ##__VA_ARGS__))
 // Debug logging macro with object pointer and class name.
 #define RTSPMLOG(msg, ...) \
         RTSP_LOG("%p [RtspMediaResource]: " msg, this, ##__VA_ARGS__)
@@ -349,31 +353,31 @@ void RtspTrackBuffer::Reset() {
 }
 
 RtspMediaResource::RtspMediaResource(MediaDecoder* aDecoder,
     nsIChannel* aChannel, nsIURI* aURI, const nsACString& aContentType)
   : BaseMediaResource(aDecoder, aChannel, aURI, aContentType)
   , mIsConnected(false)
   , mRealTime(false)
 {
-  nsCOMPtr<nsIStreamingProtocolControllerService> mediaControllerService =
-    do_GetService(MEDIASTREAMCONTROLLERSERVICE_CONTRACTID);
-  MOZ_ASSERT(mediaControllerService);
-  if (mediaControllerService) {
-    mediaControllerService->Create(mChannel,
-                                   getter_AddRefs(mMediaStreamController));
-    MOZ_ASSERT(mMediaStreamController);
-    mListener = new Listener(this);
-    mMediaStreamController->AsyncOpen(mListener);
-  }
+#ifndef NECKO_PROTOCOL_rtsp
+  MOZ_CRASH("Should not be called except for B2G platform");
+#else
+  MOZ_ASSERT(aChannel);
+  mMediaStreamController =
+    static_cast<RtspChannelChild*>(aChannel)->GetController();
+  MOZ_ASSERT(mMediaStreamController);
+  mListener = new Listener(this);
+  mMediaStreamController->AsyncOpen(mListener);
 #ifdef PR_LOGGING
   if (!gRtspMediaResourceLog) {
     gRtspMediaResourceLog = PR_NewLogModule("RtspMediaResource");
   }
 #endif
+#endif
 }
 
 RtspMediaResource::~RtspMediaResource()
 {
   RTSPMLOG("~RtspMediaResource");
   if (mListener) {
     // Kill its reference to us since we're going away
     mListener->Revoke();
@@ -629,29 +633,35 @@ RtspMediaResource::OnDisconnected(uint8_
   }
 
   return NS_OK;
 }
 
 void RtspMediaResource::Suspend(bool aCloseImmediately)
 {
   NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
+  if (NS_WARN_IF(!mDecoder)) {
+    return;
+  }
 
   MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
   NS_ENSURE_TRUE_VOID(owner);
   dom::HTMLMediaElement* element = owner->GetMediaElement();
   NS_ENSURE_TRUE_VOID(element);
 
   mMediaStreamController->Suspend();
   element->DownloadSuspended();
 }
 
 void RtspMediaResource::Resume()
 {
   NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
+  if (NS_WARN_IF(!mDecoder)) {
+    return;
+  }
 
   MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
   NS_ENSURE_TRUE_VOID(owner);
   dom::HTMLMediaElement* element = owner->GetMediaElement();
   NS_ENSURE_TRUE_VOID(element);
 
   if (mChannel) {
     element->DownloadResumed();
--- a/content/media/moz.build
+++ b/content/media/moz.build
@@ -170,16 +170,17 @@ MSVC_ENABLE_PGO = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'gklayout'
 LOCAL_INCLUDES += [
     '/content/base/src',
     '/layout/generic',
     '/layout/xul',
+    '/netwerk/base/src',
 ]
 
 if CONFIG['MOZ_DIRECTSHOW']:
     LOCAL_INCLUDES += [
         '/media/webrtc/trunk/webrtc/modules/video_capture/windows',
     ]
 
 DEFINES['MOZILLA_INTERNAL_API'] = True
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -2,16 +2,17 @@
 /* vim: set sw=2 ts=8 et tw=80 ft=c: */
 
 /* 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 protocol PHttpChannel;
 include protocol PFTPChannel;
+include protocol PRtspChannel;
 include URIParams;
 include InputStreamParams;
 
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 using RequestHeaderTuples from "mozilla/net/PHttpChannelParams.h";
 using struct nsHttpAtom from "nsHttp.h";
 
 namespace mozilla {
@@ -84,10 +85,20 @@ union FTPChannelCreationArgs
 };
 
 union ChannelDiverterArgs
 {
   PHttpChannel;
   PFTPChannel;
 };
 
+//-----------------------------------------------------------------------------
+// RTSP IPDL structs
+//-----------------------------------------------------------------------------
+
+struct RtspChannelConnectArgs
+{
+  URIParams uri;
+  uint32_t channelId;
+};
+
 } // namespace ipc
 } // namespace mozilla
--- a/netwerk/ipc/NeckoChild.cpp
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -17,16 +17,17 @@
 #include "mozilla/net/DNSRequestChild.h"
 #include "mozilla/net/RemoteOpenFileChild.h"
 #include "mozilla/net/ChannelDiverterChild.h"
 #include "mozilla/dom/network/TCPSocketChild.h"
 #include "mozilla/dom/network/TCPServerSocketChild.h"
 #include "mozilla/dom/network/UDPSocketChild.h"
 #ifdef NECKO_PROTOCOL_rtsp
 #include "mozilla/net/RtspControllerChild.h"
+#include "mozilla/net/RtspChannelChild.h"
 #endif
 #include "SerializedLoadContext.h"
 
 using mozilla::dom::TCPSocketChild;
 using mozilla::dom::TCPServerSocketChild;
 using mozilla::dom::UDPSocketChild;
 
 namespace mozilla {
@@ -176,16 +177,33 @@ NeckoChild::DeallocPRtspControllerChild(
 {
 #ifdef NECKO_PROTOCOL_rtsp
   RtspControllerChild* p = static_cast<RtspControllerChild*>(child);
   p->ReleaseIPDLReference();
 #endif
   return true;
 }
 
+PRtspChannelChild*
+NeckoChild::AllocPRtspChannelChild(const RtspChannelConnectArgs& aArgs)
+{
+  NS_NOTREACHED("AllocPRtspController should not be called");
+  return nullptr;
+}
+
+bool
+NeckoChild::DeallocPRtspChannelChild(PRtspChannelChild* child)
+{
+#ifdef NECKO_PROTOCOL_rtsp
+  RtspChannelChild* p = static_cast<RtspChannelChild*>(child);
+  p->ReleaseIPDLReference();
+#endif
+  return true;
+}
+
 PTCPSocketChild*
 NeckoChild::AllocPTCPSocketChild()
 {
   TCPSocketChild* p = new TCPSocketChild();
   p->AddIPDLReference();
   return p;
 }
 
--- a/netwerk/ipc/NeckoChild.h
+++ b/netwerk/ipc/NeckoChild.h
@@ -57,16 +57,20 @@ protected:
                                                   const uint32_t& aFlags) MOZ_OVERRIDE;
   virtual bool DeallocPDNSRequestChild(PDNSRequestChild*) MOZ_OVERRIDE;
   virtual PRemoteOpenFileChild*
     AllocPRemoteOpenFileChild(const URIParams&,
                               const OptionalURIParams&) MOZ_OVERRIDE;
   virtual bool DeallocPRemoteOpenFileChild(PRemoteOpenFileChild*) MOZ_OVERRIDE;
   virtual PRtspControllerChild* AllocPRtspControllerChild() MOZ_OVERRIDE;
   virtual bool DeallocPRtspControllerChild(PRtspControllerChild*) MOZ_OVERRIDE;
+  virtual PRtspChannelChild*
+    AllocPRtspChannelChild(const RtspChannelConnectArgs& aArgs)
+                           MOZ_OVERRIDE;
+  virtual bool DeallocPRtspChannelChild(PRtspChannelChild*) MOZ_OVERRIDE;
   virtual PChannelDiverterChild*
   AllocPChannelDiverterChild(const ChannelDiverterArgs& channel) MOZ_OVERRIDE;
   virtual bool
   DeallocPChannelDiverterChild(PChannelDiverterChild* actor) MOZ_OVERRIDE;
 };
 
 /**
  * Reference to the PNecko Child protocol.
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -10,16 +10,17 @@
 #include "mozilla/net/NeckoParent.h"
 #include "mozilla/net/HttpChannelParent.h"
 #include "mozilla/net/CookieServiceParent.h"
 #include "mozilla/net/WyciwygChannelParent.h"
 #include "mozilla/net/FTPChannelParent.h"
 #include "mozilla/net/WebSocketChannelParent.h"
 #ifdef NECKO_PROTOCOL_rtsp
 #include "mozilla/net/RtspControllerParent.h"
+#include "mozilla/net/RtspChannelParent.h"
 #endif
 #include "mozilla/net/DNSRequestParent.h"
 #include "mozilla/net/RemoteOpenFileParent.h"
 #include "mozilla/net/ChannelDiverterParent.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/dom/network/TCPSocketParent.h"
 #include "mozilla/dom/network/TCPServerSocketParent.h"
@@ -331,16 +332,52 @@ NeckoParent::DeallocPRtspControllerParen
 {
 #ifdef NECKO_PROTOCOL_rtsp
   RtspControllerParent* p = static_cast<RtspControllerParent*>(actor);
   p->Release();
 #endif
   return true;
 }
 
+PRtspChannelParent*
+NeckoParent::AllocPRtspChannelParent(const RtspChannelConnectArgs& aArgs)
+{
+#ifdef NECKO_PROTOCOL_rtsp
+  nsCOMPtr<nsIURI> uri = DeserializeURI(aArgs.uri());
+  RtspChannelParent *p = new RtspChannelParent(uri);
+  p->AddRef();
+  return p;
+#else
+  return nullptr;
+#endif
+}
+
+bool
+NeckoParent::RecvPRtspChannelConstructor(
+                      PRtspChannelParent* aActor,
+                      const RtspChannelConnectArgs& aConnectArgs)
+{
+#ifdef NECKO_PROTOCOL_rtsp
+  RtspChannelParent* p = static_cast<RtspChannelParent*>(aActor);
+  return p->Init(aConnectArgs);
+#else
+  return nullptr;
+#endif
+}
+
+bool
+NeckoParent::DeallocPRtspChannelParent(PRtspChannelParent* actor)
+{
+#ifdef NECKO_PROTOCOL_rtsp
+  RtspChannelParent* p = static_cast<RtspChannelParent*>(actor);
+  p->Release();
+#endif
+  return true;
+}
+
 PTCPSocketParent*
 NeckoParent::AllocPTCPSocketParent()
 {
   TCPSocketParent* p = new TCPSocketParent();
   p->AddIPDLReference();
   return p;
 }
 
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -139,16 +139,25 @@ protected:
                                          const nsresult& reason) MOZ_OVERRIDE;
 
   virtual mozilla::ipc::IProtocol*
   CloneProtocol(Channel* aChannel,
                 mozilla::ipc::ProtocolCloneContext* aCtx) MOZ_OVERRIDE;
   virtual PRtspControllerParent* AllocPRtspControllerParent() MOZ_OVERRIDE;
   virtual bool DeallocPRtspControllerParent(PRtspControllerParent*) MOZ_OVERRIDE;
 
+  virtual PRtspChannelParent*
+    AllocPRtspChannelParent(const RtspChannelConnectArgs& aArgs)
+                            MOZ_OVERRIDE;
+  virtual bool
+    RecvPRtspChannelConstructor(PRtspChannelParent* aActor,
+                                const RtspChannelConnectArgs& aArgs)
+                                MOZ_OVERRIDE;
+  virtual bool DeallocPRtspChannelParent(PRtspChannelParent*) MOZ_OVERRIDE;
+
   virtual PChannelDiverterParent*
   AllocPChannelDiverterParent(const ChannelDiverterArgs& channel) MOZ_OVERRIDE;
   virtual bool
   RecvPChannelDiverterConstructor(PChannelDiverterParent* actor,
                                   const ChannelDiverterArgs& channel) MOZ_OVERRIDE;
   virtual bool DeallocPChannelDiverterParent(PChannelDiverterParent* actor)
                                                                 MOZ_OVERRIDE;
 
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -17,16 +17,17 @@ include protocol PTCPServerSocket;
 include protocol PUDPSocket;
 include protocol PRemoteOpenFile;
 include protocol PDNSRequest;
 include protocol PChannelDiverter;
 include protocol PBlob; //FIXME: bug #792908
 include protocol PFileDescriptorSet;
 
 include protocol PRtspController;
+include protocol PRtspChannel;
 include URIParams;
 include InputStreamParams;
 include NeckoChannelParams;
 
 
 using class IPC::SerializedLoadContext from "SerializedLoadContext.h";
 
 namespace mozilla {
@@ -42,16 +43,17 @@ sync protocol PNecko
   manages PFTPChannel;
   manages PWebSocket;
   manages PTCPSocket;
   manages PTCPServerSocket;
   manages PUDPSocket;
   manages PDNSRequest;
   manages PRemoteOpenFile;
   manages PRtspController;
+  manages PRtspChannel;
   manages PChannelDiverter;
 
 parent:
   __delete__();
 
   PCookieService();
   PHttpChannel(nullable PBrowser browser,
                SerializedLoadContext loadContext,
@@ -66,16 +68,17 @@ parent:
 
   PDNSRequest(nsCString hostName, uint32_t flags);
 
   PRemoteOpenFile(URIParams fileuri, OptionalURIParams appuri);
 
   HTMLDNSPrefetch(nsString hostname, uint16_t flags);
   CancelHTMLDNSPrefetch(nsString hostname, uint16_t flags, nsresult reason);
   PRtspController();
+  PRtspChannel(RtspChannelConnectArgs args);
   PChannelDiverter(ChannelDiverterArgs channel);
 
 both:
   PTCPSocket();
 };
 
 
 } // namespace net
new file mode 100644
--- /dev/null
+++ b/netwerk/ipc/PRtspChannel.ipdl
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
+
+/* 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 protocol PNecko;
+include URIParams;
+
+namespace mozilla {
+namespace net {
+
+async protocol PRtspChannel
+{
+  manager PNecko;
+
+parent:
+  // Note: channels are opened during construction, so no open method here:
+  // see PNecko.ipdl
+  __delete__();
+};
+
+} // namespace net
+} // namespace mozilla
--- a/netwerk/ipc/moz.build
+++ b/netwerk/ipc/moz.build
@@ -29,16 +29,17 @@ UNIFIED_SOURCES += [
     'RemoteOpenFileParent.cpp',
 ]
 
 IPDL_SOURCES = [
     'NeckoChannelParams.ipdlh',
     'PChannelDiverter.ipdl',
     'PNecko.ipdl',
     'PRemoteOpenFile.ipdl',
+    'PRtspChannel.ipdl',
     'PRtspController.ipdl',
 ]
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'necko'
--- a/netwerk/protocol/rtsp/RtspChannelChild.cpp
+++ b/netwerk/protocol/rtsp/RtspChannelChild.cpp
@@ -1,62 +1,271 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et tw=80 : */
 /* 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 "RtspChannelChild.h"
-#include "nsIURI.h"
-#include "nsAutoPtr.h"
-#include "nsStandardURL.h"
+#include "mozilla/ipc/URIUtils.h"
+
+using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace net {
 
-NS_IMPL_ISUPPORTS_INHERITED1(RtspChannelChild,
-                             nsBaseChannel,
-                             nsIChannel)
+//-----------------------------------------------------------------------------
+// RtspChannelChild
+//-----------------------------------------------------------------------------
+RtspChannelChild::RtspChannelChild(nsIURI *aUri)
+  : mIPCOpen(false)
+  , mCanceled(false)
+{
+  nsBaseChannel::SetURI(aUri);
+}
+
+RtspChannelChild::~RtspChannelChild()
+{
+}
+
+nsIStreamingProtocolController*
+RtspChannelChild::GetController()
+{
+  return mMediaStreamController;
+}
+
+void
+RtspChannelChild::ReleaseController()
+{
+  if (mMediaStreamController) {
+    mMediaStreamController = nullptr;
+  }
+}
 
 //-----------------------------------------------------------------------------
-// RtspChannelChild::nsIChannel
+// IPDL
 //-----------------------------------------------------------------------------
-
-NS_IMETHODIMP
-RtspChannelChild::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
+void
+RtspChannelChild::AddIPDLReference()
 {
-  MOZ_ASSERT(aListener);
-
-  nsCOMPtr<nsIURI> uri = nsBaseChannel::URI();
-  NS_ENSURE_TRUE(uri, NS_ERROR_ILLEGAL_VALUE);
-
-  nsAutoCString uriSpec;
-  uri->GetSpec(uriSpec);
-
-  mListener = aListener;
-  mListenerContext = aContext;
-
-  // Call OnStartRequest directly. mListener is expected to create/load an
-  // RtspMediaResource which will create an RtspMediaController. This controller
-  // manages the control and data streams to and from the network.
-  mListener->OnStartRequest(this, aContext);
-  return NS_OK;
+  NS_ABORT_IF_FALSE(!mIPCOpen,
+                    "Attempt to retain more than one IPDL reference");
+  mIPCOpen = true;
+  AddRef();
 }
 
+void
+RtspChannelChild::ReleaseIPDLReference()
+{
+  NS_ABORT_IF_FALSE(mIPCOpen, "Attempt to release nonexistent IPDL reference");
+  mIPCOpen = false;
+  Release();
+}
+
+//-----------------------------------------------------------------------------
+// nsISupports
+//-----------------------------------------------------------------------------
+NS_IMPL_ISUPPORTS_INHERITED2(RtspChannelChild,
+                             nsBaseChannel,
+                             nsIChannel,
+                             nsIChildChannel)
+
+//-----------------------------------------------------------------------------
+// nsBaseChannel::nsIChannel
+//-----------------------------------------------------------------------------
 NS_IMETHODIMP
 RtspChannelChild::GetContentType(nsACString& aContentType)
 {
   aContentType.AssignLiteral("RTSP");
   return NS_OK;
 }
 
+class CallListenerOnStartRequestEvent : public nsRunnable
+{
+public:
+  CallListenerOnStartRequestEvent(nsIStreamListener *aListener,
+                                  nsIRequest *aRequest, nsISupports *aContext)
+    : mListener(aListener)
+    , mRequest(aRequest)
+    , mContext(aContext)
+  {
+    MOZ_RELEASE_ASSERT(aListener);
+  }
+  NS_IMETHOD Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    mListener->OnStartRequest(mRequest, mContext);
+    return NS_OK;
+  }
+private:
+  nsRefPtr<nsIStreamListener> mListener;
+  nsRefPtr<nsIRequest> mRequest;
+  nsRefPtr<nsISupports> mContext;
+};
+
 NS_IMETHODIMP
-RtspChannelChild::Init(nsIURI* aUri)
+RtspChannelChild::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
 {
-  MOZ_ASSERT(aUri);
+  // Precondition checks.
+  MOZ_ASSERT(aListener);
+  nsCOMPtr<nsIURI> uri = nsBaseChannel::URI();
+  NS_ENSURE_TRUE(uri, NS_ERROR_ILLEGAL_VALUE);
+
+  // Create RtspController.
+  nsCOMPtr<nsIStreamingProtocolControllerService> mediaControllerService =
+    do_GetService(MEDIASTREAMCONTROLLERSERVICE_CONTRACTID);
+  MOZ_RELEASE_ASSERT(mediaControllerService,
+    "Cannot proceed if media controller service is unavailable!");
+  mediaControllerService->Create(this, getter_AddRefs(mMediaStreamController));
+  MOZ_ASSERT(mMediaStreamController);
 
-  nsBaseChannel::Init();
-  nsBaseChannel::SetURI(aUri);
+  // Add ourselves to the load group.
+  if (mLoadGroup) {
+    mLoadGroup->AddRequest(this, nullptr);
+  }
+
+  // Dispatch mListener's OnStartRequest directly. mListener is expected to
+  // create an RtspMediaResource and use the RtspController we just created to
+  // manage the control and data streams to and from the network.
+  mListener = aListener;
+  mListenerContext = aContext;
+  NS_DispatchToMainThread(
+    new CallListenerOnStartRequestEvent(mListener, this, mListenerContext));
+
   return NS_OK;
 }
 
-} // namespace mozilla::net
+//-----------------------------------------------------------------------------
+// nsBaseChannel::nsIStreamListener::nsIRequestObserver
+//-----------------------------------------------------------------------------
+NS_IMETHODIMP
+RtspChannelChild::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
+{
+  MOZ_CRASH("Should never be called");
+}
+
+NS_IMETHODIMP
+RtspChannelChild::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
+                                nsresult aStatusCode)
+{
+  MOZ_CRASH("Should never be called");
+}
+
+//-----------------------------------------------------------------------------
+// nsBaseChannel::nsIStreamListener
+//-----------------------------------------------------------------------------
+NS_IMETHODIMP
+RtspChannelChild::OnDataAvailable(nsIRequest *aRequest,
+                                  nsISupports *aContext,
+                                  nsIInputStream *aInputStream,
+                                  uint64_t aOffset,
+                                  uint32_t aCount)
+{
+  MOZ_CRASH("Should never be called");
+}
+
+//-----------------------------------------------------------------------------
+// nsBaseChannel::nsIChannel::nsIRequest
+//-----------------------------------------------------------------------------
+class CallListenerOnStopRequestEvent : public nsRunnable
+{
+public:
+  CallListenerOnStopRequestEvent(nsIStreamListener *aListener,
+                                 nsIRequest *aRequest,
+                                 nsISupports *aContext, nsresult aStatus)
+    : mListener(aListener)
+    , mRequest(aRequest)
+    , mContext(aContext)
+    , mStatus(aStatus)
+  {
+    MOZ_RELEASE_ASSERT(aListener);
+  }
+  NS_IMETHOD Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    mListener->OnStopRequest(mRequest, mContext, mStatus);
+    return NS_OK;
+  }
+private:
+  nsRefPtr<nsIStreamListener> mListener;
+  nsRefPtr<nsIRequest> mRequest;
+  nsRefPtr<nsISupports> mContext;
+  nsresult mStatus;
+};
+
+NS_IMETHODIMP
+RtspChannelChild::Cancel(nsresult status)
+{
+  if (mCanceled) {
+    return NS_OK;
+  }
+
+  mCanceled = true;
+  // Stop RtspController.
+  if (mMediaStreamController) {
+    mMediaStreamController->Stop();
+  }
+
+  // Call mListener's OnStopRequest to do clean up.
+  NS_DispatchToMainThread(
+    new CallListenerOnStopRequestEvent(mListener, this,
+                                       mListenerContext, status));
+  mListener = nullptr;
+  mListenerContext = nullptr;
+
+  // Remove ourselves from the load group.
+  if (mLoadGroup) {
+    mLoadGroup->RemoveRequest(this, nullptr, status);
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RtspChannelChild::Suspend()
+{
+  MOZ_CRASH("Should never be called");
+}
+
+NS_IMETHODIMP
+RtspChannelChild::Resume()
+{
+  MOZ_CRASH("Should never be called");
+}
+
+//-----------------------------------------------------------------------------
+// nsBaseChannel
+//-----------------------------------------------------------------------------
+NS_IMETHODIMP
+RtspChannelChild::OpenContentStream(bool aAsync,
+                                    nsIInputStream **aStream,
+                                    nsIChannel **aChannel)
+{
+  MOZ_CRASH("Should never be called");
+}
+
+//-----------------------------------------------------------------------------
+// nsIChildChannel
+//-----------------------------------------------------------------------------
+NS_IMETHODIMP
+RtspChannelChild::ConnectParent(uint32_t id)
+{
+  // Create RtspChannelParent for redirection.
+  AddIPDLReference();
+  RtspChannelConnectArgs connectArgs;
+  SerializeURI(nsBaseChannel::URI(), connectArgs.uri());
+  connectArgs.channelId() = id;
+  if (!gNeckoChild->SendPRtspChannelConstructor(this, connectArgs)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RtspChannelChild::CompleteRedirectSetup(nsIStreamListener *aListener,
+                                        nsISupports *aContext)
+{
+  return AsyncOpen(aListener, aContext);
+}
+
+} // namespace net
 } // namespace mozilla
--- a/netwerk/protocol/rtsp/RtspChannelChild.h
+++ b/netwerk/protocol/rtsp/RtspChannelChild.h
@@ -2,74 +2,87 @@
 /* vim: set sw=2 ts=8 et tw=80 : */
 /* 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 RtspChannelChild_h
 #define RtspChannelChild_h
 
+#include "mozilla/net/PRtspChannelChild.h"
+#include "mozilla/net/NeckoChild.h"
 #include "nsBaseChannel.h"
+#include "nsIChildChannel.h"
+#include "nsIStreamingProtocolController.h"
+#include "nsIStreamingProtocolService.h"
 
 namespace mozilla {
 namespace net {
 
 //-----------------------------------------------------------------------------
 // RtspChannelChild is a dummy channel used to aid MediaResource creation in
-// HTMLMediaElement. Actual network control and data flows are managed by an
-// RtspController object created and owned by RtspMediaResource.
-// Therefore, when RtspChannelChild::AsyncOpen is called, mListener->OnStartRequest
-// will be called immediately. It is expected that an RtspMediaResource object
-// will be created in that calling context or after; the RtspController object
-// will be created internally by RtspMediaResource."
+// HTMLMediaElement. Network control and data flows are managed by an
+// RtspController object, which is created by us and manipulated by
+// RtspMediaResource. This object is also responsible for inter-process
+// communication with the parent process.
+// When RtspChannelChild::AsyncOpen is called, it should create an
+// RtspController object, dispatch an OnStartRequest and immediately return.
+// We expect an RtspMediaResource object will be created in the calling context
+// and it will use the RtpController we create.
 
-class RtspChannelChild : public nsBaseChannel
+class RtspChannelChild : public PRtspChannelChild
+                       , public nsBaseChannel
+                       , public nsIChildChannel
 {
 public:
   NS_DECL_ISUPPORTS
-
-  RtspChannelChild() { }
-
-  ~RtspChannelChild() { }
+  NS_DECL_NSICHILDCHANNEL
 
-  // Overrides nsBaseChannel::AsyncOpen and call listener's OnStartRequest immediately.
-  NS_IMETHOD AsyncOpen(nsIStreamListener *listener,
-                       nsISupports *aContext) MOZ_OVERRIDE MOZ_FINAL;
-  // Set Rtsp URL.
-  NS_IMETHOD Init(nsIURI* uri);
-  // Overrides nsBaseChannel::GetContentType, return streaming protocol type "RTSP".
-  NS_IMETHOD GetContentType(nsACString & aContentType) MOZ_OVERRIDE MOZ_FINAL;
+  RtspChannelChild(nsIURI *aUri);
+  ~RtspChannelChild();
 
-  NS_IMETHOD OpenContentStream(bool aAsync,
-                               nsIInputStream **aStream,
-                               nsIChannel **aChannel) MOZ_OVERRIDE MOZ_FINAL
-  {
-    return NS_ERROR_NOT_IMPLEMENTED;
-  }
+  // nsBaseChannel::nsIChannel
+  NS_IMETHOD GetContentType(nsACString & aContentType) MOZ_OVERRIDE MOZ_FINAL;
+  NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *aContext)
+                       MOZ_OVERRIDE MOZ_FINAL;
 
-  // nsIRequestObserver
-  NS_IMETHOD OnStartRequest(nsIRequest *aRequest,
-                            nsISupports *aContext) MOZ_OVERRIDE MOZ_FINAL
-  {
-    return NS_ERROR_NOT_IMPLEMENTED;
-  }
-
+  // nsBaseChannel::nsIStreamListener::nsIRequestObserver
+  NS_IMETHOD OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
+                            MOZ_OVERRIDE MOZ_FINAL;
   NS_IMETHOD OnStopRequest(nsIRequest *aRequest,
                            nsISupports *aContext,
-                           nsresult aStatusCode) MOZ_OVERRIDE MOZ_FINAL
-  {
-    return NS_ERROR_NOT_IMPLEMENTED;
-  }
+                           nsresult aStatusCode) MOZ_OVERRIDE MOZ_FINAL;
 
-  // nsIStreamListener
+  // nsBaseChannel::nsIStreamListener
   NS_IMETHOD OnDataAvailable(nsIRequest *aRequest,
                              nsISupports *aContext,
                              nsIInputStream *aInputStream,
                              uint64_t aOffset,
-                             uint32_t aCount) MOZ_OVERRIDE MOZ_FINAL
-  {
-    return NS_ERROR_NOT_IMPLEMENTED;
-  }
+                             uint32_t aCount) MOZ_OVERRIDE MOZ_FINAL;
+
+  // nsBaseChannel::nsIChannel::nsIRequest
+  NS_IMETHOD Cancel(nsresult status) MOZ_OVERRIDE MOZ_FINAL;
+  NS_IMETHOD Suspend() MOZ_OVERRIDE MOZ_FINAL;
+  NS_IMETHOD Resume() MOZ_OVERRIDE MOZ_FINAL;
+
+  // nsBaseChannel
+  NS_IMETHOD OpenContentStream(bool aAsync,
+                               nsIInputStream **aStream,
+                               nsIChannel **aChannel) MOZ_OVERRIDE MOZ_FINAL;
+
+  // IPDL
+  void AddIPDLReference();
+  void ReleaseIPDLReference();
+
+  // RtspChannelChild
+  nsIStreamingProtocolController* GetController();
+  void ReleaseController();
+
+private:
+  bool mIPCOpen;
+  bool mCanceled;
+  nsCOMPtr<nsIStreamingProtocolController> mMediaStreamController;
 };
 
-}
-} // namespace mozilla::net
+} // namespace net
+} // namespace mozilla
+
 #endif // RtspChannelChild_h
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/rtsp/RtspChannelParent.cpp
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* 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 "RtspChannelParent.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla {
+namespace net {
+
+//-----------------------------------------------------------------------------
+// RtspChannelParent
+//-----------------------------------------------------------------------------
+RtspChannelParent::RtspChannelParent(nsIURI *aUri)
+  : mIPCClosed(false)
+{
+  nsBaseChannel::SetURI(aUri);
+}
+
+RtspChannelParent::~RtspChannelParent()
+{
+}
+
+void
+RtspChannelParent::ActorDestroy(ActorDestroyReason why)
+{
+  mIPCClosed = true;
+}
+
+//-----------------------------------------------------------------------------
+// nsISupports
+//-----------------------------------------------------------------------------
+NS_IMPL_ISUPPORTS_INHERITED1(RtspChannelParent,
+                             nsBaseChannel,
+                             nsIParentChannel)
+
+//-----------------------------------------------------------------------------
+// RtspChannelParent methods
+//-----------------------------------------------------------------------------
+bool
+RtspChannelParent::Init(const RtspChannelConnectArgs& aArgs)
+{
+  return ConnectChannel(aArgs.channelId());
+}
+
+bool
+RtspChannelParent::ConnectChannel(const uint32_t& channelId)
+{
+  nsresult rv;
+  nsCOMPtr<nsIChannel> channel;
+  rv = NS_LinkRedirectChannels(channelId, this, getter_AddRefs(channel));
+
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+// nsBaseChannel::nsIChannel
+//-----------------------------------------------------------------------------
+NS_IMETHODIMP
+RtspChannelParent::GetContentType(nsACString& aContentType)
+{
+  aContentType.AssignLiteral("RTSP");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RtspChannelParent::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
+{
+  return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+// nsBaseChannel::nsIStreamListener::nsIRequestObserver
+//-----------------------------------------------------------------------------
+NS_IMETHODIMP
+RtspChannelParent::OnStartRequest(nsIRequest *aRequest,
+                            nsISupports *aContext)
+{
+  MOZ_CRASH("Should never be called");
+}
+
+NS_IMETHODIMP
+RtspChannelParent::OnStopRequest(nsIRequest *aRequest,
+                           nsISupports *aContext,
+                           nsresult aStatusCode)
+{
+  MOZ_CRASH("Should never be called");
+}
+
+//-----------------------------------------------------------------------------
+// nsBaseChannel::nsIStreamListener
+//-----------------------------------------------------------------------------
+NS_IMETHODIMP
+RtspChannelParent::OnDataAvailable(nsIRequest *aRequest,
+                             nsISupports *aContext,
+                             nsIInputStream *aInputStream,
+                             uint64_t aOffset,
+                             uint32_t aCount)
+{
+  MOZ_CRASH("Should never be called");
+}
+
+//-----------------------------------------------------------------------------
+// nsBaseChannel::nsIChannel::nsIRequeset
+//-----------------------------------------------------------------------------
+NS_IMETHODIMP
+RtspChannelParent::Cancel(nsresult status)
+{
+  // FIXME: This method will be called by
+  // nsXMLHttpRequest::CloseRequestWithError while closing the browser app.
+  // However, the root cause is RtspChannelParent will be created by
+  // nsXMLHttpRequest::Open when we navigate away from an RTSP web page.
+  // We should find out why it happens and decide how to fix it.
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RtspChannelParent::Suspend()
+{
+  MOZ_CRASH("Should never be called");
+}
+
+NS_IMETHODIMP
+RtspChannelParent::Resume()
+{
+  MOZ_CRASH("Should never be called");
+}
+
+//-----------------------------------------------------------------------------
+// nsBaseChannel
+//-----------------------------------------------------------------------------
+NS_IMETHODIMP
+RtspChannelParent::OpenContentStream(bool aAsync,
+                               nsIInputStream **aStream,
+                               nsIChannel **aChannel)
+{
+  MOZ_CRASH("Should never be called");
+}
+
+//-----------------------------------------------------------------------------
+// nsIParentChannel
+//-----------------------------------------------------------------------------
+NS_IMETHODIMP
+RtspChannelParent::SetParentListener(HttpChannelParentListener *aListener)
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RtspChannelParent::Delete()
+{
+  return NS_OK;
+}
+
+} // namespace net
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/rtsp/RtspChannelParent.h
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* 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 RtspChannelParent_h
+#define RtspChannelParent_h
+
+#include "mozilla/net/PRtspChannelParent.h"
+#include "mozilla/net/NeckoParent.h"
+#include "nsBaseChannel.h"
+#include "nsIParentChannel.h"
+
+namespace mozilla {
+namespace net {
+
+//-----------------------------------------------------------------------------
+// Note: RtspChannel doesn't transport streams as normal channel does.
+// (See RtspChannelChild.h for detail).
+// The reason for the existence of RtspChannelParent is to support HTTP->RTSP
+// redirection.
+// When redirection happens, two instances of RtspChannelParent will be created:
+// - One will be created when HTTP creates the new channel for redirects, and
+//   will be registered as an nsIChannel.
+// - The other will be created via IPDL by RtspChannelChild, and will be
+//   registered as an nsIParentChannel.
+class RtspChannelParent : public PRtspChannelParent
+                        , public nsBaseChannel
+                        , public nsIParentChannel
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPARENTCHANNEL
+
+  RtspChannelParent(nsIURI *aUri);
+  ~RtspChannelParent();
+
+  // nsBaseChannel::nsIChannel
+  NS_IMETHOD GetContentType(nsACString & aContentType) MOZ_OVERRIDE MOZ_FINAL;
+  NS_IMETHOD AsyncOpen(nsIStreamListener *listener,
+                       nsISupports *aContext) MOZ_OVERRIDE MOZ_FINAL;
+
+  // nsBaseChannel::nsIStreamListener::nsIRequestObserver
+  NS_IMETHOD OnStartRequest(nsIRequest *aRequest,
+                            nsISupports *aContext) MOZ_OVERRIDE MOZ_FINAL;
+  NS_IMETHOD OnStopRequest(nsIRequest *aRequest,
+                           nsISupports *aContext,
+                           nsresult aStatusCode) MOZ_OVERRIDE MOZ_FINAL;
+
+  // nsBaseChannel::nsIStreamListener
+  NS_IMETHOD OnDataAvailable(nsIRequest *aRequest,
+                             nsISupports *aContext,
+                             nsIInputStream *aInputStream,
+                             uint64_t aOffset,
+                             uint32_t aCount) MOZ_OVERRIDE MOZ_FINAL;
+
+  // nsBaseChannel::nsIChannel::nsIRequest
+  NS_IMETHOD Cancel(nsresult status) MOZ_OVERRIDE MOZ_FINAL;
+  NS_IMETHOD Suspend() MOZ_OVERRIDE MOZ_FINAL;
+  NS_IMETHOD Resume() MOZ_OVERRIDE MOZ_FINAL;
+
+  // nsBaseChannel
+  NS_IMETHOD OpenContentStream(bool aAsync,
+                               nsIInputStream **aStream,
+                               nsIChannel **aChannel) MOZ_OVERRIDE MOZ_FINAL;
+
+  // RtspChannelParent
+  bool Init(const RtspChannelConnectArgs& aArgs);
+
+protected:
+  // Used to connect redirected-to channel in parent with just created
+  // ChildChannel. Used during HTTP->RTSP redirection.
+  bool ConnectChannel(const uint32_t& channelId);
+
+private:
+  bool mIPCClosed;
+  virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif // RtspChannelParent_h
--- a/netwerk/protocol/rtsp/RtspHandler.cpp
+++ b/netwerk/protocol/rtsp/RtspHandler.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et tw=80 : */
 /* 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 "RtspChannelChild.h"
+#include "RtspChannelParent.h"
 #include "RtspHandler.h"
 #include "nsILoadGroup.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIURI.h"
 #include "nsAutoPtr.h"
 #include "nsStandardURL.h"
 #include "mozilla/net/NeckoChild.h"
 
@@ -63,25 +64,29 @@ RtspHandler::NewURI(const nsACString & a
   url.forget(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 RtspHandler::NewChannel(nsIURI *aURI, nsIChannel **aResult)
 {
   bool isRtsp = false;
-  nsRefPtr<RtspChannelChild> rtspChannel;
+  nsRefPtr<nsBaseChannel> rtspChannel;
 
   nsresult rv = aURI->SchemeIs("rtsp", &isRtsp);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(isRtsp, NS_ERROR_UNEXPECTED);
 
-  rtspChannel = new RtspChannelChild();
+  if (IsNeckoChild()) {
+    rtspChannel = new RtspChannelChild(aURI);
+  } else {
+    rtspChannel = new RtspChannelParent(aURI);
+  }
 
-  rv = rtspChannel->Init(aURI);
+  rv = rtspChannel->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   rtspChannel.forget(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 RtspHandler::AllowPort(int32_t port, const char *scheme, bool *aResult)
--- a/netwerk/protocol/rtsp/controller/RtspControllerChild.cpp
+++ b/netwerk/protocol/rtsp/controller/RtspControllerChild.cpp
@@ -73,16 +73,22 @@ RtspControllerChild::RtspControllerChild
   gNeckoChild->SendPRtspControllerConstructor(this);
 }
 
 RtspControllerChild::~RtspControllerChild()
 {
   LOG(("RtspControllerChild::~RtspControllerChild()"));
 }
 
+void
+RtspControllerChild::ReleaseChannel()
+{
+  static_cast<RtspChannelChild*>(mChannel.get())->ReleaseController();
+}
+
 bool
 RtspControllerChild::OKToSendIPC()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mIPCOpen == false) {
     return false;
   }
   return mIPCAllowed;
@@ -169,27 +175,29 @@ RtspControllerChild::RecvOnDisconnected(
                        const uint8_t& index,
                        const nsresult& reason)
 {
   DisallowIPC();
   LOG(("RtspControllerChild::RecvOnDisconnected for track %d reason = 0x%x", index, reason));
   if (mListener) {
     mListener->OnDisconnected(index, reason);
   }
+  ReleaseChannel();
   return true;
 }
 
 bool
 RtspControllerChild::RecvAsyncOpenFailed(const nsresult& reason)
 {
   DisallowIPC();
   LOG(("RtspControllerChild::RecvAsyncOpenFailed reason = 0x%x", reason));
   if (mListener) {
     mListener->OnDisconnected(0, NS_ERROR_CONNECTION_REFUSED);
   }
+  ReleaseChannel();
   return true;
 }
 
 void
 RtspControllerChild::AddIPDLReference()
 {
   NS_ABORT_IF_FALSE(!mIPCOpen,
                     "Attempt to retain more than one IPDL reference");
--- a/netwerk/protocol/rtsp/controller/RtspControllerChild.h
+++ b/netwerk/protocol/rtsp/controller/RtspControllerChild.h
@@ -8,16 +8,17 @@
 #define RtspControllerChild_h
 
 #include "mozilla/net/PRtspControllerChild.h"
 #include "nsIStreamingProtocolController.h"
 #include "nsIChannel.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsTArray.h"
+#include "mozilla/net/RtspChannelChild.h"
 
 namespace mozilla {
 namespace net {
 
 class RtspControllerChild : public nsIStreamingProtocolController
                           , public nsIStreamingProtocolListener
                           , public PRtspControllerChild
 {
@@ -65,13 +66,15 @@ class RtspControllerChild : public nsISt
   // Array refer to metadata of the media stream.
   nsTArray<nsCOMPtr<nsIStreamingProtocolMetaData>> mMetaArray;
   // ASCII encoded URL spec
   nsCString mSpec;
   // The total tracks for the given media stream session.
   uint32_t mTotalTracks;
   // Current suspension depth for this channel object
   uint32_t mSuspendCount;
+  // Detach channel-controller relationship.
+  void ReleaseChannel();
 };
 } // namespace net
 } // namespace mozilla
 
 #endif // RtspControllerChild_h
--- a/netwerk/protocol/rtsp/moz.build
+++ b/netwerk/protocol/rtsp/moz.build
@@ -5,26 +5,28 @@
 
 EXPORTS.mozilla.net += [
     'controller/RtspController.h',
     'controller/RtspControllerChild.h',
     'controller/RtspControllerParent.h',
     'controller/RtspMetaData.h',
     'rtsp/RTSPSource.h',
     'RtspChannelChild.h',
+    'RtspChannelParent.h',
     'RtspHandler.h',
 ]
 
 # These files cannot be built in unified mode because they force NSPR logging.
 SOURCES += [
     'controller/RtspController.cpp',
     'controller/RtspControllerChild.cpp',
     'controller/RtspControllerParent.cpp',
     'controller/RtspMetaData.cpp',
     'RtspChannelChild.cpp',
+    'RtspChannelParent.cpp',
     'RtspHandler.cpp',
 ]
 
 # Android sources
 SOURCES += [
     'rtsp/AAMRAssembler.cpp',
     'rtsp/AAVCAssembler.cpp',
     'rtsp/AH263Assembler.cpp',