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 "components/copresence/handlers/audio/audio_directive_list.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/logging.h" | |
9 #include "base/strings/string_util.h" | |
10 #include "media/base/audio_bus.h" | |
11 | |
12 namespace { | |
13 | |
14 // UrlSafe is defined as: | |
15 // '/' represented by a '_' and '+' represented by a '-' | |
16 // TODO(rkc): Move this processing to the whispernet wrapper. | |
17 std::string FromUrlSafe(std::string token) { | |
18 base::ReplaceChars(token, "-", "+", &token); | |
19 base::ReplaceChars(token, "_", "/", &token); | |
20 return token; | |
21 } | |
22 | |
23 const int kSampleExpiryTimeMs = 60 * 60 * 1000; // 60 minutes. | |
24 const int kMaxSamples = 10000; | |
25 | |
26 } // namespace | |
27 | |
28 namespace copresence { | |
29 | |
30 // Public methods. | |
31 | |
32 AudioDirective::AudioDirective() { | |
33 } | |
34 | |
35 AudioDirective::AudioDirective(const std::string& op_id, base::Time end_time) | |
36 : op_id(op_id), end_time(end_time) { | |
37 } | |
38 | |
39 AudioDirective::AudioDirective(const std::string& token, | |
40 const std::string& op_id, | |
41 base::Time end_time) | |
42 : token(token), op_id(op_id), end_time(end_time) { | |
43 } | |
44 | |
45 AudioDirective::AudioDirective( | |
46 const std::string& token, | |
47 const std::string& op_id, | |
48 base::Time end_time, | |
49 const scoped_refptr<media::AudioBusRefCounted>& samples) | |
50 : token(token), op_id(op_id), end_time(end_time), samples(samples) { | |
51 } | |
52 | |
53 AudioDirective::~AudioDirective() { | |
54 } | |
55 | |
56 AudioDirectiveList::AudioDirectiveList( | |
57 const EncodeTokenCallback& encode_token_callback, | |
58 const base::Closure& token_added_callback) | |
59 : encode_token_callback_(encode_token_callback), | |
60 token_added_callback_(token_added_callback), | |
61 samples_cache_(base::TimeDelta::FromMilliseconds(kSampleExpiryTimeMs), | |
62 kMaxSamples) { | |
63 } | |
64 | |
65 AudioDirectiveList::~AudioDirectiveList() { | |
66 } | |
67 | |
68 void AudioDirectiveList::AddTransmitDirective(const std::string& token, | |
69 const std::string& op_id, | |
70 base::TimeDelta ttl) { | |
71 std::string valid_token = FromUrlSafe(token); | |
72 base::Time end_time = base::Time::Now() + ttl; | |
73 | |
74 if (samples_cache_.HasKey(valid_token)) { | |
75 active_transmit_tokens_.push(AudioDirective( | |
76 valid_token, op_id, end_time, samples_cache_.GetValue(valid_token))); | |
77 return; | |
78 } | |
79 | |
80 // If an encode request for this token has been sent, don't send it again. | |
81 if (pending_transmit_tokens_.find(valid_token) != | |
82 pending_transmit_tokens_.end()) { | |
83 return; | |
84 } | |
85 | |
86 pending_transmit_tokens_[valid_token] = | |
87 AudioDirective(valid_token, op_id, end_time); | |
88 // All whispernet callbacks will be cleared before we are destructed, so | |
89 // unretained is safe to use here. | |
90 encode_token_callback_.Run( | |
91 valid_token, | |
92 base::Bind(&AudioDirectiveList::OnTokenEncoded, base::Unretained(this))); | |
93 } | |
94 | |
95 void AudioDirectiveList::AddReceiveDirective(const std::string& op_id, | |
96 base::TimeDelta ttl) { | |
97 active_receive_tokens_.push(AudioDirective(op_id, base::Time::Now() + ttl)); | |
98 } | |
99 | |
100 scoped_ptr<AudioDirective> AudioDirectiveList::GetNextTransmit() { | |
101 return GetNextFromList(&active_transmit_tokens_); | |
102 } | |
103 | |
104 scoped_ptr<AudioDirective> AudioDirectiveList::GetNextReceive() { | |
105 return GetNextFromList(&active_receive_tokens_); | |
106 } | |
107 | |
108 scoped_ptr<AudioDirective> AudioDirectiveList::GetNextFromList( | |
109 AudioDirectiveQueue* list) { | |
110 CHECK(list); | |
111 | |
112 // Checks if we have any valid tokens at all (since the top of the list is | |
113 // always pointing to the token with the latest expiry time). If we don't | |
114 // have any valid tokens left, clear the list. | |
115 while (!list->empty() && list->top().end_time < base::Time::Now()) { | |
xiyuan
2014/07/29 00:22:26
Can we do:
if (!list->empty() && list->top().end_
rkc
2014/07/29 00:33:36
Done.
| |
116 while (!list->empty()) | |
117 list->pop(); | |
118 } | |
119 | |
120 if (list->empty()) | |
121 return make_scoped_ptr<AudioDirective>(NULL); | |
122 | |
123 return make_scoped_ptr(new AudioDirective(list->top())); | |
124 } | |
125 | |
126 void AudioDirectiveList::OnTokenEncoded( | |
127 const std::string& token, | |
128 const scoped_refptr<media::AudioBusRefCounted>& samples) { | |
129 // We shouldn't re-encode a token if it's already in the cache. | |
130 DCHECK(!samples_cache_.HasKey(token)); | |
131 DVLOG(3) << "Token: " << token << " encoded."; | |
132 samples_cache_.Add(token, samples); | |
133 | |
134 // Copy the samples into its corresponding directive object and move | |
135 // that object into the active queue. TODO(rkc): The actual directive without | |
136 // the samples is small, but we should find a better way to move around | |
137 // the samples vector. | |
138 pending_transmit_tokens_[token].samples = samples; | |
139 active_transmit_tokens_.push(pending_transmit_tokens_[token]); | |
140 pending_transmit_tokens_.erase(token); | |
141 | |
142 if (!token_added_callback_.is_null()) | |
143 token_added_callback_.Run(); | |
144 } | |
145 | |
146 } // namespace copresence | |
OLD | NEW |