xref: /aosp_15_r20/external/webrtc/modules/audio_device/win/core_audio_base_win.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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