blob: 9a7973803a094937b275122e343fc336b27314ec [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/audio/audio_directive_handler.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/time/default_tick_clock.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/copresence/mediums/audio/audio_manager_impl.h"
#include "components/copresence/proto/data.pb.h"
#include "components/copresence/public/copresence_constants.h"
#include "media/base/audio_bus.h"
namespace copresence {
namespace {
base::TimeTicks GetEarliestEventTime(AudioDirectiveList* list,
base::TimeTicks event_time) {
if (!list->GetActiveDirective())
return event_time;
if (event_time.is_null())
return list->GetActiveDirective()->end_time;
else
return std::min(list->GetActiveDirective()->end_time, event_time);
}
} // namespace
// Public methods.
AudioDirectiveHandler::AudioDirectiveHandler()
: audio_event_timer_(new base::OneShotTimer<AudioDirectiveHandler>),
clock_(new base::DefaultTickClock) {
}
AudioDirectiveHandler::~AudioDirectiveHandler() {
}
void AudioDirectiveHandler::Initialize(
const AudioManager::DecodeSamplesCallback& decode_cb,
const AudioManager::EncodeTokenCallback& encode_cb) {
if (!audio_manager_)
audio_manager_.reset(new AudioManagerImpl());
audio_manager_->Initialize(decode_cb, encode_cb);
}
void AudioDirectiveHandler::AddInstruction(const TokenInstruction& instruction,
const std::string& op_id,
base::TimeDelta ttl) {
switch (instruction.token_instruction_type()) {
case TRANSMIT:
DVLOG(2) << "Audio Transmit Directive received. Token: "
<< instruction.token_id()
<< " with medium=" << instruction.medium()
<< " with TTL=" << ttl.InMilliseconds();
switch (instruction.medium()) {
case AUDIO_ULTRASOUND_PASSBAND:
transmits_list_[INAUDIBLE].AddDirective(op_id, ttl);
audio_manager_->SetToken(INAUDIBLE, instruction.token_id());
break;
case AUDIO_AUDIBLE_DTMF:
transmits_list_[AUDIBLE].AddDirective(op_id, ttl);
audio_manager_->SetToken(AUDIBLE, instruction.token_id());
break;
default:
NOTREACHED();
}
break;
case RECEIVE:
DVLOG(2) << "Audio Receive Directive received."
<< " with medium=" << instruction.medium()
<< " with TTL=" << ttl.InMilliseconds();
switch (instruction.medium()) {
case AUDIO_ULTRASOUND_PASSBAND:
receives_list_[INAUDIBLE].AddDirective(op_id, ttl);
break;
case AUDIO_AUDIBLE_DTMF:
receives_list_[AUDIBLE].AddDirective(op_id, ttl);
break;
default:
NOTREACHED();
}
break;
case UNKNOWN_TOKEN_INSTRUCTION_TYPE:
default:
LOG(WARNING) << "Unknown Audio Transmit Directive received. type = "
<< instruction.token_instruction_type();
}
ProcessNextInstruction();
}
void AudioDirectiveHandler::RemoveInstructions(const std::string& op_id) {
transmits_list_[AUDIBLE].RemoveDirective(op_id);
transmits_list_[INAUDIBLE].RemoveDirective(op_id);
receives_list_[AUDIBLE].RemoveDirective(op_id);
receives_list_[INAUDIBLE].RemoveDirective(op_id);
ProcessNextInstruction();
}
const std::string AudioDirectiveHandler::PlayingToken(AudioType type) const {
return audio_manager_->GetToken(type);
}
// Private methods.
void AudioDirectiveHandler::ProcessNextInstruction() {
DCHECK(audio_event_timer_);
audio_event_timer_->Stop();
// Change |audio_manager_| state for audible transmits.
if (transmits_list_[AUDIBLE].GetActiveDirective())
audio_manager_->StartPlaying(AUDIBLE);
else
audio_manager_->StopPlaying(AUDIBLE);
// Change audio_manager_ state for inaudible transmits.
if (transmits_list_[INAUDIBLE].GetActiveDirective())
audio_manager_->StartPlaying(INAUDIBLE);
else
audio_manager_->StopPlaying(INAUDIBLE);
// Change audio_manager_ state for audible receives.
if (receives_list_[AUDIBLE].GetActiveDirective())
audio_manager_->StartRecording(AUDIBLE);
else
audio_manager_->StopRecording(AUDIBLE);
// Change audio_manager_ state for inaudible receives.
if (receives_list_[INAUDIBLE].GetActiveDirective())
audio_manager_->StartRecording(INAUDIBLE);
else
audio_manager_->StopRecording(INAUDIBLE);
base::TimeTicks next_event_time;
if (GetNextInstructionExpiry(&next_event_time)) {
audio_event_timer_->Start(
FROM_HERE,
next_event_time - clock_->NowTicks(),
base::Bind(&AudioDirectiveHandler::ProcessNextInstruction,
base::Unretained(this)));
}
}
bool AudioDirectiveHandler::GetNextInstructionExpiry(base::TimeTicks* expiry) {
DCHECK(expiry);
*expiry = GetEarliestEventTime(&transmits_list_[AUDIBLE], base::TimeTicks());
*expiry = GetEarliestEventTime(&transmits_list_[INAUDIBLE], *expiry);
*expiry = GetEarliestEventTime(&receives_list_[AUDIBLE], *expiry);
*expiry = GetEarliestEventTime(&receives_list_[INAUDIBLE], *expiry);
return !expiry->is_null();
}
} // namespace copresence