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