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 a5d3435c3c4864d71e83ef20d4416dccba1514cd..fcf1d8247c66c93a3cbe08e8d489b61f02eeba92 100644 |
--- a/components/copresence/handlers/audio/audio_directive_handler.cc |
+++ b/components/copresence/handlers/audio/audio_directive_handler.cc |
@@ -4,70 +4,88 @@ |
#include "components/copresence/handlers/audio/audio_directive_handler.h" |
-#include <algorithm> |
- |
#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 "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 AudioDirectiveList::EncodeTokenCallback& encode_cb) |
- : directive_list_inaudible_( |
- encode_cb, |
- base::Bind(&AudioDirectiveHandler::ExecuteNextTransmit, |
- base::Unretained(this)), |
- false), |
- directive_list_audible_( |
- encode_cb, |
- base::Bind(&AudioDirectiveHandler::ExecuteNextTransmit, |
- base::Unretained(this)), |
- true), |
- player_(NULL), |
+ const AudioDirectiveHandler::EncodeTokenCallback& encode_cb) |
+ : player_audible_(NULL), |
+ player_inaudible_(NULL), |
recorder_(NULL), |
- decode_cb_(decode_cb) { |
+ 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() { |
- if (player_) |
- player_->Finalize(); |
+ if (player_audible_) |
+ player_audible_->Finalize(); |
+ if (player_inaudible_) |
+ player_inaudible_->Finalize(); |
if (recorder_) |
recorder_->Finalize(); |
} |
void AudioDirectiveHandler::Initialize() { |
- player_ = new AudioPlayer(); |
- player_->Initialize(); |
+ player_audible_ = new AudioPlayer(); |
+ player_audible_->Initialize(); |
+ |
+ player_inaudible_ = new AudioPlayer(); |
+ player_inaudible_->Initialize(); |
recorder_ = new AudioRecorder(decode_cb_); |
recorder_->Initialize(); |
} |
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 TTL=" << ttl.InMilliseconds(); |
- // TODO(rkc): Fill in the op_id once we get it from the directive. |
switch (instruction.medium()) { |
case AUDIO_ULTRASOUND_PASSBAND: |
- directive_list_inaudible_.AddTransmitDirective( |
- instruction.token_id(), std::string(), ttl); |
+ transmits_list_inaudible_.AddDirective(op_id, ttl); |
+ HandleToken(instruction.token_id(), false); |
break; |
case AUDIO_AUDIBLE_DTMF: |
- directive_list_audible_.AddTransmitDirective( |
- instruction.token_id(), std::string(), ttl); |
+ transmits_list_audible_.AddDirective(op_id, ttl); |
+ HandleToken(instruction.token_id(), true); |
break; |
default: |
NOTREACHED(); |
@@ -76,88 +94,128 @@ void AudioDirectiveHandler::AddInstruction(const TokenInstruction& instruction, |
case RECEIVE: |
DVLOG(2) << "Audio Receive Directive received. TTL=" |
<< ttl.InMilliseconds(); |
- // TODO(rkc): Fill in the op_id once we get it from the directive. |
- switch (instruction.medium()) { |
- case AUDIO_ULTRASOUND_PASSBAND: |
- directive_list_inaudible_.AddReceiveDirective(std::string(), ttl); |
- break; |
- case AUDIO_AUDIBLE_DTMF: |
- directive_list_audible_.AddReceiveDirective(std::string(), ttl); |
- break; |
- default: |
- NOTREACHED(); |
- } |
+ receives_list_.AddDirective(op_id, ttl); |
break; |
case UNKNOWN_TOKEN_INSTRUCTION_TYPE: |
default: |
LOG(WARNING) << "Unknown Audio Transmit Directive received."; |
} |
// ExecuteNextTransmit will be called by directive_list_ when Add is done. |
- ExecuteNextReceive(); |
+ ProcessNextReceive(); |
} |
-// Protected methods. |
- |
-void AudioDirectiveHandler::PlayAudio( |
- const scoped_refptr<media::AudioBusRefCounted>& samples, |
- base::TimeDelta duration) { |
- player_->Play(samples); |
- stop_playback_timer_.Start( |
- FROM_HERE, duration, this, &AudioDirectiveHandler::StopPlayback); |
-} |
+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); |
-void AudioDirectiveHandler::RecordAudio(base::TimeDelta duration) { |
- recorder_->Record(); |
- stop_recording_timer_.Start( |
- FROM_HERE, duration, this, &AudioDirectiveHandler::StopRecording); |
+ ProcessNextTransmit(); |
+ ProcessNextReceive(); |
} |
// Private methods. |
-void AudioDirectiveHandler::StopPlayback() { |
- player_->Stop(); |
- DVLOG(2) << "Done playing audio."; |
- ExecuteNextTransmit(); |
+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()) { |
+ 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(); |
+ } |
+ |
+ scoped_ptr<AudioDirective> inaudible_transmit( |
+ transmits_list_inaudible_.GetActiveDirective()); |
+ if (inaudible_transmit && !player_inaudible_->IsPlaying()) { |
+ 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(); |
+ } |
} |
-void AudioDirectiveHandler::StopRecording() { |
- recorder_->Stop(); |
- DVLOG(2) << "Done recording audio."; |
- ExecuteNextReceive(); |
+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(); |
+ } |
} |
-void AudioDirectiveHandler::ExecuteNextTransmit() { |
- scoped_ptr<AudioDirective> audible_transmit( |
- directive_list_audible_.GetNextTransmit()); |
- scoped_ptr<AudioDirective> inaudible_transmit( |
- directive_list_inaudible_.GetNextTransmit()); |
+void AudioDirectiveHandler::HandleToken(const std::string token, bool audible) { |
+ std::string valid_token = FromUrlSafe(token); |
- if (inaudible_transmit) { |
- PlayAudio(inaudible_transmit->samples, |
- inaudible_transmit->end_time - base::Time::Now()); |
+ if (audible && samples_cache_audible_.HasKey(valid_token)) { |
+ current_token_audible_ = token; |
+ ProcessNextTransmit(); |
+ return; |
} |
- if (audible_transmit) { |
- PlayAudio(audible_transmit->samples, |
- audible_transmit->end_time - base::Time::Now()); |
+ |
+ if (!audible && samples_cache_inaudible_.HasKey(valid_token)) { |
+ current_token_inaudible_ = token; |
+ ProcessNextTransmit(); |
+ return; |
} |
+ |
+ encode_cb_.Run(valid_token, |
+ audible, |
+ base::Bind(&AudioDirectiveHandler::OnTokenEncoded, |
+ base::Unretained(this))); |
} |
-void AudioDirectiveHandler::ExecuteNextReceive() { |
- scoped_ptr<AudioDirective> audible_receive( |
- directive_list_audible_.GetNextReceive()); |
- scoped_ptr<AudioDirective> inaudible_receive( |
- directive_list_inaudible_.GetNextReceive()); |
- |
- base::TimeDelta record_duration; |
- if (inaudible_receive) |
- record_duration = inaudible_receive->end_time - base::Time::Now(); |
- if (audible_receive) { |
- record_duration = std::max(record_duration, |
- audible_receive->end_time - base::Time::Now()); |
+void AudioDirectiveHandler::OnTokenEncoded( |
+ 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(); |
} |
- if (record_duration > base::TimeDelta::FromSeconds(0)) |
- RecordAudio(record_duration); |
+ ProcessNextTransmit(); |
} |
} // namespace copresence |