media/webrtc/signaling/src/mediapipeline/MediaPipeline.h

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     4  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 // Original author: ekr@rtfm.com
     8 #ifndef mediapipeline_h__
     9 #define mediapipeline_h__
    11 #include "sigslot.h"
    13 #ifdef USE_FAKE_MEDIA_STREAMS
    14 #include "FakeMediaStreams.h"
    15 #else
    16 #include "DOMMediaStream.h"
    17 #include "MediaStreamGraph.h"
    18 #include "VideoUtils.h"
    19 #endif
    20 #include "MediaConduitInterface.h"
    21 #include "MediaPipelineFilter.h"
    22 #include "AudioSegment.h"
    23 #include "mozilla/ReentrantMonitor.h"
    24 #include "SrtpFlow.h"
    25 #include "databuffer.h"
    26 #include "runnable_utils.h"
    27 #include "transportflow.h"
    29 #ifdef MOZILLA_INTERNAL_API
    30 #include "VideoSegment.h"
    31 #endif
    33 #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
    35 namespace mozilla {
    37 // A class that represents the pipeline of audio and video
    38 // The dataflow looks like:
    39 //
    40 // TRANSMIT
    41 // CaptureDevice -> stream -> [us] -> conduit -> [us] -> transport -> network
    42 //
    43 // RECEIVE
    44 // network -> transport -> [us] -> conduit -> [us] -> stream -> Playout
    45 //
    46 // The boxes labeled [us] are just bridge logic implemented in this class
    47 //
    48 // We have to deal with a number of threads:
    49 //
    50 // GSM:
    51 //   * Assembles the pipeline
    52 // SocketTransportService
    53 //   * Receives notification that ICE and DTLS have completed
    54 //   * Processes incoming network data and passes it to the conduit
    55 //   * Processes outgoing RTP and RTCP
    56 // MediaStreamGraph
    57 //   * Receives outgoing data from the MediaStreamGraph
    58 //   * Receives pull requests for more data from the
    59 //     MediaStreamGraph
    60 // One or another GIPS threads
    61 //   * Receives RTCP messages to send to the other side
    62 //   * Processes video frames GIPS wants to render
    63 //
    64 // For a transmitting conduit, "output" is RTP and "input" is RTCP.
    65 // For a receiving conduit, "input" is RTP and "output" is RTCP.
    66 //
    67 class MediaPipeline : public sigslot::has_slots<> {
    68  public:
    69   enum Direction { TRANSMIT, RECEIVE };
    70   enum State { MP_CONNECTING, MP_OPEN, MP_CLOSED };
    71   MediaPipeline(const std::string& pc,
    72                 Direction direction,
    73                 nsCOMPtr<nsIEventTarget> main_thread,
    74                 nsCOMPtr<nsIEventTarget> sts_thread,
    75                 MediaStream *stream,
    76                 TrackID track_id,
    77                 int level,
    78                 RefPtr<MediaSessionConduit> conduit,
    79                 RefPtr<TransportFlow> rtp_transport,
    80                 RefPtr<TransportFlow> rtcp_transport)
    81       : direction_(direction),
    82         stream_(stream),
    83         track_id_(track_id),
    84         level_(level),
    85         conduit_(conduit),
    86         rtp_(rtp_transport, rtcp_transport ? RTP : MUX),
    87         rtcp_(rtcp_transport ? rtcp_transport : rtp_transport,
    88               rtcp_transport ? RTCP : MUX),
    89         main_thread_(main_thread),
    90         sts_thread_(sts_thread),
    91         rtp_packets_sent_(0),
    92         rtcp_packets_sent_(0),
    93         rtp_packets_received_(0),
    94         rtcp_packets_received_(0),
    95         rtp_bytes_sent_(0),
    96         rtp_bytes_received_(0),
    97         pc_(pc),
    98         description_() {
    99       // To indicate rtcp-mux rtcp_transport should be nullptr.
   100       // Therefore it's an error to send in the same flow for
   101       // both rtp and rtcp.
   102       MOZ_ASSERT(rtp_transport != rtcp_transport);
   104       // PipelineTransport() will access this->sts_thread_; moved here for safety
   105       transport_ = new PipelineTransport(this);
   106   }
   108   virtual ~MediaPipeline();
   110   // Must be called on the STS thread.  Must be called after ShutdownMedia_m().
   111   void ShutdownTransport_s();
   113   // Must be called on the main thread.
   114   void ShutdownMedia_m() {
   115     ASSERT_ON_THREAD(main_thread_);
   117     if (stream_) {
   118       DetachMediaStream();
   119     }
   120   }
   122   virtual nsresult Init();
   124   // When we have offered bundle, the MediaPipelines are created in an
   125   // indeterminate state; we do not know whether the answerer will take us
   126   // up on our offer. In the meantime, we need to behave in a manner that
   127   // errs on the side of packet loss when it is unclear whether an arriving
   128   // packet is meant for us. We want to get out of this indeterminate state
   129   // ASAP, which is what this function can be used for.
   130   void SetUsingBundle_s(bool decision);
   131   MediaPipelineFilter* UpdateFilterFromRemoteDescription_s(
   132       nsAutoPtr<MediaPipelineFilter> filter);
   134   virtual Direction direction() const { return direction_; }
   135   virtual TrackID trackid() const { return track_id_; }
   136   virtual int level() const { return level_; }
   138   bool IsDoingRtcpMux() const {
   139     return (rtp_.type_ == MUX);
   140   }
   142   int32_t rtp_packets_sent() const { return rtp_packets_sent_; }
   143   int64_t rtp_bytes_sent() const { return rtp_bytes_sent_; }
   144   int32_t rtcp_packets_sent() const { return rtcp_packets_sent_; }
   145   int32_t rtp_packets_received() const { return rtp_packets_received_; }
   146   int64_t rtp_bytes_received() const { return rtp_bytes_received_; }
   147   int32_t rtcp_packets_received() const { return rtcp_packets_received_; }
   149   MediaSessionConduit *Conduit() const { return conduit_; }
   151   // Thread counting
   152   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaPipeline)
   154   typedef enum {
   155     RTP,
   156     RTCP,
   157     MUX,
   158     MAX_RTP_TYPE
   159   } RtpType;
   161  protected:
   162   virtual void DetachMediaStream() {}
   164   // Separate class to allow ref counting
   165   class PipelineTransport : public TransportInterface {
   166    public:
   167     // Implement the TransportInterface functions
   168     explicit PipelineTransport(MediaPipeline *pipeline)
   169         : pipeline_(pipeline),
   170           sts_thread_(pipeline->sts_thread_) {}
   172     void Detach() { pipeline_ = nullptr; }
   173     MediaPipeline *pipeline() const { return pipeline_; }
   175     virtual nsresult SendRtpPacket(const void* data, int len);
   176     virtual nsresult SendRtcpPacket(const void* data, int len);
   178    private:
   179     virtual nsresult SendRtpPacket_s(nsAutoPtr<DataBuffer> data);
   180     virtual nsresult SendRtcpPacket_s(nsAutoPtr<DataBuffer> data);
   182     MediaPipeline *pipeline_;  // Raw pointer to avoid cycles
   183     nsCOMPtr<nsIEventTarget> sts_thread_;
   184   };
   185   friend class PipelineTransport;
   187   class TransportInfo {
   188     public:
   189       TransportInfo(RefPtr<TransportFlow> flow, RtpType type) :
   190         transport_(flow),
   191         state_(MP_CONNECTING),
   192         type_(type) {
   193         MOZ_ASSERT(flow);
   194       }
   196       RefPtr<TransportFlow> transport_;
   197       State state_;
   198       RefPtr<SrtpFlow> send_srtp_;
   199       RefPtr<SrtpFlow> recv_srtp_;
   200       RtpType type_;
   201   };
   203   // The transport is down
   204   virtual nsresult TransportFailed_s(TransportInfo &info);
   205   // The transport is ready
   206   virtual nsresult TransportReady_s(TransportInfo &info);
   207   void UpdateRtcpMuxState(TransportInfo &info);
   209   // Unhooks from signals
   210   void DisconnectTransport_s(TransportInfo &info);
   211   nsresult ConnectTransport_s(TransportInfo &info);
   213   TransportInfo* GetTransportInfo_s(TransportFlow *flow);
   215   void increment_rtp_packets_sent(int bytes);
   216   void increment_rtcp_packets_sent();
   217   void increment_rtp_packets_received(int bytes);
   218   void increment_rtcp_packets_received();
   220   virtual nsresult SendPacket(TransportFlow *flow, const void *data, int len);
   222   // Process slots on transports
   223   void StateChange(TransportFlow *flow, TransportLayer::State);
   224   void RtpPacketReceived(TransportLayer *layer, const unsigned char *data,
   225                          size_t len);
   226   void RtcpPacketReceived(TransportLayer *layer, const unsigned char *data,
   227                           size_t len);
   228   void PacketReceived(TransportLayer *layer, const unsigned char *data,
   229                       size_t len);
   231   Direction direction_;
   232   RefPtr<MediaStream> stream_;  // A pointer to the stream we are servicing.
   233                                 // Written on the main thread.
   234                                 // Used on STS and MediaStreamGraph threads.
   235   TrackID track_id_;            // The track on the stream.
   236                                 // Written and used as the stream_;
   237   int level_; // The m-line index (starting at 1, to match convention)
   238   RefPtr<MediaSessionConduit> conduit_;  // Our conduit. Written on the main
   239                                          // thread. Read on STS thread.
   241   // The transport objects. Read/written on STS thread.
   242   TransportInfo rtp_;
   243   TransportInfo rtcp_;
   244   // These are for bundle. We have a separate set because when we have offered
   245   // bundle, we do not know whether we will receive traffic on the transport
   246   // in this pipeline's m-line, or the transport in the "master" m-line for
   247   // the bundle. We need to be ready for either. Once this ambiguity is
   248   // resolved, the transport we know that we'll be using will be set in
   249   // rtp_transport_ and rtcp_transport_, and these will be unset.
   250   // TODO(bcampen@mozilla.com): I'm pretty sure this could be leveraged for
   251   // re-offer with a new address on an m-line too, with a little work.
   252   nsAutoPtr<TransportInfo> possible_bundle_rtp_;
   253   nsAutoPtr<TransportInfo> possible_bundle_rtcp_;
   255   // Pointers to the threads we need. Initialized at creation
   256   // and used all over the place.
   257   nsCOMPtr<nsIEventTarget> main_thread_;
   258   nsCOMPtr<nsIEventTarget> sts_thread_;
   260   // Created on Init. Referenced by the conduit and eventually
   261   // destroyed on the STS thread.
   262   RefPtr<PipelineTransport> transport_;
   264   // Only safe to access from STS thread.
   265   // Build into TransportInfo?
   266   int32_t rtp_packets_sent_;
   267   int32_t rtcp_packets_sent_;
   268   int32_t rtp_packets_received_;
   269   int32_t rtcp_packets_received_;
   270   int64_t rtp_bytes_sent_;
   271   int64_t rtp_bytes_received_;
   273   // Written on Init. Read on STS thread.
   274   std::string pc_;
   275   std::string description_;
   277   // Written on Init, all following accesses are on the STS thread.
   278   nsAutoPtr<MediaPipelineFilter> filter_;
   279   nsAutoPtr<webrtc::RtpHeaderParser> rtp_parser_;
   281  private:
   282   nsresult Init_s();
   284   bool IsRtp(const unsigned char *data, size_t len);
   285 };
   287 class GenericReceiveListener : public MediaStreamListener
   288 {
   289  public:
   290   GenericReceiveListener(SourceMediaStream *source, TrackID track_id,
   291                          TrackRate track_rate)
   292     : source_(source),
   293       track_id_(track_id),
   294       track_rate_(track_rate),
   295       played_ticks_(0) {}
   297   virtual ~GenericReceiveListener() {}
   299   void AddSelf(MediaSegment* segment);
   301   void SetPlayedTicks(TrackTicks time) {
   302     played_ticks_ = time;
   303   }
   305   void EndTrack() {
   306     source_->EndTrack(track_id_);
   307   }
   309  protected:
   310   SourceMediaStream *source_;
   311   TrackID track_id_;
   312   TrackRate track_rate_;
   313   TrackTicks played_ticks_;
   314 };
   316 class TrackAddedCallback {
   317  public:
   318   virtual void TrackAdded(TrackTicks current_ticks) = 0;
   320   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TrackAddedCallback);
   322  protected:
   323   virtual ~TrackAddedCallback() {}
   324 };
   326 class GenericReceiveListener;
   328 class GenericReceiveCallback : public TrackAddedCallback
   329 {
   330  public:
   331   GenericReceiveCallback(GenericReceiveListener* listener)
   332     : listener_(listener) {}
   334   void TrackAdded(TrackTicks time) {
   335     listener_->SetPlayedTicks(time);
   336   }
   338  private:
   339   RefPtr<GenericReceiveListener> listener_;
   340 };
   342 class ConduitDeleteEvent: public nsRunnable
   343 {
   344 public:
   345   ConduitDeleteEvent(TemporaryRef<MediaSessionConduit> aConduit) :
   346     mConduit(aConduit) {}
   348   /* we exist solely to proxy release of the conduit */
   349   NS_IMETHOD Run() { return NS_OK; }
   350 private:
   351   RefPtr<MediaSessionConduit> mConduit;
   352 };
   354 // A specialization of pipeline for reading from an input device
   355 // and transmitting to the network.
   356 class MediaPipelineTransmit : public MediaPipeline {
   357  public:
   358   // Set rtcp_transport to nullptr to use rtcp-mux
   359   MediaPipelineTransmit(const std::string& pc,
   360                         nsCOMPtr<nsIEventTarget> main_thread,
   361                         nsCOMPtr<nsIEventTarget> sts_thread,
   362                         DOMMediaStream *domstream,
   363                         TrackID track_id,
   364                         int level,
   365                         RefPtr<MediaSessionConduit> conduit,
   366                         RefPtr<TransportFlow> rtp_transport,
   367                         RefPtr<TransportFlow> rtcp_transport) :
   368       MediaPipeline(pc, TRANSMIT, main_thread, sts_thread,
   369                     domstream->GetStream(), track_id, level,
   370                     conduit, rtp_transport, rtcp_transport),
   371       listener_(new PipelineListener(conduit)),
   372       domstream_(domstream)
   373   {}
   375   // Initialize (stuff here may fail)
   376   virtual nsresult Init();
   378   // Called on the main thread.
   379   virtual void DetachMediaStream() {
   380     ASSERT_ON_THREAD(main_thread_);
   381     domstream_->RemoveDirectListener(listener_);
   382     domstream_ = nullptr;
   383     stream_->RemoveListener(listener_);
   384     // Let the listener be destroyed with the pipeline (or later).
   385     stream_ = nullptr;
   386   }
   388   // Override MediaPipeline::TransportReady.
   389   virtual nsresult TransportReady_s(TransportInfo &info);
   391   // Separate class to allow ref counting
   392   class PipelineListener : public MediaStreamDirectListener {
   393    friend class MediaPipelineTransmit;
   394    public:
   395     PipelineListener(const RefPtr<MediaSessionConduit>& conduit)
   396       : conduit_(conduit),
   397         active_(false),
   398         direct_connect_(false),
   399         samples_10ms_buffer_(nullptr),
   400         buffer_current_(0),
   401         samplenum_10ms_(0)
   402 #ifdef MOZILLA_INTERNAL_API
   403         , last_img_(-1)
   404 #endif // MOZILLA_INTERNAL_API
   405     {
   406     }
   408     ~PipelineListener()
   409     {
   410       // release conduit on mainthread.  Must use forget()!
   411       nsresult rv = NS_DispatchToMainThread(new
   412         ConduitDeleteEvent(conduit_.forget()), NS_DISPATCH_NORMAL);
   413       MOZ_ASSERT(!NS_FAILED(rv),"Could not dispatch conduit shutdown to main");
   414       if (NS_FAILED(rv)) {
   415         MOZ_CRASH();
   416       }
   417     }
   420     // XXX. This is not thread-safe but the hazard is just
   421     // that active_ = true takes a while to propagate. Revisit
   422     // when 823600 lands.
   423     void SetActive(bool active) { active_ = active; }
   425     // Implement MediaStreamListener
   426     virtual void NotifyQueuedTrackChanges(MediaStreamGraph* graph, TrackID tid,
   427                                           TrackRate rate,
   428                                           TrackTicks offset,
   429                                           uint32_t events,
   430                                           const MediaSegment& queued_media) MOZ_OVERRIDE;
   431     virtual void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime) MOZ_OVERRIDE {}
   433     // Implement MediaStreamDirectListener
   434     virtual void NotifyRealtimeData(MediaStreamGraph* graph, TrackID tid,
   435                                     TrackRate rate,
   436                                     TrackTicks offset,
   437                                     uint32_t events,
   438                                     const MediaSegment& media) MOZ_OVERRIDE;
   440    private:
   441     void NewData(MediaStreamGraph* graph, TrackID tid,
   442                  TrackRate rate,
   443                  TrackTicks offset,
   444                  uint32_t events,
   445                  const MediaSegment& media);
   447     virtual void ProcessAudioChunk(AudioSessionConduit *conduit,
   448                                    TrackRate rate, AudioChunk& chunk);
   449 #ifdef MOZILLA_INTERNAL_API
   450     virtual void ProcessVideoChunk(VideoSessionConduit *conduit,
   451                                    TrackRate rate, VideoChunk& chunk);
   452 #endif
   453     RefPtr<MediaSessionConduit> conduit_;
   454     volatile bool active_;
   455     bool direct_connect_;
   457     // These vars handle breaking audio samples into exact 10ms chunks:
   458     // The buffer of 10ms audio samples that we will send once full
   459     // (can be carried over from one call to another).
   460     nsAutoArrayPtr<int16_t> samples_10ms_buffer_;
   461     // The location of the pointer within that buffer (in units of samples).
   462     int64_t buffer_current_;
   463     // The number of samples in a 10ms audio chunk.
   464     int64_t samplenum_10ms_;
   466 #ifdef MOZILLA_INTERNAL_API
   467     int32_t last_img_; // serial number of last Image
   468 #endif // MOZILLA_INTERNAL_API
   469   };
   471  private:
   472   RefPtr<PipelineListener> listener_;
   473   DOMMediaStream *domstream_;
   474 };
   477 // A specialization of pipeline for reading from the network and
   478 // rendering video.
   479 class MediaPipelineReceive : public MediaPipeline {
   480  public:
   481   // Set rtcp_transport to nullptr to use rtcp-mux
   482   MediaPipelineReceive(const std::string& pc,
   483                        nsCOMPtr<nsIEventTarget> main_thread,
   484                        nsCOMPtr<nsIEventTarget> sts_thread,
   485                        MediaStream *stream,
   486                        TrackID track_id,
   487                        int level,
   488                        RefPtr<MediaSessionConduit> conduit,
   489                        RefPtr<TransportFlow> rtp_transport,
   490                        RefPtr<TransportFlow> rtcp_transport,
   491                        RefPtr<TransportFlow> bundle_rtp_transport,
   492                        RefPtr<TransportFlow> bundle_rtcp_transport,
   493                        nsAutoPtr<MediaPipelineFilter> filter) :
   494       MediaPipeline(pc, RECEIVE, main_thread, sts_thread,
   495                     stream, track_id, level, conduit, rtp_transport,
   496                     rtcp_transport),
   497       segments_added_(0) {
   498     filter_ = filter;
   499     rtp_parser_ = webrtc::RtpHeaderParser::Create();
   500     if (bundle_rtp_transport) {
   501       if (bundle_rtcp_transport) {
   502         MOZ_ASSERT(bundle_rtp_transport != bundle_rtcp_transport);
   503         possible_bundle_rtp_ = new TransportInfo(bundle_rtp_transport, RTP);
   504         possible_bundle_rtcp_ = new TransportInfo(bundle_rtcp_transport, RTCP);
   505       } else {
   506         possible_bundle_rtp_ = new TransportInfo(bundle_rtp_transport, MUX);
   507         possible_bundle_rtcp_ = new TransportInfo(bundle_rtp_transport, MUX);
   508       }
   509     }
   510   }
   512   int segments_added() const { return segments_added_; }
   514  protected:
   515   int segments_added_;
   517  private:
   518 };
   521 // A specialization of pipeline for reading from the network and
   522 // rendering audio.
   523 class MediaPipelineReceiveAudio : public MediaPipelineReceive {
   524  public:
   525   MediaPipelineReceiveAudio(const std::string& pc,
   526                             nsCOMPtr<nsIEventTarget> main_thread,
   527                             nsCOMPtr<nsIEventTarget> sts_thread,
   528                             MediaStream *stream,
   529                             TrackID track_id,
   530                             int level,
   531                             RefPtr<AudioSessionConduit> conduit,
   532                             RefPtr<TransportFlow> rtp_transport,
   533                             RefPtr<TransportFlow> rtcp_transport,
   534                             RefPtr<TransportFlow> bundle_rtp_transport,
   535                             RefPtr<TransportFlow> bundle_rtcp_transport,
   536                             nsAutoPtr<MediaPipelineFilter> filter) :
   537       MediaPipelineReceive(pc, main_thread, sts_thread,
   538                            stream, track_id, level, conduit, rtp_transport,
   539                            rtcp_transport, bundle_rtp_transport,
   540                            bundle_rtcp_transport, filter),
   541       listener_(new PipelineListener(stream->AsSourceStream(),
   542                                      track_id, conduit)) {
   543   }
   545   virtual void DetachMediaStream() {
   546     ASSERT_ON_THREAD(main_thread_);
   547     listener_->EndTrack();
   548     stream_->RemoveListener(listener_);
   549     stream_ = nullptr;
   550   }
   552   virtual nsresult Init();
   554  private:
   555   // Separate class to allow ref counting
   556   class PipelineListener : public GenericReceiveListener {
   557    public:
   558     PipelineListener(SourceMediaStream * source, TrackID track_id,
   559                      const RefPtr<MediaSessionConduit>& conduit);
   561     ~PipelineListener()
   562     {
   563       // release conduit on mainthread.  Must use forget()!
   564       nsresult rv = NS_DispatchToMainThread(new
   565         ConduitDeleteEvent(conduit_.forget()), NS_DISPATCH_NORMAL);
   566       MOZ_ASSERT(!NS_FAILED(rv),"Could not dispatch conduit shutdown to main");
   567       if (NS_FAILED(rv)) {
   568         MOZ_CRASH();
   569       }
   570     }
   572     // Implement MediaStreamListener
   573     virtual void NotifyQueuedTrackChanges(MediaStreamGraph* graph, TrackID tid,
   574                                           TrackRate rate,
   575                                           TrackTicks offset,
   576                                           uint32_t events,
   577                                           const MediaSegment& queued_media) MOZ_OVERRIDE {}
   578     virtual void NotifyPull(MediaStreamGraph* graph, StreamTime desired_time) MOZ_OVERRIDE;
   580    private:
   581     RefPtr<MediaSessionConduit> conduit_;
   582   };
   584   RefPtr<PipelineListener> listener_;
   585 };
   588 // A specialization of pipeline for reading from the network and
   589 // rendering video.
   590 class MediaPipelineReceiveVideo : public MediaPipelineReceive {
   591  public:
   592   MediaPipelineReceiveVideo(const std::string& pc,
   593                             nsCOMPtr<nsIEventTarget> main_thread,
   594                             nsCOMPtr<nsIEventTarget> sts_thread,
   595                             MediaStream *stream,
   596                             TrackID track_id,
   597                             int level,
   598                             RefPtr<VideoSessionConduit> conduit,
   599                             RefPtr<TransportFlow> rtp_transport,
   600                             RefPtr<TransportFlow> rtcp_transport,
   601                             RefPtr<TransportFlow> bundle_rtp_transport,
   602                             RefPtr<TransportFlow> bundle_rtcp_transport,
   603                             nsAutoPtr<MediaPipelineFilter> filter) :
   604       MediaPipelineReceive(pc, main_thread, sts_thread,
   605                            stream, track_id, level, conduit, rtp_transport,
   606                            rtcp_transport, bundle_rtp_transport,
   607                            bundle_rtcp_transport, filter),
   608       renderer_(new PipelineRenderer(MOZ_THIS_IN_INITIALIZER_LIST())),
   609       listener_(new PipelineListener(stream->AsSourceStream(), track_id)) {
   610   }
   612   // Called on the main thread.
   613   virtual void DetachMediaStream() {
   614     ASSERT_ON_THREAD(main_thread_);
   616     listener_->EndTrack();
   617     // stop generating video and thus stop invoking the PipelineRenderer
   618     // and PipelineListener - the renderer has a raw ptr to the Pipeline to
   619     // avoid cycles, and the render callbacks are invoked from a different
   620     // thread so simple null-checks would cause TSAN bugs without locks.
   621     static_cast<VideoSessionConduit*>(conduit_.get())->DetachRenderer();
   622     stream_->RemoveListener(listener_);
   623     stream_ = nullptr;
   624   }
   626   virtual nsresult Init();
   628  private:
   629   class PipelineRenderer : public VideoRenderer {
   630    public:
   631     PipelineRenderer(MediaPipelineReceiveVideo *pipeline) :
   632       pipeline_(pipeline) {}
   634     void Detach() { pipeline_ = nullptr; }
   636     // Implement VideoRenderer
   637     virtual void FrameSizeChange(unsigned int width,
   638                                  unsigned int height,
   639                                  unsigned int number_of_streams) {
   640       pipeline_->listener_->FrameSizeChange(width, height, number_of_streams);
   641     }
   643     virtual void RenderVideoFrame(const unsigned char* buffer,
   644                                   unsigned int buffer_size,
   645                                   uint32_t time_stamp,
   646                                   int64_t render_time,
   647                                   const ImageHandle& handle) {
   648       pipeline_->listener_->RenderVideoFrame(buffer, buffer_size, time_stamp,
   649                                              render_time,
   650                                              handle.GetImage());
   651     }
   653    private:
   654     MediaPipelineReceiveVideo *pipeline_;  // Raw pointer to avoid cycles
   655   };
   657   // Separate class to allow ref counting
   658   class PipelineListener : public GenericReceiveListener {
   659    public:
   660     PipelineListener(SourceMediaStream * source, TrackID track_id);
   662     // Implement MediaStreamListener
   663     virtual void NotifyQueuedTrackChanges(MediaStreamGraph* graph, TrackID tid,
   664                                           TrackRate rate,
   665                                           TrackTicks offset,
   666                                           uint32_t events,
   667                                           const MediaSegment& queued_media) MOZ_OVERRIDE {}
   668     virtual void NotifyPull(MediaStreamGraph* graph, StreamTime desired_time) MOZ_OVERRIDE;
   670     // Accessors for external writes from the renderer
   671     void FrameSizeChange(unsigned int width,
   672                          unsigned int height,
   673                          unsigned int number_of_streams) {
   674       ReentrantMonitorAutoEnter enter(monitor_);
   676       width_ = width;
   677       height_ = height;
   678     }
   680     void RenderVideoFrame(const unsigned char* buffer,
   681                           unsigned int buffer_size,
   682                           uint32_t time_stamp,
   683                           int64_t render_time,
   684                           const RefPtr<layers::Image>& video_image);
   686    private:
   687     int width_;
   688     int height_;
   689 #ifdef MOZILLA_INTERNAL_API
   690     nsRefPtr<layers::ImageContainer> image_container_;
   691     nsRefPtr<layers::Image> image_;
   692 #endif
   693     mozilla::ReentrantMonitor monitor_; // Monitor for processing WebRTC frames.
   694                                         // Protects image_ against:
   695                                         // - Writing from the GIPS thread
   696                                         // - Reading from the MSG thread
   697   };
   699   friend class PipelineRenderer;
   701   RefPtr<PipelineRenderer> renderer_;
   702   RefPtr<PipelineListener> listener_;
   703 };
   706 }  // end namespace
   707 #endif

mercurial