Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/MediaStreamGraph.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; 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/. */
5
6
#ifndef MOZILLA_MEDIASTREAMGRAPH_H_
7
#define MOZILLA_MEDIASTREAMGRAPH_H_
8
9
#include "AudioStream.h"
10
#include "MainThreadUtils.h"
11
#include "MediaStreamTypes.h"
12
#include "StreamTracks.h"
13
#include "VideoSegment.h"
14
#include "mozilla/LinkedList.h"
15
#include "mozilla/Maybe.h"
16
#include "mozilla/Mutex.h"
17
#include "mozilla/TaskQueue.h"
18
#include "nsAutoPtr.h"
19
#include "nsAutoRef.h"
20
#include "nsIRunnable.h"
21
#include "nsTArray.h"
22
#include <speex/speex_resampler.h>
23
24
class nsIRunnable;
25
class nsIGlobalObject;
26
class nsPIDOMWindowInner;
27
28
namespace mozilla {
29
  class AsyncLogger;
30
};
31
32
extern mozilla::AsyncLogger gMSGTraceLogger;
33
34
35
template <>
36
class nsAutoRefTraits<SpeexResamplerState> : public nsPointerRefTraits<SpeexResamplerState>
37
{
38
  public:
39
0
  static void Release(SpeexResamplerState* aState) { speex_resampler_destroy(aState); }
40
};
41
42
namespace mozilla {
43
44
extern LazyLogModule gMediaStreamGraphLog;
45
46
namespace dom {
47
  enum class AudioContextOperation;
48
}
49
50
namespace media {
51
  template<typename V, typename E> class Pledge;
52
}
53
54
/*
55
 * MediaStreamGraph is a framework for synchronized audio/video processing
56
 * and playback. It is designed to be used by other browser components such as
57
 * HTML media elements, media capture APIs, real-time media streaming APIs,
58
 * multitrack media APIs, and advanced audio APIs.
59
 *
60
 * The MediaStreamGraph uses a dedicated thread to process media --- the media
61
 * graph thread. This ensures that we can process media through the graph
62
 * without blocking on main-thread activity. The media graph is only modified
63
 * on the media graph thread, to ensure graph changes can be processed without
64
 * interfering with media processing. All interaction with the media graph
65
 * thread is done with message passing.
66
 *
67
 * APIs that modify the graph or its properties are described as "control APIs".
68
 * These APIs are asynchronous; they queue graph changes internally and
69
 * those changes are processed all-at-once by the MediaStreamGraph. The
70
 * MediaStreamGraph monitors the main thread event loop via nsIAppShell::RunInStableState
71
 * to ensure that graph changes from a single event loop task are always
72
 * processed all together. Control APIs should only be used on the main thread,
73
 * currently; we may be able to relax that later.
74
 *
75
 * To allow precise synchronization of times in the control API, the
76
 * MediaStreamGraph maintains a "media timeline". Control APIs that take or
77
 * return times use that timeline. Those times never advance during
78
 * an event loop task. This time is returned by MediaStreamGraph::GetCurrentTime().
79
 *
80
 * Media decoding, audio processing and media playback use thread-safe APIs to
81
 * the media graph to ensure they can continue while the main thread is blocked.
82
 *
83
 * When the graph is changed, we may need to throw out buffered data and
84
 * reprocess it. This is triggered automatically by the MediaStreamGraph.
85
 */
86
87
class AudioNodeEngine;
88
class AudioNodeExternalInputStream;
89
class AudioNodeStream;
90
class MediaInputPort;
91
class MediaStream;
92
class MediaStreamGraph;
93
class MediaStreamGraphImpl;
94
class ProcessedMediaStream;
95
class SourceMediaStream;
96
97
class AudioDataListenerInterface {
98
protected:
99
  // Protected destructor, to discourage deletion outside of Release():
100
  virtual ~AudioDataListenerInterface() {}
101
102
public:
103
  /* These are for cubeb audio input & output streams: */
104
  /**
105
   * Output data to speakers, for use as the "far-end" data for echo
106
   * cancellation.  This is not guaranteed to be in any particular size
107
   * chunks.
108
   */
109
  virtual void NotifyOutputData(MediaStreamGraphImpl* aGraph,
110
                                AudioDataValue* aBuffer, size_t aFrames,
111
                                TrackRate aRate, uint32_t aChannels) = 0;
112
  /**
113
   * Input data from a microphone (or other audio source.  This is not
114
   * guaranteed to be in any particular size chunks.
115
   */
116
  virtual void NotifyInputData(MediaStreamGraphImpl* aGraph,
117
                               const AudioDataValue* aBuffer, size_t aFrames,
118
                               TrackRate aRate, uint32_t aChannels) = 0;
119
120
  /**
121
   * Number of audio input channels.
122
   */
123
  virtual uint32_t RequestedInputChannelCount(MediaStreamGraphImpl* aGraph) = 0;
124
125
  /**
126
   * Called when the underlying audio device has changed.
127
   */
128
  virtual void DeviceChanged(MediaStreamGraphImpl* aGraph) = 0;
129
130
  /**
131
   * Called when the underlying audio device is being closed.
132
   */
133
  virtual void Disconnect(MediaStreamGraphImpl* aGraph) = 0;
134
};
135
136
class AudioDataListener : public AudioDataListenerInterface {
137
protected:
138
  // Protected destructor, to discourage deletion outside of Release():
139
0
  virtual ~AudioDataListener() {}
140
141
public:
142
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioDataListener)
143
};
144
145
/**
146
 * This is a base class for main-thread listener callbacks.
147
 * This callback is invoked on the main thread when the main-thread-visible
148
 * state of a stream has changed.
149
 *
150
 * These methods are called with the media graph monitor held, so
151
 * reentry into general media graph methods is not possible.
152
 * You should do something non-blocking and non-reentrant (e.g. dispatch an
153
 * event) and return. DispatchFromMainThreadAfterNextStreamStateUpdate
154
 * would be a good choice.
155
 * The listener is allowed to synchronously remove itself from the stream, but
156
 * not add or remove any other listeners.
157
 */
158
class MainThreadMediaStreamListener {
159
public:
160
  virtual void NotifyMainThreadStreamFinished() = 0;
161
};
162
163
/**
164
 * Helper struct used to keep track of memory usage by AudioNodes.
165
 */
166
struct AudioNodeSizes
167
{
168
0
  AudioNodeSizes() : mStream(0), mEngine(0), mNodeType() {}
169
  size_t mStream;
170
  size_t mEngine;
171
  const char* mNodeType;
172
};
173
174
class AudioNodeEngine;
175
class AudioNodeExternalInputStream;
176
class AudioNodeStream;
177
class AudioSegment;
178
class DirectMediaStreamTrackListener;
179
class MediaInputPort;
180
class MediaStreamGraphImpl;
181
class MediaStreamListener;
182
class MediaStreamTrackListener;
183
class MediaStreamVideoSink;
184
class ProcessedMediaStream;
185
class SourceMediaStream;
186
class TrackUnionStream;
187
188
/**
189
 * Helper struct for binding a track listener to a specific TrackID.
190
 */
