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 "gmock/gmock.h"
7 #include "gtest/gtest.h"
8
9 #include "AudioGenerator.h"
10 #include "MediaEngineWebRTCAudio.h"
11 #include "MediaTrackGraphImpl.h"
12 #include "mozilla/Attributes.h"
13 #include "mozilla/UniquePtr.h"
14 #include "nsTArray.h"
15
16 using namespace mozilla;
17 using testing::NiceMock;
18 using testing::Return;
19
20 class MockGraph : public MediaTrackGraphImpl {
21 public:
MockGraph(TrackRate aRate,uint32_t aChannels)22 MockGraph(TrackRate aRate, uint32_t aChannels)
23 : MediaTrackGraphImpl(OFFLINE_THREAD_DRIVER, DIRECT_DRIVER, aRate,
24 aChannels, nullptr, AbstractThread::MainThread()) {
25 ON_CALL(*this, OnGraphThread).WillByDefault(Return(true));
26 // Remove this graph's driver since it holds a ref. If no AppendMessage
27 // takes place, the driver never starts. This will also make sure no-one
28 // tries to use it. We are still kept alive by the self-ref. Destroy() must
29 // be called to break that cycle.
30 SetCurrentDriver(nullptr);
31 }
32
33 MOCK_CONST_METHOD0(OnGraphThread, bool());
34
35 protected:
36 ~MockGraph() = default;
37 };
38
TEST(TestAudioInputProcessing,UnaccountedPacketizerBuffering)39 TEST(TestAudioInputProcessing, UnaccountedPacketizerBuffering)
40 {
41 const TrackRate rate = 48000;
42 const uint32_t channels = 2;
43 auto graph = MakeRefPtr<NiceMock<MockGraph>>(48000, 2);
44 auto aip = MakeRefPtr<AudioInputProcessing>(channels, PRINCIPAL_HANDLE_NONE);
45 AudioGenerator<AudioDataValue> generator(channels, rate);
46
47 // The packetizer takes 480 frames. To trigger this we need to populate the
48 // packetizer without filling it completely the first iteration, then trigger
49 // the unbounded-buffering-assertion on the second iteration.
50
51 const size_t nrFrames = 440;
52 const size_t bufferSize = nrFrames * channels;
53 GraphTime processedTime;
54 GraphTime nextTime;
55 nsTArray<AudioDataValue> buffer(bufferSize);
56 buffer.AppendElements(bufferSize);
57 AudioSegment segment;
58 bool ended;
59
60 aip->Start();
61
62 {
63 // First iteration.
64 // 440 does not fill the packetizer but accounts for pre-silence buffering.
65 // Iterations have processed 72 frames more than provided by callbacks:
66 // 512 - 440 = 72
67 // Thus the total amount of pre-silence buffering added is:
68 // 480 + 128 - 72 = 536
69 // The iteration pulls in 512 frames of silence, leaving 24 frames buffered.
70 processedTime = 0;
71 nextTime = MediaTrackGraphImpl::RoundUpToEndOfAudioBlock(nrFrames);
72 generator.GenerateInterleaved(buffer.Elements(), nrFrames);
73 aip->NotifyInputData(graph,
74 AudioInputProcessing::BufferInfo{
75 buffer.Elements(), nrFrames, channels, rate},
76 nextTime - nrFrames);
77 aip->ProcessInput(graph, nullptr);
78 aip->Pull(graph, processedTime, nextTime, segment.GetDuration(), &segment,
79 true, &ended);
80 EXPECT_EQ(aip->NumBufferedFrames(graph), 24U);
81 }
82
83 {
84 // Second iteration.
85 // 880 fills a packet of 480 frames. 400 left in the packetizer.
86 // Last iteration left 24 frames buffered, making this iteration have 504
87 // frames in the buffer while pulling 384 frames.
88 // That leaves 120 frames buffered, which must be no more than the total
89 // intended buffering of 480 + 128 = 608 frames.
90 processedTime = nextTime;
91 nextTime = MediaTrackGraphImpl::RoundUpToEndOfAudioBlock(2 * nrFrames);
92 generator.GenerateInterleaved(buffer.Elements(), nrFrames);
93 aip->NotifyInputData(graph,
94 AudioInputProcessing::BufferInfo{
95 buffer.Elements(), nrFrames, channels, rate},
96 nextTime - (2 * nrFrames));
97 aip->ProcessInput(graph, nullptr);
98 aip->Pull(graph, processedTime, nextTime, segment.GetDuration(), &segment,
99 true, &ended);
100 EXPECT_EQ(aip->NumBufferedFrames(graph), 120U);
101 }
102
103 graph->Destroy();
104 }
105