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/. */
6 #include "MediaTrackGraphImpl.h"
7 #include "MediaTrackListener.h"
8 #include "mozilla/MathAlgorithms.h"
9 #include "mozilla/Unused.h"
11 #include "AudioSegment.h"
12 #include "mozilla/Logging.h"
13 #include "mozilla/Attributes.h"
14 #include "AudioCaptureTrack.h"
15 #include "ImageContainer.h"
16 #include "AudioNodeEngine.h"
17 #include "AudioNodeTrack.h"
18 #include "AudioNodeExternalInputTrack.h"
19 #include "webaudio/MediaStreamAudioDestinationNode.h"
21 #include "DOMMediaStream.h"
23 using namespace mozilla::layers
;
24 using namespace mozilla::dom
;
25 using namespace mozilla::gfx
;
29 // We are mixing to mono until PeerConnection can accept stereo
30 static const uint32_t MONO
= 1;
32 AudioCaptureTrack::AudioCaptureTrack(TrackRate aRate
)
33 : ProcessedMediaTrack(aRate
, MediaSegment::AUDIO
, new AudioSegment()),
35 MOZ_ASSERT(NS_IsMainThread());
36 MOZ_COUNT_CTOR(AudioCaptureTrack
);
37 mMixer
.AddCallback(WrapNotNull(this));
40 AudioCaptureTrack::~AudioCaptureTrack() {
41 MOZ_COUNT_DTOR(AudioCaptureTrack
);
42 mMixer
.RemoveCallback(this);
45 void AudioCaptureTrack::Start() {
46 class Message
: public ControlMessage
{
48 explicit Message(AudioCaptureTrack
* aTrack
)
49 : ControlMessage(aTrack
), mTrack(aTrack
) {}
51 virtual void Run() { mTrack
->mStarted
= true; }
54 AudioCaptureTrack
* mTrack
;
56 GraphImpl()->AppendMessage(MakeUnique
<Message
>(this));
59 void AudioCaptureTrack::ProcessInput(GraphTime aFrom
, GraphTime aTo
,
65 uint32_t inputCount
= mInputs
.Length();
71 // If the captured track is connected back to a object on the page (be it an
72 // HTMLMediaElement with a track as source, or an AudioContext), a cycle
73 // situation occur. This can work if it's an AudioContext with at least one
74 // DelayNode, but the MTG will mute the whole cycle otherwise.
75 if (InMutedCycle() || inputCount
== 0) {
76 GetData
<AudioSegment
>()->AppendNullData(aTo
- aFrom
);
78 // We mix down all the tracks of all inputs, to a stereo track. Everything
79 // is {up,down}-mixed to stereo.
82 for (uint32_t i
= 0; i
< inputCount
; i
++) {
83 MediaTrack
* s
= mInputs
[i
]->GetSource();
84 AudioSegment
* inputSegment
= s
->GetData
<AudioSegment
>();
85 TrackTime inputStart
= s
->GraphTimeToTrackTimeWithBlocking(aFrom
);
86 TrackTime inputEnd
= s
->GraphTimeToTrackTimeWithBlocking(aTo
);
88 if (s
->Ended() && inputSegment
->GetDuration() <= inputStart
) {
89 toMix
.AppendNullData(aTo
- aFrom
);
91 toMix
.AppendSlice(*inputSegment
, inputStart
, inputEnd
);
92 // Care for tracks blocked in the [aTo, aFrom] range.
93 if (inputEnd
- inputStart
< aTo
- aFrom
) {
94 toMix
.AppendNullData((aTo
- aFrom
) - (inputEnd
- inputStart
));
97 toMix
.Mix(mMixer
, MONO
, Graph()->GraphRate());
99 // This calls MixerCallback below
100 mMixer
.FinishMixing();
104 uint32_t AudioCaptureTrack::NumberOfChannels() const {
105 return GetData
<AudioSegment
>()->MaxChannelCount();
108 void AudioCaptureTrack::MixerCallback(AudioDataValue
* aMixedBuffer
,
109 AudioSampleFormat aFormat
,
110 uint32_t aChannels
, uint32_t aFrames
,
111 uint32_t aSampleRate
) {
112 AutoTArray
<nsTArray
<AudioDataValue
>, MONO
> output
;
113 AutoTArray
<const AudioDataValue
*, MONO
> bufferPtrs
;
114 output
.SetLength(MONO
);
115 bufferPtrs
.SetLength(MONO
);
117 uint32_t written
= 0;
118 // We need to copy here, because the mixer will reuse the storage, we should
119 // not hold onto it. Buffers are in planar format.
120 for (uint32_t channel
= 0; channel
< aChannels
; channel
++) {
121 AudioDataValue
* out
= output
[channel
].AppendElements(aFrames
);
122 PodCopy(out
, aMixedBuffer
+ written
, aFrames
);
123 bufferPtrs
[channel
] = out
;
128 new mozilla::SharedChannelArrayBuffer
<AudioDataValue
>(std::move(output
));
129 chunk
.mDuration
= aFrames
;
130 chunk
.mBufferFormat
= aFormat
;
131 chunk
.mChannelData
.SetLength(MONO
);
132 for (uint32_t channel
= 0; channel
< aChannels
; channel
++) {
133 chunk
.mChannelData
[channel
] = bufferPtrs
[channel
];
136 // Now we have mixed data, simply append it.
137 GetData
<AudioSegment
>()->AppendAndConsumeChunk(std::move(chunk
));
139 } // namespace mozilla