blob: 45eaa259e14e32ea854fec683c8f816499426d68 [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 "base/bind.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.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 "testing/gtest/include/gtest/gtest.h"
namespace copresence {
class AudioManagerStub final : public AudioManager {
public:
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:
// Indexed using enum AudioType.
bool playing_[2];
bool recording_[2];
DISALLOW_COPY_AND_ASSIGN(AudioManagerStub);
};
class AudioDirectiveHandlerTest : public testing::Test {
public:
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());
}
~AudioDirectiveHandlerTest() override {}
protected:
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;
}
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);
};
TEST_F(AudioDirectiveHandlerTest, Basic) {
const base::TimeDelta kTtl = base::TimeDelta::FromMilliseconds(9999);
directive_handler_->AddInstruction(
CreateTransmitInstruction("token", true), "op_id1", kTtl);
directive_handler_->AddInstruction(
CreateTransmitInstruction("token", false), "op_id1", kTtl);
directive_handler_->AddInstruction(
CreateTransmitInstruction("token", false), "op_id2", kTtl);
directive_handler_->AddInstruction(
CreateReceiveInstruction(false), "op_id1", kTtl);
directive_handler_->AddInstruction(
CreateReceiveInstruction(true), "op_id2", kTtl);
directive_handler_->AddInstruction(
CreateReceiveInstruction(false), "op_id3", kTtl);
EXPECT_TRUE(IsPlaying(AUDIBLE));
EXPECT_TRUE(IsPlaying(INAUDIBLE));
EXPECT_TRUE(IsRecording(AUDIBLE));
EXPECT_TRUE(IsRecording(INAUDIBLE));
directive_handler_->RemoveInstructions("op_id1");
EXPECT_FALSE(IsPlaying(AUDIBLE));
EXPECT_TRUE(IsPlaying(INAUDIBLE));
EXPECT_TRUE(IsRecording(AUDIBLE));
EXPECT_TRUE(IsRecording(INAUDIBLE));
directive_handler_->RemoveInstructions("op_id2");
EXPECT_FALSE(IsPlaying(INAUDIBLE));
EXPECT_FALSE(IsRecording(AUDIBLE));
EXPECT_TRUE(IsRecording(INAUDIBLE));
directive_handler_->RemoveInstructions("op_id3");
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
// transmits/receives.
} // namespace copresence