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 "chrome/browser/extensions/api/copresence_private/copresence_private_api.h"
8#include "chrome/browser/extensions/component_loader.h"
9#include "chrome/browser/extensions/extension_service.h"
10#include "chrome/common/extensions/api/copresence_private.h"
11#include "components/copresence/public/copresence_constants.h"
12#include "content/public/browser/browser_context.h"
13#include "extensions/browser/event_router.h"
14#include "extensions/browser/extension_system.h"
15#include "grit/browser_resources.h"
16
17// static
18const char ChromeWhispernetClient::kWhispernetProxyExtensionId[] =
19    "bpfmnplchembfbdgieamdodgaencleal";
20
21// Public:
22
23ChromeWhispernetClient::ChromeWhispernetClient(
24    content::BrowserContext* browser_context)
25    : browser_context_(browser_context), extension_loaded_(false) {
26}
27
28ChromeWhispernetClient::~ChromeWhispernetClient() {
29}
30
31void ChromeWhispernetClient::Initialize(const SuccessCallback& init_callback) {
32  DVLOG(3) << "Initializing whispernet proxy client.";
33  init_callback_ = init_callback;
34
35  extensions::ExtensionSystem* es =
36      extensions::ExtensionSystem::Get(browser_context_);
37  DCHECK(es);
38  ExtensionService* service = es->extension_service();
39  DCHECK(service);
40  extensions::ComponentLoader* loader = service->component_loader();
41  DCHECK(loader);
42
43  // This callback is cancelled in Shutdown().
44  extension_loaded_callback_ = base::Bind(
45      &ChromeWhispernetClient::OnExtensionLoaded, base::Unretained(this));
46
47  if (!loader->Exists(kWhispernetProxyExtensionId)) {
48    DVLOG(3) << "Loading Whispernet proxy.";
49    loader->Add(IDR_WHISPERNET_PROXY_MANIFEST,
50                base::FilePath(FILE_PATH_LITERAL("whispernet_proxy")));
51  } else {
52    init_callback_.Run(true);
53  }
54}
55
56void ChromeWhispernetClient::Shutdown() {
57  extension_loaded_callback_.Reset();
58  init_callback_.Reset();
59  tokens_callback_.Reset();
60  samples_callback_.Reset();
61  db_callback_.Reset();
62}
63
64// Fire an event to request a token encode.
65void ChromeWhispernetClient::EncodeToken(const std::string& token,
66                                         bool audible) {
67  DCHECK(extension_loaded_);
68  DCHECK(browser_context_);
69  DCHECK(extensions::EventRouter::Get(browser_context_));
70
71  scoped_ptr<extensions::Event> event(new extensions::Event(
72      extensions::api::copresence_private::OnEncodeTokenRequest::kEventName,
73      extensions::api::copresence_private::OnEncodeTokenRequest::Create(
74          token, audible),
75      browser_context_));
76
77  extensions::EventRouter::Get(browser_context_)
78      ->DispatchEventToExtension(kWhispernetProxyExtensionId, event.Pass());
79}
80
81// Fire an event to request a decode for the given samples.
82void ChromeWhispernetClient::DecodeSamples(const std::string& samples) {
83  DCHECK(extension_loaded_);
84  DCHECK(browser_context_);
85  DCHECK(extensions::EventRouter::Get(browser_context_));
86
87  scoped_ptr<extensions::Event> event(new extensions::Event(
88      extensions::api::copresence_private::OnDecodeSamplesRequest::kEventName,
89      extensions::api::copresence_private::OnDecodeSamplesRequest::Create(
90          samples),
91      browser_context_));
92
93  extensions::EventRouter::Get(browser_context_)
94      ->DispatchEventToExtension(kWhispernetProxyExtensionId, event.Pass());
95}
96
97void ChromeWhispernetClient::DetectBroadcast() {
98  DCHECK(extension_loaded_);
99  DCHECK(browser_context_);
100  DCHECK(extensions::EventRouter::Get(browser_context_));
101
102  scoped_ptr<extensions::Event> event(new extensions::Event(
103      extensions::api::copresence_private::OnDetectBroadcastRequest::kEventName,
104      make_scoped_ptr(new base::ListValue()),
105      browser_context_));
106
107  extensions::EventRouter::Get(browser_context_)
108      ->DispatchEventToExtension(kWhispernetProxyExtensionId, event.Pass());
109}
110
111void ChromeWhispernetClient::RegisterTokensCallback(
112    const TokensCallback& tokens_callback) {
113  tokens_callback_ = tokens_callback;
114}
115
116void ChromeWhispernetClient::RegisterSamplesCallback(
117    const SamplesCallback& samples_callback) {
118  samples_callback_ = samples_callback;
119}
120
121void ChromeWhispernetClient::RegisterDetectBroadcastCallback(
122    const SuccessCallback& db_callback) {
123  db_callback_ = db_callback;
124}
125
126ChromeWhispernetClient::TokensCallback
127ChromeWhispernetClient::GetTokensCallback() {
128  return tokens_callback_;
129}
130
131ChromeWhispernetClient::SamplesCallback
132ChromeWhispernetClient::GetSamplesCallback() {
133  return samples_callback_;
134}
135
136ChromeWhispernetClient::SuccessCallback
137ChromeWhispernetClient::GetDetectBroadcastCallback() {
138  return db_callback_;
139}
140
141ChromeWhispernetClient::SuccessCallback
142ChromeWhispernetClient::GetInitializedCallback() {
143  return extension_loaded_callback_;
144}
145
146// Private:
147
148// Fire an event to initialize whispernet with the given parameters.
149void ChromeWhispernetClient::InitializeWhispernet(
150    const extensions::api::copresence_private::AudioParameters& params) {
151  DCHECK(browser_context_);
152  DCHECK(extensions::EventRouter::Get(browser_context_));
153
154  scoped_ptr<extensions::Event> event(new extensions::Event(
155      extensions::api::copresence_private::OnInitialize::kEventName,
156      extensions::api::copresence_private::OnInitialize::Create(params),
157      browser_context_));
158
159  extensions::EventRouter::Get(browser_context_)
160      ->DispatchEventToExtension(kWhispernetProxyExtensionId, event.Pass());
161}
162
163void ChromeWhispernetClient::OnExtensionLoaded(bool success) {
164  if (extension_loaded_) {
165    if (!init_callback_.is_null())
166      init_callback_.Run(success);
167    return;
168  }
169
170  // Our extension just got loaded, initialize whispernet.
171  extension_loaded_ = true;
172
173  // This will fire another OnExtensionLoaded call once the initialization is
174  // done, which means we've initialized for realz, hence call the init
175  // callback.
176
177  // At this point, we have the same parameters for record and play. This
178  // may change later though (ongoing discussion with research).
179  extensions::api::copresence_private::AudioParameters params;
180  params.play.sample_rate = copresence::kDefaultSampleRate;
181  params.play.bits_per_sample = copresence::kDefaultBitsPerSample;
182  params.play.carrier_frequency = copresence::kDefaultCarrierFrequency;
183  params.play.repetitions = copresence::kDefaultRepetitions;
184
185  params.record.sample_rate = copresence::kDefaultSampleRate;
186  params.record.bits_per_sample = copresence::kDefaultBitsPerSample;
187  params.record.carrier_frequency = copresence::kDefaultCarrierFrequency;
188  params.record.channels = copresence::kDefaultChannels;
189
190  InitializeWhispernet(params);
191}
192