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.
8 * Function to convert an array of bytes to a base64 string
9 * TODO(rkc): Change this to use a Uint8array instead of a string.
10 * @param {string} bytes String containing the bytes we want to convert.
11 * @return {string} String containing the base64 representation.
13 function bytesToBase64(bytes
) {
15 for (var i
= 0; i
< bytes
.length
; ++i
)
16 bstr
+= String
.fromCharCode(bytes
[i
]);
17 return btoa(bstr
).replace(/=/g
, '');
21 * Function to convert a string to an array of bytes.
22 * @param {string} str String to convert.
23 * @return {Array} Array containing the string.
25 function stringToArray(str
) {
27 for (var i
= 0; i
< str
.length
; ++i
)
28 buffer
[i
] = str
.charCodeAt(i
);
33 * Creates a whispernet encoder.
35 * @param {Object} params Audio parameters for the whispernet encoder.
36 * @param {Object} whisperNacl The NaclBridge object, used to communicate with
37 * the whispernet wrapper.
38 * @param {string} clientId A string identifying the requester.
40 function WhisperEncoder(params
, whisperNacl
, clientId
) {
41 this.whisperNacl_
= whisperNacl
;
42 this.whisperNacl_
.addListener(this.onNaclMessage_
.bind(this));
43 this.clientId_
= clientId
;
46 type
: 'initialize_encoder',
51 this.whisperNacl_
.send(msg
);
55 * Method to encode a token.
56 * @param {Object} params Encode token parameters object.
58 WhisperEncoder
.prototype.encode = function(params
) {
59 // Pad the token before decoding it.
60 var token
= params
.token
.token
;
61 while (token
.length
% 4 > 0)
66 client_id
: this.clientId_
,
67 // Trying to send the token in binary form to Nacl doesn't work correctly.
68 // We end up with the correct string + a bunch of extra characters. This is
69 // true of returning a binary string too; hence we communicate back and
70 // forth by converting the bytes into an array of integers.
71 token
: stringToArray(atob(token
)),
72 repetitions
: params
.repetitions
,
73 use_dtmf
: params
.token
.audible
,
74 use_crc
: params
.tokenParams
.crc
,
75 use_parity
: params
.tokenParams
.parity
78 this.whisperNacl_
.send(msg
);
82 * Method to handle messages from the whispernet NaCl wrapper.
83 * @param {Event} e Event from the whispernet wrapper.
86 WhisperEncoder
.prototype.onNaclMessage_ = function(e
) {
88 if (msg
.type
== 'encode_token_response' && msg
.client_id
== this.clientId_
) {
89 chrome
.copresencePrivate
.sendSamples(this.clientId_
,
90 { token
: bytesToBase64(msg
.token
), audible
: msg
.audible
}, msg
.samples
);
95 * Creates a whispernet decoder.
97 * @param {Object} params Audio parameters for the whispernet decoder.
98 * @param {Object} whisperNacl The NaclBridge object, used to communicate with
99 * the whispernet wrapper.
100 * @param {string} clientId A string identifying the requester.
102 function WhisperDecoder(params
, whisperNacl
, clientId
) {
103 this.whisperNacl_
= whisperNacl
;
104 this.whisperNacl_
.addListener(this.onNaclMessage_
.bind(this));
105 this.clientId_
= clientId
;
108 type
: 'initialize_decoder',
112 this.whisperNacl_
.send(msg
);
116 * Method to request the decoder to process samples.
117 * @param {Object} params Process samples parameters object.
119 WhisperDecoder
.prototype.processSamples = function(params
) {
121 type
: 'decode_tokens',
122 client_id
: this.clientId_
,
123 data
: params
.samples
,
125 decode_audible
: params
.decodeAudible
,
126 token_length_dtmf
: params
.audibleTokenParams
.length
,
127 crc_dtmf
: params
.audibleTokenParams
.crc
,
128 parity_dtmf
: params
.audibleTokenParams
.parity
,
130 decode_inaudible
: params
.decodeInaudible
,
131 token_length_dsss
: params
.inaudibleTokenParams
.length
,
132 crc_dsss
: params
.inaudibleTokenParams
.crc
,
133 parity_dsss
: params
.inaudibleTokenParams
.parity
,
136 this.whisperNacl_
.send(msg
);
140 * Method to handle messages from the whispernet NaCl wrapper.
141 * @param {Event} e Event from the whispernet wrapper.
144 WhisperDecoder
.prototype.onNaclMessage_ = function(e
) {
146 if (msg
.type
== 'decode_tokens_response' && msg
.client_id
== this.clientId_
) {
147 this.handleCandidates_(msg
.tokens
, msg
.audible
);
152 * Method to receive tokens from the decoder and process and forward them to the
153 * token callback registered with us.
154 * @param {!Array.string} candidates Array of token candidates.
155 * @param {boolean} audible Whether the received candidates are from the audible
159 WhisperDecoder
.prototype.handleCandidates_ = function(candidates
, audible
) {
160 if (!candidates
|| candidates
.length
== 0)
163 var returnCandidates
= [];
164 for (var i
= 0; i
< candidates
.length
; ++i
) {
165 returnCandidates
[i
] = { token
: bytesToBase64(candidates
[i
]),
168 chrome
.copresencePrivate
.sendFound(this.clientId_
, returnCandidates
);