blob: 4c82802504a70e7565d63696ad9f0f98ec9c1319 [file] [log] [blame]
// Copyright (c) 2012 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 <string>
#include "base/bind.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "content/browser/browser_thread_impl.h"
#include "content/browser/renderer_host/media/audio_input_device_manager.h"
#include "content/browser/renderer_host/media/audio_input_device_manager_event_handler.h"
#include "content/public/common/media_stream_request.h"
#include "media/audio/audio_manager_base.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using content::BrowserThread;
using content::BrowserThreadImpl;
using media_stream::AudioInputDeviceManager;
using testing::_;
using testing::InSequence;
using testing::Return;
namespace media_stream {
class MockAudioInputDeviceManagerListener
: public MediaStreamProviderListener {
public:
MockAudioInputDeviceManagerListener() {}
virtual ~MockAudioInputDeviceManagerListener() {}
MOCK_METHOD2(Opened, void(MediaStreamType, const int));
MOCK_METHOD2(Closed, void(MediaStreamType, const int));
MOCK_METHOD1(DevicesEnumerated, void(const StreamDeviceInfoArray&));
MOCK_METHOD3(Error, void(MediaStreamType, int, MediaStreamProviderError));
virtual void DevicesEnumerated(MediaStreamType service_type,
const StreamDeviceInfoArray& devices) {
if (service_type != content::MEDIA_DEVICE_AUDIO_CAPTURE)
return;
devices_ = devices;
DevicesEnumerated(devices);
}
StreamDeviceInfoArray devices_;
private:
DISALLOW_COPY_AND_ASSIGN(MockAudioInputDeviceManagerListener);
};
class MockAudioInputDeviceManagerEventHandler
: public AudioInputDeviceManagerEventHandler {
public:
explicit MockAudioInputDeviceManagerEventHandler(MessageLoop* message_loop)
: message_loop_(message_loop) {}
virtual ~MockAudioInputDeviceManagerEventHandler() {}
MOCK_METHOD2(DeviceStarted, void(int, const std::string&));
MOCK_METHOD1(DeviceStopped, void(int));
virtual void OnDeviceStarted(int session_id,
const std::string& device_id) {
message_loop_->PostTask(
FROM_HERE, base::Bind(
&MockAudioInputDeviceManagerEventHandler::DeviceStarted,
base::Unretained(this), session_id, device_id));
}
virtual void OnDeviceStopped(int session_id) {
message_loop_->PostTask(
FROM_HERE, base::Bind(
&MockAudioInputDeviceManagerEventHandler::DeviceStopped,
base::Unretained(this), session_id));
}
private:
MessageLoop* message_loop_;
DISALLOW_COPY_AND_ASSIGN(MockAudioInputDeviceManagerEventHandler);
};
class AudioInputDeviceManagerTest : public testing::Test {
public:
AudioInputDeviceManagerTest() {}
// Returns true iff machine has an audio input device.
bool CanRunAudioInputDeviceTests() {
return audio_manager_->HasAudioInputDevices();
}
protected:
virtual void SetUp() OVERRIDE {
// The test must run on Browser::IO.
message_loop_.reset(new MessageLoop(MessageLoop::TYPE_IO));
io_thread_.reset(new BrowserThreadImpl(BrowserThread::IO,
message_loop_.get()));
audio_manager_.reset(media::AudioManager::Create());
manager_ = new AudioInputDeviceManager(audio_manager_.get());
audio_input_listener_.reset(new MockAudioInputDeviceManagerListener());
manager_->Register(audio_input_listener_.get(),
message_loop_->message_loop_proxy());
// Gets the enumerated device list from the AudioInputDeviceManager.
manager_->EnumerateDevices();
EXPECT_CALL(*audio_input_listener_, DevicesEnumerated(_))
.Times(1);
// Wait until we get the list.
message_loop_->RunAllPending();
}
virtual void TearDown() OVERRIDE {
manager_->Unregister();
io_thread_.reset();
}
scoped_ptr<MessageLoop> message_loop_;
scoped_ptr<BrowserThreadImpl> io_thread_;
scoped_refptr<AudioInputDeviceManager> manager_;
scoped_ptr<MockAudioInputDeviceManagerListener> audio_input_listener_;
scoped_ptr<media::AudioManager> audio_manager_;
private:
DISALLOW_COPY_AND_ASSIGN(AudioInputDeviceManagerTest);
};
// Opens and closes the devices.
TEST_F(AudioInputDeviceManagerTest, OpenAndCloseDevice) {
if (!CanRunAudioInputDeviceTests())
return;
ASSERT_FALSE(audio_input_listener_->devices_.empty());
InSequence s;
for (StreamDeviceInfoArray::const_iterator iter =
audio_input_listener_->devices_.begin();
iter != audio_input_listener_->devices_.end(); ++iter) {
// Opens/closes the devices.
int session_id = manager_->Open(*iter);
manager_->Close(session_id);
// Expected mock call with expected return value.
EXPECT_CALL(*audio_input_listener_,
Opened(content::MEDIA_DEVICE_AUDIO_CAPTURE, session_id))
.Times(1);
EXPECT_CALL(*audio_input_listener_,
Closed(content::MEDIA_DEVICE_AUDIO_CAPTURE, session_id))
.Times(1);
// Waits for the callback.
message_loop_->RunAllPending();
}
}
// Opens multiple devices at one time and closes them later.
TEST_F(AudioInputDeviceManagerTest, OpenMultipleDevices) {
if (!CanRunAudioInputDeviceTests())
return;
ASSERT_FALSE(audio_input_listener_->devices_.empty());
InSequence s;
int index = 0;
const int kDeviceSize = audio_input_listener_->devices_.size();
scoped_array<int> session_id(new int[kDeviceSize]);
// Opens the devices in a loop.
for (StreamDeviceInfoArray::const_iterator iter =
audio_input_listener_->devices_.begin();
iter != audio_input_listener_->devices_.end(); ++iter, ++index) {
// Opens the devices.
session_id[index] = manager_->Open(*iter);
// Expected mock call with expected returned value.
EXPECT_CALL(*audio_input_listener_,
Opened(content::MEDIA_DEVICE_AUDIO_CAPTURE, session_id[index]))
.Times(1);
// Waits for the callback.
message_loop_->RunAllPending();
}
// Checks if the session_ids are unique.
for (int i = 0; i < kDeviceSize - 1; ++i) {
for (int k = i+1; k < kDeviceSize; ++k) {
EXPECT_TRUE(session_id[i] != session_id[k]);
}
}
for (int i = 0; i < kDeviceSize; ++i) {
// Closes the devices.
manager_->Close(session_id[i]);
EXPECT_CALL(*audio_input_listener_,
Closed(content::MEDIA_DEVICE_AUDIO_CAPTURE, session_id[i]))
.Times(1);
// Waits for the callback.
message_loop_->RunAllPending();
}
}
// Opens a non-existing device.
TEST_F(AudioInputDeviceManagerTest, OpenNotExistingDevice) {
if (!CanRunAudioInputDeviceTests())
return;
InSequence s;
MediaStreamType stream_type = content::MEDIA_DEVICE_AUDIO_CAPTURE;
std::string device_name("device_doesnt_exist");
std::string device_id("id_doesnt_exist");
StreamDeviceInfo dummy_device(stream_type, device_name, device_id, false);
int session_id = manager_->Open(dummy_device);
EXPECT_CALL(*audio_input_listener_,
Opened(content::MEDIA_DEVICE_AUDIO_CAPTURE, session_id))
.Times(1);
// Waits for the callback.
message_loop_->RunAllPending();
}
// Opens default device twice.
TEST_F(AudioInputDeviceManagerTest, OpenDeviceTwice) {
if (!CanRunAudioInputDeviceTests())
return;
ASSERT_FALSE(audio_input_listener_->devices_.empty());
InSequence s;
// Opens and closes the default device twice.
int first_session_id = manager_->Open(
audio_input_listener_->devices_.front());
int second_session_id = manager_->Open(
audio_input_listener_->devices_.front());
manager_->Close(first_session_id);
manager_->Close(second_session_id);
// Expected mock calls with expected returned values.
EXPECT_NE(first_session_id, second_session_id);
EXPECT_CALL(*audio_input_listener_,
Opened(content::MEDIA_DEVICE_AUDIO_CAPTURE, first_session_id))
.Times(1);
EXPECT_CALL(*audio_input_listener_,
Opened(content::MEDIA_DEVICE_AUDIO_CAPTURE, second_session_id))
.Times(1);
EXPECT_CALL(*audio_input_listener_,
Closed(content::MEDIA_DEVICE_AUDIO_CAPTURE, first_session_id))
.Times(1);
EXPECT_CALL(*audio_input_listener_,
Closed(content::MEDIA_DEVICE_AUDIO_CAPTURE, second_session_id))
.Times(1);
// Waits for the callback.
message_loop_->RunAllPending();
}
// Starts and closes the sessions after opening the devices.
TEST_F(AudioInputDeviceManagerTest, StartAndStopSession) {
if (!CanRunAudioInputDeviceTests())
return;
ASSERT_FALSE(audio_input_listener_->devices_.empty());
InSequence s;
int index = 0;
const int kDeviceSize = audio_input_listener_->devices_.size();
scoped_array<int> session_id(new int[kDeviceSize]);
// Creates the EventHandler for the sessions.
scoped_ptr<MockAudioInputDeviceManagerEventHandler>
audio_input_event_handler(
new MockAudioInputDeviceManagerEventHandler(message_loop_.get()));
// Loops through the devices and calls Open()/Start()/Stop()/Close() for
// each device.
for (StreamDeviceInfoArray::const_iterator iter =
audio_input_listener_->devices_.begin();
iter != audio_input_listener_->devices_.end(); ++iter, ++index) {
// Note that no DeviceStopped() notification for Event Handler as we have
// stopped the device before calling close.
session_id[index] = manager_->Open(*iter);
EXPECT_CALL(*audio_input_listener_,
Opened(content::MEDIA_DEVICE_AUDIO_CAPTURE, session_id[index]))
.Times(1);
message_loop_->RunAllPending();
manager_->Start(session_id[index], audio_input_event_handler.get());
EXPECT_CALL(*audio_input_event_handler,
DeviceStarted(session_id[index], iter->device_id))
.Times(1);
message_loop_->RunAllPending();
manager_->Stop(session_id[index]);
manager_->Close(session_id[index]);
EXPECT_CALL(*audio_input_listener_,
Closed(content::MEDIA_DEVICE_AUDIO_CAPTURE, session_id[index]))
.Times(1);
message_loop_->RunAllPending();
}
}
// Tests the behavior of calling Close() without calling Stop().
TEST_F(AudioInputDeviceManagerTest, CloseWithoutStopSession) {
if (!CanRunAudioInputDeviceTests())
return;
ASSERT_FALSE(audio_input_listener_->devices_.empty());
InSequence s;
int index = 0;
const int kDeviceSize = audio_input_listener_->devices_.size();
scoped_array<int> session_id(new int[kDeviceSize]);
// Creates the EventHandlers for the sessions.
scoped_ptr<MockAudioInputDeviceManagerEventHandler>
audio_input_event_handler(
new MockAudioInputDeviceManagerEventHandler(message_loop_.get()));
// Loop through the devices, and calls Open()/Start()/Close() for the devices.
// Note that we do not call stop.
for (StreamDeviceInfoArray::const_iterator iter =
audio_input_listener_->devices_.begin();
iter != audio_input_listener_->devices_.end(); ++iter, ++index) {
// Calls Open()/Start()/Close() for each device.
session_id[index] = manager_->Open(*iter);
EXPECT_CALL(*audio_input_listener_,
Opened(content::MEDIA_DEVICE_AUDIO_CAPTURE, session_id[index]))
.Times(1);
message_loop_->RunAllPending();
manager_->Start(session_id[index], audio_input_event_handler.get());
EXPECT_CALL(*audio_input_event_handler,
DeviceStarted(session_id[index], iter->device_id))
.Times(1);
message_loop_->RunAllPending();
// Event Handler should get a stop device notification as no stop is called
// before closing the device.
manager_->Close(session_id[index]);
EXPECT_CALL(*audio_input_event_handler,
DeviceStopped(session_id[index]))
.Times(1);
EXPECT_CALL(*audio_input_listener_,
Closed(content::MEDIA_DEVICE_AUDIO_CAPTURE, session_id[index]))
.Times(1);
message_loop_->RunAllPending();
}
}
// Starts the same device twice.
TEST_F(AudioInputDeviceManagerTest, StartDeviceTwice) {
if (!CanRunAudioInputDeviceTests())
return;
ASSERT_FALSE(audio_input_listener_->devices_.empty());
InSequence s;
// Create one EventHandler for each session.
scoped_ptr<MockAudioInputDeviceManagerEventHandler>
first_event_handler(
new MockAudioInputDeviceManagerEventHandler(message_loop_.get()));
scoped_ptr<MockAudioInputDeviceManagerEventHandler>
second_event_handler(
new MockAudioInputDeviceManagerEventHandler(message_loop_.get()));
// Open the default device twice.
StreamDeviceInfoArray::const_iterator iter =
audio_input_listener_->devices_.begin();
int first_session_id = manager_->Open(*iter);
int second_session_id = manager_->Open(*iter);
EXPECT_NE(first_session_id, second_session_id);
EXPECT_CALL(*audio_input_listener_,
Opened(content::MEDIA_DEVICE_AUDIO_CAPTURE, first_session_id))
.Times(1);
EXPECT_CALL(*audio_input_listener_,
Opened(content::MEDIA_DEVICE_AUDIO_CAPTURE, second_session_id))
.Times(1);
message_loop_->RunAllPending();
// Calls Start()/Stop()/Close() for the default device twice.
manager_->Start(first_session_id, first_event_handler.get());
manager_->Start(second_session_id, second_event_handler.get());
EXPECT_CALL(*first_event_handler,
DeviceStarted(first_session_id,
media::AudioManagerBase::kDefaultDeviceId))
.Times(1);
EXPECT_CALL(*second_event_handler,
DeviceStarted(second_session_id,
media::AudioManagerBase::kDefaultDeviceId))
.Times(1);
message_loop_->RunAllPending();
manager_->Stop(first_session_id);
manager_->Stop(second_session_id);
manager_->Close(first_session_id);
manager_->Close(second_session_id);
EXPECT_CALL(*audio_input_listener_,
Closed(content::MEDIA_DEVICE_AUDIO_CAPTURE, first_session_id))
.Times(1);
EXPECT_CALL(*audio_input_listener_,
Closed(content::MEDIA_DEVICE_AUDIO_CAPTURE, second_session_id))
.Times(1);
message_loop_->RunAllPending();
}
// Starts an invalid session.
TEST_F(AudioInputDeviceManagerTest, StartInvalidSession) {
if (!CanRunAudioInputDeviceTests())
return;
InSequence s;
// Creates the EventHandlers for the sessions.
scoped_ptr<MockAudioInputDeviceManagerEventHandler>
audio_input_event_handler(
new MockAudioInputDeviceManagerEventHandler(message_loop_.get()));
// Opens the first device.
StreamDeviceInfoArray::const_iterator iter =
audio_input_listener_->devices_.begin();
int session_id = manager_->Open(*iter);
EXPECT_CALL(*audio_input_listener_,
Opened(content::MEDIA_DEVICE_AUDIO_CAPTURE, session_id))
.Times(1);
message_loop_->RunAllPending();
// Starts a non-opened device.
// This should fail and trigger error code 'kDeviceNotAvailable'.
int invalid_session_id = session_id + 1;
manager_->Start(invalid_session_id, audio_input_event_handler.get());
EXPECT_CALL(*audio_input_event_handler,
DeviceStarted(invalid_session_id, std::string()))
.Times(1);
message_loop_->RunAllPending();
manager_->Close(session_id);
EXPECT_CALL(*audio_input_listener_,
Closed(content::MEDIA_DEVICE_AUDIO_CAPTURE, session_id))
.Times(1);
message_loop_->RunAllPending();
}
// Starts a session twice, the first time should succeed, while the second
// time should fail.
TEST_F(AudioInputDeviceManagerTest, StartSessionTwice) {
if (!CanRunAudioInputDeviceTests())
return;
InSequence s;
// Creates the EventHandlers for the sessions.
scoped_ptr<MockAudioInputDeviceManagerEventHandler>
audio_input_event_handler(
new MockAudioInputDeviceManagerEventHandler(message_loop_.get()));
// Opens the first device.
StreamDeviceInfoArray::const_iterator iter =
audio_input_listener_->devices_.begin();
int session_id = manager_->Open(*iter);
EXPECT_CALL(*audio_input_listener_,
Opened(content::MEDIA_DEVICE_AUDIO_CAPTURE, session_id))
.Times(1);
message_loop_->RunAllPending();
// Starts the session, it should succeed.
manager_->Start(session_id, audio_input_event_handler.get());
EXPECT_CALL(*audio_input_event_handler,
DeviceStarted(session_id,
media::AudioManagerBase::kDefaultDeviceId))
.Times(1);
message_loop_->RunAllPending();
// Starts the session for the second time, it should fail.
manager_->Start(session_id, audio_input_event_handler.get());
EXPECT_CALL(*audio_input_event_handler,
DeviceStarted(session_id, std::string()))
.Times(1);
manager_->Stop(session_id);
manager_->Close(session_id);
EXPECT_CALL(*audio_input_listener_,
Closed(content::MEDIA_DEVICE_AUDIO_CAPTURE, session_id))
.Times(1);
message_loop_->RunAllPending();
}
} // namespace media_stream