12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 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 <CoreAudio/AudioHardware.h> 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind_helpers.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/scoped_ptr.h" 10ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/mac/audio_device_listener_mac.h" 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "media/base/bind_to_current_loop.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)namespace media { 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class AudioDeviceListenerMacTest : public testing::Test { 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AudioDeviceListenerMacTest() { 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // It's important to create the device listener from the message loop in 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // order to ensure we don't end up with unbalanced TaskObserver calls. 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message_loop_.PostTask(FROM_HERE, base::Bind( 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &AudioDeviceListenerMacTest::CreateDeviceListener, 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Unretained(this))); 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message_loop_.RunUntilIdle(); 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual ~AudioDeviceListenerMacTest() { 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // It's important to destroy the device listener from the message loop in 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // order to ensure we don't end up with unbalanced TaskObserver calls. 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message_loop_.PostTask(FROM_HERE, base::Bind( 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &AudioDeviceListenerMacTest::DestroyDeviceListener, 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Unretained(this))); 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message_loop_.RunUntilIdle(); 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void CreateDeviceListener() { 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Force a post task using BindToCurrentLoop() to ensure device listener 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // internals are working correctly. 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) output_device_listener_.reset(new AudioDeviceListenerMac(BindToCurrentLoop( 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&AudioDeviceListenerMacTest::OnDeviceChange, 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Unretained(this))))); 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void DestroyDeviceListener() { 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) output_device_listener_.reset(); 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool ListenerIsValid() { 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return !output_device_listener_->listener_cb_.is_null(); 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Simulate a device change where no output devices are available. 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool SimulateDefaultOutputDeviceChange() { 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Include multiple addresses to ensure only a single device change event 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // occurs. 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const AudioObjectPropertyAddress addresses[] = { 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AudioDeviceListenerMac::kDeviceChangePropertyAddress, 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) { kAudioHardwarePropertyDevices, 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kAudioObjectPropertyScopeGlobal, 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kAudioObjectPropertyElementMaster } 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }; 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return noErr == output_device_listener_->OnDefaultDeviceChanged( 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kAudioObjectSystemObject, 1, addresses, output_device_listener_.get()); 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MOCK_METHOD0(OnDeviceChange, void()); 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) protected: 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::MessageLoop message_loop_; 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<AudioDeviceListenerMac> output_device_listener_; 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(AudioDeviceListenerMacTest); 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Simulate a device change events and ensure we get the right callbacks. 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(AudioDeviceListenerMacTest, OutputDeviceChange) { 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(ListenerIsValid()); 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_CALL(*this, OnDeviceChange()).Times(1); 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(SimulateDefaultOutputDeviceChange()); 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message_loop_.RunUntilIdle(); 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace media 87