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 "MediaTrackGraphImpl.h"
7
8 #include "gmock/gmock.h"
9 #include "gtest/gtest-printers.h"
10 #include "gtest/gtest.h"
11
12 #include "GMPTestMonitor.h"
13 #include "MockCubeb.h"
14
TEST(TestAudioTrackGraph,DifferentDeviceIDs)15 TEST(TestAudioTrackGraph, DifferentDeviceIDs)
16 {
17 MockCubeb* cubeb = new MockCubeb();
18 CubebUtils::ForceSetCubebContext(cubeb->AsCubebContext());
19
20 MediaTrackGraph* g1 = MediaTrackGraph::GetInstance(
21 MediaTrackGraph::AUDIO_THREAD_DRIVER, /*window*/ nullptr,
22 MediaTrackGraph::REQUEST_DEFAULT_SAMPLE_RATE,
23 /*OutputDeviceID*/ nullptr);
24
25 MediaTrackGraph* g2 = MediaTrackGraph::GetInstance(
26 MediaTrackGraph::AUDIO_THREAD_DRIVER, /*window*/ nullptr,
27 MediaTrackGraph::REQUEST_DEFAULT_SAMPLE_RATE,
28 /*OutputDeviceID*/ reinterpret_cast<cubeb_devid>(1));
29
30 MediaTrackGraph* g1_2 = MediaTrackGraph::GetInstance(
31 MediaTrackGraph::AUDIO_THREAD_DRIVER, /*window*/ nullptr,
32 MediaTrackGraph::REQUEST_DEFAULT_SAMPLE_RATE,
33 /*OutputDeviceID*/ nullptr);
34
35 MediaTrackGraph* g2_2 = MediaTrackGraph::GetInstance(
36 MediaTrackGraph::AUDIO_THREAD_DRIVER, /*window*/ nullptr,
37 MediaTrackGraph::REQUEST_DEFAULT_SAMPLE_RATE,
38 /*OutputDeviceID*/ reinterpret_cast<cubeb_devid>(1));
39
40 EXPECT_NE(g1, g2) << "Different graphs have due to different device ids";
41 EXPECT_EQ(g1, g1_2) << "Same graphs for same device ids";
42 EXPECT_EQ(g2, g2_2) << "Same graphs for same device ids";
43
44 // Dummy track to make graph rolling. Add it and remove it to remove the
45 // graph from the global hash table and let it shutdown.
46 RefPtr<SourceMediaTrack> dummySource1 =
47 g1->CreateSourceTrack(MediaSegment::AUDIO);
48 RefPtr<SourceMediaTrack> dummySource2 =
49 g2->CreateSourceTrack(MediaSegment::AUDIO);
50
51 // Use a test monitor and a counter to wait for the current Graphs. It will
52 // wait for the Graphs to init and shutting down before the test finish.
53 // Otherwise, the workflow of the current graphs might affect the following
54 // tests (cubeb is a single instance process-wide).
55 GMPTestMonitor testMonitor;
56 Atomic<int> counter{0};
57
58 /* Use a ControlMessage to signal that the Graph has requested shutdown. */
59 class Message : public ControlMessage {
60 public:
61 explicit Message(MediaTrack* aTrack) : ControlMessage(aTrack) {}
62 void Run() override {
63 MOZ_ASSERT(mTrack->GraphImpl()->CurrentDriver()->AsAudioCallbackDriver());
64 if (++(*mCounter) == 2) {
65 mTestMonitor->SetFinished();
66 }
67 }
68 void RunDuringShutdown() override {
69 // During shutdown we still want the listener's NotifyRemoved to be
70 // called, since not doing that might block shutdown of other modules.
71 Run();
72 }
73 GMPTestMonitor* mTestMonitor = nullptr;
74 Atomic<int>* mCounter = nullptr;
75 };
76
77 UniquePtr<Message> message1 = MakeUnique<Message>(dummySource1);
78 message1->mTestMonitor = &testMonitor;
79 message1->mCounter = &counter;
80 dummySource1->GraphImpl()->AppendMessage(std::move(message1));
81
82 UniquePtr<Message> message2 = MakeUnique<Message>(dummySource2);
83 message2->mTestMonitor = &testMonitor;
84 message2->mCounter = &counter;
85 dummySource2->GraphImpl()->AppendMessage(std::move(message2));
86
87 dummySource1->Destroy();
88 dummySource2->Destroy();
89
90 testMonitor.AwaitFinished();
91 }
92
TEST(TestAudioTrackGraph,SetOutputDeviceID)93 TEST(TestAudioTrackGraph, SetOutputDeviceID)
94 {
95 MockCubeb* cubeb = new MockCubeb();
96 CubebUtils::ForceSetCubebContext(cubeb->AsCubebContext());
97
98 // Set the output device id in GetInstance method confirm that it is the one
99 // used in cubeb_stream_init.
100 MediaTrackGraph* graph = MediaTrackGraph::GetInstance(
101 MediaTrackGraph::AUDIO_THREAD_DRIVER, /*window*/ nullptr,
102 MediaTrackGraph::REQUEST_DEFAULT_SAMPLE_RATE,
103 /*OutputDeviceID*/ reinterpret_cast<cubeb_devid>(2));
104
105 EXPECT_EQ(cubeb->CurrentStream(), nullptr)
106 << "Cubeb stream has not been initialized yet";
107
108 // Dummy track to make graph rolling. Add it and remove it to remove the
109 // graph from the global hash table and let it shutdown.
110 RefPtr<SourceMediaTrack> dummySource =
111 graph->CreateSourceTrack(MediaSegment::AUDIO);
112
113 GMPTestMonitor mon;
114 RefPtr<GenericPromise> p = graph->NotifyWhenDeviceStarted(dummySource);
115 p->Then(GetMainThreadSerialEventTarget(), __func__,
116 [&mon, cubeb, dummySource]() {
117 EXPECT_EQ(cubeb->CurrentStream()->GetOutputDeviceID(),
118 reinterpret_cast<cubeb_devid>(2))
119 << "After init confirm the expected output device id";
120 // Test has finished, destroy the track to shutdown the MTG.
121 dummySource->Destroy();
122 mon.SetFinished();
123 });
124
125 mon.AwaitFinished();
126 }
127
TEST(TestAudioTrackGraph,NotifyDeviceStarted)128 TEST(TestAudioTrackGraph, NotifyDeviceStarted)
129 {
130 MockCubeb* cubeb = new MockCubeb();
131 CubebUtils::ForceSetCubebContext(cubeb->AsCubebContext());
132
133 MediaTrackGraph* graph = MediaTrackGraph::GetInstance(
134 MediaTrackGraph::AUDIO_THREAD_DRIVER, /*window*/ nullptr,
135 MediaTrackGraph::REQUEST_DEFAULT_SAMPLE_RATE, nullptr);
136
137 // Dummy track to make graph rolling. Add it and remove it to remove the
138 // graph from the global hash table and let it shutdown.
139 RefPtr<SourceMediaTrack> dummySource =
140 graph->CreateSourceTrack(MediaSegment::AUDIO);
141
142 RefPtr<GenericPromise> p = graph->NotifyWhenDeviceStarted(dummySource);
143
144 GMPTestMonitor mon;
145 p->Then(GetMainThreadSerialEventTarget(), __func__, [&mon, dummySource]() {
146 {
147 MediaTrackGraphImpl* graph = dummySource->GraphImpl();
148 MonitorAutoLock lock(graph->GetMonitor());
149 EXPECT_TRUE(graph->CurrentDriver()->AsAudioCallbackDriver());
150 EXPECT_TRUE(graph->CurrentDriver()->ThreadRunning());
151 }
152 // Test has finished, destroy the track to shutdown the MTG.
153 dummySource->Destroy();
154 mon.SetFinished();
155 });
156
157 mon.AwaitFinished();
158 }
159
TEST(TestAudioTrackGraph,ErrorStateCrash)160 TEST(TestAudioTrackGraph, ErrorStateCrash)
161 {
162 MockCubeb* cubeb = new MockCubeb();
163 CubebUtils::ForceSetCubebContext(cubeb->AsCubebContext());
164
165 MediaTrackGraph* graph = MediaTrackGraph::GetInstance(
166 MediaTrackGraph::AUDIO_THREAD_DRIVER, /*window*/ nullptr,
167 MediaTrackGraph::REQUEST_DEFAULT_SAMPLE_RATE, nullptr);
168
169 // Dummy track to make graph rolling. Add it and remove it to remove the
170 // graph from the global hash table and let it shutdown.
171 RefPtr<SourceMediaTrack> dummySource =
172 graph->CreateSourceTrack(MediaSegment::AUDIO);
173
174 RefPtr<GenericPromise> p = graph->NotifyWhenDeviceStarted(dummySource);
175
176 GMPTestMonitor mon;
177
178 p->Then(GetMainThreadSerialEventTarget(), __func__,
179 [&mon, dummySource, cubeb]() {
180 cubeb->CurrentStream()->ForceError();
181 std::this_thread::sleep_for(std::chrono::milliseconds(50));
182 // Test has finished, destroy the track to shutdown the MTG.
183 dummySource->Destroy();
184 mon.SetFinished();
185 });
186
187 mon.AwaitFinished();
188 }
189