Index: components/copresence/handlers/audio/audio_directive_list.cc |
diff --git a/components/copresence/handlers/audio/audio_directive_list.cc b/components/copresence/handlers/audio/audio_directive_list.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..486dfa33ad96ce743bb951c85bee56ec82aa705b |
--- /dev/null |
+++ b/components/copresence/handlers/audio/audio_directive_list.cc |
@@ -0,0 +1,141 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "components/copresence/handlers/audio/audio_directive_list.h" |
+ |
+#include "base/bind.h" |
+#include "base/logging.h" |
+#include "base/strings/string_util.h" |
+#include "media/base/audio_bus.h" |
+ |
+namespace { |
+ |
+// UrlSafe is defined as: |
+// '/' represented by a '_' and '+' represented by a '-' |
+// TODO(rkc): Move this processing to the whispernet wrapper. |
+std::string FromUrlSafe(std::string token) { |
Daniel Erat
2014/07/28 21:18:17
const std::string&
rkc
2014/07/29 00:33:34
I need to change the string in the function so I'd
|
+ base::ReplaceChars(token, "-", "+", &token); |
+ base::ReplaceChars(token, "_", "/", &token); |
+ return token; |
+} |
+ |
+const int kSampleExpiryTimeMs = 60 * 60 * 1000; // 60 minutes. |
+const int kMaxSamples = 10000; |
+ |
+} // namespace |
+ |
+namespace copresence { |
+ |
+// Public methods. |
+ |
+AudioDirective::AudioDirective() { |
+} |
+ |
+AudioDirective::AudioDirective(const std::string& op_id, base::Time end_time) |
+ : op_id(op_id), end_time(end_time) { |
Daniel Erat
2014/07/28 21:18:17
nit: one per line if they don't all fit on the sam
rkc
2014/07/29 00:33:34
BTW, git cl format keeps overriding this to put th
|
+} |
+ |
+AudioDirective::AudioDirective(const std::string& token, |
+ const std::string& op_id, |
+ base::Time end_time) |
+ : token(token), op_id(op_id), end_time(end_time) { |
+} |
+ |
+AudioDirective::AudioDirective( |
+ const std::string& token, |
+ const std::string& op_id, |
+ base::Time end_time, |
+ const scoped_refptr<media::AudioBusRefCounted>& samples) |
+ : token(token), op_id(op_id), end_time(end_time), samples(samples) { |
Daniel Erat
2014/07/28 21:18:17
same here
rkc
2014/07/29 00:33:34
Done.
|
+} |
+ |
+AudioDirective::~AudioDirective() { |
+} |
+ |
+AudioDirectiveList::AudioDirectiveList( |
+ const EncodeTokenCallback& encode_token_callback, |
+ const base::Closure& token_added_callback) |
+ : encode_token_callback_(encode_token_callback), |
+ token_added_callback_(token_added_callback), |
+ samples_cache_(base::TimeDelta::FromMilliseconds(kSampleExpiryTimeMs), |
+ kMaxSamples) { |
+} |
+ |
+AudioDirectiveList::~AudioDirectiveList() { |
+} |
+ |
+void AudioDirectiveList::AddTransmitDirective(const std::string& token, |
+ const std::string& op_id, |
+ base::TimeDelta ttl) { |
+ std::string valid_token = FromUrlSafe(token); |
+ base::Time end_time = base::Time::Now() + ttl; |
+ |
+ if (samples_cache_.HasKey(valid_token)) { |
+ active_transmit_tokens_.push(AudioDirective( |
+ valid_token, op_id, end_time, samples_cache_.GetValue(valid_token))); |
+ return; |
+ } |
+ |
+ // If an encode request for this token has been sent, don't send it again. |
+ if (pending_transmit_tokens_.find(valid_token) != |
+ pending_transmit_tokens_.end()) { |
+ return; |
+ } |
+ |
+ pending_transmit_tokens_[valid_token] = |
+ AudioDirective(valid_token, op_id, end_time); |
+ // All whispernet callbacks will be cleared before we are destructed, so |
+ // unretained is safe to use here. |
+ encode_token_callback_.Run( |
+ valid_token, |
+ base::Bind(&AudioDirectiveList::OnTokenEncoded, base::Unretained(this))); |
+} |
+ |
+void AudioDirectiveList::AddReceiveDirective(const std::string& op_id, |
+ base::TimeDelta ttl) { |
+ active_receive_tokens_.push(AudioDirective(op_id, base::Time::Now() + ttl)); |
+} |
+ |
+scoped_ptr<AudioDirective> AudioDirectiveList::GetNextTransmit() { |
+ return GetNextFromList(&active_transmit_tokens_); |
+} |
+ |
+scoped_ptr<AudioDirective> AudioDirectiveList::GetNextReceive() { |
+ return GetNextFromList(&active_receive_tokens_); |
+} |
+ |
+scoped_ptr<AudioDirective> AudioDirectiveList::GetNextFromList( |
+ AudioDirectiveQueue* list) { |
+ CHECK(list); |
+ |
+ while (!list->empty() && list->top().end_time < base::Time::Now()) |
xiyuan
2014/07/25 21:02:09
AudioDirectiveQueue is sorted by LatestFirstCompar
rkc
2014/07/28 21:02:02
No, you're right. Added a comment explaining that
|
+ list->pop(); |
+ |
+ if (list->empty()) |
+ return make_scoped_ptr<AudioDirective>(NULL); |
+ |
+ return make_scoped_ptr(new AudioDirective(list->top())); |
+} |
+ |
+void AudioDirectiveList::OnTokenEncoded( |
+ const std::string& token, |
+ const scoped_refptr<media::AudioBusRefCounted>& samples) { |
+ // We shouldn't re-encode a token if it's already in the cache. |
+ DCHECK(!samples_cache_.HasKey(token)); |
+ DVLOG(3) << "Token: " << token << " encoded."; |
+ samples_cache_.Add(token, samples); |
+ |
+ // Copy the samples into its corresponding directive object and move |
+ // that object into the active queue. TODO(rkc): The actual directive without |
+ // the samples is small, but we should find a better way to move around |
+ // the samples vector. |
+ pending_transmit_tokens_[token].samples = samples; |
Daniel Erat
2014/07/28 21:18:17
use find() to avoid doing the same lookup three ti
rkc
2014/07/29 00:33:34
Done.
|
+ active_transmit_tokens_.push(pending_transmit_tokens_[token]); |
+ pending_transmit_tokens_.erase(token); |
+ |
+ if (!token_added_callback_.is_null()) |
+ token_added_callback_.Run(); |
+} |
+ |
+} // namespace copresence |