blob: a9160069636e59b3a46ac3760fe84bc4dec5902f [file] [log] [blame]
// 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/directive_handler.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/time/time.h"
#include "components/copresence/handlers/audio/audio_directive_handler_impl.h"
#include "components/copresence/proto/data.pb.h"
namespace copresence {
// Public functions
DirectiveHandler::DirectiveHandler()
: audio_handler_(new AudioDirectiveHandlerImpl),
whispernet_client_(nullptr) {}
DirectiveHandler::~DirectiveHandler() {}
void DirectiveHandler::Start(WhispernetClient* whispernet_client) {
DCHECK(whispernet_client);
whispernet_client_ = whispernet_client;
// TODO(ckehoe): Just pass Whispernet all the way down to the AudioManager.
// We shouldn't be concerned with these details here.
audio_handler_->Initialize(
base::Bind(&WhispernetClient::DecodeSamples,
base::Unretained(whispernet_client_)),
base::Bind(&DirectiveHandler::EncodeToken,
base::Unretained(this)));
// Run all the queued directives.
for (const auto& op_id : pending_directives_) {
for (const Directive& directive : op_id.second) {
StartDirective(op_id.first, directive);
}
}
pending_directives_.clear();
}
void DirectiveHandler::AddDirective(const Directive& directive) {
// We only handle transmit and receive directives.
// WiFi and BLE scans aren't implemented.
DCHECK_EQ(directive.instruction_type(), TOKEN);
std::string op_id;
if (directive.has_published_message_id()) {
op_id = directive.published_message_id();
} else if (directive.has_subscription_id()) {
op_id = directive.subscription_id();
} else {
NOTREACHED() << "No operation associated with directive!";
return;
}
if (!whispernet_client_) {
pending_directives_[op_id].push_back(directive);
} else {
StartDirective(op_id, directive);
}
}
void DirectiveHandler::RemoveDirectives(const std::string& op_id) {
// If whispernet_client_ is null, audio_handler_ hasn't been Initialized.
if (whispernet_client_) {
audio_handler_->RemoveInstructions(op_id);
} else {
pending_directives_.erase(op_id);
}
}
const std::string DirectiveHandler::GetCurrentAudioToken(AudioType type) const {
// If whispernet_client_ is null, audio_handler_ hasn't been Initialized.
return whispernet_client_ ? audio_handler_->PlayingToken(type) : "";
}
// Private functions
void DirectiveHandler::StartDirective(const std::string& op_id,
const Directive& directive) {
const TokenInstruction& ti = directive.token_instruction();
if (ti.medium() == AUDIO_ULTRASOUND_PASSBAND ||
ti.medium() == AUDIO_AUDIBLE_DTMF) {
audio_handler_->AddInstruction(
ti, op_id, base::TimeDelta::FromMilliseconds(directive.ttl_millis()));
} else {
// We should only get audio directives.
NOTREACHED() << "Received directive for unimplemented medium "
<< ti.medium();
}
}
// TODO(ckehoe): We don't need to re-register the samples callback
// every time. Which means this whole function is unnecessary.
void DirectiveHandler::EncodeToken(
const std::string& token,
AudioType type,
const WhispernetClient::SamplesCallback& samples_callback) {
DCHECK(type == AUDIBLE || type == INAUDIBLE);
// TODO(ckehoe): This null check shouldn't be necessary.
// It's only here for tests.
if (whispernet_client_) {
whispernet_client_->RegisterSamplesCallback(samples_callback);
whispernet_client_->EncodeToken(token, type);
}
}
} // namespace copresence