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