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_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 BindToLoop to ensure device listener internals 40 // are working correctly. 41 output_device_listener_.reset(new AudioDeviceListenerMac(BindToLoop( 42 message_loop_.message_loop_proxy(), base::Bind( 43 &AudioDeviceListenerMacTest::OnDeviceChange, 44 base::Unretained(this))))); 45 } 46 47 void DestroyDeviceListener() { 48 output_device_listener_.reset(); 49 } 50 51 bool ListenerIsValid() { 52 return !output_device_listener_->listener_cb_.is_null(); 53 } 54 55 // Simulate a device change where no output devices are available. 56 bool SimulateDefaultOutputDeviceChange() { 57 // Include multiple addresses to ensure only a single device change event 58 // occurs. 59 const AudioObjectPropertyAddress addresses[] = { 60 AudioDeviceListenerMac::kDeviceChangePropertyAddress, 61 { kAudioHardwarePropertyDevices, 62 kAudioObjectPropertyScopeGlobal, 63 kAudioObjectPropertyElementMaster } 64 }; 65 66 return noErr == output_device_listener_->OnDefaultDeviceChanged( 67 kAudioObjectSystemObject, 1, addresses, output_device_listener_.get()); 68 } 69 70 MOCK_METHOD0(OnDeviceChange, void()); 71 72 protected: 73 base::MessageLoop message_loop_; 74 scoped_ptr<AudioDeviceListenerMac> output_device_listener_; 75 76 DISALLOW_COPY_AND_ASSIGN(AudioDeviceListenerMacTest); 77}; 78 79// Simulate a device change events and ensure we get the right callbacks. 80TEST_F(AudioDeviceListenerMacTest, OutputDeviceChange) { 81 ASSERT_TRUE(ListenerIsValid()); 82 EXPECT_CALL(*this, OnDeviceChange()).Times(1); 83 ASSERT_TRUE(SimulateDefaultOutputDeviceChange()); 84 message_loop_.RunUntilIdle(); 85} 86 87} // namespace media 88