| 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 |