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.
5 #include "chrome/browser/copresence/chrome_whispernet_client.h"
7 #include "base/stl_util.h"
8 #include "chrome/browser/copresence/chrome_whispernet_config.h"
9 #include "chrome/browser/extensions/api/copresence_private/copresence_private_api.h"
10 #include "chrome/browser/extensions/component_loader.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/common/extensions/api/copresence_private.h"
13 #include "content/public/browser/browser_context.h"
14 #include "extensions/browser/event_router.h"
15 #include "extensions/browser/extension_system.h"
16 #include "grit/browser_resources.h"
17 #include "media/audio/audio_manager.h"
18 #include "media/audio/audio_manager_base.h"
19 #include "media/audio/audio_parameters.h"
21 using audio_modem::AUDIBLE
;
22 using audio_modem::AudioType
;
23 using audio_modem::BOTH
;
24 using audio_modem::INAUDIBLE
;
25 using audio_modem::SamplesCallback
;
26 using audio_modem::SuccessCallback
;
27 using audio_modem::TokensCallback
;
28 using audio_modem::TokenParameters
;
30 using extensions::api::copresence_private::AudioParameters
;
31 using extensions::api::copresence_private::DecodeSamplesParameters
;
32 using extensions::api::copresence_private::EncodeTokenParameters
;
33 using ApiTokenParams
= extensions::api::copresence_private::TokenParameters
;
35 namespace OnConfigAudio
=
36 extensions::api::copresence_private::OnConfigAudio
;
37 namespace OnDecodeSamplesRequest
=
38 extensions::api::copresence_private::OnDecodeSamplesRequest
;
39 namespace OnEncodeTokenRequest
=
40 extensions::api::copresence_private::OnEncodeTokenRequest
;
42 using extensions::Event
;
43 using extensions::copresence_private::RegisterWhispernetClient
;
47 AudioParamData
GetDefaultAudioConfig() {
48 media::AudioParameters params
=
49 media::AudioManager::Get()->GetInputStreamParameters(
50 media::AudioManagerBase::kDefaultDeviceId
);
52 AudioParamData config_data
= {};
54 config_data
.audio_dtmf
.coder_sample_rate
=
55 config_data
.audio_dsss
.coder_sample_rate
=
56 audio_modem::kDefaultSampleRate
;
58 config_data
.audio_dtmf
.recording_sample_rate
=
59 config_data
.audio_dsss
.recording_sample_rate
= params
.sample_rate();
61 config_data
.audio_dtmf
.num_repetitions_to_play
=
62 config_data
.audio_dsss
.num_repetitions_to_play
=
63 audio_modem::kDefaultRepetitions
;
65 config_data
.audio_dsss
.upsampling_factor
= audio_modem::kDefaultBitsPerSample
;
66 config_data
.audio_dsss
.desired_carrier_frequency
=
67 audio_modem::kDefaultCarrierFrequency
;
69 config_data
.recording_channels
= params
.channels();
74 // ApiTokenParams is not copyable, so we must take it as an output argument.
75 // TODO(ckehoe): Pass protos to Whispernet to avoid all these conversions.
76 void ConvertTokenParams(const TokenParameters
& in
, ApiTokenParams
* out
) {
77 out
->length
= in
.length
;
79 out
->parity
= in
.parity
;
85 const char ChromeWhispernetClient::kWhispernetProxyExtensionId
[] =
86 "bpfmnplchembfbdgieamdodgaencleal";
91 ChromeWhispernetClient::ChromeWhispernetClient(
92 content::BrowserContext
* browser_context
)
93 : browser_context_(browser_context
),
94 event_router_(extensions::EventRouter::Get(browser_context
)),
95 extension_loaded_(false) {
96 DCHECK(browser_context_
);
99 ChromeWhispernetClient::~ChromeWhispernetClient() {}
101 void ChromeWhispernetClient::Initialize(
102 const SuccessCallback
& init_callback
) {
103 DVLOG(3) << "Initializing whispernet proxy client.";
105 DCHECK(!init_callback
.is_null());
106 init_callback_
= init_callback
;
108 extensions::ComponentLoader
* loader
=
109 extensions::ExtensionSystem::Get(browser_context_
)
110 ->extension_service()->component_loader();
113 if (!loader
->Exists(kWhispernetProxyExtensionId
)) {
114 DVLOG(3) << "Loading Whispernet proxy.";
115 loader
->Add(IDR_WHISPERNET_PROXY_MANIFEST
,
116 base::FilePath(FILE_PATH_LITERAL("whispernet_proxy")));
119 client_id_
= RegisterWhispernetClient(this);
120 AudioConfiguration(GetDefaultAudioConfig());
123 void ChromeWhispernetClient::EncodeToken(
124 const std::string
& token_str
,
126 const TokenParameters token_params
[2]) {
127 DCHECK(type
== AUDIBLE
|| type
== INAUDIBLE
);
129 EncodeTokenParameters params
;
130 params
.token
.token
= token_str
;
131 params
.token
.audible
= (type
== AUDIBLE
);
132 ConvertTokenParams(token_params
[type
], ¶ms
.token_params
);
134 SendEventIfLoaded(make_scoped_ptr(new Event(
135 OnEncodeTokenRequest::kEventName
,
136 OnEncodeTokenRequest::Create(client_id_
, params
),
140 void ChromeWhispernetClient::DecodeSamples(
142 const std::string
& samples
,
143 const TokenParameters token_params
[2]) {
144 DecodeSamplesParameters params
;
145 params
.samples
.assign(samples
.begin(), samples
.end());
146 params
.decode_audible
= (type
== AUDIBLE
|| type
== BOTH
);
147 params
.decode_inaudible
= (type
== INAUDIBLE
|| type
== BOTH
);
148 ConvertTokenParams(token_params
[AUDIBLE
], ¶ms
.audible_token_params
);
149 ConvertTokenParams(token_params
[INAUDIBLE
], ¶ms
.inaudible_token_params
);
151 SendEventIfLoaded(make_scoped_ptr(new Event(
152 OnDecodeSamplesRequest::kEventName
,
153 OnDecodeSamplesRequest::Create(client_id_
, params
),
157 void ChromeWhispernetClient::RegisterTokensCallback(
158 const TokensCallback
& tokens_callback
) {
159 tokens_callback_
= tokens_callback
;
162 void ChromeWhispernetClient::RegisterSamplesCallback(
163 const SamplesCallback
& samples_callback
) {
164 samples_callback_
= samples_callback
;
167 TokensCallback
ChromeWhispernetClient::GetTokensCallback() {
168 return tokens_callback_
;
171 SamplesCallback
ChromeWhispernetClient::GetSamplesCallback() {
172 return samples_callback_
;
175 SuccessCallback
ChromeWhispernetClient::GetInitializedCallback() {
176 return base::Bind(&ChromeWhispernetClient::OnExtensionLoaded
,
177 base::Unretained(this));
181 // Private functions.
183 void ChromeWhispernetClient::AudioConfiguration(const AudioParamData
& params
) {
184 AudioParameters audio_params
;
186 // We serialize AudioConfigData to a string and send it to the whispernet
188 const size_t params_size
= sizeof(params
);
189 audio_params
.param_data
.resize(params_size
);
190 memcpy(vector_as_array(&audio_params
.param_data
), ¶ms
, params_size
);
192 DVLOG(3) << "Configuring audio for client " << client_id_
;
193 SendEventIfLoaded(make_scoped_ptr(new Event(
194 OnConfigAudio::kEventName
,
195 OnConfigAudio::Create(client_id_
, audio_params
),
199 void ChromeWhispernetClient::SendEventIfLoaded(
200 scoped_ptr
<extensions::Event
> event
) {
201 DCHECK(event_router_
);
203 if (extension_loaded_
) {
204 event_router_
->DispatchEventToExtension(kWhispernetProxyExtensionId
,
207 DVLOG(2) << "Queueing event " << event
->event_name
208 << " for client " << client_id_
;
209 queued_events_
.push_back(event
.release());
213 void ChromeWhispernetClient::OnExtensionLoaded(bool success
) {
214 DCHECK(!init_callback_
.is_null());
215 init_callback_
.Run(success
);
217 DVLOG(3) << "Sending " << queued_events_
.size()
218 << " queued requests to whispernet from client "
221 // In this loop, ownership of each Event is passed to a scoped_ptr instead.
222 // Thus we can just discard the pointers at the end.
223 DCHECK(event_router_
);
224 for (Event
* event
: queued_events_
) {
225 event_router_
->DispatchEventToExtension(kWhispernetProxyExtensionId
,
226 make_scoped_ptr(event
));
228 queued_events_
.weak_clear();
230 extension_loaded_
= true;