146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <CoreAudio/AudioHardware.h> 6f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 7116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/bind.h" 8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/bind_helpers.h" 9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/memory/scoped_ptr.h" 10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/message_loop/message_loop.h" 11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/audio/mac/audio_device_listener_mac.h" 12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/base/bind_to_current_loop.h" 13116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "testing/gmock/include/gmock/gmock.h" 14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "testing/gtest/include/gtest/gtest.h" 15116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 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