191
template<typename Listener>
192
struct TrackBound
193
{
194
  RefPtr<Listener> mListener;
195
  TrackID mTrackID;
196
};
197
198
/**
199
 * A stream of synchronized audio and video data. All (not blocked) streams
200
 * progress at the same rate --- "real time". Streams cannot seek. The only
201
 * operation readers can perform on a stream is to read the next data.
202
 *
203
 * Consumers of a stream can be reading from it at different offsets, but that
204
 * should only happen due to the order in which consumers are being run.
205
 * Those offsets must not diverge in the long term, otherwise we would require
206
 * unbounded buffering.
207
 *
208
 * Streams can be in a "blocked" state. While blocked, a stream does not
209
 * produce data. A stream can be explicitly blocked via the control API,
210
 * or implicitly blocked by whatever's generating it (e.g. an underrun in the
211
 * source resource), or implicitly blocked because something consuming it
212
 * blocks, or implicitly because it has finished.
213
 *
214
 * A stream can be in a "finished" state. "Finished" streams are permanently
215
 * blocked.
216
 *
217
 * Transitions into and out of the "blocked" and "finished" states are managed
218
 * by the MediaStreamGraph on the media graph thread.
219
 *
220
 * We buffer media data ahead of the consumers' reading offsets. It is possible
221
 * to have buffered data but still be blocked.
222
 *
223
 * Any stream can have its audio and video playing when requested. The media
224
 * stream graph plays audio by constructing audio output streams as necessary.
225
 * Video is played by setting video frames into an MediaStreamVideoSink at the right
226
 * time. To ensure video plays in sync with audio, make sure that the same
227
 * stream is playing both the audio and video.
228
 *
229
 * The data in a stream is managed by StreamTracks. It consists of a set of
230
 * tracks of various types that can start and end over time.
231
 *
232
 * Streams are explicitly managed. The client creates them via
233
 * MediaStreamGraph::CreateInput/ProcessedMediaStream, and releases them by calling
234
 * Destroy() when no longer needed (actual destruction will be deferred).
235
 * The actual object is owned by the MediaStreamGraph. The basic idea is that
236
 * main thread objects will keep Streams alive as long as necessary (using the
237
 * cycle collector to clean up whenever needed).
238
 *
239
 * We make them refcounted only so that stream-related messages with MediaStream*
240
 * pointers can be sent to the main thread safely.
241
 *
242
 * The lifetimes of MediaStreams are controlled from the main thread.
243
 * For MediaStreams exposed to the DOM, the lifetime is controlled by the DOM
244
 * wrapper; the DOM wrappers own their associated MediaStreams. When a DOM
245
 * wrapper is destroyed, it sends a Destroy message for the associated
246
 * MediaStream and clears its reference (the last main-thread reference to
247
 * the object). When the Destroy message is processed on the graph manager
248
 * thread we immediately release the affected objects (disentangling them
249
 * from other objects as necessary).
250
 *
251
 * This could cause problems for media processing if a MediaStream is
252
 * destroyed while a downstream MediaStream is still using it. Therefore
253
 * the DOM wrappers must keep upstream MediaStreams alive as long as they
254
 * could be being used in the media graph.
255
 *
256
 * At any time, however, a set of MediaStream wrappers could be
257
 * collected via cycle collection. Destroy messages will be sent
258
 * for those objects in arbitrary order and the MediaStreamGraph has to be able
259
 * to handle this.
260
 */
261
262
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
263
// GetTickCount() and conflicts with MediaStream::GetCurrentTime.
264
#ifdef GetCurrentTime
265
#undef GetCurrentTime
266
#endif
267
268
class MediaStream : public mozilla::LinkedListElement<MediaStream>
269
{
270
public:
271
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaStream)
272
273
  explicit MediaStream();
274
275
protected:
276
  // Protected destructor, to discourage deletion outside of Release():
277
  virtual ~MediaStream();
278
279
public:
280
  /**
281
   * Returns the graph that owns this stream.
282
   */
283
  MediaStreamGraphImpl* GraphImpl();
284
  const MediaStreamGraphImpl* GraphImpl() const;
285
  MediaStreamGraph* Graph();
286
  /**
287
   * Sets the graph that owns this stream.  Should only be called once.
288
   */
289
  void SetGraphImpl(MediaStreamGraphImpl* aGraph);
290
  void SetGraphImpl(MediaStreamGraph* aGraph);
291
292
  /**
293
   * Returns sample rate of the graph.
294
   */
295
  TrackRate GraphRate() const { return mTracks.GraphRate(); }
296
297
  // Control API.
298
  // Since a stream can be played multiple ways, we need to combine independent
299
  // volume settings. The aKey parameter is used to keep volume settings
300
  // separate. Since the stream is always playing the same contents, only
301
  // a single audio output stream is used; the volumes are combined.
302
  // Currently only the first enabled audio track is played.
303
  // XXX change this so all enabled audio tracks are mixed and played.
304
  virtual void AddAudioOutput(void* aKey);
305
  virtual void SetAudioOutputVolume(void* aKey, float aVolume);
306
  virtual void RemoveAudioOutput(void* aKey);
307
  // Since a stream can be played multiple ways, we need to be able to
308
  // play to multiple MediaStreamVideoSinks.
309
  // Only the first enabled video track is played.
310
  virtual void AddVideoOutput(MediaStreamVideoSink* aSink,
311
                              TrackID aID = TRACK_ANY);
312
  virtual void RemoveVideoOutput(MediaStreamVideoSink* aSink,
313
                                 TrackID aID = TRACK_ANY);
314
  // Explicitly suspend. Useful for example if a media element is pausing
315
  // and we need to stop its stream emitting its buffered data. As soon as the
316
  // Suspend message reaches the graph, the stream stops processing. It
317
  // ignores its inputs and produces silence/no video until Resumed. Its
318
  // current time does not advance.
319
  virtual void Suspend();
320
  virtual void Resume();
321
  // Events will be dispatched by calling methods of aListener.
322
  virtual void AddListener(MediaStreamListener* aListener);
323
  virtual void RemoveListener(MediaStreamListener* aListener);
324
  virtual void AddTrackListener(MediaStreamTrackListener* aListener,
325
                                TrackID aTrackID);
326
  virtual void RemoveTrackListener(MediaStreamTrackListener* aListener,
327
                                   TrackID aTrackID);
328
329
  /**
330
   * Adds aListener to the source stream of track aTrackID in this stream.
331
   * When the MediaStreamGraph processes the added listener, it will traverse
332
   * the graph and add it to the track's source stream (remapping the TrackID
333
   * along the way).
334
   * Note that the listener will be notified on the MediaStreamGraph thread
335
   * with whether the installation of it at the source was successful or not.
336
   */
337
  virtual void AddDirectTrackListener(DirectMediaStreamTrackListener* aListener,
338
                                      TrackID aTrackID);
339
340
  /**
341
   * Removes aListener from the source stream of track aTrackID in this stream.
342
   * Note that the listener has already been removed if the link between the
343
   * source of track aTrackID and this stream has been broken (and made track
344
   * aTrackID end). The caller doesn't have to care about this, removing when
345
   * the source cannot be found, or when the listener had already been removed
346
   * does nothing.
347
   */
348
  virtual void RemoveDirectTrackListener(DirectMediaStreamTrackListener* aListener,
349
                                         TrackID aTrackID);
350
351
  // A disabled track has video replaced by black, and audio replaced by
352
  // silence.
353
  void SetTrackEnabled(TrackID aTrackID, DisabledTrackMode aMode);
354
355
  // Finish event will be notified by calling methods of aListener. It is the
356
  // responsibility of the caller to remove aListener before it is destroyed.
357
  void AddMainThreadListener(MainThreadMediaStreamListener* aListener);
358
  // It's safe to call this even if aListener is not currently a listener;
359
  // the call will be ignored.
360
  void RemoveMainThreadListener(MainThreadMediaStreamListener* aListener)
361
  {
362
    MOZ_ASSERT(NS_IsMainThread());
363
    MOZ_ASSERT(aListener);
364
    mMainThreadListeners.RemoveElement(aListener);
365
  }
