OLD | NEW |
| (Empty) |
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 <stddef.h> | |
8 | |
9 #include <utility> | |
10 | |
11 #include "base/memory/ptr_util.h" | |
12 #include "chrome/browser/copresence/chrome_whispernet_config.h" | |
13 #include "chrome/browser/extensions/api/copresence_private/copresence_private_ap
i.h" | |
14 #include "chrome/browser/extensions/component_loader.h" | |
15 #include "chrome/browser/extensions/extension_service.h" | |
16 #include "chrome/common/extensions/api/copresence_private.h" | |
17 #include "content/public/browser/browser_context.h" | |
18 #include "extensions/browser/event_router.h" | |
19 #include "extensions/browser/extension_system.h" | |
20 #include "grit/browser_resources.h" | |
21 #include "media/audio/audio_device_description.h" | |
22 #include "media/audio/audio_manager.h" | |
23 #include "media/base/audio_parameters.h" | |
24 | |
25 using audio_modem::AUDIBLE; | |
26 using audio_modem::AudioType; | |
27 using audio_modem::BOTH; | |
28 using audio_modem::INAUDIBLE; | |
29 using audio_modem::SamplesCallback; | |
30 using audio_modem::SuccessCallback; | |
31 using audio_modem::TokensCallback; | |
32 using audio_modem::TokenParameters; | |
33 | |
34 using extensions::api::copresence_private::AudioParameters; | |
35 using extensions::api::copresence_private::DecodeSamplesParameters; | |
36 using extensions::api::copresence_private::EncodeTokenParameters; | |
37 using ApiTokenParams = extensions::api::copresence_private::TokenParameters; | |
38 | |
39 namespace OnConfigAudio = | |
40 extensions::api::copresence_private::OnConfigAudio; | |
41 namespace OnDecodeSamplesRequest = | |
42 extensions::api::copresence_private::OnDecodeSamplesRequest; | |
43 namespace OnEncodeTokenRequest = | |
44 extensions::api::copresence_private::OnEncodeTokenRequest; | |
45 | |
46 using extensions::Event; | |
47 | |
48 namespace { | |
49 | |
50 AudioParamData GetDefaultAudioConfig() { | |
51 media::AudioParameters params = | |
52 media::AudioManager::Get()->GetInputStreamParameters( | |
53 media::AudioDeviceDescription::kDefaultDeviceId); | |
54 | |
55 AudioParamData config_data = {}; | |
56 | |
57 config_data.audio_dtmf.coder_sample_rate = | |
58 config_data.audio_dsss.coder_sample_rate = | |
59 audio_modem::kDefaultSampleRate; | |
60 | |
61 config_data.audio_dtmf.recording_sample_rate = | |
62 config_data.audio_dsss.recording_sample_rate = params.sample_rate(); | |
63 | |
64 config_data.audio_dtmf.num_repetitions_to_play = | |
65 config_data.audio_dsss.num_repetitions_to_play = | |
66 audio_modem::kDefaultRepetitions; | |
67 | |
68 config_data.audio_dsss.upsampling_factor = audio_modem::kDefaultBitsPerSample; | |
69 config_data.audio_dsss.desired_carrier_frequency = | |
70 audio_modem::kDefaultCarrierFrequency; | |
71 | |
72 config_data.recording_channels = params.channels(); | |
73 | |
74 return config_data; | |
75 } | |
76 | |
77 // ApiTokenParams is not copyable, so we must take it as an output argument. | |
78 // TODO(ckehoe): Pass protos to Whispernet to avoid all these conversions. | |
79 void ConvertTokenParams(const TokenParameters& in, ApiTokenParams* out) { | |
80 out->length = in.length; | |
81 out->crc = in.crc; | |
82 out->parity = in.parity; | |
83 } | |
84 | |
85 } // namespace | |
86 | |
87 // static | |
88 const char ChromeWhispernetClient::kWhispernetProxyExtensionId[] = | |
89 "bpfmnplchembfbdgieamdodgaencleal"; | |
90 | |
91 | |
92 // Public functions. | |
93 | |
94 ChromeWhispernetClient::ChromeWhispernetClient( | |
95 content::BrowserContext* browser_context) | |
96 : browser_context_(browser_context), | |
97 event_router_(extensions::EventRouter::Get(browser_context)), | |
98 extension_loaded_(false) { | |
99 DCHECK(browser_context_); | |
100 } | |
101 | |
102 ChromeWhispernetClient::~ChromeWhispernetClient() {} | |
103 | |
104 void ChromeWhispernetClient::Initialize( | |
105 const SuccessCallback& init_callback) { | |
106 DVLOG(3) << "Initializing whispernet proxy client."; | |
107 | |
108 DCHECK(!init_callback.is_null()); | |
109 init_callback_ = init_callback; | |
110 | |
111 ExtensionService* extension_service = | |
112 extensions::ExtensionSystem::Get(browser_context_)->extension_service(); | |
113 CHECK(extension_service); | |
114 | |
115 extensions::ComponentLoader* loader = extension_service->component_loader(); | |
116 CHECK(loader); | |
117 if (!loader->Exists(kWhispernetProxyExtensionId)) { | |
118 DVLOG(3) << "Loading Whispernet proxy."; | |
119 loader->Add(IDR_WHISPERNET_PROXY_MANIFEST, | |
120 base::FilePath(FILE_PATH_LITERAL("whispernet_proxy"))); | |
121 } | |
122 | |
123 client_id_ = extensions::CopresencePrivateService::GetFactoryInstance() | |
124 ->Get(browser_context_)->RegisterWhispernetClient(this); | |
125 AudioConfiguration(GetDefaultAudioConfig()); | |
126 } | |
127 | |
128 void ChromeWhispernetClient::EncodeToken( | |
129 const std::string& token_str, | |
130 AudioType type, | |
131 const TokenParameters token_params[2]) { | |
132 DCHECK(type == AUDIBLE || type == INAUDIBLE); | |
133 | |
134 EncodeTokenParameters params; | |
135 params.token.token = token_str; | |
136 params.token.audible = (type == AUDIBLE); | |
137 ConvertTokenParams(token_params[type], ¶ms.token_params); | |
138 | |
139 SendEventIfLoaded(base::WrapUnique(new Event( | |
140 extensions::events::COPRESENCE_PRIVATE_ON_ENCODE_TOKEN_REQUEST, | |
141 OnEncodeTokenRequest::kEventName, | |
142 OnEncodeTokenRequest::Create(client_id_, params), browser_context_))); | |
143 } | |
144 | |
145 void ChromeWhispernetClient::DecodeSamples( | |
146 AudioType type, | |
147 const std::string& samples, | |
148 const TokenParameters token_params[2]) { | |
149 DecodeSamplesParameters params; | |
150 params.samples.assign(samples.begin(), samples.end()); | |
151 params.decode_audible = (type == AUDIBLE || type == BOTH); | |
152 params.decode_inaudible = (type == INAUDIBLE || type == BOTH); | |
153 ConvertTokenParams(token_params[AUDIBLE], ¶ms.audible_token_params); | |
154 ConvertTokenParams(token_params[INAUDIBLE], ¶ms.inaudible_token_params); | |
155 | |
156 SendEventIfLoaded(base::WrapUnique(new Event( | |
157 extensions::events::COPRESENCE_PRIVATE_ON_DECODE_SAMPLES_REQUEST, | |
158 OnDecodeSamplesRequest::kEventName, | |
159 OnDecodeSamplesRequest::Create(client_id_, params), browser_context_))); | |
160 } | |
161 | |
162 void ChromeWhispernetClient::RegisterTokensCallback( | |
163 const TokensCallback& tokens_callback) { | |
164 tokens_callback_ = tokens_callback; | |
165 } | |
166 | |
167 void ChromeWhispernetClient::RegisterSamplesCallback( | |
168 const SamplesCallback& samples_callback) { | |
169 samples_callback_ = samples_callback; | |
170 } | |
171 | |
172 TokensCallback ChromeWhispernetClient::GetTokensCallback() { | |
173 return tokens_callback_; | |
174 } | |
175 | |
176 SamplesCallback ChromeWhispernetClient::GetSamplesCallback() { | |
177 return samples_callback_; | |
178 } | |
179 | |
180 SuccessCallback ChromeWhispernetClient::GetInitializedCallback() { | |
181 return base::Bind(&ChromeWhispernetClient::OnExtensionLoaded, | |
182 base::Unretained(this)); | |
183 } | |
184 | |
185 | |
186 // Private functions. | |
187 | |
188 void ChromeWhispernetClient::AudioConfiguration(const AudioParamData& params) { | |
189 AudioParameters audio_params; | |
190 | |
191 // We serialize AudioConfigData to a string and send it to the whispernet | |
192 // nacl wrapper. | |
193 const size_t params_size = sizeof(params); | |
194 audio_params.param_data.resize(params_size); | |
195 memcpy(audio_params.param_data.data(), ¶ms, params_size); | |
196 | |
197 DVLOG(3) << "Configuring audio for client " << client_id_; | |
198 SendEventIfLoaded(base::WrapUnique(new Event( | |
199 extensions::events::COPRESENCE_PRIVATE_ON_CONFIG_AUDIO, | |
200 OnConfigAudio::kEventName, | |
201 OnConfigAudio::Create(client_id_, audio_params), browser_context_))); | |
202 } | |
203 | |
204 void ChromeWhispernetClient::SendEventIfLoaded( | |
205 std::unique_ptr<extensions::Event> event) { | |
206 DCHECK(event_router_); | |
207 | |
208 if (extension_loaded_) { | |
209 event_router_->DispatchEventToExtension(kWhispernetProxyExtensionId, | |
210 std::move(event)); | |
211 } else { | |
212 DVLOG(2) << "Queueing event " << event->event_name | |
213 << " for client " << client_id_; | |
214 queued_events_.push_back(event.release()); | |
215 } | |
216 } | |
217 | |
218 void ChromeWhispernetClient::OnExtensionLoaded(bool success) { | |
219 DCHECK(!init_callback_.is_null()); | |
220 init_callback_.Run(success); | |
221 | |
222 DVLOG(3) << "Sending " << queued_events_.size() | |
223 << " queued requests to whispernet from client " | |
224 << client_id_; | |
225 | |
226 // In this loop, ownership of each Event is passed to a scoped_ptr instead. | |
227 // Thus we can just discard the pointers at the end. | |
228 DCHECK(event_router_); | |
229 for (Event* event : queued_events_) { | |
230 event_router_->DispatchEventToExtension(kWhispernetProxyExtensionId, | |
231 base::WrapUnique(event)); | |
232 } | |
233 queued_events_.weak_clear(); | |
234 | |
235 extension_loaded_ = true; | |
236 } | |
OLD | NEW |