Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/MediaStreamGraphImpl.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_MEDIASTREAMGRAPHIMPL_H_
7
#define MOZILLA_MEDIASTREAMGRAPHIMPL_H_
8
9
#include "MediaStreamGraph.h"
10
11
#include "AudioMixer.h"
12
#include "GraphDriver.h"
13
#include "Latency.h"
14
#include "mozilla/Atomics.h"
15
#include "mozilla/Monitor.h"
16
#include "mozilla/Services.h"
17
#include "mozilla/TimeStamp.h"
18
#include "mozilla/UniquePtr.h"
19
#include "mozilla/WeakPtr.h"
20
#include "nsClassHashtable.h"
21
#include "nsIMemoryReporter.h"
22
#include "nsINamed.h"
23
#include "nsIRunnable.h"
24
#include "nsIThread.h"
25
#include "nsITimer.h"
26
#include "AsyncLogger.h"
27
28
namespace mozilla {
29
30
namespace media {
31
class ShutdownTicket;
32
}
33
34
template <typename T>
35
class LinkedList;
36
37
/**
38
 * A per-stream update message passed from the media graph thread to the
39
 * main thread.
40
 */
41
struct StreamUpdate
42
{
43
  RefPtr<MediaStream> mStream;
44
  StreamTime mNextMainThreadCurrentTime;
45
  bool mNextMainThreadFinished;
46
};
47
48
/**
49
 * This represents a message run on the graph thread to modify stream or graph
50
 * state.  These are passed from main thread to graph thread through
51
 * AppendMessage(), or scheduled on the graph thread with
52
 * RunMessageAfterProcessing().  A ControlMessage
53
 * always has a weak reference to a particular affected stream.
54
 */
55
class ControlMessage
56
{
57
public:
58
  explicit ControlMessage(MediaStream* aStream) : mStream(aStream)
59
0
  {
60
0
    MOZ_COUNT_CTOR(ControlMessage);
61
0
  }
62
  // All these run on the graph thread
63
  virtual ~ControlMessage()
64
0
  {
65
0
    MOZ_COUNT_DTOR(ControlMessage);
66
0
  }
67
  // Do the action of this message on the MediaStreamGraph thread. Any actions
68
  // affecting graph processing should take effect at mProcessedTime.
69
  // All stream data for times < mProcessedTime has already been
70
  // computed.
71
  virtual void Run() = 0;
72
  // RunDuringShutdown() is only relevant to messages generated on the main
73
  // thread (for AppendMessage()).
74
  // When we're shutting down the application, most messages are ignored but
75
  // some cleanup messages should still be processed (on the main thread).
76
  // This must not add new control messages to the graph.
77
0
  virtual void RunDuringShutdown() {}
78
0
  MediaStream* GetStream() { return mStream; }
79
80
protected:
81
  // We do not hold a reference to mStream. The graph will be holding
82
  // a reference to the stream until the Destroy message is processed. The
83
  // last message referencing a stream is the Destroy message for that stream.
84
  MediaStream* mStream;
85
};
86
87
class MessageBlock
88
{
89
public:
90
  nsTArray<UniquePtr<ControlMessage>> mMessages;
91
};
92
93
/**
94
 * The implementation of a media stream graph. This class is private to this
95
 * file. It's not in the anonymous namespace because MediaStream needs to
96
 * be able to friend it.
97
 *
98
 * There can be multiple MediaStreamGraph per process: one per document.
99
 * Additionaly, each OfflineAudioContext object creates its own MediaStreamGraph
100
 * object too.
101
 */
102
class MediaStreamGraphImpl : public MediaStreamGraph,
103
                             public nsIMemoryReporter,
104
                             public nsITimerCallback,
105
                             public nsINamed
106
{
107
public:
108
  NS_DECL_THREADSAFE_ISUPPORTS
109
  NS_DECL_NSIMEMORYREPORTER
110
  NS_DECL_NSITIMERCALLBACK
111
  NS_DECL_NSINAMED
112
113
  /**
114
   * Use aGraphDriverRequested with SYSTEM_THREAD_DRIVER or AUDIO_THREAD_DRIVER
115
   * to create a MediaStreamGraph which provides support for real-time audio
116
   * and/or video.  Set it to OFFLINE_THREAD_DRIVER in order to create a
117
   * non-realtime instance which just churns through its inputs and produces
118
   * output.  Those objects currently only support audio, and are used to
119
   * implement OfflineAudioContext.  They do not support MediaStream inputs.
120
   */
121
  explicit MediaStreamGraphImpl(GraphDriverType aGraphDriverRequested,
122
                                TrackRate aSampleRate,
123
                                AbstractThread* aWindow);
124
125
  /**
126
   * Unregisters memory reporting and deletes this instance. This should be
127
   * called instead of calling the destructor directly.
128
   */
129
  void Destroy();
130
131
  // Main thread only.
132
  /**
133
   * This runs every time we need to sync state from the media graph thread
134
   * to the main thread while the main thread is not in the middle
135
   * of a script. It runs during a "stable state" (per HTML5) or during
136
   * an event posted to the main thread.
137
   * The boolean affects which boolean controlling runnable dispatch is cleared
138
   */
139
  void RunInStableState(bool aSourceIsMSG);
140
  /**
141
   * Ensure a runnable to run RunInStableState is posted to the appshell to
142
   * run at the next stable state (per HTML5).
143
   * See EnsureStableStateEventPosted.
144
   */
145
  void EnsureRunInStableState();
146
  /**
147
   * Called to apply a StreamUpdate to its stream.
148
   */
149
  void ApplyStreamUpdate(StreamUpdate* aUpdate);
150
  /**
151
   * Append a ControlMessage to the message queue. This queue is drained
152
   * during RunInStableState; the messages will run on the graph thread.
153
   */
154
  void AppendMessage(UniquePtr<ControlMessage> aMessage);
155
156
  /**
157
   * Dispatches a runnable from any thread to the correct main thread for this
158
   * MediaStreamGraph.
159
   */
160
  void Dispatch(already_AddRefed<nsIRunnable>&& aRunnable);
161
162
  /**
163
   * Make this MediaStreamGraph enter forced-shutdown state. This state
164
   * will be noticed by the media graph thread, which will shut down all streams
165
   * and other state controlled by the media graph thread.
166
   * This is called during application shutdown.
167
   */
168
  void ForceShutDown(media::ShutdownTicket* aShutdownTicket);
169
170
  /**
171
   * Called before the thread runs.
172
   */
173
  void Init();
174
175
  /**
176
   * Respond to CollectReports with sizes collected on the graph thread.
177
   */
178
  static void
179
  FinishCollectReports(nsIHandleReportCallback* aHandleReport,
180
                       nsISupports* aData,
181
                       const nsTArray<AudioNodeSizes>& aAudioStreamSizes);
182
183
  // The following methods run on the graph thread (or possibly the main thread
184
  // if mLifecycleState > LIFECYCLE_RUNNING)
185
  void CollectSizesForMemoryReport(
186
         already_AddRefed<nsIHandleReportCallback> aHandleReport,
187
         already_AddRefed<nsISupports> aHandlerData);
188
189
  /**
190
   * Returns true if this MediaStreamGraph should keep running
191
   */
192
  bool UpdateMainThreadState();
193
194
  /**
195
   * Returns true if this MediaStreamGraph should keep running
196
   */
197
  bool OneIteration(GraphTime aStateEnd);
198
199
  /**
200
   * Called from the driver, when the graph thread is about to stop, to tell
201
   * the main thread to attempt to begin cleanup.  The main thread may either
202
   * shutdown or revive the graph depending on whether it receives new
203
   * messages.
204
   */
205
  void SignalMainThreadCleanup();
206
207
  bool Running() const
208
0
  {
209
0
    return LifecycleStateRef() == LIFECYCLE_RUNNING;
210
0
  }
211
212
  /* This is the end of the current iteration, that is, the current time of the
213
   * graph. */
214
  GraphTime IterationEnd() const;
215
216
  /**
217
   * Ensure there is an event posted to the main thread to run RunInStableState.
218
   * mMonitor must be held.
219
   * See EnsureRunInStableState
220
   */
221
  void EnsureStableStateEventPosted();
222
  /**
223
   * Generate messages to the main thread to update it for all state changes.
224
   * mMonitor must be held.
225
   */
226
  void PrepareUpdatesToMainThreadState(bool aFinalUpdate);
227
  /**
228
   * Returns false if there is any stream that has finished but not yet finished
229
   * playing out.
230
   */
231
  bool AllFinishedStreamsNotified();
232
  /**
233
   * If we are rendering in non-realtime mode, we don't want to send messages to
234
   * the main thread at each iteration for performance reasons. We instead
235
   * notify the main thread at the same rate
236
   */
237
  bool ShouldUpdateMainThread();
238
  // The following methods are the various stages of RunThread processing.
239
  /**
240
   * Advance all stream state to mStateComputedTime.
241
   */
242
  void UpdateCurrentTimeForStreams(GraphTime aPrevCurrentTime);
243
  /**
244
   * Process chunks for all streams and raise events for properties that have
245
   * changed, such as principalId.
246
   */
247
  void ProcessChunkMetadata(GraphTime aPrevCurrentTime);
248
  /**
249
   * Process chunks for the given stream and interval, and raise events for
250
   * properties that have changed, such as principalId.
251
   */
252
  template<typename C, typename Chunk>
253
  void ProcessChunkMetadataForInterval(MediaStream* aStream,
254
                                       TrackID aTrackID,
255
                                       C& aSegment,
256
                                       StreamTime aStart,
257
                                       StreamTime aEnd);
258
  /**
259
   * Process graph messages in mFrontMessageQueue.
260
   */
261
  void RunMessagesInQueue();
262
  /**
263
   * Update stream processing order and recompute stream blocking until
264
   * aEndBlockingDecisions.
265
   */
266
  void UpdateGraph(GraphTime aEndBlockingDecisions);
267
268
  void SwapMessageQueues()
269
0
  {
270
0
    MOZ_ASSERT(CurrentDriver()->OnThread());
271
0
    MOZ_ASSERT(mFrontMessageQueue.IsEmpty());
272
0
    mMonitor.AssertCurrentThreadOwns();
273
0
    mFrontMessageQueue.SwapElements(mBackMessageQueue);
274
0
  }
275
  /**
276
   * Do all the processing and play the audio and video, from
277
   * mProcessedTime to mStateComputedTime.
278
   */
279
  void Process();
280
281
  /**
282
   * For use during ProcessedMediaStream::ProcessInput() or
283
   * MediaStreamListener callbacks, when graph state cannot be changed.
284
   * Schedules |aMessage| to run after processing, at a time when graph state
285
   * can be changed.  Graph thread.
286
   */
287
  void RunMessageAfterProcessing(UniquePtr<ControlMessage> aMessage);
288
289
  /**
290
   * Called when a suspend/resume/close operation has been completed, on the
291
   * graph thread.
292
   */
293
  void AudioContextOperationCompleted(MediaStream* aStream,
294
                                      void* aPromise,
295
                                      dom::AudioContextOperation aOperation);
296
297
  /**
298
   * Apply and AudioContext operation (suspend/resume/closed), on the graph
299
   * thread.
300
   */
301
  void ApplyAudioContextOperationImpl(MediaStream* aDestinationStream,
302
                                      const nsTArray<MediaStream*>& aStreams,
303
                                      dom::AudioContextOperation aOperation,
304
                                      void* aPromise);
305
306
  /**
307
   * Increment suspend count on aStream and move it to mSuspendedStreams if
308
   * necessary.
309
   */
310
  void IncrementSuspendCount(MediaStream* aStream);
311
  /**
312
   * Increment suspend count on aStream and move it to mStreams if
313
   * necessary.
314
   */
315
  void DecrementSuspendCount(MediaStream* aStream);
316
317
  /*
318
   * Move streams from the mStreams to mSuspendedStream if suspending/closing an
319
   * AudioContext, or the inverse when resuming an AudioContext.
320
   */
321
  void SuspendOrResumeStreams(dom::AudioContextOperation aAudioContextOperation,
322
                              const nsTArray<MediaStream*>& aStreamSet);
323
324
  /**
325
   * Determine if we have any audio tracks, or are about to add any audiotracks.
326
   */
327
  bool AudioTrackPresent();
328
329
  /**
330
   * Sort mStreams so that every stream not in a cycle is after any streams
331
   * it depends on, and every stream in a cycle is marked as being in a cycle.
332
   * Also sets mIsConsumed on every stream.
333
   */
334
  void UpdateStreamOrder();
335
336
  /**
337
   * Returns smallest value of t such that t is a multiple of
338
   * WEBAUDIO_BLOCK_SIZE and t >= aTime.
339
   */
340
  GraphTime RoundUpToEndOfAudioBlock(GraphTime aTime);
341
  /**
342
   * Returns smallest value of t such that t is a multiple of
343
   * WEBAUDIO_BLOCK_SIZE and t > aTime.
344
   */
345
  GraphTime RoundUpToNextAudioBlock(GraphTime aTime);
346
  /**
347
   * Produce data for all streams >= aStreamIndex for the current time interval.
348
   * Advances block by block, each iteration producing data for all streams
349
   * for a single block.
350
   * This is called whenever we have an AudioNodeStream in the graph.
351
   */
352
  void ProduceDataForStreamsBlockByBlock(uint32_t aStreamIndex,
353
                                         TrackRate aSampleRate);
354
  /**
355
   * If aStream will underrun between aTime, and aEndBlockingDecisions, returns
356
   * the time at which the underrun will start. Otherwise return
357
   * aEndBlockingDecisions.
358
   */
359
  GraphTime WillUnderrun(MediaStream* aStream, GraphTime aEndBlockingDecisions);
360
361
  /**
362
   * Given a graph time aTime, convert it to a stream time taking into
363
   * account the time during which aStream is scheduled to be blocked.
364
   */
365
  StreamTime GraphTimeToStreamTimeWithBlocking(const MediaStream* aStream, GraphTime aTime) const;
366
367
  /**
368
   * Call NotifyHaveCurrentData on aStream's listeners.
369
   */
370
  void NotifyHasCurrentData(MediaStream* aStream);
371
  /**
372
   * If aStream needs an audio stream but doesn't have one, create it.
373
   * If aStream doesn't need an audio stream but has one, destroy it.
374
   */
375
  void CreateOrDestroyAudioStreams(MediaStream* aStream);
376
  /**
377
   * Queue audio (mix of stream audio and silence for blocked intervals)
378
   * to the audio output stream. Returns the number of frames played.
379
   */
380
  StreamTime PlayAudio(MediaStream* aStream);
381
  /* Runs off a message on the graph thread when something requests audio from
382
   * an input audio device of ID aID, and delivers the input audio frames to
383
   * aListener. */
384
  void OpenAudioInputImpl(CubebUtils::AudioDeviceID aID,
385
                          AudioDataListener* aListener);
386
  /* Called on the main thread when something requests audio from an input
387
   * audio device aID. */
388
  virtual nsresult OpenAudioInput(CubebUtils::AudioDeviceID aID,
389
                                  AudioDataListener* aListener) override;
390
  /* Runs off a message on the graph when input audio from aID is not needed
391
   * anymore, for a particular stream. It can be that other streams still need
392
   * audio from this audio input device. */
393
  void CloseAudioInputImpl(Maybe<CubebUtils::AudioDeviceID>& aID,
394
                           AudioDataListener* aListener);
395
  /* Called on the main thread when input audio from aID is not needed
396
   * anymore, for a particular stream. It can be that other streams still need
397
   * audio from this audio input device. */
398
  virtual void CloseAudioInput(Maybe<CubebUtils::AudioDeviceID>& aID,
399
                               AudioDataListener* aListener) override;
400
  /* Called on the graph thread when the input device settings should be
401
   * reevaluated, for example, if the channel count of the input stream should
402
   * be changed. */
403
  void ReevaluateInputDevice();
404
  /* Called on the graph thread when there is new output data for listeners.
405
   * This is the mixed audio output of this MediaStreamGraph. */
406
  void NotifyOutputData(AudioDataValue* aBuffer, size_t aFrames,
407
                        TrackRate aRate, uint32_t aChannels);
408
  /* Called on the graph thread when there is new input data for listeners. This
409
   * is the raw audio input for this MediaStreamGraph. */
410
  void NotifyInputData(const AudioDataValue* aBuffer, size_t aFrames,
411
                       TrackRate aRate, uint32_t aChannels);
412
  /* Called every time there are changes to input/output audio devices like
413
   * plug/unplug etc. This can be called on any thread, and posts a message to
414
   * the main thread so that it can post a message to the graph thread. */
415
  void DeviceChanged();
416
  /* Called every time there are changes to input/output audio devices. This is
417
   * called on the graph thread. */
418
  void DeviceChangedImpl();
419
420
  /**
421
   * Compute how much stream data we would like to buffer for aStream.
422
   */
423
  StreamTime GetDesiredBufferEnd(MediaStream* aStream);
424
  /**
425
   * Returns true when there are no active streams.
426
   */
427
  bool IsEmpty() const
428
0
  {
429
0
    MOZ_ASSERT(OnGraphThreadOrNotRunning() ||
430
0
               (NS_IsMainThread() &&
431
0
                LifecycleStateRef() >= LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP));
432
0
    return mStreams.IsEmpty() && mSuspendedStreams.IsEmpty() && mPortCount == 0;
433
0
  }
434
435
  /**
436
   * Add aStream to the graph and initializes its graph-specific state.
437
   */
438
  void AddStreamGraphThread(MediaStream* aStream);
439
  /**
440
   * Remove aStream from the graph. Ensures that pending messages about the
441
   * stream back to the main thread are flushed.
442
   */
443
  void RemoveStreamGraphThread(MediaStream* aStream);
444
  /**
445
   * Remove aPort from the graph and release it.
446
   */
447
  void DestroyPort(MediaInputPort* aPort);
448
  /**
449
   * Mark the media stream order as dirty.
450
   */
451
  void SetStreamOrderDirty()
452
0
  {
453
0
    MOZ_ASSERT(OnGraphThreadOrNotRunning());
454
0
    mStreamOrderDirty = true;
455
0
  }
456
457
  uint32_t AudioOutputChannelCount() const
458
0
  {
459
0
    return mOutputChannels;
460
0
  }
461
462
  /**
463
   * The audio input channel count for a MediaStreamGraph is the max of all the
464
   * channel counts requested by the listeners. The max channel count is
465
   * delivered to the listeners themselves, and they take care of downmixing.
466
   */
467
  uint32_t AudioInputChannelCount()
468
0
  {
469
0
    MOZ_ASSERT(OnGraphThreadOrNotRunning());
470
0
471
#ifdef ANDROID
472
    if (!mInputDeviceUsers.GetValue(mInputDeviceID)) {
473
      return 0;
474
    }
475
#else
476
0
    if (!mInputDeviceID) {
477
0
      MOZ_ASSERT(mInputDeviceUsers.Count() == 0,
478
0
        "If running on a platform other than android,"
479
0
        "an explicit device id should be present");
480
0
      return 0;
481
0
    }
482
0
#endif
483
0
    uint32_t maxInputChannels = 0;
484
0
    // When/if we decide to support multiple input device per graph, this needs
485
0
    // loop over them.
486
0
    nsTArray<RefPtr<AudioDataListener>>* listeners =
487
0
      mInputDeviceUsers.GetValue(mInputDeviceID);
488
0
    MOZ_ASSERT(listeners);
489
0
    for (const auto& listener : *listeners) {
490
0
      maxInputChannels =
491
0
        std::max(maxInputChannels, listener->RequestedInputChannelCount(this));
492
0
    }
493
0
    return maxInputChannels;
494
0
  }
495
496
  CubebUtils::AudioDeviceID InputDeviceID()
497
0
  {
498
0
    return mInputDeviceID;
499
0
  }
500
501
  double MediaTimeToSeconds(GraphTime aTime) const
502
0
  {
503
0
    NS_ASSERTION(aTime > -STREAM_TIME_MAX && aTime <= STREAM_TIME_MAX,
504
0
                 "Bad time");
505
0
    return static_cast<double>(aTime)/GraphRate();
506
0
  }
507
508
  GraphTime SecondsToMediaTime(double aS) const
509
0
  {
510
0
    NS_ASSERTION(0 <= aS && aS <= TRACK_TICKS_MAX/TRACK_RATE_MAX,
511
0
                 "Bad seconds");
512
0
    return GraphRate() * aS;
513
0
  }
514
515
  GraphTime MillisecondsToMediaTime(int32_t aMS) const
516
0
  {
517
0
    return RateConvertTicksRoundDown(GraphRate(), 1000, aMS);
518
0
  }
519
520
  /**
521
   * Signal to the graph that the thread has paused indefinitly,
522
   * or resumed.
523
   */
524
  void PausedIndefinitly();
525
  void ResumedFromPaused();
526
527
  /**
528
   * Not safe to call off the MediaStreamGraph thread unless monitor is held!
529
   */
530
  GraphDriver* CurrentDriver() const
531
0
  {
532
#ifdef DEBUG
533
    if (!OnGraphThreadOrNotRunning()) {
534
      mMonitor.AssertCurrentThreadOwns();
535
    }
536
#endif
537
    return mDriver;
538
0
  }
539
540
  /**
541
   * Effectively set the new driver, while we are switching.
542
   * It is only safe to call this at the very end of an iteration, when there
543
   * has been a SwitchAtNextIteration call during the iteration. The driver
544
   * should return and pass the control to the new driver shortly after.
545
   * We can also switch from Revive() (on MainThread). Monitor must be held.
546
   */
547
  void SetCurrentDriver(GraphDriver* aDriver)
548
0
  {
549
0
    MOZ_ASSERT(mDriver->OnThread() || !mDriver->ThreadRunning());
550
#ifdef DEBUG
551
    mMonitor.AssertCurrentThreadOwns();
552
#endif
553
    mDriver = aDriver;
554
0
  }
555
556
  Monitor& GetMonitor()
557
0
  {
558
0
    return mMonitor;
559
0
  }
560
561
  void EnsureNextIteration()
562
0
  {
563
0
    mNeedAnotherIteration = true; // atomic
564
0
    // Note: GraphDriver must ensure that there's no race on setting
565
0
    // mNeedAnotherIteration and mGraphDriverAsleep -- see WaitForNextIteration()
566
0
    if (mGraphDriverAsleep) { // atomic
567
0
      MonitorAutoLock mon(mMonitor);
568
0
      CurrentDriver()->WakeUp(); // Might not be the same driver; might have woken already
569
0
    }
570
0
  }
571
572
  void EnsureNextIterationLocked()
573
0
  {
574
0
    mNeedAnotherIteration = true; // atomic
575
0
    if (mGraphDriverAsleep) { // atomic
576
0
      CurrentDriver()->WakeUp(); // Might not be the same driver; might have woken already
577
0
    }
578
0
  }
579
580
  // Capture Stream API. This allows to get a mixed-down output for a window.
581
  void RegisterCaptureStreamForWindow(uint64_t aWindowId,
582
                                      ProcessedMediaStream* aCaptureStream);
583
  void UnregisterCaptureStreamForWindow(uint64_t aWindowId);
584
  already_AddRefed<MediaInputPort>
585
  ConnectToCaptureStream(uint64_t aWindowId, MediaStream* aMediaStream);
586
587
  class StreamSet {
588
  public:
589
    class iterator {
590
    public:
591
      explicit iterator(MediaStreamGraphImpl& aGraph)
592
        : mGraph(&aGraph), mArrayNum(-1), mArrayIndex(0)
593
0
      {
594
0
        ++(*this);
595
0
      }
596
0
      iterator() : mGraph(nullptr), mArrayNum(2), mArrayIndex(0) {}
597
      MediaStream* operator*()
598
0
      {
599
0
        return Array()->ElementAt(mArrayIndex);
600
0
      }
601
      iterator operator++()
602
0
      {
603
0
        ++mArrayIndex;
604
0
        while (mArrayNum < 2 &&
605
0
          (mArrayNum < 0 || mArrayIndex >= Array()->Length())) {
606
0
          ++mArrayNum;
607
0
          mArrayIndex = 0;
608
0
        }
609
0
        return *this;
610
0
      }
611
      bool operator==(const iterator& aOther) const
612
0
      {
613
0
        return mArrayNum == aOther.mArrayNum && mArrayIndex == aOther.mArrayIndex;
614
0
      }
615
      bool operator!=(const iterator& aOther) const
616
0
      {
617
0
        return !(*this == aOther);
618
0
      }
619
    private:
620
      nsTArray<MediaStream*>* Array()
621
0
      {
622
0
        return mArrayNum == 0 ? &mGraph->mStreams : &mGraph->mSuspendedStreams;
623
0
      }
624
      MediaStreamGraphImpl* mGraph;
625
      int mArrayNum;
626
      uint32_t mArrayIndex;
627
    };
628
629
0
    explicit StreamSet(MediaStreamGraphImpl& aGraph) : mGraph(aGraph) {}
630
0
    iterator begin() { return iterator(mGraph); }
631
0
    iterator end() { return iterator(); }
632
  private:
633
    MediaStreamGraphImpl& mGraph;
634
  };
635
0
  StreamSet AllStreams() { return StreamSet(*this); }
636
637
  // Data members
638
  //
639
  /**
640
   * Graphs own owning references to their driver, until shutdown. When a driver
641
   * switch occur, previous driver is either deleted, or it's ownership is
642
   * passed to a event that will take care of the asynchronous cleanup, as
643
   * audio stream can take some time to shut down.
644
   * Accessed on both the main thread and the graph thread; both read and write.
645
   * Must hold monitor to access it.
646
   */
647
  RefPtr<GraphDriver> mDriver;
648
649
  // The following state is managed on the graph thread only, unless
650
  // mLifecycleState > LIFECYCLE_RUNNING in which case the graph thread
651
  // is not running and this state can be used from the main thread.
652
653
  /**
654
   * The graph keeps a reference to each stream.
655
   * References are maintained manually to simplify reordering without
656
   * unnecessary thread-safe refcount changes.
657
   * Must satisfy OnGraphThreadOrNotRunning().
658
   */
659
  nsTArray<MediaStream*> mStreams;
660
  /**
661
   * This stores MediaStreams that are part of suspended AudioContexts.
662
   * mStreams and mSuspendStream are disjoint sets: a stream is either suspended
663
   * or not suspended. Suspended streams are not ordered in UpdateStreamOrder,
664
   * and are therefore not doing any processing.
665
   * Must satisfy OnGraphThreadOrNotRunning().
666
   */
667
  nsTArray<MediaStream*> mSuspendedStreams;
668
  /**
669
   * Streams from mFirstCycleBreaker to the end of mStreams produce output
670
   * before they receive input.  They correspond to DelayNodes that are in
671
   * cycles.
672
   */
673
  uint32_t mFirstCycleBreaker;
674
  /**
675
   * Blocking decisions have been computed up to this time.
676
   * Between each iteration, this is the same as mProcessedTime.
677
   */
678
  GraphTime mStateComputedTime = 0;
679
  /**
680
   * All stream contents have been computed up to this time.
681
   * The next batch of updates from the main thread will be processed
682
   * at this time.  This is behind mStateComputedTime during processing.
683
   */
684
  GraphTime mProcessedTime = 0;
685
  /**
686
   * Date of the last time we updated the main thread with the graph state.
687
   */
688
  TimeStamp mLastMainThreadUpdate;
689
  /**
690
   * Number of active MediaInputPorts
691
   */
692
  int32_t mPortCount;
693
694
  /**
695
   * Devices to use for cubeb input & output, or nullptr for default device.
696
   * A MediaStreamGraph always has an output (even if silent).
697
   * If `mInputDeviceUsers.Count() != 0`, this MediaStreamGraph wants audio
698
   * input.
699
   *
700
   * In any case, the number of channels to use can be queried (on the graph
701
   * thread) by AudioInputChannelCount() and AudioOutputChannelCount().
702
   */
703
  CubebUtils::AudioDeviceID mInputDeviceID;
704
  CubebUtils::AudioDeviceID mOutputDeviceID;
705
  // Maps AudioDeviceID to an array of their users (that are listeners). This is
706
  // used to deliver audio input frames and to notify the listeners that the
707
  // audio device that delivers the audio frames has changed.
708
  // This is only touched on the graph thread.
709
  nsDataHashtable<nsVoidPtrHashKey,
710
                  nsTArray<RefPtr<AudioDataListener>>> mInputDeviceUsers;
711
712
  // True if the graph needs another iteration after the current iteration.
713
  Atomic<bool> mNeedAnotherIteration;
714
  // GraphDriver may need a WakeUp() if something changes
715
  Atomic<bool> mGraphDriverAsleep;
716
717
  // mMonitor guards the data below.
718
  // MediaStreamGraph normally does its work without holding mMonitor, so it is
719
  // not safe to just grab mMonitor from some thread and start monkeying with
720
  // the graph. Instead, communicate with the graph thread using provided
721
  // mechanisms such as the ControlMessage queue.
722
  Monitor mMonitor;
723
724
  // Data guarded by mMonitor (must always be accessed with mMonitor held,
725
  // regardless of the value of mLifecycleState).
726
727
  /**
728
   * State to copy to main thread
729
   */
730
  nsTArray<StreamUpdate> mStreamUpdates;
731
  /**
732
   * Runnables to run after the next update to main thread state.
733
   */
734
  nsTArray<nsCOMPtr<nsIRunnable> > mUpdateRunnables;
735
  /**
736
   * A list of batches of messages to process. Each batch is processed
737
   * as an atomic unit.
738
   */
739
  /*
740
   * Message queue processed by the MSG thread during an iteration.
741
   * Accessed on graph thread only.
742
   */
743
  nsTArray<MessageBlock> mFrontMessageQueue;
744
  /*
745
   * Message queue in which the main thread appends messages.
746
   * Access guarded by mMonitor.
747
   */
748
  nsTArray<MessageBlock> mBackMessageQueue;
749
750
  /* True if there will messages to process if we swap the message queues. */
751
  bool MessagesQueued() const
752
0
  {
753
0
    mMonitor.AssertCurrentThreadOwns();
754
0
    return !mBackMessageQueue.IsEmpty();
755
0
  }
756
  /**
757
   * This enum specifies where this graph is in its lifecycle. This is used
758
   * to control shutdown.
759
   * Shutdown is tricky because it can happen in two different ways:
760
   * 1) Shutdown due to inactivity. RunThread() detects that it has no
761
   * pending messages and no streams, and exits. The next RunInStableState()
762
   * checks if there are new pending messages from the main thread (true only
763
   * if new stream creation raced with shutdown); if there are, it revives
764
   * RunThread(), otherwise it commits to shutting down the graph. New stream
765
   * creation after this point will create a new graph. An async event is
766
   * dispatched to Shutdown() the graph's threads and then delete the graph
767
   * object.
768
   * 2) Forced shutdown at application shutdown, or completion of a
769
   * non-realtime graph. A flag is set, RunThread() detects the flag and
770
   * exits, the next RunInStableState() detects the flag, and dispatches the
771
   * async event to Shutdown() the graph's threads. However the graph object
772
   * is not deleted. New messages for the graph are processed synchronously on
773
   * the main thread if necessary. When the last stream is destroyed, the
774
   * graph object is deleted.
775
   *
776
   * This should be kept in sync with the LifecycleState_str array in
777
   * MediaStreamGraph.cpp
778
   */
779
  enum LifecycleState
780
  {
781
    // The graph thread hasn't started yet.
782
    LIFECYCLE_THREAD_NOT_STARTED,
783
    // RunThread() is running normally.
784
    LIFECYCLE_RUNNING,
785
    // In the following states, the graph thread is not running so
786
    // all "graph thread only" state in this class can be used safely
787
    // on the main thread.
788
    // RunThread() has exited and we're waiting for the next
789
    // RunInStableState(), at which point we can clean up the main-thread
790
    // side of the graph.
791
    LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP,
792
    // RunInStableState() posted a ShutdownRunnable, and we're waiting for it
793
    // to shut down the graph thread(s).
794
    LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN,
795
    // Graph threads have shut down but we're waiting for remaining streams
796
    // to be destroyed. Only happens during application shutdown and on
797
    // completed non-realtime graphs, since normally we'd only shut down a
798
    // realtime graph when it has no streams.
799
    LIFECYCLE_WAITING_FOR_STREAM_DESTRUCTION
800
  };
801
802
  /**
803
   * Modified only in mMonitor.  Transitions to
804
   * LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP occur on the graph thread at
805
   * the end of an iteration.  All other transitions occur on the main thread.
806
   */
807
  LifecycleState mLifecycleState;
808
  LifecycleState& LifecycleStateRef()
809
0
  {
810
#if DEBUG
811
    if (!mDetectedNotRunning) {
812
      mMonitor.AssertCurrentThreadOwns();
813
    }
814
#endif
815
    return mLifecycleState;
816
0
  }
817
  const LifecycleState& LifecycleStateRef() const
818
0
  {
819
0
#if DEBUG
820
0
    if (!mDetectedNotRunning) {
821
0
      mMonitor.AssertCurrentThreadOwns();
822
0
    }
823
0
#endif
824
0
    return mLifecycleState;
825
0
  }
826
  /**
827
   * The graph should stop processing at or after this time.
828
   * Only set on main thread. Read on both main and MSG thread.
829
   */
830
  Atomic<GraphTime> mEndTime;
831
832
  /**
833
   * True when we need to do a forced shutdown during application shutdown.
834
   * Only set on main thread.
835
   * Can be read safely on the main thread, on all other threads mMonitor must
836
   * be held.
837
   */
838
  bool mForceShutDown;
839
840
  /**
841
   * Drop this reference during shutdown to unblock shutdown.
842
   * Only accessed on the main thread.
843
   **/
844
  RefPtr<media::ShutdownTicket> mForceShutdownTicket;
845
846
  /**
847
   * True when we have posted an event to the main thread to run
848
   * RunInStableState() and the event hasn't run yet.
849
   * Accessed on both main and MSG thread, mMonitor must be held.
850
   */
851
  bool mPostedRunInStableStateEvent;
852
853
  // Main thread only
854
855
  /**
856
   * Messages posted by the current event loop task. These are forwarded to
857
   * the media graph thread during RunInStableState. We can't forward them
858
   * immediately because we want all messages between stable states to be
859
   * processed as an atomic batch.
860
   */
861
  nsTArray<UniquePtr<ControlMessage>> mCurrentTaskMessageQueue;
862
  /**
863
   * True when RunInStableState has determined that mLifecycleState is >
864
   * LIFECYCLE_RUNNING. Since only the main thread can reset mLifecycleState to
865
   * LIFECYCLE_RUNNING, this can be relied on to not change unexpectedly.
866
   */
867
  Atomic<bool> mDetectedNotRunning;
868
  /**
869
   * True when a stable state runner has been posted to the appshell to run
870
   * RunInStableState at the next stable state.
871
   * Only accessed on the main thread.
872
   */
873
  bool mPostedRunInStableState;
874
  /**
875
   * True when processing real-time audio/video.  False when processing non-realtime
876
   * audio.
877
   */
878
  const bool mRealtime;
879
  /**
880
   * True when a non-realtime MediaStreamGraph has started to process input.  This
881
   * value is only accessed on the main thread.
882
   */
883
  bool mNonRealtimeProcessing;
884
  /**
885
   * True when a change has happened which requires us to recompute the stream
886
   * blocking order.
887
   */
888
  bool mStreamOrderDirty;
889
  /**
890
   * Hold a ref to the Latency logger
891
   */
892
  RefPtr<AsyncLatencyLogger> mLatencyLog;
893
  AudioMixer mMixer;
894
  const RefPtr<AbstractThread> mAbstractMainThread;
895
896
  // used to limit graph shutdown time
897
  // Only accessed on the main thread.
898
  nsCOMPtr<nsITimer> mShutdownTimer;
899
900
private:
901
  virtual ~MediaStreamGraphImpl();
902
903
  MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
904
905
  /**
906
   * This class uses manual memory management, and all pointers to it are raw
907
   * pointers. However, in order for it to implement nsIMemoryReporter, it needs
908
   * to implement nsISupports and so be ref-counted. So it maintains a single
909
   * nsRefPtr to itself, giving it a ref-count of 1 during its entire lifetime,
910
   * and Destroy() nulls this self-reference in order to trigger self-deletion.
911
   */
912
  RefPtr<MediaStreamGraphImpl> mSelfRef;
913
914
  struct WindowAndStream
915
  {
916
    uint64_t mWindowId;
917
    RefPtr<ProcessedMediaStream> mCaptureStreamSink;
918
  };
919
  /**
920
   * Stream for window audio capture.
921
   */
922
  nsTArray<WindowAndStream> mWindowCaptureStreams;
923
924
  /**
925
   * Number of channels on output.
926
   */
927
  const uint32_t mOutputChannels;
928
929
  /**
930
   * Global volume scale. Used when running tests so that the output is not too
931
   * loud.
932
   */
933
  const float mGlobalVolume;
934
935
#ifdef DEBUG
936
  /**
937
   * Used to assert when AppendMessage() runs ControlMessages synchronously.
938
   */
939
  bool mCanRunMessagesSynchronously;
940
#endif
941
};
942
943
} // namespace mozilla
944
945
#endif /* MEDIASTREAMGRAPHIMPL_H_ */