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), | |
37 end_time(end_time) { | |
38 } | |
39 | |
40 AudioDirective::AudioDirective(const std::string& token, | |
41 const std::string& op_id, | |
42 base::Time end_time) | |
43 : token(token), | |
44 op_id(op_id), | |
45 end_time(end_time) { | |
46 } | |
47 | |
48 AudioDirective::AudioDirective( | |
49 const std::string& token, | |
50 const std::string& op_id, | |
51 base::Time end_time, | |
52 const scoped_refptr<media::AudioBusRefCounted>& samples) | |
53 : token(token), | |
54 op_id(op_id), | |
55 end_time(end_time), | |
56 samples(samples) { | |
57 } | |
58 | |
59 AudioDirective::~AudioDirective() { | |
60 } | |
61 | |
62 AudioDirectiveList::AudioDirectiveList( | |
63 const EncodeTokenCallback& encode_token_callback, | |
64 const base::Closure& token_added_callback) | |
65 : encode_token_callback_(encode_token_callback), | |
66 token_added_callback_(token_added_callback), | |
67 samples_cache_(base::TimeDelta::FromMilliseconds(kSampleExpiryTimeMs), | |
68 kMaxSamples) { | |
69 } | |
70 | |
71 AudioDirectiveList::~AudioDirectiveList() { | |
72 } | |
73 | |
74 void AudioDirectiveList::AddTransmitDirective(const std::string& token, | |
75 const std::string& op_id, | |
76 base::TimeDelta ttl) { | |
77 std::string valid_token = FromUrlSafe(token); | |
78 base::Time end_time = base::Time::Now() + ttl; | |
79 | |
80 if (samples_cache_.HasKey(valid_token)) { | |
81 active_transmit_tokens_.push(AudioDirective( | |
82 valid_token, op_id, end_time, samples_cache_.GetValue(valid_token))); | |
83 return; | |
84 } | |
85 | |
86 // If an encode request for this token has been sent, don't send it again. | |
87 if (pending_transmit_tokens_.find(valid_token) != | |
88 pending_transmit_tokens_.end()) { | |
89 return; | |
90 } | |
91 | |
92 pending_transmit_tokens_[valid_token] = | |
93 AudioDirective(valid_token, op_id, end_time); | |
94 // All whispernet callbacks will be cleared before we are destructed, so | |
95 // unretained is safe to use here. | |
96 encode_token_callback_.Run( | |
97 valid_token, | |
98 base::Bind(&AudioDirectiveList::OnTokenEncoded, base::Unretained(this))); | |
99 } | |
100 | |
101 void AudioDirectiveList::AddReceiveDirective(const std::string& op_id, | |
102 base::TimeDelta ttl) { | |
103 active_receive_tokens_.push(AudioDirective(op_id, base::Time::Now() + ttl)); | |
104 } | |
105 | |
106 scoped_ptr<AudioDirective> AudioDirectiveList::GetNextTransmit() { | |
107 return GetNextFromList(&active_transmit_tokens_); | |
108 } | |
109 | |
110 scoped_ptr<AudioDirective> AudioDirectiveList::GetNextReceive() { | |
111 return GetNextFromList(&active_receive_tokens_); | |
112 } | |
113 | |
114 scoped_ptr<AudioDirective> AudioDirectiveList::GetNextFromList( | |
Daniel Erat
2014/07/31 22:31:15
this doesn't look like it needs to be a member fun
rkc
2014/08/01 21:08:56
Done.
| |
115 AudioDirectiveQueue* list) { | |
116 CHECK(list); | |
117 | |
118 // Checks if we have any valid tokens at all (since the top of the list is | |
119 // always pointing to the token with the latest expiry time). If we don't | |
120 // have any valid tokens left, clear the list. | |
121 if (!list->empty() && list->top().end_time < base::Time::Now()) { | |
122 AudioDirectiveQueue empty; | |
123 list->swap(empty); | |
124 } | |
125 | |
126 if (list->empty()) | |
127 return make_scoped_ptr<AudioDirective>(NULL); | |
128 | |
129 return make_scoped_ptr(new AudioDirective(list->top())); | |
Daniel Erat
2014/07/31 22:31:15
where do directives get removed from the list?
rkc
2014/08/01 21:08:56
We don't really remove directives individually. If
| |
130 } | |
131 | |
132 void AudioDirectiveList::OnTokenEncoded( | |
133 const std::string& token, | |
134 const scoped_refptr<media::AudioBusRefCounted>& samples) { | |
135 // We shouldn't re-encode a token if it's already in the cache. | |
136 DCHECK(!samples_cache_.HasKey(token)); | |
137 DVLOG(3) << "Token: " << token << " encoded."; | |
138 samples_cache_.Add(token, samples); | |
139 | |
140 // Copy the samples into its corresponding directive object and move | |
Daniel Erat
2014/07/31 22:31:15
s/its/their/
rkc
2014/08/01 21:08:56
Done.
| |
141 // that object into the active queue. TODO(rkc): The actual directive without | |
142 // the samples is small, but we should find a better way to move around | |
143 // the samples vector. | |
Daniel Erat
2014/07/31 22:31:15
re TODO: aren't you using a scoped_refptr for the
rkc
2014/08/01 21:08:56
The TODO is DONE :) Removed.
Done.
| |
144 std::map<std::string, AudioDirective>::iterator it = | |
145 pending_transmit_tokens_.find(token); | |
146 | |
147 it->second.samples = samples; | |
148 active_transmit_tokens_.push(it->second); | |
149 pending_transmit_tokens_.erase(it); | |
150 | |
151 if (!token_added_callback_.is_null()) | |
152 token_added_callback_.Run(); | |
153 } | |
154 | |
155 } // namespace copresence | |
OLD | NEW |