1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "CrossGraphPort.h"
7 #include "AudioDeviceInfo.h"
8 #include "AudioStreamTrack.h"
9 #include "MediaTrackGraph.h"
10 #include "mozilla/Logging.h"
11 #include "mozilla/Preferences.h"
22 extern LazyLogModule gMediaTrackGraphLog
;
23 #define LOG(type, msg) MOZ_LOG(gMediaTrackGraphLog, type, msg)
24 #define LOG_TEST(type) MOZ_LOG_TEST(gMediaTrackGraphLog, type)
26 UniquePtr
<CrossGraphPort
> CrossGraphPort::Connect(
27 const RefPtr
<dom::AudioStreamTrack
>& aStreamTrack
,
28 MediaTrackGraph
* aPartnerGraph
) {
29 MOZ_ASSERT(aStreamTrack
);
30 MOZ_ASSERT(aPartnerGraph
);
31 if (aStreamTrack
->Graph() == aPartnerGraph
) {
32 // Primary graph the same as partner graph, just remove the existing cross
37 RefPtr
<CrossGraphReceiver
> receiver
= aPartnerGraph
->CreateCrossGraphReceiver(
38 aStreamTrack
->Graph()->GraphRate());
40 RefPtr
<CrossGraphTransmitter
> transmitter
=
41 aStreamTrack
->Graph()->CreateCrossGraphTransmitter(receiver
);
43 RefPtr
<MediaInputPort
> port
=
44 aStreamTrack
->ForwardTrackContentsTo(transmitter
);
46 return WrapUnique(new CrossGraphPort(std::move(port
), std::move(transmitter
),
47 std::move(receiver
)));
50 CrossGraphPort::~CrossGraphPort() {
51 mTransmitter
->Destroy();
53 mTransmitterPort
->Destroy();
56 /** CrossGraphTransmitter **/
58 CrossGraphTransmitter::CrossGraphTransmitter(
59 TrackRate aSampleRate
, RefPtr
<CrossGraphReceiver
> aReceiver
)
60 : ProcessedMediaTrack(aSampleRate
, MediaSegment::AUDIO
,
61 nullptr /* aSegment */),
62 mReceiver(std::move(aReceiver
)) {}
64 void CrossGraphTransmitter::ProcessInput(GraphTime aFrom
, GraphTime aTo
,
66 MOZ_ASSERT(!mInputs
.IsEmpty());
67 MOZ_ASSERT(mDisabledMode
== DisabledTrackMode::ENABLED
);
69 MediaTrack
* input
= mInputs
[0]->GetSource();
72 (input
->GetEnd() <= input
->GraphTimeToTrackTimeWithBlocking(aFrom
))) {
77 LOG(LogLevel::Verbose
,
78 ("Transmitter (%p) from %" PRId64
", to %" PRId64
", ticks %" PRId64
"",
79 this, aFrom
, aTo
, aTo
- aFrom
));
83 for (GraphTime t
= aFrom
; t
< aTo
; t
= next
) {
84 MediaInputPort::InputInterval interval
=
85 MediaInputPort::GetNextInputInterval(mInputs
[0], t
);
86 interval
.mEnd
= std::min(interval
.mEnd
, aTo
);
88 TrackTime ticks
= interval
.mEnd
- interval
.mStart
;
91 if (interval
.mStart
>= interval
.mEnd
) {
95 if (interval
.mInputIsBlocked
) {
96 audio
.AppendNullData(ticks
);
97 } else if (input
->IsSuspended()) {
98 audio
.AppendNullData(ticks
);
100 MOZ_ASSERT(GetEnd() == GraphTimeToTrackTimeWithBlocking(interval
.mStart
),
102 TrackTime inputStart
=
103 input
->GraphTimeToTrackTimeWithBlocking(interval
.mStart
);
105 input
->GraphTimeToTrackTimeWithBlocking(interval
.mEnd
);
106 audio
.AppendSlice(*input
->GetData(), inputStart
, inputEnd
);
112 for (AudioSegment::ChunkIterator
iter(audio
); !iter
.IsEnded(); iter
.Next()) {
113 Unused
<< mReceiver
->EnqueueAudio(*iter
);
117 /** CrossGraphReceiver **/
119 CrossGraphReceiver::CrossGraphReceiver(TrackRate aSampleRate
,
120 TrackRate aTransmitterRate
)
121 : ProcessedMediaTrack(aSampleRate
, MediaSegment::AUDIO
,
122 static_cast<MediaSegment
*>(new AudioSegment())),
123 mDriftCorrection(aTransmitterRate
, aSampleRate
, PRINCIPAL_HANDLE_NONE
) {}
125 uint32_t CrossGraphReceiver::NumberOfChannels() const {
126 return GetData
<AudioSegment
>()->MaxChannelCount();
129 void CrossGraphReceiver::ProcessInput(GraphTime aFrom
, GraphTime aTo
,
131 LOG(LogLevel::Verbose
,
132 ("Receiver (%p) mSegment: duration: %" PRId64
", from %" PRId64
133 ", to %" PRId64
", ticks %" PRId64
"",
134 this, mSegment
->GetDuration(), aFrom
, aTo
, aTo
- aFrom
));
136 AudioSegment transmittedAudio
;
137 while (mCrossThreadFIFO
.AvailableRead()) {
139 Unused
<< mCrossThreadFIFO
.Dequeue(&chunk
, 1);
140 transmittedAudio
.AppendAndConsumeChunk(std::move(chunk
));
141 mTransmitterHasStarted
= true;
144 if (mTransmitterHasStarted
) {
145 // If it does not have enough frames the result will be silence.
146 AudioSegment audioCorrected
=
147 mDriftCorrection
.RequestFrames(transmittedAudio
, aTo
- aFrom
);
148 if (LOG_TEST(LogLevel::Verbose
) && audioCorrected
.IsNull()) {
149 LOG(LogLevel::Verbose
,
150 ("Receiver(%p): Silence has been added, not enough input", this));
152 mSegment
->AppendFrom(&audioCorrected
);
154 mSegment
->AppendNullData(aTo
- aFrom
);
158 int CrossGraphReceiver::EnqueueAudio(AudioChunk
& aChunk
) {
159 // This will take place on transmitter graph thread only.
160 return mCrossThreadFIFO
.Enqueue(aChunk
);
163 } // namespace mozilla