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.

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

mercurial