| Index: content/browser/renderer_host/media/render_frame_audio_output_service_unittest.cc
|
| diff --git a/content/browser/renderer_host/media/render_frame_audio_output_service_unittest.cc b/content/browser/renderer_host/media/render_frame_audio_output_service_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3e73719cbe181bca31cb79a0b005a0278c906538
|
| --- /dev/null
|
| +++ b/content/browser/renderer_host/media/render_frame_audio_output_service_unittest.cc
|
| @@ -0,0 +1,255 @@
|
| +// Copyright 2016 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 "content/browser/renderer_host/media/render_frame_audio_output_service.h"
|
| +
|
| +#include <cmath>
|
| +#include <limits>
|
| +#include <utility>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/memory/shared_memory.h"
|
| +#include "base/memory/shared_memory_handle.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/sync_socket.h"
|
| +#include "content/browser/audio_manager_thread.h"
|
| +#include "content/browser/renderer_host/media/audio_output_service_context_impl.h"
|
| +#include "content/browser/renderer_host/media/media_stream_manager.h"
|
| +#include "content/common/media/audio_output.mojom.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +#include "content/public/test/mock_render_process_host.h"
|
| +#include "content/public/test/test_browser_context.h"
|
| +#include "content/public/test/test_browser_thread_bundle.h"
|
| +#include "media/audio/audio_output_controller.h"
|
| +#include "media/audio/fake_audio_log_factory.h"
|
| +#include "media/audio/fake_audio_manager.h"
|
| +#include "media/base/audio_parameters.h"
|
| +#include "media/base/media_switches.h"
|
| +#include "mojo/public/cpp/bindings/binding.h"
|
| +#include "mojo/public/cpp/system/platform_handle.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace content {
|
| +
|
| +namespace {
|
| +
|
| +using testing::_;
|
| +using testing::StrictMock;
|
| +using testing::Return;
|
| +using testing::Test;
|
| +using AudioOutputService = mojom::RendererAudioOutputService;
|
| +using AudioOutputServicePtr = mojo::InterfacePtr<AudioOutputService>;
|
| +using AudioOutputServiceRequest = mojo::InterfaceRequest<AudioOutputService>;
|
| +using AudioOutput = mojom::AudioOutput;
|
| +using AudioOutputPtr = mojo::InterfacePtr<AudioOutput>;
|
| +using AudioOutputRequest = mojo::InterfaceRequest<AudioOutput>;
|
| +
|
| +const int kRenderProcessId = 42;
|
| +const int kRenderFrameId = 24;
|
| +const char kSecurityOrigin[] = "http://localhost";
|
| +const char kSalt[] = "salt";
|
| +const media::AudioParameters params(
|
| + media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
|
| + media::CHANNEL_LAYOUT_MONO,
|
| + 44100 /*sample frequency*/,
|
| + 16 /*bits per sample*/,
|
| + 441 /*10 ms buffers*/);
|
| +
|
| +class MockAudioOutputDelegate : public AudioOutputDelegate {
|
| + MOCK_CONST_METHOD0(GetController,
|
| + scoped_refptr<media::AudioOutputController>());
|
| + MOCK_CONST_METHOD0(GetStreamId, int());
|
| + MOCK_METHOD0(OnPlayStream, void());
|
| + MOCK_METHOD0(OnPauseStream, void());
|
| + MOCK_METHOD1(OnSetVolume, void(double));
|
| +};
|
| +
|
| +class MockContext : public AudioOutputServiceContext {
|
| + public:
|
| + explicit MockContext(bool auth_ok, int render_process_id = kRenderProcessId)
|
| + : render_process_id_(render_process_id),
|
| + salt_(kSalt),
|
| + auth_ok_(auth_ok) {}
|
| +
|
| + ~MockContext() { EXPECT_EQ(nullptr, delegate_); }
|
| +
|
| + int GetRenderProcessId() const override { return render_process_id_; }
|
| +
|
| + void RequestDeviceAuthorization(
|
| + int render_frame_id,
|
| + int session_id,
|
| + const std::string& device_id,
|
| + const url::Origin& security_origin,
|
| + AuthorizationCompletedCallback cb) const override {
|
| + EXPECT_EQ(render_frame_id, kRenderFrameId);
|
| + EXPECT_EQ(session_id, 0);
|
| + if (auth_ok_) {
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(cb, media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
|
| + false, media::AudioParameters::UnavailableDeviceParams(),
|
| + "default"));
|
| + return;
|
| + }
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(cb, media::OutputDeviceStatus::
|
| + OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED,
|
| + false, media::AudioParameters::UnavailableDeviceParams(),
|
| + "default"));
|
| + }
|
| +
|
| + const std::string& GetSalt() const override { return salt_; }
|
| +
|
| + void PrepareDelegateForCreation(
|
| + std::unique_ptr<AudioOutputDelegate> delegate) {
|
| + EXPECT_EQ(nullptr, delegate_);
|
| + delegate_ = std::move(delegate);
|
| + }
|
| +
|
| + std::unique_ptr<AudioOutputDelegate> CreateDelegate(
|
| + const std::string& unique_device_id,
|
| + int render_frame_id,
|
| + AudioOutputDelegate::EventHandler* handler,
|
| + const media::AudioParameters& params) override {
|
| + EXPECT_NE(nullptr, delegate_);
|
| + return std::move(delegate_);
|
| + }
|
| +
|
| + MOCK_METHOD1(OnServiceFinished,
|
| + void(mojom::RendererAudioOutputService* service));
|
| +
|
| + private:
|
| + int render_process_id_ = kRenderProcessId;
|
| + const std::string salt_;
|
| + const bool auth_ok_;
|
| + std::unique_ptr<AudioOutputDelegate> delegate_;
|
| +};
|
| +
|
| +void AuthCallback(media::OutputDeviceStatus* status_out,
|
| + media::AudioParameters* params_out,
|
| + std::string* id_out,
|
| + media::OutputDeviceStatus status,
|
| + const media::AudioParameters& params,
|
| + const std::string& id) {
|
| + *status_out = status;
|
| + *params_out = params;
|
| + *id_out = id;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +class RenderFrameAudioOutputServiceTest : public Test {
|
| + public:
|
| + RenderFrameAudioOutputServiceTest() {}
|
| +
|
| + ~RenderFrameAudioOutputServiceTest() override {}
|
| +
|
| + private:
|
| + TestBrowserThreadBundle thread_bundle_;
|
| +};
|
| +
|
| +TEST_F(RenderFrameAudioOutputServiceTest, AuthWithoutStreamRequest) {
|
| + AudioOutputServicePtr service_ptr;
|
| + auto service_context_ = base::MakeUnique<MockContext>(true);
|
| + auto service_ = base::MakeUnique<RenderFrameAudioOutputService>(
|
| + service_context_.get(), kRenderFrameId, mojo::MakeRequest(&service_ptr));
|
| +
|
| + media::OutputDeviceStatus status;
|
| + media::AudioParameters params2;
|
| + std::string id;
|
| + service_ptr->RequestDeviceAuthorization(
|
| + nullptr, /*session_id*/ 0, "default", url::Origin(GURL(kSecurityOrigin)),
|
| + base::Bind(&AuthCallback, base::Unretained(&status),
|
| + base::Unretained(¶ms2), base::Unretained(&id)));
|
| + base::RunLoop().RunUntilIdle();
|
| + EXPECT_EQ(status, media::OUTPUT_DEVICE_STATUS_OK);
|
| + EXPECT_TRUE(id.empty());
|
| +}
|
| +
|
| +TEST_F(RenderFrameAudioOutputServiceTest, AuthWithStreamRequest) {
|
| + AudioOutputServicePtr service_ptr;
|
| + AudioOutputPtr output_ptr;
|
| + auto service_context = base::MakeUnique<MockContext>(true);
|
| + service_context->PrepareDelegateForCreation(
|
| + base::MakeUnique<MockAudioOutputDelegate>());
|
| + auto service = base::MakeUnique<RenderFrameAudioOutputService>(
|
| + service_context.get(), kRenderFrameId, mojo::MakeRequest(&service_ptr));
|
| +
|
| + media::OutputDeviceStatus status;
|
| + media::AudioParameters params2;
|
| + std::string id;
|
| + service_ptr->RequestDeviceAuthorization(
|
| + mojo::MakeRequest<AudioOutput>(&output_ptr), /*session_id*/ 0, "default",
|
| + url::Origin(GURL(kSecurityOrigin)),
|
| + base::Bind(&AuthCallback, base::Unretained(&status),
|
| + base::Unretained(¶ms2), base::Unretained(&id)));
|
| + base::RunLoop().RunUntilIdle();
|
| + EXPECT_EQ(status, media::OUTPUT_DEVICE_STATUS_OK);
|
| + EXPECT_TRUE(id.empty());
|
| +
|
| + output_ptr->Start(params,
|
| + base::Bind([](mojo::ScopedSharedBufferHandle handle1,
|
| + mojo::ScopedHandle handle2) {}));
|
| + base::RunLoop().RunUntilIdle();
|
| + output_ptr.reset();
|
| +}
|
| +
|
| +TEST_F(RenderFrameAudioOutputServiceTest, AuthWithStreamRequestDenied) {
|
| + AudioOutputServicePtr service_ptr;
|
| + AudioOutputPtr output_ptr;
|
| + auto service_context = base::MakeUnique<MockContext>(false);
|
| + auto service = base::MakeUnique<RenderFrameAudioOutputService>(
|
| + service_context.get(), kRenderFrameId, mojo::MakeRequest(&service_ptr));
|
| +
|
| + media::OutputDeviceStatus status;
|
| + media::AudioParameters params2;
|
| + std::string id;
|
| + service_ptr->RequestDeviceAuthorization(
|
| + mojo::MakeRequest<AudioOutput>(&output_ptr), /*session_id*/ 0, "default",
|
| + url::Origin(GURL(kSecurityOrigin)),
|
| + base::Bind(&AuthCallback, base::Unretained(&status),
|
| + base::Unretained(¶ms2), base::Unretained(&id)));
|
| + base::RunLoop().RunUntilIdle();
|
| + EXPECT_EQ(status, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED);
|
| + EXPECT_TRUE(id.empty());
|
| +
|
| + output_ptr->Start(params,
|
| + base::Bind([](mojo::ScopedSharedBufferHandle handle1,
|
| + mojo::ScopedHandle handle2) {}));
|
| + base::RunLoop().RunUntilIdle();
|
| + output_ptr.reset();
|
| +}
|
| +
|
| +TEST_F(RenderFrameAudioOutputServiceTest, OutOfRangeSessionId_BadMessage) {
|
| + // This test checks that we get a bad message if session_id is too large
|
| + // to fit in an integer. This ensures that we don't overflow when casting the
|
| + // int64_t to an int
|
| + if (sizeof(int) >= sizeof(int64_t)) {
|
| + // In this case, any int64_t would fit in an int, and the case we are
|
| + // checking for is impossible.
|
| + return;
|
| + }
|
| +
|
| + TestBrowserContext browser_context;
|
| + MockRenderProcessHost rph(&browser_context);
|
| +
|
| + AudioOutputServicePtr service_ptr;
|
| + auto service_context = base::MakeUnique<MockContext>(true, rph.GetID());
|
| + auto service = base::MakeUnique<RenderFrameAudioOutputService>(
|
| + service_context.get(), kRenderFrameId, mojo::MakeRequest(&service_ptr));
|
| + EXPECT_CALL(*service_context, OnServiceFinished(service.get()));
|
| +
|
| + int64_t session_id = std::numeric_limits<int>::max();
|
| + ++session_id;
|
| + service_ptr->RequestDeviceAuthorization(
|
| + nullptr, session_id, "default", url::Origin(GURL(kSecurityOrigin)),
|
| + base::Bind([](media::OutputDeviceStatus, const media::AudioParameters&,
|
| + const std::string&) { EXPECT_FALSE(true); }));
|
| + base::RunLoop().RunUntilIdle();
|
| + EXPECT_EQ(1, rph.bad_msg_count());
|
| +}
|
| +
|
| +} // namespace content
|
|
|