366
367
  /**
368
   * Ensure a runnable will run on the main thread after running all pending
369
   * updates that were sent from the graph thread or will be sent before the
370
   * graph thread receives the next graph update.
371
   *
372
   * If the graph has been shut down or destroyed, then the runnable will be
373
   * dispatched to the event queue immediately.  If the graph is non-realtime
374
   * and has not started, then the runnable will be run
375
   * synchronously/immediately.  (There are no pending updates in these
376
   * situations.)
377
   *
378
   * Main thread only.
379
   */
380
  void RunAfterPendingUpdates(already_AddRefed<nsIRunnable> aRunnable);
381
382
  // Signal that the client is done with this MediaStream. It will be deleted
383
  // later. Do not mix usage of Destroy() with RegisterUser()/UnregisterUser().
384
  // That will cause the MediaStream to be destroyed twice, which will cause
385
  // some assertions to fail.
386
  virtual void Destroy();
387
  // Signal that a client is using this MediaStream. Useful to not have to
388
  // explicitly manage ownership (responsibility to Destroy()) when there are
389
  // multiple clients using a MediaStream.
390
  void RegisterUser();
391
  // Signal that a client no longer needs this MediaStream. When the number of
392
  // clients using this MediaStream reaches 0, it will be destroyed.
393
  void UnregisterUser();
394
395
  // Returns the main-thread's view of how much data has been processed by
396
  // this stream.
397
  StreamTime GetCurrentTime() const
398
  {
399
    NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
400
    return mMainThreadCurrentTime;
401
  }
402
  // Return the main thread's view of whether this stream has finished.
403
  bool IsFinished() const
404
  {
405
    NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
406
    return mMainThreadFinished;
407
  }
408
409
  bool IsDestroyed() const
410
  {
411
    NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
412
    return mMainThreadDestroyed;
413
  }
414
415
  friend class MediaStreamGraphImpl;
416
  friend class MediaInputPort;
417
  friend class AudioNodeExternalInputStream;
418
419
0
  virtual SourceMediaStream* AsSourceStream() { return nullptr; }
420
0
  virtual ProcessedMediaStream* AsProcessedStream() { return nullptr; }
421
0
  virtual AudioNodeStream* AsAudioNodeStream() { return nullptr; }
422
0
  virtual TrackUnionStream* AsTrackUnionStream() { return nullptr; }
423
424
  // These Impl methods perform the core functionality of the control methods
425
  // above, on the media graph thread.
426
  /**
427
   * Stop all stream activity and disconnect it from all inputs and outputs.
428
   * This must be idempotent.
429
   */
430
  virtual void DestroyImpl();
431
0
  StreamTime GetTracksEnd() const { return mTracks.GetEnd(); }
432
#ifdef DEBUG
433
  void DumpTrackInfo() const { return mTracks.DumpTrackInfo(); }
434
#endif
435
  void SetAudioOutputVolumeImpl(void* aKey, float aVolume);
436
  void AddAudioOutputImpl(void* aKey);
437
  // Returns true if this stream has an audio output.
438
  bool HasAudioOutput() const
439
0
  {
440
0
    return !mAudioOutputs.IsEmpty();
441
0
  }
442
  void RemoveAudioOutputImpl(void* aKey);
443
  void AddVideoOutputImpl(already_AddRefed<MediaStreamVideoSink> aSink,
444
                          TrackID aID);
445
  void RemoveVideoOutputImpl(MediaStreamVideoSink* aSink, TrackID aID);
446
  void AddListenerImpl(already_AddRefed<MediaStreamListener> aListener);
447
  void RemoveListenerImpl(MediaStreamListener* aListener);
448
449
  /**
450
   * Removes all direct listeners and signals to them that they have been
451
   * uninstalled.
452
   */
453
0
  virtual void RemoveAllDirectListenersImpl() {}
454
  void RemoveAllListenersImpl();
455
  virtual void AddTrackListenerImpl(already_AddRefed<MediaStreamTrackListener> aListener,
456
                                    TrackID aTrackID);
457
  virtual void RemoveTrackListenerImpl(MediaStreamTrackListener* aListener,
458
                                       TrackID aTrackID);
459
  virtual void AddDirectTrackListenerImpl(already_AddRefed<DirectMediaStreamTrackListener> aListener,
460
                                          TrackID aTrackID);
461
  virtual void RemoveDirectTrackListenerImpl(DirectMediaStreamTrackListener* aListener,
462
                                             TrackID aTrackID);
463
  virtual void SetTrackEnabledImpl(TrackID aTrackID, DisabledTrackMode aMode);
464
  DisabledTrackMode GetDisabledTrackMode(TrackID aTrackID);
465
466
  void AddConsumer(MediaInputPort* aPort)
467
0
  {
468
0
    mConsumers.AppendElement(aPort);
469
0
  }
470
  void RemoveConsumer(MediaInputPort* aPort)
471
0
  {
472
0
    mConsumers.RemoveElement(aPort);
473
0
  }
474
  uint32_t ConsumerCount() const
475
0
  {
476
0
    return mConsumers.Length();
477
0
  }
478
0
  StreamTracks& GetStreamTracks() { return mTracks; }
479
0
  GraphTime GetStreamTracksStartTime() const { return mTracksStartTime; }
480
481
  double StreamTimeToSeconds(StreamTime aTime) const
482
  {
483
    NS_ASSERTION(0 <= aTime && aTime <= STREAM_TIME_MAX, "Bad time");
484
    return static_cast<double>(aTime)/mTracks.GraphRate();
485
  }
486
  int64_t StreamTimeToMicroseconds(StreamTime aTime) const
487
0
  {
488
0
    NS_ASSERTION(0 <= aTime && aTime <= STREAM_TIME_MAX, "Bad time");
489
0
    return (aTime*1000000) / mTracks.GraphRate();
490
0
  }
491
  StreamTime SecondsToNearestStreamTime(double aSeconds) const
492
  {
493
    NS_ASSERTION(0 <= aSeconds && aSeconds <= TRACK_TICKS_MAX/TRACK_RATE_MAX,
494
                 "Bad seconds");
495
    return mTracks.GraphRate() * aSeconds + 0.5;
496
  }
497
  StreamTime MicrosecondsToStreamTimeRoundDown(int64_t aMicroseconds) const
498
0
  {
499
0
    return (aMicroseconds*mTracks.GraphRate())/1000000;
500
0
  }
501
502
  TrackTicks TimeToTicksRoundUp(TrackRate aRate, StreamTime aTime) const
503
  {
504
    return RateConvertTicksRoundUp(aRate, mTracks.GraphRate(), aTime);
505
  }
506
  StreamTime TicksToTimeRoundDown(TrackRate aRate, TrackTicks aTicks) const
507
0
  {
508
0
    return RateConvertTicksRoundDown(mTracks.GraphRate(), aRate, aTicks);
509
0
  }
510
  /**
511
   * Convert graph time to stream time. aTime must be <= mStateComputedTime
512
   * to ensure we know exactly how much time this stream will be blocked during
513
   * the interval.
514
   */
515
  StreamTime GraphTimeToStreamTimeWithBlocking(GraphTime aTime) const;
516
  /**
517
   * Convert graph time to stream time. This assumes there is no blocking time
518
   * to take account of, which is always true except between a stream
519
   * having its blocking time calculated in UpdateGraph and its blocking time
520
   * taken account of in UpdateCurrentTimeForStreams.
521
   */
522
  StreamTime GraphTimeToStreamTime(GraphTime aTime) const;
523
  /**
524
   * Convert stream time to graph time. This assumes there is no blocking time
525
   * to take account of, which is always true except between a stream
526
   * having its blocking time calculated in UpdateGraph and its blocking time
527
   * taken account of in UpdateCurrentTimeForStreams.
528
   */
529
  GraphTime StreamTimeToGraphTime(StreamTime aTime) const;
530
531
0
  bool IsFinishedOnGraphThread() const { return mFinished; }
