| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "third_party/blink/renderer/modules/media/audio/mojo_audio_output_ipc.h" |
| |
| #include <algorithm> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "base/optional.h" |
| #include "base/run_loop.h" |
| #include "base/test/gtest_util.h" |
| #include "media/audio/audio_device_description.h" |
| #include "media/base/audio_parameters.h" |
| #include "mojo/public/cpp/bindings/pending_receiver.h" |
| #include "mojo/public/cpp/bindings/pending_remote.h" |
| #include "mojo/public/cpp/bindings/receiver.h" |
| #include "mojo/public/cpp/bindings/remote.h" |
| #include "mojo/public/cpp/system/platform_handle.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h" |
| #include "third_party/blink/renderer/platform/wtf/functional.h" |
| |
| using testing::_; |
| using testing::AtLeast; |
| using testing::Invoke; |
| using testing::Mock; |
| using testing::StrictMock; |
| |
| namespace blink { |
| |
| namespace { |
| |
| const size_t kMemoryLength = 4321; |
| const char kDeviceId[] = "device_id"; |
| const char kReturnedDeviceId[] = "returned_device_id"; |
| const double kNewVolume = 0.271828; |
| |
| media::AudioParameters Params() { |
| return media::AudioParameters::UnavailableDeviceParams(); |
| } |
| |
| MojoAudioOutputIPC::FactoryAccessorCB NullAccessor() { |
| return WTF::BindRepeating( |
| []() -> blink::mojom::blink::RendererAudioOutputStreamFactory* { |
| return nullptr; |
| }); |
| } |
| |
| // TODO(https://crbug.com/787252): Convert the test away from using std::string. |
| class TestStreamProvider |
| : public media::mojom::blink::AudioOutputStreamProvider { |
| public: |
| explicit TestStreamProvider(media::mojom::blink::AudioOutputStream* stream) |
| : stream_(stream) {} |
| |
| ~TestStreamProvider() override { |
| // If we expected a stream to be acquired, make sure it is so. |
| if (stream_) |
| EXPECT_TRUE(receiver_); |
| } |
| |
| void Acquire( |
| const media::AudioParameters& params, |
| mojo::PendingRemote<media::mojom::blink::AudioOutputStreamProviderClient> |
| pending_provider_client) override { |
| EXPECT_EQ(receiver_, base::nullopt); |
| EXPECT_NE(stream_, nullptr); |
| provider_client_.reset(); |
| provider_client_.Bind(std::move(pending_provider_client)); |
| mojo::PendingRemote<media::mojom::blink::AudioOutputStream> |
| stream_pending_remote; |
| receiver_.emplace(stream_, |
| stream_pending_remote.InitWithNewPipeAndPassReceiver()); |
| base::CancelableSyncSocket foreign_socket; |
| EXPECT_TRUE( |
| base::CancelableSyncSocket::CreatePair(&socket_, &foreign_socket)); |
| provider_client_->Created( |
| std::move(stream_pending_remote), |
| {base::in_place, base::UnsafeSharedMemoryRegion::Create(kMemoryLength), |
| mojo::PlatformHandle(foreign_socket.Take())}); |
| } |
| |
| void SignalErrorToProviderClient() { |
| provider_client_.ResetWithReason( |
| static_cast<uint32_t>(media::mojom::blink::AudioOutputStreamObserver:: |
| DisconnectReason::kPlatformError), |
| std::string()); |
| } |
| |
| private: |
| media::mojom::blink::AudioOutputStream* stream_; |
| mojo::Remote<media::mojom::blink::AudioOutputStreamProviderClient> |
| provider_client_; |
| base::Optional<mojo::Receiver<media::mojom::blink::AudioOutputStream>> |
| receiver_; |
| base::CancelableSyncSocket socket_; |
| }; |
| |
| class TestRemoteFactory |
| : public blink::mojom::blink::RendererAudioOutputStreamFactory { |
| public: |
| TestRemoteFactory() |
| : expect_request_(false), |
| receiver_(this, this_remote_.BindNewPipeAndPassReceiver()) {} |
| |
| ~TestRemoteFactory() override {} |
| |
| void RequestDeviceAuthorization( |
| mojo::PendingReceiver<media::mojom::blink::AudioOutputStreamProvider> |
| stream_provider_receiver, |
| const base::Optional<base::UnguessableToken>& session_id, |
| const String& device_id, |
| RequestDeviceAuthorizationCallback callback) override { |
| EXPECT_EQ(session_id, expected_session_id_); |
| EXPECT_EQ(device_id.Utf8(), expected_device_id_); |
| EXPECT_TRUE(expect_request_); |
| if (provider_) { |
| std::move(callback).Run( |
| static_cast<media::mojom::blink::OutputDeviceStatus>( |
| media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK), |
| Params(), String(kReturnedDeviceId)); |
| provider_receiver_.emplace(provider_.get(), |
| std::move(stream_provider_receiver)); |
| } else { |
| std::move(callback).Run( |
| static_cast<media::mojom::blink::OutputDeviceStatus>( |
| media::OutputDeviceStatus:: |
| OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED), |
| Params(), String("")); |
| } |
| expect_request_ = false; |
| } |
| |
| void PrepareProviderForAuthorization( |
| const base::UnguessableToken& session_id, |
| const std::string& device_id, |
| std::unique_ptr<TestStreamProvider> provider) { |
| EXPECT_FALSE(expect_request_); |
| expect_request_ = true; |
| expected_session_id_ = session_id.is_empty() |
| ? base::Optional<base::UnguessableToken>() |
| : session_id; |
| expected_device_id_ = device_id; |
| provider_receiver_.reset(); |
| std::swap(provider_, provider); |
| } |
| |
| void RefuseNextRequest(const base::UnguessableToken& session_id, |
| const std::string& device_id) { |
| EXPECT_FALSE(expect_request_); |
| expect_request_ = true; |
| expected_session_id_ = session_id; |
| expected_device_id_ = device_id; |
| } |
| |
| void SignalErrorToProviderClient() { |
| provider_->SignalErrorToProviderClient(); |
| } |
| |
| void Disconnect() { |
| receiver_.reset(); |
| this_remote_.reset(); |
| receiver_.Bind(this_remote_.BindNewPipeAndPassReceiver()); |
| provider_receiver_.reset(); |
| provider_.reset(); |
| expect_request_ = false; |
| } |
| |
| MojoAudioOutputIPC::FactoryAccessorCB GetAccessor() { |
| return WTF::BindRepeating(&TestRemoteFactory::get, WTF::Unretained(this)); |
| } |
| |
| private: |
| blink::mojom::blink::RendererAudioOutputStreamFactory* get() { |
| return this_remote_.get(); |
| } |
| |
| bool expect_request_; |
| base::Optional<base::UnguessableToken> expected_session_id_; |
| std::string expected_device_id_; |
| |
| mojo::Remote<blink::mojom::blink::RendererAudioOutputStreamFactory> |
| this_remote_; |
| mojo::Receiver<blink::mojom::blink::RendererAudioOutputStreamFactory> |
| receiver_{this}; |
| std::unique_ptr<TestStreamProvider> provider_; |
| base::Optional<mojo::Receiver<media::mojom::blink::AudioOutputStreamProvider>> |
| provider_receiver_; |
| }; |
| |
| class MockStream : public media::mojom::blink::AudioOutputStream { |
| public: |
| MOCK_METHOD0(Play, void()); |
| MOCK_METHOD0(Pause, void()); |
| MOCK_METHOD0(Flush, void()); |
| MOCK_METHOD1(SetVolume, void(double)); |
| }; |
| |
| class MockDelegate : public media::AudioOutputIPCDelegate { |
| public: |
| MockDelegate() = default; |
| ~MockDelegate() override = default; |
| |
| void OnStreamCreated(base::UnsafeSharedMemoryRegion mem_handle, |
| base::SyncSocket::ScopedHandle socket_handle, |
| bool playing_automatically) override { |
| GotOnStreamCreated(); |
| } |
| |
| MOCK_METHOD0(OnError, void()); |
| MOCK_METHOD3(OnDeviceAuthorized, |
| void(media::OutputDeviceStatus device_status, |
| const media::AudioParameters& output_params, |
| const std::string& matched_device_id)); |
| MOCK_METHOD0(GotOnStreamCreated, void()); |
| MOCK_METHOD0(OnIPCClosed, void()); |
| }; |
| |
| } // namespace |
| |
| TEST(MojoAudioOutputIPC, AuthorizeWithoutFactory_CallsAuthorizedWithError) { |
| const base::UnguessableToken session_id = base::UnguessableToken::Create(); |
| StrictMock<MockDelegate> delegate; |
| |
| std::unique_ptr<media::AudioOutputIPC> ipc = |
| std::make_unique<MojoAudioOutputIPC>( |
| NullAccessor(), |
| blink::scheduler::GetSingleThreadTaskRunnerForTesting()); |
| |
| ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId); |
| |
| // Don't call OnDeviceAuthorized synchronously, should wait until we run the |
| // RunLoop. |
| EXPECT_CALL(delegate, |
| OnDeviceAuthorized(media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL, _, |
| std::string())); |
| base::RunLoop().RunUntilIdle(); |
| ipc->CloseStream(); |
| } |
| |
| TEST(MojoAudioOutputIPC, |
| CreateWithoutAuthorizationWithoutFactory_CallsAuthorizedWithError) { |
| StrictMock<MockDelegate> delegate; |
| |
| std::unique_ptr<media::AudioOutputIPC> ipc = |
| std::make_unique<MojoAudioOutputIPC>( |
| NullAccessor(), |
| blink::scheduler::GetSingleThreadTaskRunnerForTesting()); |
| |
| ipc->CreateStream(&delegate, Params(), base::nullopt); |
| |
| // No call to OnDeviceAuthorized since authotization wasn't explicitly |
| // requested. |
| base::RunLoop().RunUntilIdle(); |
| ipc->CloseStream(); |
| } |
| |
| TEST(MojoAudioOutputIPC, DeviceAuthorized_Propagates) { |
| const base::UnguessableToken session_id = base::UnguessableToken::Create(); |
| TestRemoteFactory stream_factory; |
| StrictMock<MockDelegate> delegate; |
| |
| const std::unique_ptr<media::AudioOutputIPC> ipc = |
| std::make_unique<MojoAudioOutputIPC>( |
| stream_factory.GetAccessor(), |
| blink::scheduler::GetSingleThreadTaskRunnerForTesting()); |
| stream_factory.PrepareProviderForAuthorization( |
| session_id, kDeviceId, std::make_unique<TestStreamProvider>(nullptr)); |
| |
| ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId); |
| |
| EXPECT_CALL(delegate, OnDeviceAuthorized( |
| media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK, |
| _, std::string(kReturnedDeviceId))); |
| base::RunLoop().RunUntilIdle(); |
| |
| ipc->CloseStream(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| TEST(MojoAudioOutputIPC, OnDeviceCreated_Propagates) { |
| const base::UnguessableToken session_id = base::UnguessableToken::Create(); |
| TestRemoteFactory stream_factory; |
| StrictMock<MockStream> stream; |
| StrictMock<MockDelegate> delegate; |
| |
| const std::unique_ptr<media::AudioOutputIPC> ipc = |
| std::make_unique<MojoAudioOutputIPC>( |
| stream_factory.GetAccessor(), |
| blink::scheduler::GetSingleThreadTaskRunnerForTesting()); |
| stream_factory.PrepareProviderForAuthorization( |
| session_id, kDeviceId, std::make_unique<TestStreamProvider>(&stream)); |
| |
| ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId); |
| ipc->CreateStream(&delegate, Params(), base::nullopt); |
| |
| EXPECT_CALL(delegate, OnDeviceAuthorized( |
| media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK, |
| _, std::string(kReturnedDeviceId))); |
| EXPECT_CALL(delegate, GotOnStreamCreated()); |
| base::RunLoop().RunUntilIdle(); |
| |
| ipc->CloseStream(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| TEST(MojoAudioOutputIPC, |
| CreateWithoutAuthorization_RequestsAuthorizationFirst) { |
| TestRemoteFactory stream_factory; |
| StrictMock<MockStream> stream; |
| StrictMock<MockDelegate> delegate; |
| const std::unique_ptr<media::AudioOutputIPC> ipc = |
| std::make_unique<MojoAudioOutputIPC>( |
| stream_factory.GetAccessor(), |
| blink::scheduler::GetSingleThreadTaskRunnerForTesting()); |
| |
| // Note: This call implicitly EXPECTs that authorization is requested, |
| // and constructing the TestStreamProvider with a |&stream| EXPECTs that the |
| // stream is created. This implicit request should always be for the default |
| // device and no session id. |
| stream_factory.PrepareProviderForAuthorization( |
| base::UnguessableToken(), |
| std::string(media::AudioDeviceDescription::kDefaultDeviceId), |
| std::make_unique<TestStreamProvider>(&stream)); |
| |
| ipc->CreateStream(&delegate, Params(), base::nullopt); |
| |
| EXPECT_CALL(delegate, GotOnStreamCreated()); |
| base::RunLoop().RunUntilIdle(); |
| |
| ipc->CloseStream(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| TEST(MojoAudioOutputIPC, IsReusable) { |
| const base::UnguessableToken session_id = base::UnguessableToken::Create(); |
| TestRemoteFactory stream_factory; |
| StrictMock<MockStream> stream; |
| StrictMock<MockDelegate> delegate; |
| |
| const std::unique_ptr<media::AudioOutputIPC> ipc = |
| std::make_unique<MojoAudioOutputIPC>( |
| stream_factory.GetAccessor(), |
| blink::scheduler::GetSingleThreadTaskRunnerForTesting()); |
| |
| for (int i = 0; i < 5; ++i) { |
| stream_factory.PrepareProviderForAuthorization( |
| session_id, kDeviceId, std::make_unique<TestStreamProvider>(&stream)); |
| |
| ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId); |
| ipc->CreateStream(&delegate, Params(), base::nullopt); |
| |
| EXPECT_CALL( |
| delegate, |
| OnDeviceAuthorized(media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK, |
| _, std::string(kReturnedDeviceId))); |
| EXPECT_CALL(delegate, GotOnStreamCreated()); |
| base::RunLoop().RunUntilIdle(); |
| Mock::VerifyAndClearExpectations(&delegate); |
| |
| ipc->CloseStream(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| } |
| |
| TEST(MojoAudioOutputIPC, IsReusableAfterError) { |
| const base::UnguessableToken session_id = base::UnguessableToken::Create(); |
| TestRemoteFactory stream_factory; |
| StrictMock<MockStream> stream; |
| StrictMock<MockDelegate> delegate; |
| |
| const std::unique_ptr<media::AudioOutputIPC> ipc = |
| std::make_unique<MojoAudioOutputIPC>( |
| stream_factory.GetAccessor(), |
| blink::scheduler::GetSingleThreadTaskRunnerForTesting()); |
| |
| stream_factory.PrepareProviderForAuthorization( |
| session_id, kDeviceId, std::make_unique<TestStreamProvider>(nullptr)); |
| ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId); |
| |
| EXPECT_CALL(delegate, OnDeviceAuthorized( |
| media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK, |
| _, std::string(kReturnedDeviceId))); |
| base::RunLoop().RunUntilIdle(); |
| Mock::VerifyAndClearExpectations(&delegate); |
| |
| stream_factory.Disconnect(); |
| base::RunLoop().RunUntilIdle(); |
| Mock::VerifyAndClearExpectations(&delegate); |
| |
| ipc->CloseStream(); |
| base::RunLoop().RunUntilIdle(); |
| |
| for (int i = 0; i < 5; ++i) { |
| stream_factory.PrepareProviderForAuthorization( |
| session_id, kDeviceId, std::make_unique<TestStreamProvider>(&stream)); |
| |
| ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId); |
| ipc->CreateStream(&delegate, Params(), base::nullopt); |
| |
| EXPECT_CALL( |
| delegate, |
| OnDeviceAuthorized(media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK, |
| _, std::string(kReturnedDeviceId))); |
| EXPECT_CALL(delegate, GotOnStreamCreated()); |
| base::RunLoop().RunUntilIdle(); |
| Mock::VerifyAndClearExpectations(&delegate); |
| |
| EXPECT_CALL(delegate, OnError()); |
| stream_factory.SignalErrorToProviderClient(); |
| base::RunLoop().RunUntilIdle(); |
| Mock::VerifyAndClearExpectations(&delegate); |
| |
| ipc->CloseStream(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| } |
| |
| TEST(MojoAudioOutputIPC, DeviceNotAuthorized_Propagates) { |
| const base::UnguessableToken session_id = base::UnguessableToken::Create(); |
| TestRemoteFactory stream_factory; |
| StrictMock<MockDelegate> delegate; |
| |
| std::unique_ptr<media::AudioOutputIPC> ipc = |
| std::make_unique<MojoAudioOutputIPC>( |
| stream_factory.GetAccessor(), |
| blink::scheduler::GetSingleThreadTaskRunnerForTesting()); |
| stream_factory.RefuseNextRequest(session_id, kDeviceId); |
| |
| ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId); |
| |
| EXPECT_CALL( |
| delegate, |
| OnDeviceAuthorized( |
| media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED, |
| _, std::string())) |
| .WillOnce(Invoke([&](media::OutputDeviceStatus, |
| const media::AudioParameters&, const std::string&) { |
| ipc->CloseStream(); |
| ipc.reset(); |
| })); |
| EXPECT_CALL(delegate, OnError()).Times(AtLeast(0)); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| TEST(MojoAudioOutputIPC, |
| FactoryDisconnectedBeforeAuthorizationReply_CallsAuthorizedAnyways) { |
| // The authorization IPC message might be aborted by the remote end |
| // disconnecting. In this case, the MojoAudioOutputIPC object must still |
| // send a notification to unblock the AudioOutputIPCDelegate. |
| const base::UnguessableToken session_id = base::UnguessableToken::Create(); |
| TestRemoteFactory stream_factory; |
| StrictMock<MockDelegate> delegate; |
| |
| std::unique_ptr<media::AudioOutputIPC> ipc = |
| std::make_unique<MojoAudioOutputIPC>( |
| stream_factory.GetAccessor(), |
| blink::scheduler::GetSingleThreadTaskRunnerForTesting()); |
| |
| ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId); |
| |
| EXPECT_CALL( |
| delegate, |
| OnDeviceAuthorized( |
| media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL, _, |
| std::string())) |
| .WillOnce(Invoke([&](media::OutputDeviceStatus, |
| const media::AudioParameters&, const std::string&) { |
| ipc->CloseStream(); |
| ipc.reset(); |
| })); |
| stream_factory.Disconnect(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| TEST(MojoAudioOutputIPC, |
| FactoryDisconnectedAfterAuthorizationReply_CallsAuthorizedOnlyOnce) { |
| // This test makes sure that the MojoAudioOutputIPC doesn't callback for |
| // authorization when the factory disconnects if it already got a callback |
| // for authorization. |
| const base::UnguessableToken session_id = base::UnguessableToken::Create(); |
| TestRemoteFactory stream_factory; |
| stream_factory.PrepareProviderForAuthorization( |
| session_id, kDeviceId, std::make_unique<TestStreamProvider>(nullptr)); |
| StrictMock<MockDelegate> delegate; |
| |
| const std::unique_ptr<media::AudioOutputIPC> ipc = |
| std::make_unique<MojoAudioOutputIPC>( |
| stream_factory.GetAccessor(), |
| blink::scheduler::GetSingleThreadTaskRunnerForTesting()); |
| |
| ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId); |
| |
| EXPECT_CALL(delegate, OnDeviceAuthorized( |
| media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK, |
| _, std::string(kReturnedDeviceId))); |
| base::RunLoop().RunUntilIdle(); |
| |
| stream_factory.Disconnect(); |
| base::RunLoop().RunUntilIdle(); |
| |
| ipc->CloseStream(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| TEST(MojoAudioOutputIPC, AuthorizeNoClose_DCHECKs) { |
| TestRemoteFactory stream_factory; |
| const base::UnguessableToken session_id = base::UnguessableToken::Create(); |
| StrictMock<MockDelegate> delegate; |
| |
| stream_factory.PrepareProviderForAuthorization( |
| session_id, kDeviceId, std::make_unique<TestStreamProvider>(nullptr)); |
| |
| std::unique_ptr<media::AudioOutputIPC> ipc = |
| std::make_unique<MojoAudioOutputIPC>( |
| stream_factory.GetAccessor(), |
| blink::scheduler::GetSingleThreadTaskRunnerForTesting()); |
| |
| ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId); |
| EXPECT_DCHECK_DEATH(ipc.reset()); |
| ipc->CloseStream(); |
| ipc.reset(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| TEST(MojoAudioOutputIPC, CreateNoClose_DCHECKs) { |
| TestRemoteFactory stream_factory; |
| StrictMock<MockDelegate> delegate; |
| StrictMock<MockStream> stream; |
| |
| stream_factory.PrepareProviderForAuthorization( |
| base::UnguessableToken(), |
| std::string(media::AudioDeviceDescription::kDefaultDeviceId), |
| std::make_unique<TestStreamProvider>(&stream)); |
| |
| std::unique_ptr<media::AudioOutputIPC> ipc = |
| std::make_unique<MojoAudioOutputIPC>( |
| stream_factory.GetAccessor(), |
| blink::scheduler::GetSingleThreadTaskRunnerForTesting()); |
| |
| ipc->CreateStream(&delegate, Params(), base::nullopt); |
| EXPECT_DCHECK_DEATH(ipc.reset()); |
| ipc->CloseStream(); |
| ipc.reset(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| TEST(MojoAudioOutputIPC, Play_Plays) { |
| TestRemoteFactory stream_factory; |
| const base::UnguessableToken session_id = base::UnguessableToken::Create(); |
| StrictMock<MockStream> stream; |
| StrictMock<MockDelegate> delegate; |
| |
| EXPECT_CALL(delegate, OnDeviceAuthorized( |
| media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK, |
| _, std::string(kReturnedDeviceId))); |
| EXPECT_CALL(delegate, GotOnStreamCreated()); |
| EXPECT_CALL(stream, Play()); |
| |
| const std::unique_ptr<media::AudioOutputIPC> ipc = |
| std::make_unique<MojoAudioOutputIPC>( |
| stream_factory.GetAccessor(), |
| blink::scheduler::GetSingleThreadTaskRunnerForTesting()); |
| stream_factory.PrepareProviderForAuthorization( |
| session_id, kDeviceId, std::make_unique<TestStreamProvider>(&stream)); |
| |
| ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId); |
| ipc->CreateStream(&delegate, Params(), base::nullopt); |
| base::RunLoop().RunUntilIdle(); |
| ipc->PlayStream(); |
| base::RunLoop().RunUntilIdle(); |
| ipc->CloseStream(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| TEST(MojoAudioOutputIPC, Pause_Pauses) { |
| TestRemoteFactory stream_factory; |
| const base::UnguessableToken session_id = base::UnguessableToken::Create(); |
| StrictMock<MockStream> stream; |
| StrictMock<MockDelegate> delegate; |
| |
| EXPECT_CALL(delegate, OnDeviceAuthorized( |
| media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK, |
| _, std::string(kReturnedDeviceId))); |
| EXPECT_CALL(delegate, GotOnStreamCreated()); |
| EXPECT_CALL(stream, Pause()); |
| |
| const std::unique_ptr<media::AudioOutputIPC> ipc = |
| std::make_unique<MojoAudioOutputIPC>( |
| stream_factory.GetAccessor(), |
| blink::scheduler::GetSingleThreadTaskRunnerForTesting()); |
| stream_factory.PrepareProviderForAuthorization( |
| session_id, kDeviceId, std::make_unique<TestStreamProvider>(&stream)); |
| |
| ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId); |
| ipc->CreateStream(&delegate, Params(), base::nullopt); |
| base::RunLoop().RunUntilIdle(); |
| ipc->PauseStream(); |
| base::RunLoop().RunUntilIdle(); |
| ipc->CloseStream(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| TEST(MojoAudioOutputIPC, SetVolume_SetsVolume) { |
| TestRemoteFactory stream_factory; |
| const base::UnguessableToken session_id = base::UnguessableToken::Create(); |
| StrictMock<MockStream> stream; |
| StrictMock<MockDelegate> delegate; |
| |
| EXPECT_CALL(delegate, OnDeviceAuthorized( |
| media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK, |
| _, std::string(kReturnedDeviceId))); |
| EXPECT_CALL(delegate, GotOnStreamCreated()); |
| EXPECT_CALL(stream, SetVolume(kNewVolume)); |
| |
| const std::unique_ptr<media::AudioOutputIPC> ipc = |
| std::make_unique<MojoAudioOutputIPC>( |
| stream_factory.GetAccessor(), |
| blink::scheduler::GetSingleThreadTaskRunnerForTesting()); |
| stream_factory.PrepareProviderForAuthorization( |
| session_id, kDeviceId, std::make_unique<TestStreamProvider>(&stream)); |
| |
| ipc->RequestDeviceAuthorization(&delegate, session_id, kDeviceId); |
| ipc->CreateStream(&delegate, Params(), base::nullopt); |
| base::RunLoop().RunUntilIdle(); |
| ipc->SetVolume(kNewVolume); |
| base::RunLoop().RunUntilIdle(); |
| ipc->CloseStream(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| } // namespace blink |