// 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 "remoting/host/linux/audio_pipe_reader.h" #include #include #include #include "base/files/file.h" #include "base/files/scoped_temp_dir.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/threading/thread.h" #include "base/time/time.h" #include "testing/gtest/include/gtest/gtest.h" namespace remoting { class AudioPipeReaderTest : public testing::Test, public AudioPipeReader::StreamObserver { public: AudioPipeReaderTest() : stop_at_position_(-1) { } virtual void SetUp() OVERRIDE { ASSERT_TRUE(test_dir_.CreateUniqueTempDir()); pipe_path_ = test_dir_.path().AppendASCII("test_pipe"); audio_thread_.reset(new base::Thread("TestAudioThread")); audio_thread_->StartWithOptions( base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); reader_ = AudioPipeReader::Create(audio_thread_->message_loop_proxy(), pipe_path_); reader_->AddObserver(this); } // AudioPipeReader::StreamObserver interface. virtual void OnDataRead(scoped_refptr data) OVERRIDE { read_data_ += data->data(); if (stop_at_position_ > 0 && static_cast(read_data_.size()) >= stop_at_position_) { stop_at_position_ = -1; run_loop_->Quit(); } } void CreatePipe() { ASSERT_EQ(0, mkfifo(pipe_path_.value().c_str(), 0600)); output_.reset(new base::File( pipe_path_, base::File::FLAG_OPEN | base::File::FLAG_WRITE)); ASSERT_TRUE(output_->IsValid()); } void DeletePipe() { output_.reset(); ASSERT_EQ(0, unlink(pipe_path_.value().c_str())); } void WaitForInput(int num_bytes) { run_loop_.reset(new base::RunLoop()); stop_at_position_ = read_data_.size() + num_bytes; run_loop_->Run(); } void WriteAndWait(const std::string& data) { ASSERT_EQ(static_cast(data.size()), output_->WriteAtCurrentPos(data.data(), data.size())); WaitForInput(data.size()); } protected: base::MessageLoop message_loop_; scoped_ptr run_loop_; scoped_ptr audio_thread_; base::ScopedTempDir test_dir_; base::FilePath pipe_path_; scoped_ptr output_; scoped_refptr reader_; std::string read_data_; int stop_at_position_; DISALLOW_COPY_AND_ASSIGN(AudioPipeReaderTest); }; // Verify that the reader can detect when the pipe is created and destroyed. TEST_F(AudioPipeReaderTest, CreateAndDestroyPipe) { ASSERT_NO_FATAL_FAILURE(CreatePipe()); ASSERT_NO_FATAL_FAILURE(WriteAndWait("ABCD")); ASSERT_NO_FATAL_FAILURE(DeletePipe()); ASSERT_NO_FATAL_FAILURE(CreatePipe()); ASSERT_NO_FATAL_FAILURE(WriteAndWait("abcd")); ASSERT_NO_FATAL_FAILURE(DeletePipe()); EXPECT_EQ("ABCDabcd", read_data_); } // Verifies that the reader reads at the right speed. TEST_F(AudioPipeReaderTest, Pacing) { int test_data_size = AudioPipeReader::kSamplingRate * AudioPipeReader::kChannels * AudioPipeReader::kBytesPerSample / 2; std::string test_data(test_data_size, '\0'); ASSERT_NO_FATAL_FAILURE(CreatePipe()); base::TimeTicks start_time = base::TimeTicks::Now(); ASSERT_NO_FATAL_FAILURE(WriteAndWait(test_data)); base::TimeDelta time_passed = base::TimeTicks::Now() - start_time; EXPECT_EQ(test_data, read_data_); EXPECT_GE(time_passed, base::TimeDelta::FromMilliseconds(500)); } } // namespace remoting