532
  virtual void FinishOnGraphThread();
533
534
0
  bool HasCurrentData() const { return mHasCurrentData; }
535
536
  /**
537
   * Find track by track id.
538
   */
539
  StreamTracks::Track* FindTrack(TrackID aID) const;
540
541
  StreamTracks::Track* EnsureTrack(TrackID aTrack);
542
543
  virtual void ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment, MediaSegment* aRawSegment = nullptr);
544
545
  // Return true if the main thread needs to observe updates from this stream.
546
  virtual bool MainThreadNeedsUpdates() const
547
0
  {
548
0
    return true;
549
0
  }
550
551
  virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
552
  virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
553
554
0
  bool IsSuspended() const { return mSuspendedCount > 0; }
555
  void IncrementSuspendCount();
556
  void DecrementSuspendCount();
557
558
protected:
559
  // |AdvanceTimeVaryingValuesToCurrentTime| will be override in SourceMediaStream.
560
  virtual void AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime,
561
                                                     GraphTime aBlockedTime)
562
0
  {
563
0
    mTracksStartTime += aBlockedTime;
564
0
    mTracks.ForgetUpTo(aCurrentTime - mTracksStartTime);
565
0
  }
566
567
  void NotifyMainThreadListeners()
568
0
  {
569
0
    NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
570
0
571
0
    for (int32_t i = mMainThreadListeners.Length() - 1; i >= 0; --i) {
572
0
      mMainThreadListeners[i]->NotifyMainThreadStreamFinished();
573
0
    }
574
0
    mMainThreadListeners.Clear();
575
0
  }
576
577
  bool ShouldNotifyStreamFinished()
578
0
  {
579
0
    NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
580
0
    if (!mMainThreadFinished || mFinishedNotificationSent) {
581
0
      return false;
582
0
    }
583
0
584
0
    mFinishedNotificationSent = true;
585
0
    return true;
586
0
  }
587
588
  // This state is all initialized on the main thread but
589
  // otherwise modified only on the media graph thread.
590
591
  // Buffered data. The start of the buffer corresponds to mTracksStartTime.
592
  // Conceptually the buffer contains everything this stream has ever played,
593
  // but we forget some prefix of the buffered data to bound the space usage.
594
  StreamTracks mTracks;
595
  // The time when the buffered data could be considered to have started playing.
596
  // This increases over time to account for time the stream was blocked before
597
  // mCurrentTime.
598
  GraphTime mTracksStartTime;
599
600
  // Client-set volume of this stream
601
  struct AudioOutput {
602
0
    explicit AudioOutput(void* aKey) : mKey(aKey), mVolume(1.0f) {}
603
    void* mKey;
604
    float mVolume;
605
  };
606
  nsTArray<AudioOutput> mAudioOutputs;
607
  nsTArray<TrackBound<MediaStreamVideoSink>> mVideoOutputs;
608
  // We record the last played video frame to avoid playing the frame again
609
  // with a different frame id.
610
  VideoFrame mLastPlayedVideoFrame;
611
  nsTArray<RefPtr<MediaStreamListener> > mListeners;
612
  nsTArray<TrackBound<MediaStreamTrackListener>> mTrackListeners;
613
  nsTArray<MainThreadMediaStreamListener*> mMainThreadListeners;
614
  // List of disabled TrackIDs and their associated disabled mode.
615
  // They can either by disabled by frames being replaced by black, or by
616
  // retaining the previous frame.
617
  nsTArray<DisabledTrack> mDisabledTracks;
618
619
  // GraphTime at which this stream starts blocking.
620
  // This is only valid up to mStateComputedTime. The stream is considered to
621
  // have not been blocked before mCurrentTime (its mTracksStartTime is increased
622
  // as necessary to account for that time instead).
623
  GraphTime mStartBlocking;
624
625
  // MediaInputPorts to which this is connected
626
  nsTArray<MediaInputPort*> mConsumers;
627
628
  // Where audio output is going. There is one AudioOutputStream per
629
  // audio track.
630
  struct AudioOutputStream
631
  {
632
    // When we started audio playback for this track.
633
    // Add mStream->GetPosition() to find the current audio playback position.
634
    GraphTime mAudioPlaybackStartTime;
635
    // Amount of time that we've wanted to play silence because of the stream
636
    // blocking.
637
    MediaTime mBlockedAudioTime;
638
    // Last tick written to the audio output.
639
    StreamTime mLastTickWritten;
640
    TrackID mTrackID;
641
  };
642
  nsTArray<AudioOutputStream> mAudioOutputStreams;
643
644
  /**
645
   * Number of outstanding suspend operations on this stream. Stream is
646
   * suspended when this is > 0.
647
   */
648
  int32_t mSuspendedCount;
649
650
  /**
651
   * When true, this means the stream will be finished once all
652
   * buffered data has been consumed.
653
   * Only accessed on the graph thread
654
   */
655
  bool mFinished;
656
  /**
657
   * When true, mFinished is true and we've played all the data in this stream
658
   * and fired NotifyFinished notifications.
659
   */
660
  bool mNotifiedFinished;
661
  /**
662
   * When true, the last NotifyBlockingChanged delivered to the listeners
663
   * indicated that the stream is blocked.
664
   */
665
  bool mNotifiedBlocked;
666
  /**
667
   * True if some data can be present by this stream if/when it's unblocked.
668
   * Set by the stream itself on the MediaStreamGraph thread. Only changes
669
   * from false to true once a stream has data, since we won't
670
   * unblock it until there's more data.
671
   */
672
  bool mHasCurrentData;
673
  /**
674
   * True if mHasCurrentData is true and we've notified listeners.
675
   */
676
  bool mNotifiedHasCurrentData;
677
678
  // Main-thread views of state
679
  StreamTime mMainThreadCurrentTime;
680
  bool mMainThreadFinished;
681
  bool mFinishedNotificationSent;
682
  bool mMainThreadDestroyed;
683
  int mNrOfMainThreadUsers;
684
685
  // Our media stream graph.  null if destroyed on the graph thread.
686
  MediaStreamGraphImpl* mGraph;
687
};
688
689
/**
690
 * This is a stream into which a decoder can write audio and video.
691
 *
692
 * Audio and video can be written on any thread, but you probably want to
693
 * always write from the same thread to avoid unexpected interleavings.
694
 */
