LCOV - code coverage report
Current view: top level - dom/media - AudioCaptureStream.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 79 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 10 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #include "MediaStreamGraphImpl.h"
       7             : #include "MediaStreamListener.h"
       8             : #include "mozilla/MathAlgorithms.h"
       9             : #include "mozilla/Unused.h"
      10             : 
      11             : #include "AudioSegment.h"
      12             : #include "mozilla/Logging.h"
      13             : #include "mozilla/Attributes.h"
      14             : #include "AudioCaptureStream.h"
      15             : #include "ImageContainer.h"
      16             : #include "AudioNodeEngine.h"
      17             : #include "AudioNodeStream.h"
      18             : #include "AudioNodeExternalInputStream.h"
      19             : #include "webaudio/MediaStreamAudioDestinationNode.h"
      20             : #include <algorithm>
      21             : #include "DOMMediaStream.h"
      22             : 
      23             : using namespace mozilla::layers;
      24             : using namespace mozilla::dom;
      25             : using namespace mozilla::gfx;
      26             : 
      27             : namespace mozilla
      28             : {
      29             : 
      30             : // We are mixing to mono until PeerConnection can accept stereo
      31             : static const uint32_t MONO = 1;
      32             : 
      33           0 : AudioCaptureStream::AudioCaptureStream(TrackID aTrackId)
      34             :   : ProcessedMediaStream()
      35             :   , mTrackId(aTrackId)
      36             :   , mStarted(false)
      37           0 :   , mTrackCreated(false)
      38             : {
      39           0 :   MOZ_ASSERT(NS_IsMainThread());
      40           0 :   MOZ_COUNT_CTOR(AudioCaptureStream);
      41           0 :   mMixer.AddCallback(this);
      42           0 : }
      43             : 
      44           0 : AudioCaptureStream::~AudioCaptureStream()
      45             : {
      46           0 :   MOZ_COUNT_DTOR(AudioCaptureStream);
      47           0 :   mMixer.RemoveCallback(this);
      48           0 : }
      49             : 
      50             : void
      51           0 : AudioCaptureStream::Start()
      52             : {
      53           0 :   class Message : public ControlMessage {
      54             :   public:
      55           0 :     explicit Message(AudioCaptureStream* aStream)
      56           0 :       : ControlMessage(aStream), mStream(aStream) {}
      57             : 
      58           0 :     virtual void Run()
      59             :     {
      60           0 :       mStream->mStarted = true;
      61           0 :     }
      62             : 
      63             :   protected:
      64             :     AudioCaptureStream* mStream;
      65             :   };
      66           0 :   GraphImpl()->AppendMessage(MakeUnique<Message>(this));
      67           0 : }
      68             : 
      69             : void
      70           0 : AudioCaptureStream::ProcessInput(GraphTime aFrom, GraphTime aTo,
      71             :                                  uint32_t aFlags)
      72             : {
      73           0 :   if (!mStarted) {
      74           0 :     return;
      75             :   }
      76             : 
      77           0 :   uint32_t inputCount = mInputs.Length();
      78           0 :   StreamTracks::Track* track = EnsureTrack(mTrackId);
      79             :   // Notify the DOM everything is in order.
      80           0 :   if (!mTrackCreated) {
      81           0 :     for (uint32_t i = 0; i < mListeners.Length(); i++) {
      82           0 :       MediaStreamListener* l = mListeners[i];
      83           0 :       AudioSegment tmp;
      84           0 :       l->NotifyQueuedTrackChanges(
      85           0 :         Graph(), mTrackId, 0, TrackEventCommand::TRACK_EVENT_CREATED, tmp);
      86           0 :       l->NotifyFinishedTrackCreation(Graph());
      87             :     }
      88           0 :     mTrackCreated = true;
      89             :   }
      90             : 
      91           0 :   if (IsFinishedOnGraphThread()) {
      92           0 :     return;
      93             :   }
      94             : 
      95             :   // If the captured stream is connected back to a object on the page (be it an
      96             :   // HTMLMediaElement with a stream as source, or an AudioContext), a cycle
      97             :   // situation occur. This can work if it's an AudioContext with at least one
      98             :   // DelayNode, but the MSG will mute the whole cycle otherwise.
      99           0 :   if (InMutedCycle() || inputCount == 0) {
     100           0 :     track->Get<AudioSegment>()->AppendNullData(aTo - aFrom);
     101             :   } else {
     102             :     // We mix down all the tracks of all inputs, to a stereo track. Everything
     103             :     // is {up,down}-mixed to stereo.
     104           0 :     mMixer.StartMixing();
     105           0 :     AudioSegment output;
     106           0 :     for (uint32_t i = 0; i < inputCount; i++) {
     107           0 :       MediaStream* s = mInputs[i]->GetSource();
     108           0 :       StreamTracks::TrackIter track(s->GetStreamTracks(), MediaSegment::AUDIO);
     109           0 :       if (track.IsEnded()) {
     110             :         // No tracks for this input. Still we append data to trigger the mixer.
     111           0 :         AudioSegment toMix;
     112           0 :         toMix.AppendNullData(aTo - aFrom);
     113           0 :         toMix.Mix(mMixer, MONO, Graph()->GraphRate());
     114             :       }
     115           0 :       for (; !track.IsEnded(); track.Next()) {
     116           0 :         AudioSegment* inputSegment = track->Get<AudioSegment>();
     117           0 :         StreamTime inputStart = s->GraphTimeToStreamTimeWithBlocking(aFrom);
     118           0 :         StreamTime inputEnd = s->GraphTimeToStreamTimeWithBlocking(aTo);
     119           0 :         AudioSegment toMix;
     120           0 :         if (track->IsEnded() && inputSegment->GetDuration() <= inputStart) {
     121           0 :           toMix.AppendNullData(aTo - aFrom);
     122             :         } else {
     123           0 :           toMix.AppendSlice(*inputSegment, inputStart, inputEnd);
     124             :           // Care for streams blocked in the [aTo, aFrom] range.
     125           0 :           if (inputEnd - inputStart < aTo - aFrom) {
     126           0 :             toMix.AppendNullData((aTo - aFrom) - (inputEnd - inputStart));
     127             :           }
     128             :         }
     129           0 :         toMix.Mix(mMixer, MONO, Graph()->GraphRate());
     130             :       }
     131             :     }
     132             :     // This calls MixerCallback below
     133           0 :     mMixer.FinishMixing();
     134             :   }
     135             : 
     136             :   // Regardless of the status of the input tracks, we go foward.
     137           0 :   mTracks.AdvanceKnownTracksTime(GraphTimeToStreamTimeWithBlocking((aTo)));
     138             : }
     139             : 
     140             : void
     141           0 : AudioCaptureStream::MixerCallback(AudioDataValue* aMixedBuffer,
     142             :                                   AudioSampleFormat aFormat, uint32_t aChannels,
     143             :                                   uint32_t aFrames, uint32_t aSampleRate)
     144             : {
     145           0 :   AutoTArray<nsTArray<AudioDataValue>, MONO> output;
     146           0 :   AutoTArray<const AudioDataValue*, MONO> bufferPtrs;
     147           0 :   output.SetLength(MONO);
     148           0 :   bufferPtrs.SetLength(MONO);
     149             : 
     150           0 :   uint32_t written = 0;
     151             :   // We need to copy here, because the mixer will reuse the storage, we should
     152             :   // not hold onto it. Buffers are in planar format.
     153           0 :   for (uint32_t channel = 0; channel < aChannels; channel++) {
     154           0 :     AudioDataValue* out = output[channel].AppendElements(aFrames);
     155           0 :     PodCopy(out, aMixedBuffer + written, aFrames);
     156           0 :     bufferPtrs[channel] = out;
     157           0 :     written += aFrames;
     158             :   }
     159           0 :   AudioChunk chunk;
     160           0 :   chunk.mBuffer = new mozilla::SharedChannelArrayBuffer<AudioDataValue>(&output);
     161           0 :   chunk.mDuration = aFrames;
     162           0 :   chunk.mBufferFormat = aFormat;
     163           0 :   chunk.mVolume = 1.0f;
     164           0 :   chunk.mChannelData.SetLength(MONO);
     165           0 :   for (uint32_t channel = 0; channel < aChannels; channel++) {
     166           0 :     chunk.mChannelData[channel] = bufferPtrs[channel];
     167             :   }
     168             : 
     169             :   // Now we have mixed data, simply append it to out track.
     170           0 :   EnsureTrack(mTrackId)->Get<AudioSegment>()->AppendAndConsumeChunk(&chunk);
     171           0 : }
     172             : }

Generated by: LCOV version 1.13