| Index: components/copresence/handlers/audio/audio_directive_handler.cc
|
| diff --git a/components/copresence/handlers/audio/audio_directive_handler.cc b/components/copresence/handlers/audio/audio_directive_handler.cc
|
| index 3d2e7c65aac69b8150c564c92550d5f20a486639..04bd9822ac8a392a21c9353d6b8104065234e303 100644
|
| --- a/components/copresence/handlers/audio/audio_directive_handler.cc
|
| +++ b/components/copresence/handlers/audio/audio_directive_handler.cc
|
| @@ -7,67 +7,27 @@
|
| #include "base/bind.h"
|
| #include "base/logging.h"
|
| #include "base/memory/scoped_ptr.h"
|
| -#include "base/strings/string_util.h"
|
| #include "base/time/time.h"
|
| -#include "components/copresence/mediums/audio/audio_player.h"
|
| -#include "components/copresence/mediums/audio/audio_recorder.h"
|
| #include "components/copresence/proto/data.pb.h"
|
| +#include "components/copresence/public/copresence_constants.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.
|
|
|
| -AudioDirectiveHandler::AudioDirectiveHandler(
|
| - const AudioRecorder::DecodeSamplesCallback& decode_cb,
|
| - const AudioDirectiveHandler::EncodeTokenCallback& encode_cb)
|
| - : player_audible_(NULL),
|
| - player_inaudible_(NULL),
|
| - recorder_(NULL),
|
| - decode_cb_(decode_cb),
|
| - encode_cb_(encode_cb),
|
| - samples_cache_audible_(
|
| - base::TimeDelta::FromMilliseconds(kSampleExpiryTimeMs),
|
| - kMaxSamples),
|
| - samples_cache_inaudible_(
|
| - base::TimeDelta::FromMilliseconds(kSampleExpiryTimeMs),
|
| - kMaxSamples) {
|
| +AudioDirectiveHandler::AudioDirectiveHandler()
|
| + : audio_manager_(make_scoped_ptr<AudioManager>(NULL)) {
|
| }
|
|
|
| AudioDirectiveHandler::~AudioDirectiveHandler() {
|
| - if (player_audible_)
|
| - player_audible_->Finalize();
|
| - if (player_inaudible_)
|
| - player_inaudible_->Finalize();
|
| - if (recorder_)
|
| - recorder_->Finalize();
|
| }
|
|
|
| -void AudioDirectiveHandler::Initialize() {
|
| - player_audible_ = new AudioPlayer();
|
| - player_audible_->Initialize();
|
| -
|
| - player_inaudible_ = new AudioPlayer();
|
| - player_inaudible_->Initialize();
|
| -
|
| - recorder_ = new AudioRecorder(decode_cb_);
|
| - recorder_->Initialize();
|
| +void AudioDirectiveHandler::Initialize(
|
| + const AudioManager::DecodeSamplesCallback& decode_cb,
|
| + const AudioManager::EncodeTokenCallback& encode_cb) {
|
| + audio_manager_ = make_scoped_ptr(new AudioManager());
|
| + audio_manager_->Initialize(decode_cb, encode_cb);
|
| }
|
|
|
| void AudioDirectiveHandler::AddInstruction(const TokenInstruction& instruction,
|
| @@ -77,144 +37,124 @@ void AudioDirectiveHandler::AddInstruction(const TokenInstruction& instruction,
|
| 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);
|
| - PlayToken(instruction.token_id(), false);
|
| + 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);
|
| - PlayToken(instruction.token_id(), true);
|
| + 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. TTL="
|
| - << ttl.InMilliseconds();
|
| - receives_list_.AddDirective(op_id, ttl);
|
| - ProcessNextReceive();
|
| + 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.";
|
| + 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_.RemoveDirective(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);
|
|
|
| - ProcessNextTransmit();
|
| - ProcessNextReceive();
|
| + ProcessNextInstruction();
|
| }
|
|
|
| // Private methods.
|
|
|
| -void AudioDirectiveHandler::ProcessNextTransmit() {
|
| - // If we have an active directive for audible or inaudible audio, ensure that
|
| - // we are playing our respective token; if we do not have a directive, then
|
| - // make sure we aren't playing. This is duplicate code, but for just two
|
| - // elements, it has hard to make a case for processing a loop instead.
|
| -
|
| - scoped_ptr<AudioDirective> audible_transmit(
|
| - transmits_list_audible_.GetActiveDirective());
|
| - if (audible_transmit && !player_audible_->IsPlaying() &&
|
| - samples_cache_audible_.HasKey(current_token_audible_)) {
|
| - DVLOG(3) << "Playing audible for op_id: " << audible_transmit->op_id;
|
| - player_audible_->Play(
|
| - samples_cache_audible_.GetValue(current_token_audible_));
|
| - stop_audible_playback_timer_.Start(
|
| - FROM_HERE,
|
| - audible_transmit->end_time - base::Time::Now(),
|
| - this,
|
| - &AudioDirectiveHandler::ProcessNextTransmit);
|
| - } else if (!audible_transmit && player_audible_->IsPlaying()) {
|
| - DVLOG(3) << "Stopping audible playback.";
|
| - current_token_audible_.clear();
|
| - stop_audible_playback_timer_.Stop();
|
| - player_audible_->Stop();
|
| - }
|
| +void AudioDirectiveHandler::ProcessNextInstruction() {
|
| + if (audio_event_timer_.IsRunning())
|
| + audio_event_timer_.Stop();
|
|
|
| - scoped_ptr<AudioDirective> inaudible_transmit(
|
| - transmits_list_inaudible_.GetActiveDirective());
|
| - if (inaudible_transmit && !player_inaudible_->IsPlaying() &&
|
| - samples_cache_inaudible_.HasKey(current_token_inaudible_)) {
|
| - DVLOG(3) << "Playing inaudible for op_id: " << inaudible_transmit->op_id;
|
| - player_inaudible_->Play(
|
| - samples_cache_inaudible_.GetValue(current_token_inaudible_));
|
| - stop_inaudible_playback_timer_.Start(
|
| - FROM_HERE,
|
| - inaudible_transmit->end_time - base::Time::Now(),
|
| - this,
|
| - &AudioDirectiveHandler::ProcessNextTransmit);
|
| - } else if (!inaudible_transmit && player_inaudible_->IsPlaying()) {
|
| - DVLOG(3) << "Stopping inaudible playback.";
|
| - current_token_inaudible_.clear();
|
| - stop_inaudible_playback_timer_.Stop();
|
| - player_inaudible_->Stop();
|
| + // Change audio_manager_ state for audible transmits.
|
| + if (transmits_list_[AUDIBLE].GetActiveDirective()) {
|
| + audio_manager_->StartPlaying(AUDIBLE);
|
| + } else {
|
| + audio_manager_->StopPlaying(AUDIBLE);
|
| }
|
| -}
|
|
|
| -void AudioDirectiveHandler::ProcessNextReceive() {
|
| - scoped_ptr<AudioDirective> receive(receives_list_.GetActiveDirective());
|
| -
|
| - if (receive && !recorder_->IsRecording()) {
|
| - DVLOG(3) << "Recording for op_id: " << receive->op_id;
|
| - recorder_->Record();
|
| - stop_recording_timer_.Start(FROM_HERE,
|
| - receive->end_time - base::Time::Now(),
|
| - this,
|
| - &AudioDirectiveHandler::ProcessNextReceive);
|
| - } else if (!receive && recorder_->IsRecording()) {
|
| - DVLOG(3) << "Stopping Recording";
|
| - stop_recording_timer_.Stop();
|
| - recorder_->Stop();
|
| + // Change audio_manager_ state for inaudible transmits.
|
| + if (transmits_list_[INAUDIBLE].GetActiveDirective()) {
|
| + audio_manager_->StartPlaying(INAUDIBLE);
|
| + } else {
|
| + audio_manager_->StopPlaying(INAUDIBLE);
|
| }
|
| -}
|
|
|
| -void AudioDirectiveHandler::PlayToken(const std::string token, bool audible) {
|
| - std::string valid_token = FromUrlSafe(token);
|
| + // Change audio_manager_ state for audible receives.
|
| + if (receives_list_[AUDIBLE].GetActiveDirective()) {
|
| + audio_manager_->StartRecording(AUDIBLE);
|
| + } else {
|
| + audio_manager_->StopRecording(AUDIBLE);
|
| + }
|
|
|
| - // If the token has been encoded already, use the cached samples.
|
| - if (audible && samples_cache_audible_.HasKey(valid_token)) {
|
| - current_token_audible_ = token;
|
| - ProcessNextTransmit();
|
| - } else if (!audible && samples_cache_inaudible_.HasKey(valid_token)) {
|
| - current_token_inaudible_ = token;
|
| - ProcessNextTransmit();
|
| + // Change audio_manager_ state for inaudible receives.
|
| + if (receives_list_[INAUDIBLE].GetActiveDirective()) {
|
| + audio_manager_->StartRecording(INAUDIBLE);
|
| } else {
|
| - // Otherwise, encode the token and then play it.
|
| - encode_cb_.Run(valid_token,
|
| - audible,
|
| - base::Bind(&AudioDirectiveHandler::PlayEncodedToken,
|
| - base::Unretained(this)));
|
| + audio_manager_->StopRecording(INAUDIBLE);
|
| + }
|
| +
|
| + base::TimeDelta next_event_time = NextInstructionExpiry();
|
| + if (next_event_time > base::TimeDelta::FromMilliseconds(0)) {
|
| + audio_event_timer_.Start(FROM_HERE,
|
| + next_event_time,
|
| + this,
|
| + &AudioDirectiveHandler::ProcessNextInstruction);
|
| }
|
| }
|
|
|
| -void AudioDirectiveHandler::PlayEncodedToken(
|
| - const std::string& token,
|
| - bool audible,
|
| - const scoped_refptr<media::AudioBusRefCounted>& samples) {
|
| - DVLOG(3) << "Token " << token << "[audible:" << audible << "] encoded.";
|
| - if (audible) {
|
| - samples_cache_audible_.Add(token, samples);
|
| - current_token_audible_ = token;
|
| - // Force process transmits to pick up the new token.
|
| - if (player_audible_->IsPlaying())
|
| - player_audible_->Stop();
|
| - } else {
|
| - samples_cache_inaudible_.Add(token, samples);
|
| - current_token_inaudible_ = token;
|
| - // Force process transmits to pick up the new token.
|
| - if (player_inaudible_->IsPlaying())
|
| - player_inaudible_->Stop();
|
| +base::TimeDelta AudioDirectiveHandler::NextInstructionExpiry() {
|
| + // We cache now, since, calling Now() twice doesn't gaurantee that the time
|
| + // will increase (it may even decrease). This ensures that if we have no
|
| + // instructions, we return back a 0 time.
|
| + base::Time now = base::Time::Now();
|
| +
|
| + base::Time closest_event_time = now;
|
| + if (transmits_list_[AUDIBLE].GetActiveDirective()) {
|
| + closest_event_time =
|
| + transmits_list_[AUDIBLE].GetActiveDirective()->end_time;
|
| + }
|
| + if (transmits_list_[INAUDIBLE].GetActiveDirective()) {
|
| + closest_event_time =
|
| + std::min(transmits_list_[INAUDIBLE].GetActiveDirective()->end_time,
|
| + closest_event_time);
|
| + }
|
| + if (receives_list_[AUDIBLE].GetActiveDirective()) {
|
| + closest_event_time =
|
| + std::min(receives_list_[AUDIBLE].GetActiveDirective()->end_time,
|
| + closest_event_time);
|
| + }
|
| + if (receives_list_[INAUDIBLE].GetActiveDirective()) {
|
| + closest_event_time =
|
| + std::min(receives_list_[INAUDIBLE].GetActiveDirective()->end_time,
|
| + closest_event_time);
|
| }
|
|
|
| - ProcessNextTransmit();
|
| + return closest_event_time - now;
|
| }
|
|
|
| } // namespace copresence
|
|
|