1 /* 2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef MODULES_AUDIO_DEVICE_WIN_CORE_AUDIO_BASE_WIN_H_ 12 #define MODULES_AUDIO_DEVICE_WIN_CORE_AUDIO_BASE_WIN_H_ 13 14 #include <atomic> 15 #include <functional> 16 #include <memory> 17 #include <string> 18 19 #include "absl/strings/string_view.h" 20 #include "absl/types/optional.h" 21 #include "api/sequence_checker.h" 22 #include "modules/audio_device/win/core_audio_utility_win.h" 23 #include "rtc_base/platform_thread.h" 24 25 namespace webrtc { 26 27 class AudioDeviceBuffer; 28 class FineAudioBuffer; 29 30 namespace webrtc_win { 31 32 // Serves as base class for CoreAudioInput and CoreAudioOutput and supports 33 // device handling and audio streaming where the direction (input or output) 34 // is set at constructions by the parent. 35 // The IAudioSessionEvents interface provides notifications of session-related 36 // events such as changes in the volume level, display name, and session state. 37 // This class does not use the default ref-counting memory management method 38 // provided by IUnknown: calling CoreAudioBase::Release() will not delete the 39 // object. The client will receive notification from the session manager on 40 // a separate thread owned and controlled by the manager. 41 // TODO(henrika): investigate if CoreAudioBase should implement 42 // IMMNotificationClient as well (might improve support for device changes). 43 class CoreAudioBase : public IAudioSessionEvents { 44 public: 45 enum class Direction { 46 kInput, 47 kOutput, 48 }; 49 50 // TODO(henrika): add more error types. 51 enum class ErrorType { 52 kStreamDisconnected, 53 }; 54 55 template <typename T> 56 auto as_integer(T const value) -> typename std::underlying_type<T>::type { 57 return static_cast<typename std::underlying_type<T>::type>(value); 58 } 59 60 // Callback definition for notifications of new audio data. For input clients, 61 // it means that "new audio data has now been captured", and for output 62 // clients, "the output layer now needs new audio data". 63 typedef std::function<bool(uint64_t device_frequency)> OnDataCallback; 64 65 // Callback definition for notifications of run-time error messages. It can 66 // be called e.g. when an active audio device is removed and an audio stream 67 // is disconnected (`error` is then set to kStreamDisconnected). Both input 68 // and output clients implements OnErrorCallback() and will trigger an 69 // internal restart sequence for kStreamDisconnected. 70 // This method is currently always called on the audio thread. 71 // TODO(henrika): add support for more error types. 72 typedef std::function<bool(ErrorType error)> OnErrorCallback; 73 74 void ThreadRun(); 75 76 CoreAudioBase(const CoreAudioBase&) = delete; 77 CoreAudioBase& operator=(const CoreAudioBase&) = delete; 78 79 protected: 80 explicit CoreAudioBase(Direction direction, 81 bool automatic_restart, 82 OnDataCallback data_callback, 83 OnErrorCallback error_callback); 84 ~CoreAudioBase(); 85 86 std::string GetDeviceID(int index) const; 87 int SetDevice(int index); 88 int DeviceName(int index, std::string* name, std::string* guid) const; 89 90 // Checks if the current device ID is no longer in use (e.g. due to a 91 // disconnected stream), and if so, switches device to the default audio 92 // device. Called on the audio thread during restart attempts. 93 bool SwitchDeviceIfNeeded(); 94 95 bool Init(); 96 bool Start(); 97 bool Stop(); 98 bool IsVolumeControlAvailable(bool* available) const; 99 bool Restart(); 100 direction()101 Direction direction() const { return direction_; } automatic_restart()102 bool automatic_restart() const { return automatic_restart_; } 103 104 // Releases all allocated COM resources in the base class. 105 void ReleaseCOMObjects(); 106 107 // Returns number of active devices given the specified `direction_` set 108 // by the parent (input or output). 109 int NumberOfActiveDevices() const; 110 111 // Returns total number of enumerated audio devices which is the sum of all 112 // active devices plus two extra (one default and one default 113 // communications). The value in `direction_` determines if capture or 114 // render devices are counted. 115 int NumberOfEnumeratedDevices() const; 116 117 bool IsInput() const; 118 bool IsOutput() const; 119 bool IsDefaultDevice(int index) const; 120 bool IsDefaultCommunicationsDevice(int index) const; 121 bool IsDefaultDeviceId(absl::string_view device_id) const; 122 bool IsDefaultCommunicationsDeviceId(absl::string_view device_id) const; 123 EDataFlow GetDataFlow() const; 124 bool IsRestarting() const; 125 int64_t TimeSinceStart() const; 126 127 // TODO(henrika): is the existing thread checker in WindowsAudioDeviceModule 128 // sufficient? As is, we have one top-level protection and then a second 129 // level here. In addition, calls to Init(), Start() and Stop() are not 130 // included to allow for support of internal restart (where these methods are 131 // called on the audio thread). 132 SequenceChecker thread_checker_; 133 SequenceChecker thread_checker_audio_; 134 AudioDeviceBuffer* audio_device_buffer_ = nullptr; 135 bool initialized_ = false; 136 WAVEFORMATEXTENSIBLE format_ = {}; 137 uint32_t endpoint_buffer_size_frames_ = 0; 138 Microsoft::WRL::ComPtr<IAudioClock> audio_clock_; 139 Microsoft::WRL::ComPtr<IAudioClient> audio_client_; 140 bool is_active_ = false; 141 int64_t num_data_callbacks_ = 0; 142 int latency_ms_ = 0; 143 absl::optional<uint32_t> sample_rate_; 144 145 private: 146 const Direction direction_; 147 const bool automatic_restart_; 148 const OnDataCallback on_data_callback_; 149 const OnErrorCallback on_error_callback_; 150 ScopedHandle audio_samples_event_; 151 ScopedHandle stop_event_; 152 ScopedHandle restart_event_; 153 int64_t start_time_ = 0; 154 std::string device_id_; 155 int device_index_ = -1; 156 // Used by the IAudioSessionEvents implementations. Currently only utilized 157 // for debugging purposes. 158 LONG ref_count_ = 1; 159 // Set when restart process starts and cleared when restart stops 160 // successfully. Accessed atomically. 161 std::atomic<bool> is_restarting_; 162 rtc::PlatformThread audio_thread_; 163 Microsoft::WRL::ComPtr<IAudioSessionControl> audio_session_control_; 164 165 void StopThread(); 166 AudioSessionState GetAudioSessionState() const; 167 168 // Called on the audio thread when a restart event has been set. 169 // It will then trigger calls to the installed error callbacks with error 170 // type set to kStreamDisconnected. 171 bool HandleRestartEvent(); 172 173 // IUnknown (required by IAudioSessionEvents and IMMNotificationClient). 174 ULONG __stdcall AddRef() override; 175 ULONG __stdcall Release() override; 176 HRESULT __stdcall QueryInterface(REFIID iid, void** object) override; 177 178 // IAudioSessionEvents implementation. 179 // These methods are called on separate threads owned by the session manager. 180 // More than one thread can be involved depending on the type of callback 181 // and audio session. 182 HRESULT __stdcall OnStateChanged(AudioSessionState new_state) override; 183 HRESULT __stdcall OnSessionDisconnected( 184 AudioSessionDisconnectReason disconnect_reason) override; 185 HRESULT __stdcall OnDisplayNameChanged(LPCWSTR new_display_name, 186 LPCGUID event_context) override; 187 HRESULT __stdcall OnIconPathChanged(LPCWSTR new_icon_path, 188 LPCGUID event_context) override; 189 HRESULT __stdcall OnSimpleVolumeChanged(float new_simple_volume, 190 BOOL new_mute, 191 LPCGUID event_context) override; 192 HRESULT __stdcall OnChannelVolumeChanged(DWORD channel_count, 193 float new_channel_volumes[], 194 DWORD changed_channel, 195 LPCGUID event_context) override; 196 HRESULT __stdcall OnGroupingParamChanged(LPCGUID new_grouping_param, 197 LPCGUID event_context) override; 198 }; 199 200 } // namespace webrtc_win 201 } // namespace webrtc 202 203 #endif // MODULES_AUDIO_DEVICE_WIN_CORE_AUDIO_BASE_WIN_H_ 204