device_listener_output_stream_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. // Copyright (c) 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "services/audio/device_listener_output_stream.h"
  5. #include "base/memory/raw_ptr.h"
  6. #include "base/test/gmock_callback_support.h"
  7. #include "base/test/task_environment.h"
  8. #include "media/audio/fake_audio_log_factory.h"
  9. #include "media/audio/fake_audio_manager.h"
  10. #include "media/audio/mock_audio_source_callback.h"
  11. #include "media/audio/test_audio_thread.h"
  12. #include "media/base/audio_parameters.h"
  13. #include "testing/gmock/include/gmock/gmock.h"
  14. #include "testing/gtest/include/gtest/gtest.h"
  15. #include "third_party/abseil-cpp/absl/types/optional.h"
  16. using ::testing::_;
  17. using ::testing::InSequence;
  18. using media::AudioBus;
  19. using media::AudioManager;
  20. using media::AudioOutputStream;
  21. using media::MockAudioSourceCallback;
  22. using base::test::RunOnceClosure;
  23. namespace audio {
  24. namespace {
  25. class MockAudioOutputStream : public AudioOutputStream {
  26. public:
  27. MockAudioOutputStream() = default;
  28. ~MockAudioOutputStream() override = default;
  29. void Start(AudioSourceCallback* callback) override {
  30. provided_callback_ = callback;
  31. StartCalled(provided_callback_);
  32. }
  33. MOCK_METHOD1(StartCalled, void(AudioSourceCallback*));
  34. MOCK_METHOD0(Stop, void());
  35. MOCK_METHOD0(Open, bool());
  36. MOCK_METHOD1(SetVolume, void(double volume));
  37. MOCK_METHOD1(GetVolume, void(double* volume));
  38. MOCK_METHOD0(Close, void());
  39. MOCK_METHOD0(Flush, void());
  40. int SimulateOnMoreData(base::TimeDelta delay,
  41. base::TimeTicks delay_timestamp,
  42. int prior_frames_skipped,
  43. AudioBus* dest) {
  44. DCHECK(provided_callback_);
  45. return provided_callback_->OnMoreData(delay, delay_timestamp,
  46. prior_frames_skipped, dest);
  47. }
  48. void SimulateError(AudioSourceCallback::ErrorType error) {
  49. DCHECK(provided_callback_);
  50. provided_callback_->OnError(error);
  51. }
  52. private:
  53. raw_ptr<AudioOutputStream::AudioSourceCallback> provided_callback_ = nullptr;
  54. };
  55. class FakeAudioManagerForDeviceChange : public media::FakeAudioManager {
  56. public:
  57. FakeAudioManagerForDeviceChange()
  58. : FakeAudioManager(std::make_unique<media::TestAudioThread>(),
  59. &fake_audio_log_factory_) {}
  60. ~FakeAudioManagerForDeviceChange() override = default;
  61. void AddOutputDeviceChangeListener(AudioDeviceListener* listener) override {
  62. media::FakeAudioManager::AddOutputDeviceChangeListener(listener);
  63. AddOutputDeviceChangeListenerCalled(listener);
  64. }
  65. void RemoveOutputDeviceChangeListener(
  66. AudioDeviceListener* listener) override {
  67. media::FakeAudioManager::RemoveOutputDeviceChangeListener(listener);
  68. RemoveOutputDeviceChangeListenerCalled(listener);
  69. }
  70. MOCK_METHOD1(AddOutputDeviceChangeListenerCalled,
  71. void(AudioManager::AudioDeviceListener*));
  72. MOCK_METHOD1(RemoveOutputDeviceChangeListenerCalled,
  73. void(AudioManager::AudioDeviceListener*));
  74. void SimulateDeviceChange() { NotifyAllOutputDeviceChangeListeners(); }
  75. private:
  76. media::FakeAudioLogFactory fake_audio_log_factory_;
  77. };
  78. class DeviceListenerOutputStreamTest : public ::testing::Test {
  79. public:
  80. using ErrorType = AudioOutputStream::AudioSourceCallback::ErrorType;
  81. MOCK_METHOD0(DeviceChangeCallbackCalled, void());
  82. };
  83. // Verifies DeviceListenerOutputStream forwards all calls to the wrapped stream.
  84. TEST_F(DeviceListenerOutputStreamTest, DelegatesCallsToWrappedStream) {
  85. base::test::SingleThreadTaskEnvironment task_environment;
  86. FakeAudioManagerForDeviceChange mock_audio_manager;
  87. MockAudioOutputStream mock_stream;
  88. MockAudioSourceCallback mock_callback;
  89. double volume = 200;
  90. base::TimeDelta delay = base::Milliseconds(30);
  91. base::TimeTicks delay_timestamp =
  92. base::TimeTicks() + base::Milliseconds(21);
  93. int prior_frames_skipped = 44;
  94. std::unique_ptr<media::AudioBus> dest = media::AudioBus::Create(1, 128);
  95. InSequence sequence;
  96. EXPECT_CALL(mock_audio_manager, AddOutputDeviceChangeListenerCalled(_))
  97. .Times(1);
  98. EXPECT_CALL(mock_stream, Open()).Times(1);
  99. EXPECT_CALL(mock_stream, StartCalled(_)).Times(1);
  100. EXPECT_CALL(mock_callback, OnMoreData(delay, delay_timestamp,
  101. prior_frames_skipped, dest.get()));
  102. EXPECT_CALL(mock_stream, SetVolume(volume)).Times(1);
  103. EXPECT_CALL(mock_stream, GetVolume(&volume)).Times(1);
  104. EXPECT_CALL(mock_stream, Stop()).Times(1);
  105. EXPECT_CALL(mock_stream, Flush()).Times(1);
  106. EXPECT_CALL(mock_stream, Close()).Times(1);
  107. DeviceListenerOutputStream* stream_under_test =
  108. new DeviceListenerOutputStream(
  109. &mock_audio_manager, &mock_stream,
  110. base::BindRepeating(
  111. &DeviceListenerOutputStreamTest::DeviceChangeCallbackCalled,
  112. base::Unretained(this)));
  113. EXPECT_CALL(mock_audio_manager,
  114. RemoveOutputDeviceChangeListenerCalled(stream_under_test))
  115. .Times(1);
  116. stream_under_test->Open();
  117. stream_under_test->Start(&mock_callback);
  118. mock_stream.SimulateOnMoreData(delay, delay_timestamp, prior_frames_skipped,
  119. dest.get());
  120. stream_under_test->SetVolume(volume);
  121. stream_under_test->GetVolume(&volume);
  122. stream_under_test->Stop();
  123. stream_under_test->Flush();
  124. stream_under_test->Close();
  125. mock_audio_manager.Shutdown();
  126. }
  127. // Verifies DeviceListenerOutputStream calls device change callback on device
  128. // change.
  129. TEST_F(DeviceListenerOutputStreamTest, DeviceChangeNotification) {
  130. base::test::SingleThreadTaskEnvironment task_environment;
  131. FakeAudioManagerForDeviceChange mock_audio_manager;
  132. MockAudioOutputStream mock_stream;
  133. MockAudioSourceCallback mock_callback;
  134. // |stream_under_test| should call the provided callback on device change.
  135. EXPECT_CALL(*this, DeviceChangeCallbackCalled()).Times(1);
  136. DeviceListenerOutputStream* stream_under_test =
  137. new DeviceListenerOutputStream(
  138. &mock_audio_manager, &mock_stream,
  139. base::BindRepeating(
  140. &DeviceListenerOutputStreamTest::DeviceChangeCallbackCalled,
  141. base::Unretained(this)));
  142. stream_under_test->Open();
  143. stream_under_test->Start(&mock_callback);
  144. mock_audio_manager.SimulateDeviceChange();
  145. stream_under_test->Stop();
  146. stream_under_test->Close();
  147. mock_audio_manager.Shutdown();
  148. }
  149. // Verifies DeviceListenerOutputStream calls device change callbacks on device
  150. // change errors.
  151. TEST_F(DeviceListenerOutputStreamTest, DeviceChangeError) {
  152. base::test::SingleThreadTaskEnvironment task_environment;
  153. FakeAudioManagerForDeviceChange mock_audio_manager;
  154. MockAudioOutputStream mock_stream;
  155. MockAudioSourceCallback mock_callback;
  156. base::RunLoop loop;
  157. // |stream_under_test| should call the provided callback if it received a
  158. // device change error.
  159. EXPECT_CALL(*this, DeviceChangeCallbackCalled())
  160. .WillOnce(RunOnceClosure(loop.QuitClosure()));
  161. // |stream_under_test| should not forward device change errors.
  162. EXPECT_CALL(mock_callback, OnError(_)).Times(0);
  163. DeviceListenerOutputStream* stream_under_test =
  164. new DeviceListenerOutputStream(
  165. &mock_audio_manager, &mock_stream,
  166. base::BindRepeating(
  167. &DeviceListenerOutputStreamTest::DeviceChangeCallbackCalled,
  168. base::Unretained(this)));
  169. stream_under_test->Open();
  170. stream_under_test->Start(&mock_callback);
  171. // Simulate a device change error.
  172. mock_stream.SimulateError(ErrorType::kDeviceChange);
  173. loop.Run();
  174. stream_under_test->Stop();
  175. stream_under_test->Close();
  176. mock_audio_manager.Shutdown();
  177. }
  178. // Verifies DeviceListenerOutputStream forwards error callbacks.
  179. TEST_F(DeviceListenerOutputStreamTest, UnknownError) {
  180. base::test::SingleThreadTaskEnvironment task_environment;
  181. FakeAudioManagerForDeviceChange mock_audio_manager;
  182. MockAudioOutputStream mock_stream;
  183. MockAudioSourceCallback mock_callback;
  184. base::RunLoop loop;
  185. // |stream_under_test| should forward errors.
  186. EXPECT_CALL(*this, DeviceChangeCallbackCalled()).Times(0);
  187. EXPECT_CALL(mock_callback, OnError(ErrorType::kUnknown))
  188. .WillOnce(RunOnceClosure(loop.QuitClosure()));
  189. DeviceListenerOutputStream* stream_under_test =
  190. new DeviceListenerOutputStream(
  191. &mock_audio_manager, &mock_stream,
  192. base::BindRepeating(
  193. &DeviceListenerOutputStreamTest::DeviceChangeCallbackCalled,
  194. base::Unretained(this)));
  195. stream_under_test->Open();
  196. stream_under_test->Start(&mock_callback);
  197. // Simulate a device change error.
  198. mock_stream.SimulateError(ErrorType::kUnknown);
  199. loop.Run();
  200. stream_under_test->Stop();
  201. stream_under_test->Close();
  202. mock_audio_manager.Shutdown();
  203. }
  204. // Verifies DeviceListenerOutputStream elides error notifications during device
  205. // changes.
  206. TEST_F(DeviceListenerOutputStreamTest, ErrorThenDeviceChange) {
  207. base::test::SingleThreadTaskEnvironment task_environment;
  208. FakeAudioManagerForDeviceChange mock_audio_manager;
  209. MockAudioOutputStream mock_stream;
  210. MockAudioSourceCallback mock_callback;
  211. base::RunLoop loop;
  212. // |stream_under_test| should call device change callback.
  213. EXPECT_CALL(*this, DeviceChangeCallbackCalled())
  214. .WillOnce(RunOnceClosure(loop.QuitClosure()));
  215. // |stream_under_test| should drop deferred errors.
  216. EXPECT_CALL(mock_callback, OnError(_)).Times(0);
  217. DeviceListenerOutputStream* stream_under_test =
  218. new DeviceListenerOutputStream(
  219. &mock_audio_manager, &mock_stream,
  220. base::BindRepeating(
  221. &DeviceListenerOutputStreamTest::DeviceChangeCallbackCalled,
  222. base::Unretained(this)));
  223. stream_under_test->Open();
  224. stream_under_test->Start(&mock_callback);
  225. // Simulate an error, followed by a device change.
  226. mock_stream.SimulateError(ErrorType::kUnknown);
  227. mock_audio_manager.SimulateDeviceChange();
  228. loop.Run();
  229. stream_under_test->Stop();
  230. stream_under_test->Close();
  231. mock_audio_manager.Shutdown();
  232. }
  233. // Verifies DeviceListenerOutputStream can be stopped after receiving an error.
  234. TEST_F(DeviceListenerOutputStreamTest, ErrorThenStop) {
  235. base::test::SingleThreadTaskEnvironment task_environment(
  236. base::test::TaskEnvironment::TimeSource::MOCK_TIME);
  237. FakeAudioManagerForDeviceChange mock_audio_manager;
  238. MockAudioOutputStream mock_stream;
  239. MockAudioSourceCallback mock_callback;
  240. // |stream_under_test| should not call its error callback after it has been
  241. // stopped.
  242. EXPECT_CALL(mock_callback, OnError(_)).Times(0);
  243. DeviceListenerOutputStream* stream_under_test =
  244. new DeviceListenerOutputStream(
  245. &mock_audio_manager, &mock_stream,
  246. base::BindRepeating(
  247. &DeviceListenerOutputStreamTest::DeviceChangeCallbackCalled,
  248. base::Unretained(this)));
  249. stream_under_test->Open();
  250. stream_under_test->Start(&mock_callback);
  251. // Call stop() immediately after an error.
  252. mock_stream.SimulateError(ErrorType::kUnknown);
  253. stream_under_test->Stop();
  254. // Reporting the error should be delayed by 1s.
  255. task_environment.FastForwardUntilNoTasksRemain();
  256. stream_under_test->Close();
  257. mock_audio_manager.Shutdown();
  258. }
  259. } // namespace
  260. } // namespace audio