1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133

media / audio / mac / audio_device_listener_mac.h [blame]

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_AUDIO_MAC_AUDIO_DEVICE_LISTENER_MAC_H_
#define MEDIA_AUDIO_MAC_AUDIO_DEVICE_LISTENER_MAC_H_

#include <CoreAudio/AudioHardware.h>

#include <map>
#include <memory>
#include <optional>
#include <utility>

#include "base/containers/flat_map.h"
#include "base/functional/callback.h"
#include "base/threading/thread_checker.h"
#include "media/base/media_export.h"

namespace media {

// AudioDeviceListenerMac facilitates execution of device listener callbacks
// issued via CoreAudio.
class MEDIA_EXPORT AudioDeviceListenerMac {
 public:
  // |listener_cb| will be called when a device change occurs; it's a permanent
  // callback and must outlive AudioDeviceListenerMac.  Note that |listener_cb|
  // might not be executed on the same thread as construction.
  static std::unique_ptr<AudioDeviceListenerMac> Create(
      base::RepeatingClosure listener_cb,
      bool monitor_output_sample_rate_changes,
      bool monitor_default_input,
      bool monitor_addition_removal,
      bool monitor_sources);

  AudioDeviceListenerMac(const AudioDeviceListenerMac&) = delete;
  AudioDeviceListenerMac& operator=(const AudioDeviceListenerMac&) = delete;

  // Virtual for overriding in tests.
  virtual ~AudioDeviceListenerMac();

 private:
  friend class AudioDeviceListenerMacTest;
  friend class AudioDeviceListenerMacUnderTest;
  class PropertyListener;

  struct PropertyListenerDeleter {
    void operator()(PropertyListener* listener);
  };

  using PropertyListenerPtr =
      std::unique_ptr<PropertyListener, PropertyListenerDeleter>;

  static const AudioObjectPropertyAddress
      kDefaultOutputDeviceChangePropertyAddress;
  static const AudioObjectPropertyAddress
      kDefaultInputDeviceChangePropertyAddress;
  static const AudioObjectPropertyAddress kDevicesPropertyAddress;
  static const AudioObjectPropertyAddress kPropertyOutputSampleRateChanged;
  static const AudioObjectPropertyAddress kPropertyOutputSourceChanged;
  static const AudioObjectPropertyAddress kPropertyInputSourceChanged;

  AudioDeviceListenerMac(base::RepeatingClosure listener_cb,
                         bool monitor_output_sample_rate_changes,
                         bool monitor_default_input,
                         bool monitor_addition_removal,
                         bool monitor_sources);

  // Must be called only once after constructor.
  void CreatePropertyListeners();

  void RunCallback();
  void UpdateDevicePropertyListeners();
  void OnDevicesAddedOrRemoved();
  void UpdateSourceListeners(const std::vector<AudioObjectID>& device_ids);
  void UpdateOutputSampleRateListeners(
      const std::vector<AudioObjectID>& device_ids);

  PropertyListenerPtr CreatePropertyListener(
      AudioObjectID monitored_object,
      const AudioObjectPropertyAddress* property,
      base::RepeatingClosure listener_cb);

  // Virtual for testing.
  virtual std::vector<AudioObjectID> GetAllAudioDeviceIDs();
  virtual bool IsOutputDevice(AudioObjectID id);
  virtual std::optional<uint32_t> GetDeviceSource(AudioObjectID device_id,
                                                  bool is_input);
  virtual OSStatus AddPropertyListener(
      AudioObjectID inObjectID,
      const AudioObjectPropertyAddress* inAddress,
      AudioObjectPropertyListenerProc inListener,
      void* inClientData);
  virtual OSStatus RemovePropertyListener(
      AudioObjectID inObjectID,
      const AudioObjectPropertyAddress* inAddress,
      AudioObjectPropertyListenerProc inListener,
      void* inClientData);

  std::vector<void*> GetPropertyListenersForTesting() const;

  static OSStatus SimulateEventForTesting(
      AudioObjectID object,
      UInt32 num_addresses,
      const AudioObjectPropertyAddress addresses[],
      void* context);

  const base::RepeatingClosure listener_cb_;
  PropertyListenerPtr default_output_listener_;

  const bool monitor_default_input_;
  PropertyListenerPtr default_input_listener_;

  const bool monitor_addition_removal_;
  PropertyListenerPtr addition_removal_listener_;

  const bool monitor_output_sample_rate_changes_;
  using OutputSampleRateListenerMap =
      base::flat_map<AudioObjectID, PropertyListenerPtr>;
  OutputSampleRateListenerMap output_sample_rate_listeners_;

  const bool monitor_sources_;
  using SourceListenerKey = std::pair<AudioObjectID, bool>;
  using SourceListenerMap =
      base::flat_map<SourceListenerKey, PropertyListenerPtr>;
  SourceListenerMap source_listeners_;

  THREAD_CHECKER(thread_checker_);
};

}  // namespace media

#endif  // MEDIA_AUDIO_MAC_AUDIO_DEVICE_LISTENER_MAC_H_