single_client_video_capture_host_unittest.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. // Copyright 2018 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 "components/mirroring/browser/single_client_video_capture_host.h"
  5. #include "base/bind.h"
  6. #include "base/callback_forward.h"
  7. #include "base/memory/raw_ptr.h"
  8. #include "base/memory/unsafe_shared_memory_region.h"
  9. #include "base/memory/weak_ptr.h"
  10. #include "base/run_loop.h"
  11. #include "base/test/task_environment.h"
  12. #include "base/token.h"
  13. #include "media/capture/mojom/video_capture_types.mojom.h"
  14. #include "mojo/public/cpp/bindings/pending_remote.h"
  15. #include "mojo/public/cpp/bindings/receiver.h"
  16. #include "mojo/public/cpp/bindings/remote.h"
  17. #include "mojo/public/cpp/bindings/self_owned_receiver.h"
  18. #include "testing/gmock/include/gmock/gmock.h"
  19. #include "testing/gtest/include/gtest/gtest.h"
  20. using ::testing::InvokeWithoutArgs;
  21. using media::VideoFrameReceiver;
  22. namespace mirroring {
  23. namespace {
  24. constexpr bool kNotPremapped = false;
  25. class MockVideoCaptureDevice final
  26. : public content::LaunchedVideoCaptureDevice {
  27. public:
  28. MockVideoCaptureDevice() {}
  29. MockVideoCaptureDevice(const MockVideoCaptureDevice&) = delete;
  30. MockVideoCaptureDevice& operator=(const MockVideoCaptureDevice&) = delete;
  31. ~MockVideoCaptureDevice() override {}
  32. void GetPhotoState(
  33. VideoCaptureDevice::GetPhotoStateCallback callback) override {}
  34. void SetPhotoOptions(
  35. media::mojom::PhotoSettingsPtr settings,
  36. VideoCaptureDevice::SetPhotoOptionsCallback callback) override {}
  37. void TakePhoto(VideoCaptureDevice::TakePhotoCallback callback) override {}
  38. void SetDesktopCaptureWindowIdAsync(gfx::NativeViewId window_id,
  39. base::OnceClosure done_cb) override {}
  40. MOCK_METHOD0(MaybeSuspendDevice, void());
  41. MOCK_METHOD0(ResumeDevice, void());
  42. MOCK_METHOD3(Crop,
  43. void(const base::Token&,
  44. uint32_t,
  45. base::OnceCallback<void(media::mojom::CropRequestResult)>));
  46. MOCK_METHOD0(RequestRefreshFrame, void());
  47. MOCK_METHOD1(OnUtilizationReport, void(media::VideoCaptureFeedback));
  48. };
  49. class FakeDeviceLauncher final : public content::VideoCaptureDeviceLauncher {
  50. public:
  51. using DeviceLaunchedCallback =
  52. base::OnceCallback<void(base::WeakPtr<VideoFrameReceiver>,
  53. MockVideoCaptureDevice*)>;
  54. explicit FakeDeviceLauncher(DeviceLaunchedCallback launched_cb)
  55. : after_launch_cb_(std::move(launched_cb)) {}
  56. FakeDeviceLauncher(const FakeDeviceLauncher&) = delete;
  57. FakeDeviceLauncher& operator=(const FakeDeviceLauncher&) = delete;
  58. ~FakeDeviceLauncher() override {}
  59. // content::VideoCaptureDeviceLauncher implementation.
  60. void LaunchDeviceAsync(const std::string& device_id,
  61. blink::mojom::MediaStreamType stream_type,
  62. const VideoCaptureParams& params,
  63. base::WeakPtr<VideoFrameReceiver> receiver,
  64. base::OnceClosure connection_lost_cb,
  65. Callbacks* callbacks,
  66. base::OnceClosure done_cb) override {
  67. if (!params.IsValid()) {
  68. callbacks->OnDeviceLaunchFailed(
  69. media::VideoCaptureError::
  70. kVideoCaptureControllerInvalidOrUnsupportedVideoCaptureParametersRequested);
  71. return;
  72. }
  73. base::SequencedTaskRunnerHandle::Get()->PostTask(
  74. FROM_HERE, base::BindOnce(&FakeDeviceLauncher::OnDeviceLaunched,
  75. weak_factory_.GetWeakPtr(), receiver,
  76. callbacks, std::move(done_cb)));
  77. }
  78. void AbortLaunch() override {}
  79. private:
  80. void OnDeviceLaunched(base::WeakPtr<VideoFrameReceiver> receiver,
  81. VideoCaptureDeviceLauncher::Callbacks* callbacks,
  82. base::OnceClosure done_cb) {
  83. auto launched_device = std::make_unique<MockVideoCaptureDevice>();
  84. EXPECT_FALSE(after_launch_cb_.is_null());
  85. std::move(after_launch_cb_).Run(receiver, launched_device.get());
  86. callbacks->OnDeviceLaunched(std::move(launched_device));
  87. std::move(done_cb).Run();
  88. }
  89. DeviceLaunchedCallback after_launch_cb_;
  90. base::WeakPtrFactory<FakeDeviceLauncher> weak_factory_{this};
  91. };
  92. class StubReadWritePermission final
  93. : public VideoCaptureDevice::Client::Buffer::ScopedAccessPermission {
  94. public:
  95. StubReadWritePermission() {}
  96. StubReadWritePermission(const StubReadWritePermission&) = delete;
  97. StubReadWritePermission& operator=(const StubReadWritePermission&) = delete;
  98. ~StubReadWritePermission() override {}
  99. };
  100. class MockVideoCaptureObserver final
  101. : public media::mojom::VideoCaptureObserver {
  102. public:
  103. explicit MockVideoCaptureObserver(
  104. mojo::PendingRemote<media::mojom::VideoCaptureHost> host)
  105. : host_(std::move(host)) {}
  106. MockVideoCaptureObserver(const MockVideoCaptureObserver&) = delete;
  107. MockVideoCaptureObserver& operator=(const MockVideoCaptureObserver&) = delete;
  108. MOCK_METHOD1(OnBufferCreatedCall, void(int buffer_id));
  109. void OnNewBuffer(int32_t buffer_id,
  110. media::mojom::VideoBufferHandlePtr buffer_handle) override {
  111. EXPECT_EQ(buffers_.find(buffer_id), buffers_.end());
  112. EXPECT_EQ(frame_infos_.find(buffer_id), frame_infos_.end());
  113. buffers_[buffer_id] = std::move(buffer_handle);
  114. OnBufferCreatedCall(buffer_id);
  115. }
  116. MOCK_METHOD1(OnBufferReadyCall, void(int buffer_id));
  117. void OnBufferReady(
  118. media::mojom::ReadyBufferPtr buffer,
  119. std::vector<media::mojom::ReadyBufferPtr> scaled_buffers) override {
  120. EXPECT_TRUE(buffers_.find(buffer->buffer_id) != buffers_.end());
  121. EXPECT_EQ(frame_infos_.find(buffer->buffer_id), frame_infos_.end());
  122. frame_infos_[buffer->buffer_id] = std::move(buffer->info);
  123. OnBufferReadyCall(buffer->buffer_id);
  124. }
  125. MOCK_METHOD1(OnBufferDestroyedCall, void(int buffer_id));
  126. void OnBufferDestroyed(int32_t buffer_id) override {
  127. // The consumer should have finished consuming the buffer before it is being
  128. // destroyed.
  129. EXPECT_TRUE(frame_infos_.find(buffer_id) == frame_infos_.end());
  130. const auto iter = buffers_.find(buffer_id);
  131. EXPECT_TRUE(iter != buffers_.end());
  132. buffers_.erase(iter);
  133. OnBufferDestroyedCall(buffer_id);
  134. }
  135. MOCK_METHOD1(OnNewCropVersion, void(uint32_t crop_version));
  136. MOCK_METHOD1(OnStateChangedCall, void(media::mojom::VideoCaptureState state));
  137. MOCK_METHOD1(OnVideoCaptureErrorCall, void(media::VideoCaptureError error));
  138. void OnStateChanged(media::mojom::VideoCaptureResultPtr result) override {
  139. if (result->which() == media::mojom::VideoCaptureResult::Tag::kState)
  140. OnStateChangedCall(result->get_state());
  141. else
  142. OnVideoCaptureErrorCall(result->get_error_code());
  143. }
  144. void Start(bool valid_params) {
  145. VideoCaptureParams params = VideoCaptureParams();
  146. if (!valid_params)
  147. params.requested_format.frame_rate = std::numeric_limits<float>::max();
  148. host_->Start(device_id_, session_id_, params,
  149. receiver_.BindNewPipeAndPassRemote());
  150. }
  151. void FinishConsumingBuffer(int32_t buffer_id,
  152. media::VideoCaptureFeedback feedback) {
  153. EXPECT_TRUE(buffers_.find(buffer_id) != buffers_.end());
  154. const auto iter = frame_infos_.find(buffer_id);
  155. EXPECT_TRUE(iter != frame_infos_.end());
  156. frame_infos_.erase(iter);
  157. host_->ReleaseBuffer(device_id_, buffer_id, feedback);
  158. }
  159. void Stop() { host_->Stop(device_id_); }
  160. private:
  161. const base::UnguessableToken device_id_ = base::UnguessableToken::Create();
  162. const base::UnguessableToken session_id_ = base::UnguessableToken::Create();
  163. mojo::Remote<media::mojom::VideoCaptureHost> host_;
  164. mojo::Receiver<media::mojom::VideoCaptureObserver> receiver_{this};
  165. base::flat_map<int, media::mojom::VideoBufferHandlePtr> buffers_;
  166. base::flat_map<int, media::mojom::VideoFrameInfoPtr> frame_infos_;
  167. };
  168. media::mojom::VideoFrameInfoPtr GetVideoFrameInfo() {
  169. return media::mojom::VideoFrameInfo::New(
  170. base::TimeDelta(), media::VideoFrameMetadata(), media::PIXEL_FORMAT_I420,
  171. gfx::Size(320, 180), gfx::Rect(320, 180), kNotPremapped,
  172. gfx::ColorSpace::CreateREC709(), nullptr);
  173. }
  174. } // namespace
  175. class SingleClientVideoCaptureHostTest : public ::testing::Test {
  176. public:
  177. SingleClientVideoCaptureHostTest() = default;
  178. void CustomSetUp(bool valid_params = true) {
  179. auto host_impl = std::make_unique<SingleClientVideoCaptureHost>(
  180. std::string(), blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE,
  181. base::BindRepeating(
  182. &SingleClientVideoCaptureHostTest::CreateDeviceLauncher,
  183. base::Unretained(this)));
  184. mojo::PendingRemote<media::mojom::VideoCaptureHost> host;
  185. mojo::MakeSelfOwnedReceiver(std::move(host_impl),
  186. host.InitWithNewPipeAndPassReceiver());
  187. consumer_ = std::make_unique<MockVideoCaptureObserver>(std::move(host));
  188. base::RunLoop run_loop;
  189. if (valid_params) {
  190. EXPECT_CALL(*this, OnDeviceLaunchedCall())
  191. .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
  192. } else {
  193. EXPECT_CALL(
  194. *consumer_,
  195. OnVideoCaptureErrorCall(
  196. media::VideoCaptureError::
  197. kVideoCaptureControllerInvalidOrUnsupportedVideoCaptureParametersRequested))
  198. .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
  199. }
  200. consumer_->Start(valid_params);
  201. run_loop.Run();
  202. if (valid_params) {
  203. // The video capture device is launched.
  204. EXPECT_TRUE(launched_device_);
  205. EXPECT_TRUE(frame_receiver_);
  206. }
  207. }
  208. ~SingleClientVideoCaptureHostTest() override {
  209. base::RunLoop run_loop;
  210. EXPECT_CALL(*consumer_,
  211. OnStateChangedCall(media::mojom::VideoCaptureState::ENDED))
  212. .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
  213. consumer_->Stop();
  214. run_loop.Run();
  215. }
  216. protected:
  217. void CreateBuffer(int buffer_id, int expected_buffer_context_id) {
  218. base::RunLoop run_loop;
  219. EXPECT_CALL(*consumer_, OnBufferCreatedCall(expected_buffer_context_id))
  220. .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
  221. media::mojom::VideoBufferHandlePtr stub_buffer_handle =
  222. media::mojom::VideoBufferHandle::NewUnsafeShmemRegion(
  223. base::UnsafeSharedMemoryRegion::Create(10));
  224. frame_receiver_->OnNewBuffer(buffer_id, std::move(stub_buffer_handle));
  225. run_loop.Run();
  226. }
  227. void FrameReadyInBuffer(int buffer_id,
  228. int buffer_context_id,
  229. int feedback_id) {
  230. base::RunLoop run_loop;
  231. EXPECT_CALL(*consumer_, OnBufferReadyCall(buffer_context_id))
  232. .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
  233. frame_receiver_->OnFrameReadyInBuffer(
  234. media::ReadyFrameInBuffer(buffer_id, feedback_id,
  235. std::make_unique<StubReadWritePermission>(),
  236. GetVideoFrameInfo()),
  237. {});
  238. run_loop.Run();
  239. }
  240. void FinishConsumingBuffer(int buffer_context_id,
  241. const media::VideoCaptureFeedback& feedback) {
  242. base::RunLoop run_loop;
  243. EXPECT_CALL(*launched_device_, OnUtilizationReport(feedback))
  244. .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
  245. consumer_->FinishConsumingBuffer(buffer_context_id, feedback);
  246. run_loop.Run();
  247. }
  248. void RetireBuffer(int buffer_id, int buffer_context_id) {
  249. base::RunLoop run_loop;
  250. EXPECT_CALL(*consumer_, OnBufferDestroyedCall(buffer_context_id))
  251. .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
  252. frame_receiver_->OnBufferRetired(buffer_id);
  253. run_loop.Run();
  254. }
  255. base::test::TaskEnvironment task_environment_;
  256. std::unique_ptr<MockVideoCaptureObserver> consumer_;
  257. base::WeakPtr<VideoFrameReceiver> frame_receiver_;
  258. raw_ptr<MockVideoCaptureDevice> launched_device_ = nullptr;
  259. private:
  260. std::unique_ptr<content::VideoCaptureDeviceLauncher> CreateDeviceLauncher() {
  261. return std::make_unique<FakeDeviceLauncher>(
  262. base::BindOnce(&SingleClientVideoCaptureHostTest::OnDeviceLaunched,
  263. weak_factory_.GetWeakPtr()));
  264. }
  265. MOCK_METHOD0(OnDeviceLaunchedCall, void());
  266. void OnDeviceLaunched(base::WeakPtr<VideoFrameReceiver> receiver,
  267. MockVideoCaptureDevice* launched_device) {
  268. frame_receiver_ = std::move(receiver);
  269. launched_device_ = launched_device;
  270. OnDeviceLaunchedCall();
  271. }
  272. base::WeakPtrFactory<SingleClientVideoCaptureHostTest> weak_factory_{this};
  273. };
  274. TEST_F(SingleClientVideoCaptureHostTest, Basic) {
  275. CustomSetUp();
  276. CreateBuffer(1, 0);
  277. const int feedback_id = 5;
  278. FrameReadyInBuffer(1, 0, feedback_id);
  279. auto feedback = media::VideoCaptureFeedback(1.0);
  280. feedback.frame_id = feedback_id;
  281. FinishConsumingBuffer(0, feedback);
  282. RetireBuffer(1, 0);
  283. }
  284. TEST_F(SingleClientVideoCaptureHostTest, InvalidParams) {
  285. CustomSetUp(false);
  286. }
  287. TEST_F(SingleClientVideoCaptureHostTest, ReuseBufferId) {
  288. CustomSetUp();
  289. CreateBuffer(0, 0);
  290. const int feedback_id = 3;
  291. FrameReadyInBuffer(0, 0, feedback_id);
  292. // Retire buffer 0. The consumer is not expected to receive OnBufferDestroyed
  293. // since the buffer is not returned yet.
  294. {
  295. EXPECT_CALL(*consumer_, OnBufferDestroyedCall(0)).Times(0);
  296. frame_receiver_->OnBufferRetired(0);
  297. task_environment_.RunUntilIdle();
  298. }
  299. // Re-use buffer 0.
  300. const int feedback_id_2 = 7;
  301. CreateBuffer(0, 1);
  302. FrameReadyInBuffer(0, 1, feedback_id_2);
  303. // Finish consuming frame in the retired buffer 0.
  304. auto feedback = media::VideoCaptureFeedback(1.0);
  305. feedback.frame_id = feedback_id;
  306. FinishConsumingBuffer(0, feedback);
  307. // The retired buffer is expected to be destroyed since the consumer finished
  308. // consuming the frame in that buffer.
  309. base::RunLoop run_loop;
  310. EXPECT_CALL(*consumer_, OnBufferDestroyedCall(0))
  311. .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
  312. run_loop.Run();
  313. auto feedback_2 = media::VideoCaptureFeedback(0.5);
  314. feedback_2.frame_id = feedback_id_2;
  315. FinishConsumingBuffer(1, feedback_2);
  316. RetireBuffer(0, 1);
  317. }
  318. TEST_F(SingleClientVideoCaptureHostTest, StopCapturingWhileBuffersInUse) {
  319. CustomSetUp();
  320. for (int i = 0; i < 10; ++i) {
  321. CreateBuffer(i, i);
  322. FrameReadyInBuffer(i, i, i);
  323. }
  324. }
  325. } // namespace mirroring