audio_device_listener_mac_unittest.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1// Copyright (c) 2013 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 <CoreAudio/AudioHardware.h>
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/message_loop/message_loop.h"
11#include "media/audio/mac/audio_device_listener_mac.h"
12#include "media/base/bind_to_current_loop.h"
13#include "testing/gmock/include/gmock/gmock.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16namespace media {
17
18class AudioDeviceListenerMacTest : public testing::Test {
19 public:
20  AudioDeviceListenerMacTest() {
21    // It's important to create the device listener from the message loop in
22    // order to ensure we don't end up with unbalanced TaskObserver calls.
23    message_loop_.PostTask(FROM_HERE, base::Bind(
24        &AudioDeviceListenerMacTest::CreateDeviceListener,
25        base::Unretained(this)));
26    message_loop_.RunUntilIdle();
27  }
28
29  virtual ~AudioDeviceListenerMacTest() {
30    // It's important to destroy the device listener from the message loop in
31    // order to ensure we don't end up with unbalanced TaskObserver calls.
32    message_loop_.PostTask(FROM_HERE, base::Bind(
33        &AudioDeviceListenerMacTest::DestroyDeviceListener,
34        base::Unretained(this)));
35    message_loop_.RunUntilIdle();
36  }
37
38  void CreateDeviceListener() {
39    // Force a post task using BindToCurrentLoop() to ensure device listener
40    // internals are working correctly.
41    output_device_listener_.reset(new AudioDeviceListenerMac(BindToCurrentLoop(
42        base::Bind(&AudioDeviceListenerMacTest::OnDeviceChange,
43                   base::Unretained(this)))));
44  }
45
46  void DestroyDeviceListener() {
47    output_device_listener_.reset();
48  }
49
50  bool ListenerIsValid() {
51    return !output_device_listener_->listener_cb_.is_null();
52  }
53
54  // Simulate a device change where no output devices are available.
55  bool SimulateDefaultOutputDeviceChange() {
56    // Include multiple addresses to ensure only a single device change event
57    // occurs.
58    const AudioObjectPropertyAddress addresses[] = {
59      AudioDeviceListenerMac::kDeviceChangePropertyAddress,
60      { kAudioHardwarePropertyDevices,
61        kAudioObjectPropertyScopeGlobal,
62        kAudioObjectPropertyElementMaster }
63    };
64
65    return noErr == output_device_listener_->OnDefaultDeviceChanged(
66        kAudioObjectSystemObject, 1, addresses, output_device_listener_.get());
67  }
68
69  MOCK_METHOD0(OnDeviceChange, void());
70
71 protected:
72  base::MessageLoop message_loop_;
73  scoped_ptr<AudioDeviceListenerMac> output_device_listener_;
74
75  DISALLOW_COPY_AND_ASSIGN(AudioDeviceListenerMacTest);
76};
77
78// Simulate a device change events and ensure we get the right callbacks.
79TEST_F(AudioDeviceListenerMacTest, OutputDeviceChange) {
80  ASSERT_TRUE(ListenerIsValid());
81  EXPECT_CALL(*this, OnDeviceChange()).Times(1);
82  ASSERT_TRUE(SimulateDefaultOutputDeviceChange());
83  message_loop_.RunUntilIdle();
84}
85
86}  // namespace media
87