695
class SourceMediaStream : public MediaStream
696
{
697
public:
698
  explicit SourceMediaStream();
699
700
0
  SourceMediaStream* AsSourceStream() override { return this; }
701
702
  // Main thread only
703
704
  /**
705
   * Enable or disable pulling. When pulling is enabled, NotifyPull
706
   * gets called on MediaStreamListeners for this stream during the
707
   * MediaStreamGraph control loop. Pulling is initially disabled.
708
   * Due to unavoidable race conditions, after a call to SetPullEnabled(false)
709
   * it is still possible for a NotifyPull to occur.
710
   */
711
  void SetPullEnabled(bool aEnabled);
712
713
  // Users of audio inputs go through the stream so it can track when the
714
  // last stream referencing an input goes away, so it can close the cubeb
715
  // input.  Also note: callable on any thread (though it bounces through
716
  // MainThread to set the command if needed).
717
  nsresult OpenAudioInput(CubebUtils::AudioDeviceID aID,
718
                          AudioDataListener* aListener);
719
  // Note: also implied when Destroy() happens
720
  void CloseAudioInput(Maybe<CubebUtils::AudioDeviceID>& aID,
721
                       AudioDataListener* aListener);
722
723
  // MediaStreamGraph thread only
724
  void DestroyImpl() override;
725
726
  // Call these on any thread.
727
  /**
728
   * Call all MediaStreamListeners to request new data via the NotifyPull API
729
   * (if enabled).
730
   * aDesiredUpToTime (in): end time of new data requested.
731
   *
732
   * Returns true if new data is about to be added.
733
   */
734
  bool PullNewData(StreamTime aDesiredUpToTime);
735
736
  /**
737
   * Extract any state updates pending in the stream, and apply them.
738
   */
739
  void ExtractPendingInput();
740
741
  /**
742
   * These add/remove DirectListeners, which allow bypassing the graph and any
743
   * synchronization delays for e.g. PeerConnection, which wants the data ASAP
744
   * and lets the far-end handle sync and playout timing.
745
   */
746
  void NotifyListenersEventImpl(MediaStreamGraphEvent aEvent);
747
  void NotifyListenersEvent(MediaStreamGraphEvent aEvent);
748
749
  enum {
750
    ADDTRACK_QUEUED    = 0x01 // Queue track add until FinishAddTracks()
751
  };
752
  /**
753
   * Add a new track to the stream starting at the given base time (which
754
   * must be greater than or equal to the last time passed to
755
   * AdvanceKnownTracksTime). Takes ownership of aSegment. aSegment should
756
   * contain data starting after aStart.
757
   */
758
  void AddTrack(TrackID aID, StreamTime aStart, MediaSegment* aSegment,
759
                uint32_t aFlags = 0)
760
  {
761
    AddTrackInternal(aID, GraphRate(), aStart, aSegment, aFlags);
762
  }
763
764
  /**
765
   * Like AddTrack, but resamples audio from aRate to the graph rate.
766
   */
767
  void AddAudioTrack(TrackID aID, TrackRate aRate, StreamTime aStart,
768
                     AudioSegment* aSegment, uint32_t aFlags = 0);
769
770
  /**
771
   * Call after a series of AddTrack or AddAudioTrack calls to implement
772
   * any pending track adds.
773
   */
774
  void FinishAddTracks();
775
776
  /**
777
   * Append media data to a track. Ownership of aSegment remains with the caller,
778
   * but aSegment is emptied.
779
   * Returns false if the data was not appended because no such track exists
780
   * or the stream was already finished.
781
   */
782
  virtual bool AppendToTrack(TrackID aID, MediaSegment* aSegment, MediaSegment *aRawSegment = nullptr);
783
  /**
784
   * Get the stream time of the end of the data that has been appended so far.
785
   * Can be called from any thread but won't be useful if it can race with
786
   * an AppendToTrack call, so should probably just be called from the thread
787
   * that also calls AppendToTrack.
788
   */
789
  StreamTime GetEndOfAppendedData(TrackID aID);
790
  /**
791
   * Indicate that a track has ended. Do not do any more API calls
792
   * affecting this track.
793
   * Ignored if the track does not exist.
794
   */
795
  void EndTrack(TrackID aID);
796
  /**
797
   * Indicate that no tracks will be added starting before time aKnownTime.
798
   * aKnownTime must be >= its value at the last call to AdvanceKnownTracksTime.
799
   */
800
  void AdvanceKnownTracksTime(StreamTime aKnownTime);
801
  void AdvanceKnownTracksTimeWithLockHeld(StreamTime aKnownTime);
802
  /**
803
   * Indicate that this stream should enter the "finished" state. All tracks
804
   * must have been ended via EndTrack. The finish time of the stream is
805
   * when all tracks have ended.
806
   */
807
  void FinishPendingWithLockHeld();
808
  void FinishPending()
809
0
  {
810
0
    MutexAutoLock lock(mMutex);
811
0
    FinishPendingWithLockHeld();
812
0
  }
813
814
  // Overriding allows us to hold the mMutex lock while changing the track enable status
815
  void SetTrackEnabledImpl(TrackID aTrackID, DisabledTrackMode aMode) override;
816
817
  // Overriding allows us to ensure mMutex is locked while changing the track enable status
818
  void
819
  ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment,
820
0
                      MediaSegment* aRawSegment = nullptr) override {
821
0
    mMutex.AssertCurrentThreadOwns();
822
0
    MediaStream::ApplyTrackDisabling(aTrackID, aSegment, aRawSegment);
823
0
  }
824
825
  void RemoveAllDirectListenersImpl() override;
826
827
  /**
828
   * End all tracks and Finish() this stream.  Used to voluntarily revoke access
829
   * to a LocalMediaStream.
830
   */
831
  void EndAllTrackAndFinish();
832
833
  void RegisterForAudioMixing();
834
835
  /**
836
   * Returns true if this SourceMediaStream contains at least one audio track
837
   * that is in pending state.
838
   * This is thread safe, and takes the SourceMediaStream mutex.
839
   */
840
  bool HasPendingAudioTrack();
841
842
  TimeStamp GetStreamTracksStrartTimeStamp()
843
0
  {
844
0
    MutexAutoLock lock(mMutex);
845
0
    return mStreamTracksStartTimeStamp;
846
0
  }
847
848
  // XXX need a Reset API
849
850
  friend class MediaStreamGraphImpl;
851
852
protected:
853
  enum TrackCommands : uint32_t;
854
855
  virtual ~SourceMediaStream();
856
857
  /**
858
   * Data for each track that hasn't ended.
859
   */
860
  struct TrackData {
861
    TrackID mID;
862
    // Sample rate of the input data.
863
    TrackRate mInputRate;
864
    // Resampler if the rate of the input track does not match the
865
    // MediaStreamGraph's.
866
    nsAutoRef<SpeexResamplerState> mResampler;
867
    int mResamplerChannelCount;
868
    StreamTime mStart;
869
    // End-time of data already flushed to the track (excluding mData)
870
    StreamTime mEndOfFlushedData;
871
    // Each time the track updates are flushed to the media graph thread,
872
    // the segment buffer is emptied.
873
    nsAutoPtr<MediaSegment> mData;
874
    // Each time the track updates are flushed to the media graph thread,
875
    // this is cleared.
876
    uint32_t mCommands;
877
  };
878
879
  bool NeedsMixing();
880
881
  void ResampleAudioToGraphSampleRate(TrackData* aTrackData, MediaSegment* aSegment);
882
883
  void AddDirectTrackListenerImpl(already_AddRefed<DirectMediaStreamTrackListener> aListener,
884
                                  TrackID aTrackID) override;
885
  void RemoveDirectTrackListenerImpl(DirectMediaStreamTrackListener* aListener,
886
                                     TrackID aTrackID) override;
887
888
  void AddTrackInternal(TrackID aID, TrackRate aRate,
889
                        StreamTime aStart, MediaSegment* aSegment,
890
                        uint32_t aFlags);
891
892
  TrackData* FindDataForTrack(TrackID aID)
893
0
  {
894
0
    mMutex.AssertCurrentThreadOwns();
895
0
    for (uint32_t i = 0; i < mUpdateTracks.Length(); ++i) {
896
0
      if (mUpdateTracks[i].mID == aID) {
897
0
        return &mUpdateTracks[i];
898
0
      }
899
0
    }
900
0
    return nullptr;
901
0
  }
902
903
  /**
904
   * Notify direct consumers of new data to one of the stream tracks.
905
   * The data doesn't have to be resampled (though it may be).  This is called
906
   * from AppendToTrack on the thread providing the data, and will call
907
   * the Listeners on this thread.
908
   */
909
  void NotifyDirectConsumers(TrackData *aTrack,
910
                             MediaSegment *aSegment);
911
912
  virtual void
913
  AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime,
914
                                        GraphTime aBlockedTime) override;
915
  void SetStreamTracksStartTimeStamp(const TimeStamp& aTimeStamp)
916
0
  {
917
0
    MutexAutoLock lock(mMutex);
918
0
    mStreamTracksStartTimeStamp = aTimeStamp;
919
0
  }
