// 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/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
-#include "components/copresence/mediums/audio/audio_player.h"
-#include "components/copresence/mediums/audio/audio_recorder.h"
+#include "base/test/simple_test_tick_clock.h"
+#include "base/timer/mock_timer.h"
+#include "components/copresence/handlers/audio/audio_directive_handler_impl.h"
+#include "components/copresence/handlers/audio/tick_clock_ref_counted.h"
+#include "components/copresence/mediums/audio/audio_manager.h"
+#include "components/copresence/proto/data.pb.h"
#include "components/copresence/test/audio_test_support.h"
-#include "media/base/audio_bus.h"
-#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-using ::testing::_;
-using ::testing::Le;
-
namespace copresence {
-class TestAudioPlayer : public AudioPlayer {
+class AudioManagerStub final : public AudioManager {
public:
- TestAudioPlayer() {}
- virtual ~TestAudioPlayer() {}
-
- // AudioPlayer overrides:
- virtual void Initialize() OVERRIDE {}
- virtual void Play(
- const scoped_refptr<media::AudioBusRefCounted>& /* samples */) OVERRIDE {
- set_is_playing(true);
- }
- virtual void Stop() OVERRIDE { set_is_playing(false); }
- virtual void Finalize() OVERRIDE { delete this; }
+ AudioManagerStub() {}
+ ~AudioManagerStub() override {}
+
+ // AudioManager overrides:
+ void Initialize(WhispernetClient* whispernet_client,
+ const TokensCallback& tokens_cb) override {}
+ void StartPlaying(AudioType type) override { playing_[type] = true; }
+ void StopPlaying(AudioType type) override { playing_[type] = false; }
+ void StartRecording(AudioType type) override { recording_[type] = true; }
+ void StopRecording(AudioType type) override { recording_[type] = false; }
+ void SetToken(AudioType type, const std::string& url_unsafe_token) override {}
+ const std::string GetToken(AudioType type) override { return std::string(); }
+ bool IsRecording(AudioType type) override { return recording_[type]; }
+ bool IsPlaying(AudioType type) override { return playing_[type]; }
+ bool IsPlayingTokenHeard(AudioType type) override { return false; }
private:
- DISALLOW_COPY_AND_ASSIGN(TestAudioPlayer);
-};
+ // Indexed using enum AudioType.
+ bool playing_[2];
+ bool recording_[2];
-class TestAudioRecorder : public AudioRecorder {
- public:
- TestAudioRecorder() : AudioRecorder(AudioRecorder::DecodeSamplesCallback()) {}
- virtual ~TestAudioRecorder() {}
-
- // AudioRecorder overrides:
- virtual void Initialize() OVERRIDE {}
- virtual void Record() OVERRIDE { set_is_recording(true); }
- virtual void Stop() OVERRIDE { set_is_recording(false); }
- virtual void Finalize() OVERRIDE { delete this; }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestAudioRecorder);
+ DISALLOW_COPY_AND_ASSIGN(AudioManagerStub);
};
class AudioDirectiveHandlerTest : public testing::Test {
public:
- AudioDirectiveHandlerTest()
- : directive_handler_(new AudioDirectiveHandler(
- AudioRecorder::DecodeSamplesCallback(),
- base::Bind(&AudioDirectiveHandlerTest::EncodeToken,
- base::Unretained(this)))) {
- directive_handler_->set_player_audible_for_testing(new TestAudioPlayer());
- directive_handler_->set_player_inaudible_for_testing(new TestAudioPlayer());
- directive_handler_->set_recorder_for_testing(new TestAudioRecorder());
+ AudioDirectiveHandlerTest() {
+ manager_ptr_ = new AudioManagerStub;
+ timer_ptr_ = new base::MockTimer(false, false);
+ clock_ptr_ = new base::SimpleTestTickClock;
+
+ directive_handler_.reset(new AudioDirectiveHandlerImpl(
+ make_scoped_ptr<AudioManager>(manager_ptr_),
+ make_scoped_ptr<base::Timer>(timer_ptr_),
+ make_scoped_refptr(new TickClockRefCounted(clock_ptr_))));
+ directive_handler_->Initialize(nullptr, TokensCallback());
}
- virtual ~AudioDirectiveHandlerTest() {}
-
- void DirectiveAdded() {}
+ ~AudioDirectiveHandlerTest() override {}
protected:
- void EncodeToken(const std::string& token,
- bool audible,
- const AudioDirectiveHandler::SamplesCallback& callback) {
- callback.Run(
- token, audible, CreateRandomAudioRefCounted(0x1337, 1, 0x7331));
- }
-
- copresence::TokenInstruction CreateTransmitInstruction(
- const std::string& token,
- bool audible) {
- copresence::TokenInstruction instruction;
- instruction.set_token_instruction_type(copresence::TRANSMIT);
+ TokenInstruction CreateTransmitInstruction(const std::string& token,
+ bool audible) {
+ TokenInstruction instruction;
+ instruction.set_token_instruction_type(TRANSMIT);
instruction.set_token_id(token);
instruction.set_medium(audible ? AUDIO_AUDIBLE_DTMF
: AUDIO_ULTRASOUND_PASSBAND);
return instruction;
}
- copresence::TokenInstruction CreateReceiveInstruction() {
- copresence::TokenInstruction instruction;
- instruction.set_token_instruction_type(copresence::RECEIVE);
+ TokenInstruction CreateReceiveInstruction(bool audible) {
+ TokenInstruction instruction;
+ instruction.set_token_instruction_type(RECEIVE);
+ instruction.set_medium(audible ? AUDIO_AUDIBLE_DTMF
+ : AUDIO_ULTRASOUND_PASSBAND);
return instruction;
}
+ bool IsPlaying(AudioType type) { return manager_ptr_->IsPlaying(type); }
+
+ bool IsRecording(AudioType type) { return manager_ptr_->IsRecording(type); }
+
// This order is important. We want the message loop to get created before
// our the audio directive handler since the directive list ctor (invoked
// from the directive handler ctor) will post tasks.
base::MessageLoop message_loop_;
scoped_ptr<AudioDirectiveHandler> directive_handler_;
+ // Unowned.
+ AudioManagerStub* manager_ptr_;
+ base::MockTimer* timer_ptr_;
+ base::SimpleTestTickClock* clock_ptr_;
+
private:
DISALLOW_COPY_AND_ASSIGN(AudioDirectiveHandlerTest);
};
directive_handler_->AddInstruction(
CreateTransmitInstruction("token", false), "op_id2", kTtl);
directive_handler_->AddInstruction(
- CreateReceiveInstruction(), "op_id1", kTtl);
+ CreateReceiveInstruction(false), "op_id1", kTtl);
directive_handler_->AddInstruction(
- CreateReceiveInstruction(), "op_id2", kTtl);
+ CreateReceiveInstruction(true), "op_id2", kTtl);
directive_handler_->AddInstruction(
- CreateReceiveInstruction(), "op_id3", kTtl);
+ CreateReceiveInstruction(false), "op_id3", kTtl);
- EXPECT_EQ(true, directive_handler_->player_audible_->IsPlaying());
- EXPECT_EQ(true, directive_handler_->player_inaudible_->IsPlaying());
- EXPECT_EQ(true, directive_handler_->recorder_->IsRecording());
+ EXPECT_TRUE(IsPlaying(AUDIBLE));
+ EXPECT_TRUE(IsPlaying(INAUDIBLE));
+ EXPECT_TRUE(IsRecording(AUDIBLE));
+ EXPECT_TRUE(IsRecording(INAUDIBLE));
directive_handler_->RemoveInstructions("op_id1");
- EXPECT_FALSE(directive_handler_->player_audible_->IsPlaying());
- EXPECT_EQ(true, directive_handler_->player_inaudible_->IsPlaying());
- EXPECT_EQ(true, directive_handler_->recorder_->IsRecording());
+ EXPECT_FALSE(IsPlaying(AUDIBLE));
+ EXPECT_TRUE(IsPlaying(INAUDIBLE));
+ EXPECT_TRUE(IsRecording(AUDIBLE));
+ EXPECT_TRUE(IsRecording(INAUDIBLE));
directive_handler_->RemoveInstructions("op_id2");
- EXPECT_FALSE(directive_handler_->player_inaudible_->IsPlaying());
- EXPECT_EQ(true, directive_handler_->recorder_->IsRecording());
+ EXPECT_FALSE(IsPlaying(INAUDIBLE));
+ EXPECT_FALSE(IsRecording(AUDIBLE));
+ EXPECT_TRUE(IsRecording(INAUDIBLE));
directive_handler_->RemoveInstructions("op_id3");
- EXPECT_FALSE(directive_handler_->recorder_->IsRecording());
+ EXPECT_FALSE(IsRecording(INAUDIBLE));
+}
+
+TEST_F(AudioDirectiveHandlerTest, Timed) {
+ const base::TimeDelta kTtl1 = base::TimeDelta::FromMilliseconds(1337);
+ directive_handler_->AddInstruction(
+ CreateTransmitInstruction("token", true), "op_id1", kTtl1);
+
+ const base::TimeDelta kTtl2 = base::TimeDelta::FromMilliseconds(1338);
+ directive_handler_->AddInstruction(
+ CreateTransmitInstruction("token", false), "op_id1", kTtl2);
+
+ const base::TimeDelta kTtl3 = base::TimeDelta::FromMilliseconds(1336);
+ directive_handler_->AddInstruction(
+ CreateReceiveInstruction(false), "op_id3", kTtl3);
+ EXPECT_TRUE(IsPlaying(AUDIBLE));
+ EXPECT_TRUE(IsPlaying(INAUDIBLE));
+ EXPECT_FALSE(IsRecording(AUDIBLE));
+ EXPECT_TRUE(IsRecording(INAUDIBLE));
+
+ // We *have* to call an operation on the directive handler after we advance
+ // time to trigger the next set of operations, so ensure that after calling
+ // advance, we are also calling another operation.
+ clock_ptr_->Advance(kTtl3 + base::TimeDelta::FromMilliseconds(1));
+
+ // We are now at base + 1337ms.
+ // This instruction expires at base + (1337 + 1337 = 2674)
+ directive_handler_->AddInstruction(
+ CreateReceiveInstruction(true), "op_id4", kTtl1);
+ EXPECT_TRUE(IsPlaying(AUDIBLE));
+ EXPECT_TRUE(IsPlaying(INAUDIBLE));
+ EXPECT_TRUE(IsRecording(AUDIBLE));
+ EXPECT_FALSE(IsRecording(INAUDIBLE));
+
+ clock_ptr_->Advance(base::TimeDelta::FromMilliseconds(1));
+
+ // We are now at base + 1338ms.
+ timer_ptr_->Fire();
+ EXPECT_FALSE(IsPlaying(AUDIBLE));
+ EXPECT_TRUE(IsPlaying(INAUDIBLE));
+ EXPECT_TRUE(IsRecording(AUDIBLE));
+
+ clock_ptr_->Advance(base::TimeDelta::FromMilliseconds(1));
+
+ // We are now at base + 1339ms.
+ timer_ptr_->Fire();
+ EXPECT_FALSE(IsPlaying(INAUDIBLE));
+ EXPECT_TRUE(IsRecording(AUDIBLE));
+
+ clock_ptr_->Advance(kTtl3);
+
+ // We are now at base + 2676ms.
+ timer_ptr_->Fire();
+ EXPECT_FALSE(IsRecording(AUDIBLE));
}
// TODO(rkc): Write more tests that check more convoluted sequences of