| 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) {
|
| + 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) {
|
| +}
|
| +
|
| +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) {
|
| +}
|
| +
|
| +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())
|
| + 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;
|
| + 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
|
|
|