920
921
  // Only accessed on the MSG thread.  Used so to ask the MSGImpl to usecount
922
  // users of a specific input.
923
  // XXX Should really be a CubebUtils::AudioDeviceID, but they aren't
924
  // copyable (opaque pointers)
925
  RefPtr<AudioDataListener> mInputListener;
926
927
  // This must be acquired *before* MediaStreamGraphImpl's lock, if they are
928
  // held together.
929
  Mutex mMutex;
930
  // protected by mMutex
931
  StreamTime mUpdateKnownTracksTime;
932
  // This time stamp will be updated in adding and blocked SourceMediaStream,
933
  // |AddStreamGraphThread| and |AdvanceTimeVaryingValuesToCurrentTime| in
934
  // particularly.
935
  TimeStamp mStreamTracksStartTimeStamp;
936
  nsTArray<TrackData> mUpdateTracks;
937
  nsTArray<TrackData> mPendingTracks;
938
  nsTArray<TrackBound<DirectMediaStreamTrackListener>> mDirectTrackListeners;
939
  bool mPullEnabled;
940
  bool mFinishPending;
941
  bool mNeedsMixing;
942
};
943
944
/**
945
 * The blocking mode decides how a track should be blocked in a MediaInputPort.
946
 */
947
enum class BlockingMode
948
{
949
  /**
950
   * BlockingMode CREATION blocks the source track from being created
951
   * in the destination. It'll end if it already exists.
952
   */
953
  CREATION,
954
  /**
955
   * BlockingMode END_EXISTING allows a track to be created in the destination
956
   * but will end it before any data has been passed through.
957
   */
958
  END_EXISTING,
959
};
960
961
/**
962
 * Represents a connection between a ProcessedMediaStream and one of its
963
 * input streams.
964
 * We make these refcounted so that stream-related messages with MediaInputPort*
965
 * pointers can be sent to the main thread safely.
966
 *
967
 * A port can be locked to a specific track in the source stream, in which case
968
 * only this track will be forwarded to the destination stream. TRACK_ANY
969
 * can used to signal that all tracks shall be forwarded.
970
 *
971
 * When a port is locked to a specific track in the source stream, it may also
972
 * indicate a TrackID to map this source track to in the destination stream
973
 * by setting aDestTrack to an explicit ID. When we do this, we must know
974
 * that this TrackID in the destination stream is available. We assert during
975
 * processing that the ID is available and that there are no generic input
976
 * ports already attached to the destination stream.
977
 * Note that this is currently only handled by TrackUnionStreams.
978
 *
979
 * When a port's source or destination stream dies, the stream's DestroyImpl
980
 * calls MediaInputPort::Disconnect to disconnect the port from
981
 * the source and destination streams.
982
 *
983
 * The lifetimes of MediaInputPort are controlled from the main thread.
984
 * The media graph adds a reference to the port. When a MediaInputPort is no
985
 * longer needed, main-thread code sends a Destroy message for the port and
986
 * clears its reference (the last main-thread reference to the object). When
987
 * the Destroy message is processed on the graph manager thread we disconnect
988
 * the port and drop the graph's reference, destroying the object.
989
 */
990
class MediaInputPort final
991
{
992
private:
993
  // Do not call this constructor directly. Instead call aDest->AllocateInputPort.
994
  MediaInputPort(MediaStream* aSource,
995
                 TrackID& aSourceTrack,
996
                 ProcessedMediaStream* aDest,
997
                 TrackID& aDestTrack,
998
                 uint16_t aInputNumber,
999
                 uint16_t aOutputNumber)
1000
    : mSource(aSource)
1001
    , mSourceTrack(aSourceTrack)
1002
    , mDest(aDest)
1003
    , mDestTrack(aDestTrack)
1004
    , mInputNumber(aInputNumber)
1005
    , mOutputNumber(aOutputNumber)
1006
    , mGraph(nullptr)
1007
0
  {
1008
0
    MOZ_COUNT_CTOR(MediaInputPort);
1009
0
  }
1010
1011
  // Private destructor, to discourage deletion outside of Release():
1012
  ~MediaInputPort()
1013
  {
1014
    MOZ_COUNT_DTOR(MediaInputPort);
1015
  }
1016
1017
public:
1018
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaInputPort)
1019
1020
  // Called on graph manager thread
1021
  // Do not call these from outside MediaStreamGraph.cpp!
1022
  void Init();
1023
  // Called during message processing to trigger removal of this stream.
1024
  void Disconnect();
1025
1026
  // Control API
1027
  /**
1028
   * Disconnects and destroys the port. The caller must not reference this
1029
   * object again.
1030
   */
1031
  void Destroy();
1032
1033
  // Any thread
1034
  MediaStream* GetSource() const { return mSource; }
1035
  TrackID GetSourceTrackId() const { return mSourceTrack; }
1036
  ProcessedMediaStream* GetDestination() const { return mDest; }
1037
  TrackID GetDestinationTrackId() const { return mDestTrack; }
1038
1039
  /**
1040
   * Block aTrackId in the source stream from being passed through the port.
1041
   * Consumers will interpret this track as ended.
1042
   * Returns a pledge that resolves on the main thread after the track block has
1043
   * been applied by the MSG.
1044
   */
1045
  already_AddRefed<media::Pledge<bool, nsresult>> BlockSourceTrackId(TrackID aTrackId,
1046
                                                                     BlockingMode aBlockingMode);
1047
private:
1048
  void BlockSourceTrackIdImpl(TrackID aTrackId, BlockingMode aBlockingMode);
1049
1050
public:
1051
  // Returns true if aTrackId has not been blocked for any reason and this port
1052
  // has not been locked to another track.
1053
  bool PassTrackThrough(TrackID aTrackId) const
1054
0
  {
1055
0
    bool blocked = false;
1056
0
    for (auto pair : mBlockedTracks) {
1057
0
      if (pair.first() == aTrackId &&
1058
0
          (pair.second() == BlockingMode::CREATION ||
1059
0
           pair.second() == BlockingMode::END_EXISTING)) {
1060
0
        blocked = true;
1061
0
        break;
1062
0
      }
1063
0
    }
1064
0
    return !blocked && (mSourceTrack == TRACK_ANY || mSourceTrack == aTrackId);
1065
0
  }
1066
1067
  // Returns true if aTrackId has not been blocked for track creation and this
1068
  // port has not been locked to another track.
1069
  bool AllowCreationOf(TrackID aTrackId) const
1070
0
  {
1071
0
    bool blocked = false;
1072
0
    for (auto pair : mBlockedTracks) {
1073
0
      if (pair.first() == aTrackId &&
1074
0
          pair.second() == BlockingMode::CREATION) {
1075
0
        blocked = true;
1076
0
        break;
1077
0
      }
1078
0
    }
1079
0
    return !blocked && (mSourceTrack == TRACK_ANY || mSourceTrack == aTrackId);
1080
0
  }
1081
1082
  uint16_t InputNumber() const { return mInputNumber; }
1083
  uint16_t OutputNumber() const { return mOutputNumber; }
1084
1085
  // Call on graph manager thread
1086
  struct InputInterval {
1087
    GraphTime mStart;
1088
    GraphTime mEnd;
1089
    bool mInputIsBlocked;
1090
  };
1091
  // Find the next time interval starting at or after aTime during which
1092
  // mDest is not blocked and mSource's blocking status does not change.
1093
  InputInterval GetNextInputInterval(GraphTime aTime) const;
1094
1095
  /**
1096
   * Returns the graph that owns this port.
1097
   */
1098
  MediaStreamGraphImpl* GraphImpl();
1099
  MediaStreamGraph* Graph();
1100
1101
  /**
1102
   * Sets the graph that owns this stream.  Should only be called once.
1103
   */
