12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind_helpers.h"
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/synchronization/waitable_event.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/audio_manager.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/simple_sources.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/virtual_audio_input_stream.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/virtual_audio_output_stream.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "testing/gmock/include/gmock/gmock.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using ::testing::_;
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace media {
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const AudioParameters kParams(
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_MONO, 8000, 8, 128);
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class MockVirtualAudioInputStream : public VirtualAudioInputStream {
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  explicit MockVirtualAudioInputStream(
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : VirtualAudioInputStream(
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            kParams,
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            worker_task_runner,
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            base::Bind(&base::DeletePointer<VirtualAudioInputStream>)) {}
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ~MockVirtualAudioInputStream() {}
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MOCK_METHOD2(AddOutputStream, void(VirtualAudioOutputStream* stream,
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     const AudioParameters& output_params));
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MOCK_METHOD2(RemoveOutputStream, void(VirtualAudioOutputStream* stream,
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        const AudioParameters& output_params));
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(MockVirtualAudioInputStream);
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class MockAudioDeviceListener : public AudioManager::AudioDeviceListener {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MOCK_METHOD0(OnDeviceChange, void());
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class VirtualAudioOutputStreamTest : public testing::Test {
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VirtualAudioOutputStreamTest()
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : audio_thread_(new base::Thread("AudioThread")) {
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    audio_thread_->Start();
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    audio_task_runner_ = audio_thread_->message_loop_proxy();
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const scoped_refptr<base::SingleThreadTaskRunner>& audio_task_runner() const {
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return audio_task_runner_;
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void SyncWithAudioThread() {
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::WaitableEvent done(false, false);
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    audio_task_runner()->PostTask(
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(&base::WaitableEvent::Signal,
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              base::Unretained(&done)));
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    done.Wait();
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::Thread> audio_thread_;
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner_;
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(VirtualAudioOutputStreamTest);
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(VirtualAudioOutputStreamTest, StartStopStartStop) {
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const int kCycles = 3;
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MockVirtualAudioInputStream* const input_stream =
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new MockVirtualAudioInputStream(audio_task_runner());
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  audio_task_runner()->PostTask(
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::IgnoreResult(&MockVirtualAudioInputStream::Open),
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::Unretained(input_stream)));
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  VirtualAudioOutputStream* const output_stream = new VirtualAudioOutputStream(
87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kParams,
88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      input_stream,
89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      base::Bind(&base::DeletePointer<VirtualAudioOutputStream>));
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_CALL(*input_stream, AddOutputStream(output_stream, _))
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Times(kCycles);
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_CALL(*input_stream, RemoveOutputStream(output_stream, _))
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Times(kCycles);
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  audio_task_runner()->PostTask(
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(base::IgnoreResult(&VirtualAudioOutputStream::Open),
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            base::Unretained(output_stream)));
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SineWaveAudioSource source(CHANNEL_LAYOUT_STEREO, 200.0, 128);
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < kCycles; ++i) {
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    audio_task_runner()->PostTask(
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(&VirtualAudioOutputStream::Start,
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              base::Unretained(output_stream),
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              &source));
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    audio_task_runner()->PostTask(
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(&VirtualAudioOutputStream::Stop,
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              base::Unretained(output_stream)));
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  audio_task_runner()->PostTask(
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(&VirtualAudioOutputStream::Close,
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            base::Unretained(output_stream)));
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  audio_task_runner()->PostTask(
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(&MockVirtualAudioInputStream::Close,
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            base::Unretained(input_stream)));
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWithAudioThread();
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace media
121