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