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
3// found in the LICENSE file.
4
5#include "chrome/browser/copresence/chrome_whispernet_client.h"
6
7#include <cstdlib>
8#include <string>
9
10#include "base/bind.h"
11#include "base/macros.h"
12#include "base/memory/scoped_ptr.h"
13#include "base/run_loop.h"
14#include "base/stl_util.h"
15#include "chrome/browser/extensions/api/copresence/copresence_api.h"
16#include "chrome/browser/extensions/extension_browsertest.h"
17#include "chrome/browser/profiles/profile.h"
18#include "chrome/browser/ui/browser.h"
19#include "chrome/test/base/in_process_browser_test.h"
20#include "media/base/audio_bus.h"
21
22namespace {
23
24const char kSixZeros[] = "MDAwMDAw";
25
26copresence::WhispernetClient* GetWhispernetClient(
27    content::BrowserContext* context) {
28  extensions::CopresenceService* service =
29      extensions::CopresenceService::GetFactoryInstance()->Get(context);
30  return service ? service->whispernet_client() : NULL;
31}
32
33// Copied from src/components/copresence/mediums/audio/audio_recorder.cc
34std::string AudioBusToString(scoped_refptr<media::AudioBusRefCounted> source) {
35  std::string buffer;
36  buffer.resize(source->frames() * source->channels() * sizeof(float));
37  float* buffer_view = reinterpret_cast<float*>(string_as_array(&buffer));
38
39  const int channels = source->channels();
40  for (int ch = 0; ch < channels; ++ch) {
41    for (int si = 0, di = ch; si < source->frames(); ++si, di += channels)
42      buffer_view[di] = source->channel(ch)[si];
43  }
44
45  return buffer;
46}
47
48}  // namespace
49
50class ChromeWhispernetClientTest : public ExtensionBrowserTest {
51 public:
52  ChromeWhispernetClientTest() : context_(NULL), initialized_(false) {}
53
54  virtual ~ChromeWhispernetClientTest() {}
55
56  void InitializeWhispernet() {
57    context_ = browser()->profile();
58    run_loop_.reset(new base::RunLoop());
59    GetWhispernetClient(context_)->Initialize(base::Bind(
60        &ChromeWhispernetClientTest::InitCallback, base::Unretained(this)));
61    run_loop_->Run();
62
63    EXPECT_TRUE(initialized_);
64  }
65
66  void EncodeTokenAndSaveSamples(bool audible) {
67    copresence::WhispernetClient* client = GetWhispernetClient(context_);
68    ASSERT_TRUE(client);
69
70    run_loop_.reset(new base::RunLoop());
71    client->RegisterSamplesCallback(base::Bind(
72        &ChromeWhispernetClientTest::SamplesCallback, base::Unretained(this)));
73    expected_token_ = kSixZeros;
74    expected_audible_ = audible;
75
76    client->EncodeToken(kSixZeros, audible);
77    run_loop_->Run();
78
79    EXPECT_GT(saved_samples_->frames(), 0);
80  }
81
82  void DecodeSamplesAndVerifyToken(bool expect_audible) {
83    copresence::WhispernetClient* client = GetWhispernetClient(context_);
84    ASSERT_TRUE(client);
85
86    run_loop_.reset(new base::RunLoop());
87    client->RegisterTokensCallback(base::Bind(
88        &ChromeWhispernetClientTest::TokensCallback, base::Unretained(this)));
89    expected_token_ = kSixZeros;
90    expected_audible_ = expect_audible;
91
92    ASSERT_GT(saved_samples_->frames(), 0);
93
94    // Convert our single channel samples to two channel. Decode samples
95    // expects 2 channel data.
96    scoped_refptr<media::AudioBusRefCounted> samples_bus =
97        media::AudioBusRefCounted::Create(2, saved_samples_->frames());
98    memcpy(samples_bus->channel(0),
99           saved_samples_->channel(0),
100           sizeof(float) * saved_samples_->frames());
101    memcpy(samples_bus->channel(1),
102           saved_samples_->channel(0),
103           sizeof(float) * saved_samples_->frames());
104
105    client->DecodeSamples(AudioBusToString(samples_bus));
106    run_loop_->Run();
107  }
108
109  void DetectBroadcast() {
110    copresence::WhispernetClient* client = GetWhispernetClient(context_);
111    ASSERT_TRUE(client);
112
113    run_loop_.reset(new base::RunLoop());
114    client->RegisterDetectBroadcastCallback(
115        base::Bind(&ChromeWhispernetClientTest::DetectBroadcastCallback,
116                   base::Unretained(this)));
117    client->DetectBroadcast();
118    run_loop_->Run();
119  }
120
121 protected:
122  void InitCallback(bool success) {
123    EXPECT_TRUE(success);
124    initialized_ = true;
125    ASSERT_TRUE(run_loop_);
126    run_loop_->Quit();
127  }
128
129  void SamplesCallback(
130      const std::string& token,
131      bool audible,
132      const scoped_refptr<media::AudioBusRefCounted>& samples) {
133    EXPECT_EQ(expected_token_, token);
134    EXPECT_EQ(expected_audible_, audible);
135    saved_samples_ = samples;
136    ASSERT_TRUE(run_loop_);
137    run_loop_->Quit();
138  }
139
140  void TokensCallback(const std::vector<copresence::AudioToken>& tokens) {
141    ASSERT_TRUE(run_loop_);
142    run_loop_->Quit();
143
144    EXPECT_EQ(expected_token_, tokens[0].token);
145    EXPECT_EQ(expected_audible_, tokens[0].audible);
146  }
147
148  void DetectBroadcastCallback(bool success) {
149    EXPECT_TRUE(success);
150    ASSERT_TRUE(run_loop_);
151    run_loop_->Quit();
152  }
153
154 private:
155  scoped_ptr<base::RunLoop> run_loop_;
156  content::BrowserContext* context_;
157
158  std::string expected_token_;
159  bool expected_audible_;
160  scoped_refptr<media::AudioBusRefCounted> saved_samples_;
161
162  bool initialized_;
163
164  DISALLOW_COPY_AND_ASSIGN(ChromeWhispernetClientTest);
165};
166
167IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, Initialize) {
168  InitializeWhispernet();
169}
170
171IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, EncodeToken) {
172  InitializeWhispernet();
173  EncodeTokenAndSaveSamples(false);
174}
175
176IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, DecodeSamples) {
177  InitializeWhispernet();
178  EncodeTokenAndSaveSamples(false);
179  DecodeSamplesAndVerifyToken(false);
180}
181
182IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, DetectBroadcast) {
183  InitializeWhispernet();
184  EncodeTokenAndSaveSamples(false);
185  DecodeSamplesAndVerifyToken(false);
186  DetectBroadcast();
187}
188
189IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, Audible) {
190  InitializeWhispernet();
191  EncodeTokenAndSaveSamples(true);
192  DecodeSamplesAndVerifyToken(true);
193}
194