Home | History | Annotate | Download | only in mac
      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 
     16 namespace media {
     17 
     18 class 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.
     79 TEST_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