Bug 779715. Part 8: Make it safe to call MediaInputPort::Destroy after streams at both ends of the port have been destroyed. r=jesup
authorRobert O'Callahan <robert@ocallahan.org>
Fri, 24 Aug 2012 00:46:20 +1200
changeset 105205 6797919f02f2d447b3e3758a9cea91685d934647
parent 105204 98de5d3c227b43feae7dd4d1e8cf72b847fd318a
child 105206 2995a63cf3991d9c439ee25b8783871af2f19b92
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewersjesup
bugs779715
milestone17.0a1
Bug 779715. Part 8: Make it safe to call MediaInputPort::Destroy after streams at both ends of the port have been destroyed. r=jesup We had problems because we'd call Destroy on a port after calling Destroy on its streams. This patch makes the port's Destroy ControlMessage not use a stream, instead we get the stream from the port directly. It also makes us update the graph's mPortCount only when the port is finally destroyed; this fixes a potential bug where the current graph could shut down when all streams are removed, before all ports have been completely destroyed.
content/media/MediaStreamGraph.cpp
content/media/MediaStreamGraph.h
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -2073,29 +2073,28 @@ SourceMediaStream::Finish()
 
 void
 MediaInputPort::Init()
 {
   LOG(PR_LOG_DEBUG, ("Adding MediaInputPort %p (from %p to %p) to the graph",
       this, mSource, mDest));
   mSource->AddConsumer(this);
   mDest->AddInput(this);
-  // mPortCount decremented in Disconnect()
+  // mPortCount decremented via MediaInputPort::Destroy's message
   ++mDest->GraphImpl()->mPortCount;
 }
 
 void
 MediaInputPort::Disconnect()
 {
   NS_ASSERTION(!mSource == !mDest,
                "mSource must either both be null or both non-null");
   if (!mSource)
     return;
 
-  --mDest->GraphImpl()->mPortCount;
   mSource->RemoveConsumer(this);
   mSource = nullptr;
   mDest->RemoveInput(this);
   mDest = nullptr;
 }
 
 MediaInputPort::InputInterval
 MediaInputPort::GetNextInputInterval(GraphTime aTime)
@@ -2118,32 +2117,45 @@ MediaInputPort::GetNextInputInterval(Gra
 }
 
 void
 MediaInputPort::Destroy()
 {
   class Message : public ControlMessage {
   public:
     Message(MediaInputPort* aPort)
-      : ControlMessage(aPort->GetDestination()), mPort(aPort) {}
+      : ControlMessage(nullptr), mPort(aPort) {}
     virtual void Run()
     {
       mPort->Disconnect();
+      --mPort->GraphImpl()->mPortCount;
       NS_RELEASE(mPort);
     }
     virtual void RunDuringShutdown()
     {
       Run();
     }
     // This does not need to be strongly referenced; the graph is holding
     // a strong reference to the port, which we will remove. This will be the
     // last message for the port.
     MediaInputPort* mPort;
   };
-  mSource->GraphImpl()->AppendMessage(new Message(this));
+  GraphImpl()->AppendMessage(new Message(this));
+}
+
+MediaStreamGraphImpl*
+MediaInputPort::GraphImpl()
+{
+  return gGraph;
+}
+
+MediaStreamGraph*
+MediaInputPort::Graph()
+{
+  return gGraph;
 }
 
 MediaInputPort*
 ProcessedMediaStream::AllocateInputPort(MediaStream* aStream, uint32_t aFlags)
 {
   class Message : public ControlMessage {
   public:
     Message(MediaInputPort* aPort)
--- a/content/media/MediaStreamGraph.h
+++ b/content/media/MediaStreamGraph.h
@@ -680,16 +680,22 @@ public:
     GraphTime mStart;
     GraphTime mEnd;
     bool mInputIsBlocked;
   };
   // Find the next time interval starting at or after aTime during which
   // mDest is not blocked and mSource's blocking status does not change.
   InputInterval GetNextInputInterval(GraphTime aTime);
 
+  /**
+   * Returns the graph that owns this port.
+   */
+  MediaStreamGraphImpl* GraphImpl();
+  MediaStreamGraph* Graph();
+
 protected:
   friend class MediaStreamGraphImpl;
   friend class MediaStream;
   friend class ProcessedMediaStream;
   // Never modified after Init()
   MediaStream* mSource;
   ProcessedMediaStream* mDest;
   uint32_t mFlags;