OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/copresence/chrome_whispernet_client.h" | 5 #include "chrome/browser/copresence/chrome_whispernet_client.h" |
6 | 6 |
| 7 #include <cmath> |
7 #include <cstdlib> | 8 #include <cstdlib> |
8 #include <string> | 9 #include <string> |
9 | 10 |
10 #include "base/bind.h" | 11 #include "base/bind.h" |
11 #include "base/macros.h" | 12 #include "base/macros.h" |
12 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
13 #include "base/run_loop.h" | 14 #include "base/run_loop.h" |
14 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
15 #include "chrome/browser/extensions/api/copresence/copresence_api.h" | 16 #include "chrome/browser/extensions/api/copresence/copresence_api.h" |
16 #include "chrome/browser/extensions/extension_browsertest.h" | 17 #include "chrome/browser/extensions/extension_browsertest.h" |
17 #include "chrome/browser/profiles/profile.h" | 18 #include "chrome/browser/profiles/profile.h" |
18 #include "chrome/browser/ui/browser.h" | 19 #include "chrome/browser/ui/browser.h" |
19 #include "chrome/test/base/in_process_browser_test.h" | 20 #include "chrome/test/base/in_process_browser_test.h" |
| 21 #include "components/audio_modem/public/audio_modem_types.h" |
20 #include "components/audio_modem/public/whispernet_client.h" | 22 #include "components/audio_modem/public/whispernet_client.h" |
| 23 #include "media/audio/audio_manager.h" |
| 24 #include "media/audio/audio_manager_base.h" |
| 25 #include "media/audio/audio_parameters.h" |
21 #include "media/base/audio_bus.h" | 26 #include "media/base/audio_bus.h" |
| 27 #include "media/base/audio_converter.h" |
22 | 28 |
23 using audio_modem::WhispernetClient; | 29 using audio_modem::WhispernetClient; |
24 using audio_modem::AUDIBLE; | 30 using audio_modem::AUDIBLE; |
25 using audio_modem::INAUDIBLE; | 31 using audio_modem::INAUDIBLE; |
26 using audio_modem::TokenParameters; | 32 using audio_modem::TokenParameters; |
27 | 33 |
28 namespace { | 34 namespace { |
29 | 35 |
30 // TODO(rkc): Add more varied test input. | 36 // TODO(rkc): Add more varied test input. |
31 const char kSixZeros[] = "MDAwMDAw"; | 37 const char kSixZeros[] = "MDAwMDAw"; |
(...skipping 20 matching lines...) Expand all Loading... |
52 void GetTokenParamsForLengths(const size_t token_lengths[2], | 58 void GetTokenParamsForLengths(const size_t token_lengths[2], |
53 TokenParameters* params) { | 59 TokenParameters* params) { |
54 params[0].length = token_lengths[0]; | 60 params[0].length = token_lengths[0]; |
55 params[1].length = token_lengths[1]; | 61 params[1].length = token_lengths[1]; |
56 } | 62 } |
57 | 63 |
58 void IgnoreResult(bool success) {} | 64 void IgnoreResult(bool success) {} |
59 | 65 |
60 } // namespace | 66 } // namespace |
61 | 67 |
62 class ChromeWhispernetClientTest : public ExtensionBrowserTest { | 68 class ChromeWhispernetClientTest : public ExtensionBrowserTest, |
| 69 public media::AudioConverter::InputCallback { |
63 protected: | 70 protected: |
64 ChromeWhispernetClientTest() | 71 ChromeWhispernetClientTest() |
65 : initialized_(false), expected_audible_(false) {} | 72 : initialized_(false), |
| 73 expected_audible_(false), |
| 74 saved_samples_index_(0) {} |
66 | 75 |
67 ~ChromeWhispernetClientTest() override {} | 76 ~ChromeWhispernetClientTest() override {} |
68 | 77 |
69 void InitializeWhispernet() { | 78 void InitializeWhispernet() { |
70 scoped_ptr<WhispernetClient> client( | 79 scoped_ptr<WhispernetClient> client( |
71 new ChromeWhispernetClient(browser()->profile())); | 80 new ChromeWhispernetClient(browser()->profile())); |
72 client->Initialize(base::Bind( | 81 client->Initialize(base::Bind( |
73 &ChromeWhispernetClientTest::InitCallback, base::Unretained(this))); | 82 &ChromeWhispernetClientTest::InitCallback, base::Unretained(this))); |
74 | 83 |
75 run_loop_.reset(new base::RunLoop()); | 84 run_loop_.reset(new base::RunLoop()); |
76 run_loop_->Run(); | 85 run_loop_->Run(); |
| 86 EXPECT_TRUE(initialized_); |
| 87 } |
77 | 88 |
78 EXPECT_TRUE(initialized_); | 89 // This needs to be called before any of the decoder tests are run. We can't |
| 90 // run this code in the constructor or the SetUp methods because the audio |
| 91 // manager seems to get initialized only *after* ExtensionBrowserTest::SetUp |
| 92 // has finished executing. Setting up a testing AudioMager causes the actual |
| 93 // create happening later in the browser initialization to fail. The only way |
| 94 // around this at the moment seems to be to have this method called from |
| 95 // every test before they try to decode. |
| 96 void SetupDecode() { |
| 97 // We get default parameters here instead of the constructor since |
| 98 // initializing Whispernet also creates our AudioManager. Initializing from |
| 99 // the test instead causes issues. |
| 100 default_params_ = media::AudioManager::Get()->GetInputStreamParameters( |
| 101 media::AudioManagerBase::kDefaultDeviceId); |
| 102 |
| 103 coder_params_ = media::AudioParameters( |
| 104 default_params_.format(), audio_modem::kDefaultChannelLayout, |
| 105 audio_modem::kDefaultSampleRate, audio_modem::kDefaultBitsPerSample, |
| 106 default_params_.frames_per_buffer(), |
| 107 media::AudioParameters::NO_EFFECTS); |
| 108 |
| 109 converter_.reset(new media::AudioConverter( |
| 110 coder_params_, default_params_, |
| 111 default_params_.sample_rate() == coder_params_.sample_rate())); |
| 112 converter_->AddInput(this); |
79 } | 113 } |
80 | 114 |
81 void EncodeTokenAndSaveSamples(WhispernetClient* client, | 115 void EncodeTokenAndSaveSamples(WhispernetClient* client, |
82 bool audible, | 116 bool audible, |
83 const std::string& token) { | 117 const std::string& token) { |
84 run_loop_.reset(new base::RunLoop()); | 118 run_loop_.reset(new base::RunLoop()); |
85 client->RegisterSamplesCallback( | 119 client->RegisterSamplesCallback( |
86 base::Bind(&ChromeWhispernetClientTest::SamplesCallback, | 120 base::Bind(&ChromeWhispernetClientTest::SamplesCallback, |
87 base::Unretained(this))); | 121 base::Unretained(this))); |
88 expected_token_ = token; | 122 expected_token_ = token; |
(...skipping 11 matching lines...) Expand all Loading... |
100 const std::string& expected_token, | 134 const std::string& expected_token, |
101 const TokenParameters token_params[2]) { | 135 const TokenParameters token_params[2]) { |
102 run_loop_.reset(new base::RunLoop()); | 136 run_loop_.reset(new base::RunLoop()); |
103 client->RegisterTokensCallback(base::Bind( | 137 client->RegisterTokensCallback(base::Bind( |
104 &ChromeWhispernetClientTest::TokensCallback, base::Unretained(this))); | 138 &ChromeWhispernetClientTest::TokensCallback, base::Unretained(this))); |
105 expected_token_ = expected_token; | 139 expected_token_ = expected_token; |
106 expected_audible_ = expect_audible; | 140 expected_audible_ = expect_audible; |
107 | 141 |
108 ASSERT_GT(saved_samples_->frames(), 0); | 142 ASSERT_GT(saved_samples_->frames(), 0); |
109 | 143 |
110 // Convert our single channel samples to two channel. Decode samples | |
111 // expects 2 channel data. | |
112 scoped_refptr<media::AudioBusRefCounted> samples_bus = | 144 scoped_refptr<media::AudioBusRefCounted> samples_bus = |
113 media::AudioBusRefCounted::Create(2, saved_samples_->frames()); | 145 ConvertSavedSamplesToSystemParams(); |
114 memcpy(samples_bus->channel(0), | |
115 saved_samples_->channel(0), | |
116 sizeof(float) * saved_samples_->frames()); | |
117 memcpy(samples_bus->channel(1), | |
118 saved_samples_->channel(0), | |
119 sizeof(float) * saved_samples_->frames()); | |
120 | |
121 client->DecodeSamples(expect_audible ? AUDIBLE : INAUDIBLE, | 146 client->DecodeSamples(expect_audible ? AUDIBLE : INAUDIBLE, |
122 AudioBusToString(samples_bus), | 147 AudioBusToString(samples_bus), token_params); |
123 token_params); | |
124 run_loop_->Run(); | 148 run_loop_->Run(); |
125 } | 149 } |
126 | 150 |
127 void InitCallback(bool success) { | 151 void InitCallback(bool success) { |
128 EXPECT_TRUE(success); | 152 EXPECT_TRUE(success); |
129 initialized_ = true; | 153 initialized_ = true; |
130 ASSERT_TRUE(run_loop_); | 154 ASSERT_TRUE(run_loop_); |
131 run_loop_->Quit(); | 155 run_loop_->Quit(); |
132 } | 156 } |
133 | 157 |
134 void SamplesCallback( | 158 void SamplesCallback( |
135 audio_modem::AudioType type, | 159 audio_modem::AudioType type, |
136 const std::string& token, | 160 const std::string& token, |
137 const scoped_refptr<media::AudioBusRefCounted>& samples) { | 161 const scoped_refptr<media::AudioBusRefCounted>& samples) { |
138 EXPECT_EQ(expected_token_, token); | 162 EXPECT_EQ(expected_token_, token); |
139 EXPECT_EQ(expected_audible_, type == AUDIBLE); | 163 EXPECT_EQ(expected_audible_, type == AUDIBLE); |
140 saved_samples_ = samples; | 164 saved_samples_ = samples; |
141 ASSERT_TRUE(run_loop_); | 165 ASSERT_TRUE(run_loop_); |
142 run_loop_->Quit(); | 166 run_loop_->Quit(); |
143 } | 167 } |
144 | 168 |
145 void TokensCallback(const std::vector<audio_modem::AudioToken>& tokens) { | 169 void TokensCallback(const std::vector<audio_modem::AudioToken>& tokens) { |
146 ASSERT_TRUE(run_loop_); | 170 ASSERT_TRUE(run_loop_); |
147 run_loop_->Quit(); | 171 run_loop_->Quit(); |
148 | 172 |
149 EXPECT_EQ(expected_token_, tokens[0].token); | 173 EXPECT_EQ(expected_token_, tokens[0].token); |
150 EXPECT_EQ(expected_audible_, tokens[0].audible); | 174 EXPECT_EQ(expected_audible_, tokens[0].audible); |
151 } | 175 } |
152 | 176 |
| 177 private: |
| 178 scoped_refptr<media::AudioBusRefCounted> ConvertSavedSamplesToSystemParams() { |
| 179 int new_size = |
| 180 saved_samples_->frames() * |
| 181 std::ceil(static_cast<double>(default_params_.sample_rate()) / |
| 182 coder_params_.sample_rate()); |
| 183 new_size = |
| 184 std::ceil(static_cast<double>(new_size) / converter_->ChunkSize()) * |
| 185 converter_->ChunkSize(); |
| 186 |
| 187 scoped_refptr<media::AudioBusRefCounted> converted_samples = |
| 188 media::AudioBusRefCounted::Create(default_params_.channels(), new_size); |
| 189 |
| 190 // Convert our single channel samples to two channel. Decode samples |
| 191 // expects 2 channel data. |
| 192 saved_samples_stereo_ = |
| 193 media::AudioBusRefCounted::Create(2, saved_samples_->frames()); |
| 194 memcpy(saved_samples_stereo_->channel(0), saved_samples_->channel(0), |
| 195 sizeof(float) * saved_samples_->frames()); |
| 196 memcpy(saved_samples_stereo_->channel(1), saved_samples_->channel(0), |
| 197 sizeof(float) * saved_samples_->frames()); |
| 198 |
| 199 saved_samples_index_ = 0; |
| 200 converter_->Convert(converted_samples.get()); |
| 201 |
| 202 return converted_samples; |
| 203 } |
| 204 |
| 205 // AudioConverter::InputCallback overrides: |
| 206 double ProvideInput(media::AudioBus* dest, |
| 207 base::TimeDelta /* buffer_delay */) override { |
| 208 int remaining_frames = saved_samples_->frames() - saved_samples_index_; |
| 209 int frames_to_copy = std::min(remaining_frames, dest->frames()); |
| 210 saved_samples_stereo_->CopyPartialFramesTo(saved_samples_index_, |
| 211 frames_to_copy, 0, dest); |
| 212 saved_samples_index_ += frames_to_copy; |
| 213 return 1.0; |
| 214 } |
| 215 |
153 scoped_ptr<base::RunLoop> run_loop_; | 216 scoped_ptr<base::RunLoop> run_loop_; |
154 bool initialized_; | 217 bool initialized_; |
155 | 218 |
156 private: | |
157 std::string expected_token_; | 219 std::string expected_token_; |
158 bool expected_audible_; | 220 bool expected_audible_; |
| 221 |
159 scoped_refptr<media::AudioBusRefCounted> saved_samples_; | 222 scoped_refptr<media::AudioBusRefCounted> saved_samples_; |
| 223 scoped_refptr<media::AudioBusRefCounted> saved_samples_stereo_; |
| 224 int saved_samples_index_; |
| 225 |
| 226 scoped_ptr<media::AudioConverter> converter_; |
| 227 |
| 228 media::AudioParameters default_params_; |
| 229 media::AudioParameters coder_params_; |
160 | 230 |
161 DISALLOW_COPY_AND_ASSIGN(ChromeWhispernetClientTest); | 231 DISALLOW_COPY_AND_ASSIGN(ChromeWhispernetClientTest); |
162 }; | 232 }; |
163 | 233 |
164 // These tests are irrelevant if NACL is disabled. See crbug.com/449198 | 234 // These tests are irrelevant if NACL is disabled. See crbug.com/449198 |
165 #if defined(DISABLE_NACL) | 235 #if defined(DISABLE_NACL) |
166 #define MAYBE_Initialize DISABLED_Initialize | 236 #define MAYBE_Initialize DISABLED_Initialize |
167 #define MAYBE_EncodeAndDecode DISABLED_EncodeAndDecode | 237 #define MAYBE_EncodeAndDecode DISABLED_EncodeAndDecode |
168 #define MAYBE_TokenLengths DISABLED_TokenLengths | 238 #define MAYBE_TokenLengths DISABLED_TokenLengths |
169 #define MAYBE_MultipleClients DISABLED_MultipleClients | 239 #define MAYBE_MultipleClients DISABLED_MultipleClients |
170 #else | 240 #else |
171 #define MAYBE_Initialize Initialize | 241 #define MAYBE_Initialize Initialize |
172 #define MAYBE_EncodeAndDecode EncodeAndDecode | 242 #define MAYBE_EncodeAndDecode EncodeAndDecode |
173 #define MAYBE_TokenLengths TokenLengths | 243 #define MAYBE_TokenLengths TokenLengths |
174 #define MAYBE_MultipleClients MultipleClients | 244 #define MAYBE_MultipleClients MultipleClients |
175 #endif | 245 #endif |
176 | 246 |
177 IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, MAYBE_Initialize) { | 247 IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, MAYBE_Initialize) { |
178 InitializeWhispernet(); | 248 InitializeWhispernet(); |
179 } | 249 } |
180 | 250 |
181 IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, MAYBE_EncodeAndDecode) { | 251 IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, MAYBE_EncodeAndDecode) { |
182 scoped_ptr<WhispernetClient> client( | 252 scoped_ptr<WhispernetClient> client( |
183 new ChromeWhispernetClient(browser()->profile())); | 253 new ChromeWhispernetClient(browser()->profile())); |
184 client->Initialize(base::Bind(&IgnoreResult)); | 254 client->Initialize(base::Bind(&IgnoreResult)); |
185 | 255 |
186 TokenParameters token_params[2]; | 256 TokenParameters token_params[2]; |
187 GetTokenParamsForLengths(kTokenLengths, token_params); | 257 GetTokenParamsForLengths(kTokenLengths, token_params); |
188 | 258 |
| 259 SetupDecode(); |
| 260 |
189 EncodeTokenAndSaveSamples(client.get(), true, kSixZeros); | 261 EncodeTokenAndSaveSamples(client.get(), true, kSixZeros); |
190 DecodeSamplesAndVerifyToken(client.get(), true, kSixZeros, token_params); | 262 DecodeSamplesAndVerifyToken(client.get(), true, kSixZeros, token_params); |
191 | 263 |
192 EncodeTokenAndSaveSamples(client.get(), false, kSixZeros); | 264 EncodeTokenAndSaveSamples(client.get(), false, kSixZeros); |
193 DecodeSamplesAndVerifyToken(client.get(), false, kSixZeros, token_params); | 265 DecodeSamplesAndVerifyToken(client.get(), false, kSixZeros, token_params); |
194 } | 266 } |
195 | 267 |
196 IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, MAYBE_TokenLengths) { | 268 IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, MAYBE_TokenLengths) { |
197 scoped_ptr<WhispernetClient> client( | 269 scoped_ptr<WhispernetClient> client( |
198 new ChromeWhispernetClient(browser()->profile())); | 270 new ChromeWhispernetClient(browser()->profile())); |
199 client->Initialize(base::Bind(&IgnoreResult)); | 271 client->Initialize(base::Bind(&IgnoreResult)); |
200 | 272 |
201 const size_t kLongTokenLengths[2] = {8, 9}; | 273 const size_t kLongTokenLengths[2] = {8, 9}; |
202 TokenParameters token_params[2]; | 274 TokenParameters token_params[2]; |
203 GetTokenParamsForLengths(kLongTokenLengths, token_params); | 275 GetTokenParamsForLengths(kLongTokenLengths, token_params); |
| 276 |
| 277 SetupDecode(); |
| 278 |
204 EncodeTokenAndSaveSamples(client.get(), true, kEightZeros); | 279 EncodeTokenAndSaveSamples(client.get(), true, kEightZeros); |
205 DecodeSamplesAndVerifyToken(client.get(), true, kEightZeros, token_params); | 280 DecodeSamplesAndVerifyToken(client.get(), true, kEightZeros, token_params); |
206 | 281 |
207 EncodeTokenAndSaveSamples(client.get(), false, kNineZeros); | 282 EncodeTokenAndSaveSamples(client.get(), false, kNineZeros); |
208 DecodeSamplesAndVerifyToken(client.get(), false, kNineZeros, token_params); | 283 DecodeSamplesAndVerifyToken(client.get(), false, kNineZeros, token_params); |
209 } | 284 } |
210 | 285 |
211 IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, MAYBE_MultipleClients) { | 286 IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, MAYBE_MultipleClients) { |
212 scoped_ptr<WhispernetClient> client_1( | 287 scoped_ptr<WhispernetClient> client_1( |
213 new ChromeWhispernetClient(browser()->profile())); | 288 new ChromeWhispernetClient(browser()->profile())); |
214 scoped_ptr<WhispernetClient> client_2( | 289 scoped_ptr<WhispernetClient> client_2( |
215 new ChromeWhispernetClient(browser()->profile())); | 290 new ChromeWhispernetClient(browser()->profile())); |
216 | 291 |
217 TokenParameters token_params[2]; | 292 TokenParameters token_params[2]; |
218 GetTokenParamsForLengths(kTokenLengths, token_params); | 293 GetTokenParamsForLengths(kTokenLengths, token_params); |
219 | 294 |
| 295 SetupDecode(); |
| 296 |
220 client_1->Initialize(base::Bind(&IgnoreResult)); | 297 client_1->Initialize(base::Bind(&IgnoreResult)); |
221 | 298 |
222 EncodeTokenAndSaveSamples(client_1.get(), true, kSixZeros); | 299 EncodeTokenAndSaveSamples(client_1.get(), true, kSixZeros); |
223 DecodeSamplesAndVerifyToken(client_1.get(), true, kSixZeros, token_params); | 300 DecodeSamplesAndVerifyToken(client_1.get(), true, kSixZeros, token_params); |
224 | 301 |
225 client_2->Initialize(base::Bind(&IgnoreResult)); | 302 client_2->Initialize(base::Bind(&IgnoreResult)); |
226 | 303 |
227 EncodeTokenAndSaveSamples(client_2.get(), true, kSixZeros); | 304 EncodeTokenAndSaveSamples(client_2.get(), true, kSixZeros); |
228 DecodeSamplesAndVerifyToken(client_2.get(), true, kSixZeros, token_params); | 305 DecodeSamplesAndVerifyToken(client_2.get(), true, kSixZeros, token_params); |
229 } | 306 } |
230 | 307 |
231 // TODO(ckehoe): Test crc and parity | 308 // TODO(ckehoe): Test crc and parity |
232 // TODO(ckehoe): More multi-client testing | 309 // TODO(ckehoe): More multi-client testing |
OLD | NEW |