1104
  void SetGraphImpl(MediaStreamGraphImpl* aGraph);
1105
1106
  /**
1107
   * Notify the port that the source MediaStream has been suspended.
1108
  */
1109
  void Suspended();
1110
1111
  /**
1112
   * Notify the port that the source MediaStream has been resumed.
1113
  */
1114
  void Resumed();
1115
1116
  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
1117
  {
1118
    size_t amount = 0;
1119
1120
    // Not owned:
1121
    // - mSource
1122
    // - mDest
1123
    // - mGraph
1124
    return amount;
1125
  }
1126
1127
  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
1128
  {
1129
    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
1130
  }
1131
1132
private:
1133
  friend class MediaStreamGraphImpl;
1134
  friend class MediaStream;
1135
  friend class ProcessedMediaStream;
1136
  // Never modified after Init()
1137
  MediaStream* mSource;
1138
  TrackID mSourceTrack;
1139
  ProcessedMediaStream* mDest;
1140
  TrackID mDestTrack;
1141
  // The input and output numbers are optional, and are currently only used by
1142
  // Web Audio.
1143
  const uint16_t mInputNumber;
1144
  const uint16_t mOutputNumber;
1145
1146
  typedef Pair<TrackID, BlockingMode> BlockedTrack;
1147
  nsTArray<BlockedTrack> mBlockedTracks;
1148
1149
  // Our media stream graph
1150
  MediaStreamGraphImpl* mGraph;
1151
};
1152
1153
/**
1154
 * This stream processes zero or more input streams in parallel to produce
1155
 * its output. The details of how the output is produced are handled by
1156
 * subclasses overriding the ProcessInput method.
1157
 */
1158
class ProcessedMediaStream : public MediaStream
1159
{
1160
public:
1161
  explicit ProcessedMediaStream()
1162
    : MediaStream()
1163
    , mAutofinish(false)
1164
    , mCycleMarker(0)
1165
0
  {}
1166
1167
  // Control API.
1168
  /**
1169
   * Allocates a new input port attached to source aStream.
1170
   * This stream can be removed by calling MediaInputPort::Remove().
1171
   *
1172
   * The input port is tied to aTrackID in the source stream.
1173
   * aTrackID can be set to TRACK_ANY to automatically forward all tracks from
1174
   * aStream.
1175
   *
1176
   * If aTrackID is an explicit ID, aDestTrackID can also be made explicit
1177
   * to ensure that the track is assigned this ID in the destination stream.
1178
   * To avoid intermittent TrackID collisions the destination stream may not
1179
   * have any existing generic input ports (with TRACK_ANY source track) when
1180
   * you allocate an input port with a destination TrackID.
1181
   *
1182
   * To end a track in the destination stream forwarded with TRACK_ANY,
1183
   * it can be blocked in the input port through MediaInputPort::BlockTrackId().
1184
   *
1185
   * Tracks in aBlockedTracks will be blocked in the input port initially. This
1186
   * ensures that they don't get created by the MSG-thread before we can
1187
   * BlockTrackId() on the main thread.
1188
   */
1189
  already_AddRefed<MediaInputPort>
1190
  AllocateInputPort(MediaStream* aStream,
1191
                    TrackID aTrackID = TRACK_ANY,
1192
                    TrackID aDestTrackID = TRACK_ANY,
1193
                    uint16_t aInputNumber = 0,
1194
                    uint16_t aOutputNumber = 0,
1195
                    nsTArray<TrackID>* aBlockedTracks = nullptr);
1196
  /**
1197
   * Queue a message to force this stream into the finished state.
1198
   */
1199
  void QueueFinish();
1200
  /**
1201
   * Queue a message to set the autofinish flag on this stream (defaults to
1202
   * false). When this flag is set, and all input streams are in the finished
1203
   * state (including if there are no input streams), this stream automatically
1204
   * enters the finished state.
1205
   */
1206
  void QueueSetAutofinish(bool aAutofinish);
1207
1208
0
  ProcessedMediaStream* AsProcessedStream() override { return this; }
1209
1210
  friend class MediaStreamGraphImpl;
1211
1212
  // Do not call these from outside MediaStreamGraph.cpp!
1213
  virtual void AddInput(MediaInputPort* aPort);
1214
  virtual void RemoveInput(MediaInputPort* aPort)
1215
0
  {
1216
0
    mInputs.RemoveElement(aPort) || mSuspendedInputs.RemoveElement(aPort);
1217
0
  }
1218
  bool HasInputPort(MediaInputPort* aPort) const
1219
0
  {
1220
0
    return mInputs.Contains(aPort) || mSuspendedInputs.Contains(aPort);
1221
0
  }
1222
  uint32_t InputPortCount() const
1223
0
  {
1224
0
    return mInputs.Length() + mSuspendedInputs.Length();
1225
0
  }
1226
  void InputSuspended(MediaInputPort* aPort);
1227
  void InputResumed(MediaInputPort* aPort);
1228
0
  virtual MediaStream* GetInputStreamFor(TrackID aTrackID) { return nullptr; }
1229
0
  virtual TrackID GetInputTrackIDFor(TrackID aTrackID) { return TRACK_NONE; }
1230
  void DestroyImpl() override;
1231
  /**
1232
   * This gets called after we've computed the blocking states for all
1233
   * streams (mBlocked is up to date up to mStateComputedTime).
1234
   * Also, we've produced output for all streams up to this one. If this stream
1235
   * is not in a cycle, then all its source streams have produced data.
1236
   * Generate output from aFrom to aTo.
1237
   * This will be called on streams that have finished. Most stream types should
1238
   * just return immediately if IsFinishedOnGraphThread(), but some may wish to
1239
   * update internal state (see AudioNodeStream).
1240
   * ProcessInput is allowed to call FinishOnGraphThread only if ALLOW_FINISH
1241
   * is in aFlags. (This flag will be set when aTo >= mStateComputedTime, i.e.
1242
   * when we've producing the last block of data we need to produce.) Otherwise
1243
   * we can get into a situation where we've determined the stream should not
1244
   * block before mStateComputedTime, but the stream finishes before
1245
   * mStateComputedTime, violating the invariant that finished streams are blocked.
1246
   */
1247
  enum {
1248
    ALLOW_FINISH = 0x01
1249
  };
1250
  virtual void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) = 0;
1251
0
  void SetAutofinishImpl(bool aAutofinish) { mAutofinish = aAutofinish; }
1252
1253
  // Only valid after MediaStreamGraphImpl::UpdateStreamOrder() has run.
1254
  // A DelayNode is considered to break a cycle and so this will not return
1255
  // true for echo loops, only for muted cycles.
1256
0
  bool InMutedCycle() const { return mCycleMarker; }
1257
1258
  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
1259
0
  {
1260
0
    size_t amount = MediaStream::SizeOfExcludingThis(aMallocSizeOf);
1261
0
    // Not owned:
1262
0
    // - mInputs elements
1263
0
    // - mSuspendedInputs elements
1264
0
    amount += mInputs.ShallowSizeOfExcludingThis(aMallocSizeOf);
1265
0
    amount += mSuspendedInputs.ShallowSizeOfExcludingThis(aMallocSizeOf);
1266
0
    return amount;
1267
0
  }
1268
1269
  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
1270
0
  {
1271
0
    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
1272
0
  }
1273
1274
protected:
1275
  // This state is all accessed only on the media graph thread.
1276
1277
  // The list of all inputs that are not currently suspended.
1278
  nsTArray<MediaInputPort*> mInputs;
1279
  // The list of all inputs that are currently suspended.
1280
  nsTArray<MediaInputPort*> mSuspendedInputs;
1281
  bool mAutofinish;
