1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "remoting/host/linux/audio_pipe_reader.h" 6 7#include <sys/types.h> 8#include <sys/stat.h> 9#include <unistd.h> 10 11#include "base/files/file.h" 12#include "base/files/scoped_temp_dir.h" 13#include "base/message_loop/message_loop.h" 14#include "base/run_loop.h" 15#include "base/threading/thread.h" 16#include "base/time/time.h" 17#include "testing/gtest/include/gtest/gtest.h" 18 19namespace remoting { 20 21class AudioPipeReaderTest : public testing::Test, 22 public AudioPipeReader::StreamObserver { 23 public: 24 AudioPipeReaderTest() 25 : stop_at_position_(-1) { 26 } 27 28 virtual void SetUp() OVERRIDE { 29 ASSERT_TRUE(test_dir_.CreateUniqueTempDir()); 30 pipe_path_ = test_dir_.path().AppendASCII("test_pipe"); 31 audio_thread_.reset(new base::Thread("TestAudioThread")); 32 audio_thread_->StartWithOptions( 33 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); 34 reader_ = AudioPipeReader::Create(audio_thread_->message_loop_proxy(), 35 pipe_path_); 36 reader_->AddObserver(this); 37 } 38 39 // AudioPipeReader::StreamObserver interface. 40 virtual void OnDataRead(scoped_refptr<base::RefCountedString> data) OVERRIDE { 41 read_data_ += data->data(); 42 if (stop_at_position_ > 0 && 43 static_cast<int>(read_data_.size()) >= stop_at_position_) { 44 stop_at_position_ = -1; 45 run_loop_->Quit(); 46 } 47 } 48 49 void CreatePipe() { 50 ASSERT_EQ(0, mkfifo(pipe_path_.value().c_str(), 0600)); 51 output_.reset(new base::File( 52 pipe_path_, base::File::FLAG_OPEN | base::File::FLAG_WRITE)); 53 ASSERT_TRUE(output_->IsValid()); 54 } 55 56 void DeletePipe() { 57 output_.reset(); 58 ASSERT_EQ(0, unlink(pipe_path_.value().c_str())); 59 } 60 61 void WaitForInput(int num_bytes) { 62 run_loop_.reset(new base::RunLoop()); 63 stop_at_position_ = read_data_.size() + num_bytes; 64 run_loop_->Run(); 65 } 66 67 void WriteAndWait(const std::string& data) { 68 ASSERT_EQ(static_cast<int>(data.size()), 69 output_->WriteAtCurrentPos(data.data(), data.size())); 70 WaitForInput(data.size()); 71 } 72 73 protected: 74 base::MessageLoop message_loop_; 75 scoped_ptr<base::RunLoop> run_loop_; 76 scoped_ptr<base::Thread> audio_thread_; 77 base::ScopedTempDir test_dir_; 78 base::FilePath pipe_path_; 79 scoped_ptr<base::File> output_; 80 81 scoped_refptr<AudioPipeReader> reader_; 82 83 std::string read_data_; 84 int stop_at_position_; 85 86 DISALLOW_COPY_AND_ASSIGN(AudioPipeReaderTest); 87}; 88 89// Verify that the reader can detect when the pipe is created and destroyed. 90TEST_F(AudioPipeReaderTest, CreateAndDestroyPipe) { 91 ASSERT_NO_FATAL_FAILURE(CreatePipe()); 92 ASSERT_NO_FATAL_FAILURE(WriteAndWait("ABCD")); 93 ASSERT_NO_FATAL_FAILURE(DeletePipe()); 94 95 ASSERT_NO_FATAL_FAILURE(CreatePipe()); 96 ASSERT_NO_FATAL_FAILURE(WriteAndWait("abcd")); 97 ASSERT_NO_FATAL_FAILURE(DeletePipe()); 98 99 EXPECT_EQ("ABCDabcd", read_data_); 100} 101 102// Verifies that the reader reads at the right speed. 103TEST_F(AudioPipeReaderTest, Pacing) { 104 int test_data_size = AudioPipeReader::kSamplingRate * 105 AudioPipeReader::kChannels * 106 AudioPipeReader::kBytesPerSample / 2; 107 std::string test_data(test_data_size, '\0'); 108 109 ASSERT_NO_FATAL_FAILURE(CreatePipe()); 110 111 base::TimeTicks start_time = base::TimeTicks::Now(); 112 ASSERT_NO_FATAL_FAILURE(WriteAndWait(test_data)); 113 base::TimeDelta time_passed = base::TimeTicks::Now() - start_time; 114 115 EXPECT_EQ(test_data, read_data_); 116 EXPECT_GE(time_passed, base::TimeDelta::FromMilliseconds(500)); 117} 118 119} // namespace remoting 120