1// Copyright (c) 2011 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/browser/media/media_internals.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/json/json_reader.h"
10#include "base/run_loop.h"
11#include "base/strings/utf_string_conversions.h"
12#include "content/public/test/test_browser_thread_bundle.h"
13#include "media/audio/audio_parameters.h"
14#include "media/base/channel_layout.h"
15#include "testing/gtest/include/gtest/gtest.h"
16
17namespace {
18const int kTestComponentID = 0;
19const char kTestDeviceID[] = "test-device-id";
20}  // namespace
21
22namespace content {
23
24class MediaInternalsTest
25    : public testing::TestWithParam<media::AudioLogFactory::AudioComponent> {
26 public:
27  MediaInternalsTest()
28      : media_internals_(MediaInternals::GetInstance()),
29        update_cb_(base::Bind(&MediaInternalsTest::UpdateCallbackImpl,
30                              base::Unretained(this))),
31        test_params_(media::AudioParameters::AUDIO_PCM_LINEAR,
32                     media::CHANNEL_LAYOUT_MONO,
33                     48000,
34                     16,
35                     128,
36                     media::AudioParameters::ECHO_CANCELLER |
37                     media::AudioParameters::DUCKING),
38        test_component_(GetParam()),
39        audio_log_(media_internals_->CreateAudioLog(test_component_)) {
40    media_internals_->AddUpdateCallback(update_cb_);
41  }
42
43  virtual ~MediaInternalsTest() {
44    media_internals_->RemoveUpdateCallback(update_cb_);
45  }
46
47 protected:
48  // Extracts and deserializes the JSON update data; merges into |update_data_|.
49  void UpdateCallbackImpl(const base::string16& update) {
50    // Each update string looks like "<JavaScript Function Name>({<JSON>});", to
51    // use the JSON reader we need to strip out the JavaScript code.
52    std::string utf8_update = base::UTF16ToUTF8(update);
53    const std::string::size_type first_brace = utf8_update.find('{');
54    const std::string::size_type last_brace = utf8_update.rfind('}');
55    scoped_ptr<base::Value> output_value(base::JSONReader::Read(
56        utf8_update.substr(first_brace, last_brace - first_brace + 1)));
57    CHECK(output_value);
58
59    base::DictionaryValue* output_dict = NULL;
60    CHECK(output_value->GetAsDictionary(&output_dict));
61    update_data_.MergeDictionary(output_dict);
62  }
63
64  void ExpectInt(const std::string& key, int expected_value) {
65    int actual_value = 0;
66    ASSERT_TRUE(update_data_.GetInteger(key, &actual_value));
67    EXPECT_EQ(expected_value, actual_value);
68  }
69
70  void ExpectString(const std::string& key, const std::string& expected_value) {
71    std::string actual_value;
72    ASSERT_TRUE(update_data_.GetString(key, &actual_value));
73    EXPECT_EQ(expected_value, actual_value);
74  }
75
76  void ExpectStatus(const std::string& expected_value) {
77    ExpectString("status", expected_value);
78  }
79
80  TestBrowserThreadBundle thread_bundle_;
81  MediaInternals* const media_internals_;
82  MediaInternals::UpdateCallback update_cb_;
83  base::DictionaryValue update_data_;
84  const media::AudioParameters test_params_;
85  const media::AudioLogFactory::AudioComponent test_component_;
86  scoped_ptr<media::AudioLog> audio_log_;
87};
88
89TEST_P(MediaInternalsTest, AudioLogCreateStartStopErrorClose) {
90  audio_log_->OnCreated(
91      kTestComponentID, test_params_, kTestDeviceID);
92  base::RunLoop().RunUntilIdle();
93
94  ExpectString("channel_layout",
95               media::ChannelLayoutToString(test_params_.channel_layout()));
96  ExpectInt("sample_rate", test_params_.sample_rate());
97  ExpectInt("frames_per_buffer", test_params_.frames_per_buffer());
98  ExpectInt("channels", test_params_.channels());
99  ExpectString("effects", "ECHO_CANCELLER | DUCKING");
100  ExpectString("device_id", kTestDeviceID);
101  ExpectInt("component_id", kTestComponentID);
102  ExpectInt("component_type", test_component_);
103  ExpectStatus("created");
104
105  // Verify OnStarted().
106  audio_log_->OnStarted(kTestComponentID);
107  base::RunLoop().RunUntilIdle();
108  ExpectStatus("started");
109
110  // Verify OnStopped().
111  audio_log_->OnStopped(kTestComponentID);
112  base::RunLoop().RunUntilIdle();
113  ExpectStatus("stopped");
114
115  // Verify OnError().
116  const char kErrorKey[] = "error_occurred";
117  std::string no_value;
118  ASSERT_FALSE(update_data_.GetString(kErrorKey, &no_value));
119  audio_log_->OnError(kTestComponentID);
120  base::RunLoop().RunUntilIdle();
121  ExpectString(kErrorKey, "true");
122
123  // Verify OnClosed().
124  audio_log_->OnClosed(kTestComponentID);
125  base::RunLoop().RunUntilIdle();
126  ExpectStatus("closed");
127}
128
129TEST_P(MediaInternalsTest, AudioLogCreateClose) {
130  audio_log_->OnCreated(
131      kTestComponentID, test_params_, kTestDeviceID);
132  base::RunLoop().RunUntilIdle();
133  ExpectStatus("created");
134
135  audio_log_->OnClosed(kTestComponentID);
136  base::RunLoop().RunUntilIdle();
137  ExpectStatus("closed");
138}
139
140INSTANTIATE_TEST_CASE_P(
141    MediaInternalsTest, MediaInternalsTest, testing::Values(
142        media::AudioLogFactory::AUDIO_INPUT_CONTROLLER,
143        media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER,
144        media::AudioLogFactory::AUDIO_OUTPUT_STREAM));
145
146}  // namespace content
147