OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 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 |
| 5 #include "content/renderer/media/audio_ipc_factory.h" |
| 6 |
| 7 #include <string> |
| 8 #include <utility> |
| 9 #include <vector> |
| 10 |
| 11 #include "base/message_loop/message_loop.h" |
| 12 #include "base/threading/thread.h" |
| 13 #include "content/renderer/media/audio_message_filter.h" |
| 14 #include "mojo/public/cpp/bindings/binding.h" |
| 15 #include "mojo/public/cpp/bindings/interface_request.h" |
| 16 #include "mojo/public/cpp/system/message_pipe.h" |
| 17 #include "services/service_manager/public/cpp/interface_provider.h" |
| 18 #include "testing/gmock/include/gmock/gmock.h" |
| 19 #include "testing/gtest/include/gtest/gtest.h" |
| 20 |
| 21 using ::testing::_; |
| 22 |
| 23 namespace content { |
| 24 |
| 25 namespace { |
| 26 |
| 27 const int kRenderFrameId = 0; |
| 28 |
| 29 std::unique_ptr<base::Thread> MakeIOThread() { |
| 30 auto io_thread = base::MakeUnique<base::Thread>("test IO thread"); |
| 31 base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0); |
| 32 CHECK(io_thread->StartWithOptions(thread_options)); |
| 33 return io_thread; |
| 34 } |
| 35 |
| 36 class FakeRemoteFactory : public mojom::RendererAudioOutputStreamFactory { |
| 37 public: |
| 38 FakeRemoteFactory() : binding_(this) {} |
| 39 ~FakeRemoteFactory() override {} |
| 40 |
| 41 void RequestDeviceAuthorization( |
| 42 media::mojom::AudioOutputStreamProviderRequest stream_provider, |
| 43 int64_t session_id, |
| 44 const std::string& device_id, |
| 45 RequestDeviceAuthorizationCallback callback) override { |
| 46 std::move(callback).Run( |
| 47 media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED, |
| 48 media::AudioParameters::UnavailableDeviceParams(), std::string()); |
| 49 EXPECT_FALSE(on_called_.is_null()); |
| 50 std::move(on_called_).Run(); |
| 51 } |
| 52 |
| 53 void SetOnCalledCallback(base::OnceClosure on_called) { |
| 54 on_called_ = std::move(on_called); |
| 55 } |
| 56 |
| 57 void Bind(mojo::ScopedMessagePipeHandle handle) { |
| 58 EXPECT_FALSE(binding_.is_bound()); |
| 59 binding_.Bind( |
| 60 mojo::InterfaceRequest<mojom::RendererAudioOutputStreamFactory>( |
| 61 std::move(handle))); |
| 62 } |
| 63 |
| 64 private: |
| 65 mojo::Binding<mojom::RendererAudioOutputStreamFactory> binding_; |
| 66 base::OnceClosure on_called_; |
| 67 }; |
| 68 |
| 69 class FakeAudioIPCDelegate : public media::AudioOutputIPCDelegate { |
| 70 void OnError() override {} |
| 71 void OnDeviceAuthorized(media::OutputDeviceStatus device_status, |
| 72 const media::AudioParameters& output_params, |
| 73 const std::string& matched_device_id) override {} |
| 74 void OnStreamCreated(base::SharedMemoryHandle handle, |
| 75 base::SyncSocket::Handle socket_handle, |
| 76 int length) override {} |
| 77 void OnIPCClosed() override {} |
| 78 }; |
| 79 |
| 80 } // namespace |
| 81 |
| 82 class AudioIPCFactoryTest : public testing::Test { |
| 83 public: |
| 84 AudioIPCFactoryTest() {} |
| 85 ~AudioIPCFactoryTest() override {} |
| 86 |
| 87 void RequestAuthorizationOnIOThread( |
| 88 std::unique_ptr<media::AudioOutputIPC> output_ipc) { |
| 89 output_ipc->RequestDeviceAuthorization(&fake_delegate, 0, "", |
| 90 url::Origin()); |
| 91 |
| 92 output_ipc->CloseStream(); |
| 93 } |
| 94 |
| 95 private: |
| 96 FakeAudioIPCDelegate fake_delegate; |
| 97 }; |
| 98 |
| 99 TEST_F(AudioIPCFactoryTest, CallFactoryFromIOThread) { |
| 100 // This test makes sure that AudioIPCFactory correctly binds the |
| 101 // RendererAudioOutputStreamFactoryPtr to the IO thread. |
| 102 base::MessageLoop message_loop; |
| 103 base::RunLoop run_loop; |
| 104 auto io_thread = MakeIOThread(); |
| 105 |
| 106 FakeRemoteFactory remote_factory; |
| 107 remote_factory.SetOnCalledCallback(run_loop.QuitWhenIdleClosure()); |
| 108 |
| 109 service_manager::InterfaceProvider interface_provider; |
| 110 service_manager::InterfaceProvider::TestApi(&interface_provider) |
| 111 .SetBinderForName(mojom::RendererAudioOutputStreamFactory::Name_, |
| 112 base::BindRepeating(&FakeRemoteFactory::Bind, |
| 113 base::Unretained(&remote_factory))); |
| 114 |
| 115 AudioIPCFactory ipc_factory(nullptr, io_thread->task_runner()); |
| 116 |
| 117 ipc_factory.MaybeRegisterRemoteFactory(kRenderFrameId, &interface_provider); |
| 118 |
| 119 // To make sure that the pointer stored in |ipc_factory| is connected to |
| 120 // |remote_factory|, and also that it's bound to |io_thread|, we create an |
| 121 // AudioOutputIPC object and request device authorization on the IO thread. |
| 122 // This is supposed to call |remote_factory| on the main thread. |
| 123 io_thread->task_runner()->PostTask( |
| 124 FROM_HERE, |
| 125 base::BindOnce(&AudioIPCFactoryTest::RequestAuthorizationOnIOThread, |
| 126 base::Unretained(this), |
| 127 ipc_factory.CreateAudioOutputIPC(kRenderFrameId))); |
| 128 |
| 129 // Wait for call to |remote_factory|: |
| 130 run_loop.Run(); |
| 131 |
| 132 ipc_factory.MaybeDeregisterRemoteFactory(0); |
| 133 |
| 134 io_thread.reset(); |
| 135 base::RunLoop().RunUntilIdle(); |
| 136 } |
| 137 |
| 138 TEST_F(AudioIPCFactoryTest, SeveralFactories) { |
| 139 // This test simulates having several frames being created and destructed. |
| 140 base::MessageLoop message_loop; |
| 141 auto io_thread = MakeIOThread(); |
| 142 const int n_factories = 5; |
| 143 |
| 144 std::vector<service_manager::InterfaceProvider> interface_providers( |
| 145 n_factories); |
| 146 |
| 147 std::vector<FakeRemoteFactory> remote_factories(n_factories); |
| 148 |
| 149 for (size_t i = 0; i < n_factories; i++) { |
| 150 service_manager::InterfaceProvider::TestApi(&interface_providers[i]) |
| 151 .SetBinderForName( |
| 152 mojom::RendererAudioOutputStreamFactory::Name_, |
| 153 base::BindRepeating(&FakeRemoteFactory::Bind, |
| 154 base::Unretained(&remote_factories[i]))); |
| 155 } |
| 156 |
| 157 base::RunLoop().RunUntilIdle(); |
| 158 |
| 159 AudioIPCFactory ipc_factory(nullptr, io_thread->task_runner()); |
| 160 |
| 161 for (size_t i = 0; i < n_factories; i++) { |
| 162 ipc_factory.MaybeRegisterRemoteFactory(kRenderFrameId + i, |
| 163 &interface_providers[i]); |
| 164 } |
| 165 |
| 166 base::RunLoop run_loop; |
| 167 remote_factories[0].SetOnCalledCallback(run_loop.QuitWhenIdleClosure()); |
| 168 io_thread->task_runner()->PostTask( |
| 169 FROM_HERE, |
| 170 base::BindOnce(&AudioIPCFactoryTest::RequestAuthorizationOnIOThread, |
| 171 base::Unretained(this), |
| 172 ipc_factory.CreateAudioOutputIPC(kRenderFrameId))); |
| 173 run_loop.Run(); |
| 174 |
| 175 // Do some operation and make sure the internal state isn't messed up: |
| 176 ipc_factory.MaybeDeregisterRemoteFactory(1); |
| 177 |
| 178 base::RunLoop run_loop2; |
| 179 remote_factories[2].SetOnCalledCallback(run_loop2.QuitWhenIdleClosure()); |
| 180 io_thread->task_runner()->PostTask( |
| 181 FROM_HERE, |
| 182 base::BindOnce(&AudioIPCFactoryTest::RequestAuthorizationOnIOThread, |
| 183 base::Unretained(this), |
| 184 ipc_factory.CreateAudioOutputIPC(kRenderFrameId + 2))); |
| 185 run_loop2.Run(); |
| 186 |
| 187 for (size_t i = 0; i < n_factories; i++) { |
| 188 if (i == 1) |
| 189 continue; |
| 190 ipc_factory.MaybeDeregisterRemoteFactory(i); |
| 191 } |
| 192 |
| 193 io_thread.reset(); |
| 194 base::RunLoop().RunUntilIdle(); |
| 195 } |
| 196 |
| 197 TEST_F(AudioIPCFactoryTest, RegisterDeregisterBackToBack_Deregisters) { |
| 198 // This test makes sure that calling Register... followed by Deregister... |
| 199 // correctly sequences the registration before the deregistration. |
| 200 base::MessageLoop message_loop; |
| 201 auto io_thread = MakeIOThread(); |
| 202 |
| 203 FakeRemoteFactory remote_factory; |
| 204 |
| 205 service_manager::InterfaceProvider interface_provider; |
| 206 service_manager::InterfaceProvider::TestApi(&interface_provider) |
| 207 .SetBinderForName(mojom::RendererAudioOutputStreamFactory::Name_, |
| 208 base::BindRepeating(&FakeRemoteFactory::Bind, |
| 209 base::Unretained(&remote_factory))); |
| 210 |
| 211 AudioIPCFactory ipc_factory(nullptr, io_thread->task_runner()); |
| 212 |
| 213 ipc_factory.MaybeRegisterRemoteFactory(kRenderFrameId, &interface_provider); |
| 214 ipc_factory.MaybeDeregisterRemoteFactory(kRenderFrameId); |
| 215 // That there is no factory remaining at destruction is DCHECKed in the |
| 216 // AudioIPCFactory destructor. |
| 217 |
| 218 base::RunLoop().RunUntilIdle(); |
| 219 io_thread.reset(); |
| 220 base::RunLoop().RunUntilIdle(); |
| 221 } |
| 222 |
| 223 } // namespace content |
OLD | NEW |