1282
  // After UpdateStreamOrder(), mCycleMarker is either 0 or 1 to indicate
1283
  // whether this stream is in a muted cycle.  During ordering it can contain
1284
  // other marker values - see MediaStreamGraphImpl::UpdateStreamOrder().
1285
  uint32_t mCycleMarker;
1286
};
1287
1288
/**
1289
 * There is a single MediaStreamGraph per window.
1290
 * Additionaly, each OfflineAudioContext object creates its own MediaStreamGraph
1291
 * object too..
1292
 */
1293
class MediaStreamGraph
1294
{
1295
public:
1296
1297
  // We ensure that the graph current time advances in multiples of
1298
  // IdealAudioBlockSize()/AudioStream::PreferredSampleRate(). A stream that
1299
  // never blocks and has a track with the ideal audio rate will produce audio
1300
  // in multiples of the block size.
1301
1302
  // Initializing an graph that outputs audio can be quite long on some
1303
  // platforms. Code that want to output audio at some point can express the
1304
  // fact that they will need an audio stream at some point by passing
1305
  // AUDIO_THREAD_DRIVER when getting an instance of MediaStreamGraph, so that
1306
  // the graph starts with the right driver.
1307
  enum GraphDriverType {
1308
    AUDIO_THREAD_DRIVER,
1309
    SYSTEM_THREAD_DRIVER,
1310
    OFFLINE_THREAD_DRIVER
1311
  };
1312
  static const uint32_t AUDIO_CALLBACK_DRIVER_SHUTDOWN_TIMEOUT = 20*1000;
1313
  static const TrackRate REQUEST_DEFAULT_SAMPLE_RATE = 0;
1314
1315
  // Main thread only
1316
  static MediaStreamGraph* GetInstanceIfExists(nsPIDOMWindowInner* aWindow,
1317
                                               TrackRate aSampleRate);
1318
  static MediaStreamGraph* GetInstance(GraphDriverType aGraphDriverRequested,
1319
                                       nsPIDOMWindowInner* aWindow,
1320
                                       TrackRate aSampleRate);
1321
  static MediaStreamGraph* CreateNonRealtimeInstance(
1322
    TrackRate aSampleRate,
1323
    nsPIDOMWindowInner* aWindowId);
1324
1325
  // Return the correct main thread for this graph. This always returns
1326
  // something that is valid. Thread safe.
1327
  AbstractThread* AbstractMainThread();
1328
1329
  // Idempotent
1330
  static void DestroyNonRealtimeInstance(MediaStreamGraph* aGraph);
1331
1332
  virtual nsresult OpenAudioInput(CubebUtils::AudioDeviceID aID,
1333
                                  AudioDataListener* aListener) = 0;
1334
  virtual void CloseAudioInput(Maybe<CubebUtils::AudioDeviceID>& aID,
1335
                               AudioDataListener* aListener) = 0;
1336
  // Control API.
1337
  /**
1338
   * Create a stream that a media decoder (or some other source of
1339
   * media data, such as a camera) can write to.
1340
   */
1341
  SourceMediaStream* CreateSourceStream();
1342
  /**
1343
   * Create a stream that will form the union of the tracks of its input
1344
   * streams.
1345
   * A TrackUnionStream contains all the tracks of all its input streams.
1346
   * Adding a new input stream makes that stream's tracks immediately appear as new
1347
   * tracks starting at the time the input stream was added.
1348
   * Removing an input stream makes the output tracks corresponding to the
1349
   * removed tracks immediately end.
1350
   * For each added track, the track ID of the output track is the track ID
1351
   * of the input track or one plus the maximum ID of all previously added
1352
   * tracks, whichever is greater.
1353
   * TODO at some point we will probably need to add API to select
1354
   * particular tracks of each input stream.
1355
   */
1356
  ProcessedMediaStream* CreateTrackUnionStream();
1357
  /**
1358
   * Create a stream that will mix all its audio input.
1359
   */
1360
  ProcessedMediaStream* CreateAudioCaptureStream(TrackID aTrackId);
1361
1362
  /**
1363
   * Add a new stream to the graph.  Main thread.
1364
   */
1365
  void AddStream(MediaStream* aStream);
1366
1367
  /* From the main thread, ask the MSG to send back an event when the graph
1368
   * thread is running, and audio is being processed. */
1369
  void NotifyWhenGraphStarted(AudioNodeStream* aNodeStream);
1370
  /* From the main thread, suspend, resume or close an AudioContext.
1371
   * aStreams are the streams of all the AudioNodes of the AudioContext that
1372
   * need to be suspended or resumed. This can be empty if this is a second
1373
   * consecutive suspend call and all the nodes are already suspended.
1374
   *
1375
   * This can possibly pause the graph thread, releasing system resources, if
1376
   * all streams have been suspended/closed.
1377
   *
1378
   * When the operation is complete, aPromise is resolved.
1379
   */
1380
  void ApplyAudioContextOperation(MediaStream* aDestinationStream,
1381
                                  const nsTArray<MediaStream*>& aStreams,
1382
                                  dom::AudioContextOperation aState,
1383
                                  void* aPromise);
1384
1385
  bool IsNonRealtime() const;
1386
  /**
1387
   * Start processing non-realtime for a specific number of ticks.
1388
   */
1389
  void StartNonRealtimeProcessing(uint32_t aTicksToProcess);
1390
1391
  /**
1392
   * Media graph thread only.
1393
   * Dispatches a runnable that will run on the main thread after all
1394
   * main-thread stream state has been next updated.
1395
   *
1396
   * Should only be called during MediaStreamListener callbacks or during
1397
   * ProcessedMediaStream::ProcessInput().
1398
   */
1399
  virtual void DispatchToMainThreadAfterStreamStateUpdate(
1400
    already_AddRefed<nsIRunnable> aRunnable);
1401
1402
  /**
1403
   * Returns graph sample rate in Hz.
1404
   */
1405
  TrackRate GraphRate() const { return mSampleRate; }
1406
1407
  void RegisterCaptureStreamForWindow(uint64_t aWindowId,
1408
                                      ProcessedMediaStream* aCaptureStream);
1409
  void UnregisterCaptureStreamForWindow(uint64_t aWindowId);
1410
  already_AddRefed<MediaInputPort> ConnectToCaptureStream(
1411
    uint64_t aWindowId, MediaStream* aMediaStream);
1412
1413
  void AssertOnGraphThreadOrNotRunning() const
1414
0
  {
1415
0
    MOZ_ASSERT(OnGraphThreadOrNotRunning());
1416
0
  }
1417
1418
protected:
1419
  explicit MediaStreamGraph(TrackRate aSampleRate)
1420
    : mSampleRate(aSampleRate)
1421
0
  {
1422
0
    MOZ_COUNT_CTOR(MediaStreamGraph);
1423
0
  }
1424
  virtual ~MediaStreamGraph()
1425
0
  {
1426
0
    MOZ_COUNT_DTOR(MediaStreamGraph);
1427
0
  }
1428
1429
  // Intended only for assertions, either on graph thread or not running (in
1430
  // which case we must be on the main thread).
1431
  bool OnGraphThreadOrNotRunning() const;
1432
  bool OnGraphThread() const;
1433
1434
  // Media graph thread only
1435
  nsTArray<nsCOMPtr<nsIRunnable> > mPendingUpdateRunnables;
1436
1437
  /**
1438
   * Sample rate at which this graph runs. For real time graphs, this is
1439
   * the rate of the audio mixer. For offline graphs, this is the rate specified
1440
   * at construction.
1441
   */
1442
  TrackRate mSampleRate;
1443
};
1444
1445
} // namespace mozilla
1446
1447
#endif /* MOZILLA_MEDIASTREAMGRAPH_H_ */